[balsa] Implement QUOTA, MYRIGHTS and GETACL commands.
- From: Pawel Salek <pawels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [balsa] Implement QUOTA, MYRIGHTS and GETACL commands.
- Date: Wed, 17 Feb 2010 23:04:21 +0000 (UTC)
commit 55aa6c02ca6a92156203dcdef4e025c6f9df458f
Author: Pawel Salek <pawsa damage localdomain>
Date: Thu Feb 18 00:04:03 2010 +0100
Implement QUOTA, MYRIGHTS and GETACL commands.
* libbalsa/imap/imap-commands.c: implement QUOTA, MYRIGHTS and GETACL commands.
* libbalsa/imap/imap-handle.h: register QUOTA capability.
* libbalsa/imap/imap_private.h: add private fields and enums related to
these extensions.
* libbalsa/mailbox_imap.[ch]: interface them.
* src/folder-conf.c: use them.
ChangeLog | 10 ++
libbalsa/imap/imap-commands.c | 98 ++++++++++++++++++-
libbalsa/imap/imap-commands.h | 11 ++
libbalsa/imap/imap-handle.c | 221 ++++++++++++++++++++++++++++++++++++++++-
libbalsa/imap/imap-handle.h | 1 +
libbalsa/imap/imap_private.h | 10 ++
libbalsa/imap/libimap.h | 26 +++++
libbalsa/mailbox_imap.c | 72 +++++++++++++
libbalsa/mailbox_imap.h | 6 +
src/folder-conf.c | 85 +++++++++++++++-
10 files changed, 533 insertions(+), 7 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 9a66b47..def9198 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2010-02-17 Albrecht DreÃ?
+
+ * libbalsa/imap/imap-commands.c: implement QUOTA, MYRIGHTS and GETACL
+ commands.
+ * libbalsa/imap/imap-handle.h: register QUOTA capability.
+ * libbalsa/imap/imap_private.h: add private fields and enums
+ related to these extensions.
+ * libbalsa/mailbox_imap.[ch]: interface them.
+ * src/folder-conf.c: use them.
+
2010-02-16 Albrecht DreÃ?
* libbalsa/information.c: build when libnotify is not available.
diff --git a/libbalsa/imap/imap-commands.c b/libbalsa/imap/imap-commands.c
index f8a4f52..4f628a3 100644
--- a/libbalsa/imap/imap-commands.c
+++ b/libbalsa/imap/imap-commands.c
@@ -198,6 +198,7 @@ imap_mbox_select_unlocked(ImapMboxHandle* handle, const char *mbox,
imap_mbox_resize_cache(handle, 0);
mbox_view_dispose(&handle->mbox_view);
handle->unseen = 0;
+ handle->has_rights = 0;
mbx7 = imap_utf8_to_mailbox(mbox);
@@ -211,8 +212,14 @@ imap_mbox_select_unlocked(ImapMboxHandle* handle, const char *mbox,
handle->mbox = g_strdup(mbox);
}
handle->state = IMHS_SELECTED;
- if(readonly_mbox)
+ if(readonly_mbox) {
+ /* FIXME - issue MYRIGHTS in the same packet as SELECT */
+ ImapResponse myrights_rc =
+ imap_mbox_fetch_my_rights_unlocked(handle);
*readonly_mbox = handle->readonly_mbox;
+ if (myrights_rc != IMR_OK && myrights_rc != IMR_NO)
+ rc = myrights_rc; /* Bad things happened, report it. */
+ }
} else { /* remove even traces of untagged responses */
imap_mbox_resize_cache(handle, 0);
mbox_view_dispose(&handle->mbox_view);
@@ -248,6 +255,7 @@ imap_mbox_examine(ImapMboxHandle* handle, const char* mbox)
g_free(handle->mbox);
handle->mbox = g_strdup(mbox);
handle->state = IMHS_SELECTED;
+ handle->has_rights = 0;
}
return rc;
}
@@ -699,7 +707,7 @@ imap_mbox_expunge(ImapMboxHandle *handle)
{
ImapResponse rc;
- IMAP_REQUIRED_STATE2(handle,IMHS_AUTHENTICATED, IMHS_SELECTED, IMR_BAD);
+ IMAP_REQUIRED_STATE1(handle, IMHS_SELECTED, IMR_BAD);
HANDLE_LOCK(handle);
rc = imap_cmd_exec(handle, "EXPUNGE");
HANDLE_UNLOCK(handle);
@@ -710,7 +718,7 @@ ImapResponse
imap_mbox_expunge_a(ImapMboxHandle *handle)
{
ImapResponse rc;
- IMAP_REQUIRED_STATE2(handle,IMHS_AUTHENTICATED, IMHS_SELECTED, IMR_BAD);
+ IMAP_REQUIRED_STATE1(handle, IMHS_SELECTED, IMR_BAD);
/* extra care would be required to use this once since no other
commands that use sequence numbers can be issued before this one
finishes... */
@@ -2048,3 +2056,87 @@ imap_mbox_complete_msgids(ImapMboxHandle *h,
}
return rc;
}
+
+/* RFC 2087, sect. 4.3: GETQUOTAROOT */
+ImapResponse
+imap_mbox_get_quota(ImapMboxHandle* handle, const char* mbox,
+ gulong* max, gulong* used)
+{
+ if (!imap_mbox_handle_can_do(handle, IMCAP_QUOTA))
+ return IMR_NO;
+ IMAP_REQUIRED_STATE2(handle, IMHS_AUTHENTICATED, IMHS_SELECTED, IMR_BAD);
+ {
+ gchar *mbx7 = imap_utf8_to_mailbox(mbox);
+ gchar* cmd = g_strdup_printf("GETQUOTAROOT \"%s\"", mbx7);
+ ImapResponse rc;
+
+ HANDLE_LOCK(handle);
+ rc = imap_cmd_exec(handle, cmd);
+ g_free(mbx7); g_free(cmd);
+ *max = handle->quota_max_k;
+ *used = handle->quota_used_k;
+ HANDLE_UNLOCK(handle);
+ return rc;
+ }
+}
+
+ImapResponse
+imap_mbox_fetch_my_rights_unlocked(ImapMboxHandle* handle)
+{
+ if (imap_mbox_handle_can_do(handle, IMCAP_ACL)) {
+ gchar *mbx7 = imap_utf8_to_mailbox(handle->mbox);
+ gchar* cmd = g_strdup_printf("MYRIGHTS \"%s\"", mbx7);
+ ImapResponse rc = imap_cmd_exec(handle, cmd);
+ g_free(mbx7); g_free(cmd);
+ return rc;
+ } else {
+ return IMR_NO;
+ }
+}
+
+/** get myrights for the currently selected mailbox.
+ RFC 4314, sect. 3.5: MYRIGHTS */
+ImapResponse
+imap_mbox_get_my_rights(ImapMboxHandle* handle, ImapAclType* my_rights,
+ gboolean force_update)
+{
+ ImapResponse rc;
+
+ IMAP_REQUIRED_STATE1(handle, IMHS_SELECTED, IMR_BAD);
+
+ HANDLE_LOCK(handle);
+ if (force_update || !handle->has_rights) {
+ rc = imap_mbox_fetch_my_rights_unlocked(handle);
+ } else {
+ rc = IMR_OK;
+ }
+
+ *my_rights = handle->rights;
+
+ HANDLE_UNLOCK(handle);
+ return rc;
+}
+
+/* RFC 4314, sect. 3.3: GETACL */
+ImapResponse
+imap_mbox_get_acl(ImapMboxHandle* handle, const char* mbox, GList** acls)
+{
+ if (!imap_mbox_handle_can_do(handle, IMCAP_ACL))
+ return IMR_NO;
+ IMAP_REQUIRED_STATE2(handle, IMHS_AUTHENTICATED, IMHS_SELECTED, IMR_BAD);
+ {
+ gchar *mbx7 = imap_utf8_to_mailbox(mbox);
+ gchar* cmd = g_strdup_printf("GETACL \"%s\"", mbx7);
+ ImapResponse rc;
+
+ HANDLE_LOCK(handle);
+ rc = imap_cmd_exec(handle, cmd);
+ g_free(mbx7); g_free(cmd);
+ g_list_foreach(*acls, (GFunc)imap_user_acl_free, NULL);
+ g_list_free(*acls);
+ *acls = handle->acls;
+ handle->acls = NULL;
+ HANDLE_UNLOCK(handle);
+ return rc;
+ }
+}
diff --git a/libbalsa/imap/imap-commands.h b/libbalsa/imap/imap-commands.h
index 3c719f4..138bca3 100644
--- a/libbalsa/imap/imap-commands.h
+++ b/libbalsa/imap/imap-commands.h
@@ -160,4 +160,15 @@ ImapResponse imap_mbox_complete_msgids(ImapMboxHandle *handle,
GPtrArray *msgids,
unsigned first_seqno_to_fetch);
+/* RFC 2087: Quota */
+ImapResponse imap_mbox_get_quota(ImapMboxHandle* handle, const char* mbox,
+ gulong* max, gulong* used);
+
+/* RFC 4314: ACL's */
+ImapResponse imap_mbox_get_my_rights(ImapMboxHandle* handle,
+ ImapAclType* my_rights,
+ gboolean force_update);
+ImapResponse imap_mbox_get_acl(ImapMboxHandle* handle, const char* mbox,
+ GList** acls);
+
#endif /* __IMAP_COMMANDS_H__ */
diff --git a/libbalsa/imap/imap-handle.c b/libbalsa/imap/imap-handle.c
index 1202a60..a4fffc8 100644
--- a/libbalsa/imap/imap-handle.c
+++ b/libbalsa/imap/imap-handle.c
@@ -165,6 +165,8 @@ imap_mbox_handle_init(ImapMboxHandle *handle)
handle->enable_client_sort = 0;
handle->enable_binary = 0;
handle->enable_idle = 1;
+
+ handle->has_rights = 0;
mbox_view_init(&handle->mbox_view);
#if defined(BALSA_USE_THREADS)
@@ -1018,6 +1020,9 @@ imap_mbox_handle_finalize(GObject* gobject)
imap_mbox_resize_cache(handle, 0);
g_free(handle->msg_cache); handle->msg_cache = NULL;
g_array_free(handle->flag_cache, TRUE);
+ g_list_foreach(handle->acls, (GFunc)imap_user_acl_free, NULL);
+ g_list_free(handle->acls);
+ g_free(handle->quota_root);
HANDLE_UNLOCK(handle);
#if defined(BALSA_USE_THREADS)
@@ -2307,7 +2312,7 @@ ir_capability_data(ImapMboxHandle *handle)
"ACL", "BINARY", "CHILDREN",
"COMPRESS=DEFLATE",
"ESEARCH", "IDLE", "LITERAL+",
- "LOGINDISABLED", "MULTIAPPEND", "NAMESPACE", "SASL-IR",
+ "LOGINDISABLED", "MULTIAPPEND", "NAMESPACE", "QUOTA", "SASL-IR",
"SCAN", "STARTTLS",
"SORT", "THREAD=ORDEREDSUBJECT", "THREAD=REFERENCES",
"UIDPLUS", "UNSELECT"
@@ -2884,6 +2889,214 @@ ir_msg_att_flags(ImapMboxHandle *h, int c, unsigned seqno)
return IMR_OK;
}
+/* RFC 2087, sect. 5.2: "<mailbox> [<quota root> [<quota root> ...}}" */
+static ImapResponse
+ir_quotaroot(ImapMboxHandle *h)
+{
+ int eol;
+ char *mbox;
+ ImapResponse retval = IMR_NO;
+ char *mbx7 = imap_utf8_to_mailbox(h->mbox);
+
+ free(h->quota_root);
+ h->quota_root = NULL;
+
+ /* get the mailbox and the first quota root */
+ mbox = imap_get_astring(h->sio, &eol);
+ if (mbox) {
+ if (strcmp(mbox, mbx7))
+ fprintf(stderr, "expected QUOTAROOT for %s, not for %s\n", mbx7, mbox);
+ else {
+ if (eol == ' ')
+ h->quota_root = imap_get_astring(h->sio, &eol);
+ if (eol != '\n')
+ EAT_LINE(h, eol);
+ retval = IMR_OK;
+ }
+ }
+ free(mbx7);
+ free(mbox);
+ return retval;
+}
+
+/* RFC 2087, sect. 5.1: "<mailbox> [<resource> [<resource> ...}}" */
+static ImapResponse
+ir_quota(ImapMboxHandle *h)
+{
+ int c;
+ char *root;
+ ImapResponse retval = IMR_NO;
+
+ /* get the root */
+ root = imap_get_astring(h->sio, &c);
+ h->quota_max_k = h->quota_used_k = 0;
+ if (root) {
+ if (strcmp(root, h->quota_root))
+ fprintf(stderr, "expected QUOTA for %s, not for %s\n", h->quota_root,
+ root);
+ else {
+ while ((c = sio_getc(h->sio)) != -1 && c == ' ');
+ if (c == '(') {
+ do {
+ char resource[32];
+ char usage[16];
+ char limit[16];
+
+ c = imap_get_atom(h->sio, resource, 32);
+ if (c == ' ') {
+ imap_get_atom(h->sio, usage, 16);
+ c = imap_get_atom(h->sio, limit, 16);
+
+ /* ignore other limits than 'STORAGE' */
+ if (!strcmp(resource, "STORAGE")) {
+ char *endptr1;
+ char *endptr2;
+
+ h->quota_used_k = strtoul(usage, &endptr1, 10);
+ h->quota_max_k = strtoul(limit, &endptr2, 10);
+ if (*endptr1 != '\0' || *endptr2 != '\0') {
+ fprintf(stderr, "bad QUOTA '%s %s %s'\n", resource, usage,
+ limit);
+ h->quota_max_k = h->quota_used_k = 0;
+ c = ')';
+ } else
+ retval = IMR_OK;
+ }
+ }
+ } while (c != ')');
+ }
+ EAT_LINE(h, c);
+ }
+ }
+
+ free(root);
+ return retval;
+}
+
+/** \brief Interpret a RFC 4314 ACL
+ *
+ * \param h IMAP mailbox handle
+ * \param eject a string containing all characters which shall terminate
+ * scanning the ACL
+ * \param acl filled with the extracted ACL's, or IMAP_ACL_NONE on error
+ * \param eol if not NULL, filled with 1 or 0 to indicate if the end of line
+ * has been reached
+ * \return IMAP response code
+ *
+ * Scan h's input stream for valid ACL flags (lrswipkxtea). Note that 'c', 'd'
+ * and cr are ignored according to RFC 4314, sect. 2.1.1.
+ */
+static ImapResponse
+extract_acl(ImapMboxHandle *h, const char *eject, ImapAclType *acl, int *eol)
+{
+ static const char* rights = "lrswipkxtea";
+ static const char* ignore = "cd\r";
+ int c;
+ char* p;
+
+ *acl = IMAP_ACL_NONE;
+ while ((c = sio_getc(h->sio)) != -1 && !strchr(eject, c)) {
+ if ((p = strchr(rights, c))) {
+ *acl |= 1 << (p - rights);
+ } else if (!strchr(ignore, c)) {
+ EAT_LINE(h, c);
+ if (eol)
+ *eol = TRUE;
+ return IMR_NO;
+ }
+ }
+ if (eol)
+ *eol = (c == '\n');
+ return IMR_OK;
+}
+
+/* RFC 4314, sect. 3.8: "<mailbox> <rights>" */
+static ImapResponse
+ir_myrights(ImapMboxHandle *h)
+{
+ int eol;
+ char *mbox;
+ ImapResponse retval = IMR_NO;
+ char *mbx7 = imap_utf8_to_mailbox(h->mbox);
+
+ mbox = imap_get_astring(h->sio, &eol);
+ if (mbox && eol == ' ') {
+ if (strcmp(mbox, mbx7))
+ fprintf(stderr, "expected MYRIGHTS for %s, not for %s\n", mbx7, mbox);
+ else
+ retval = extract_acl(h, "\n", &h->rights, NULL);
+ }
+ free(mbx7);
+ free(mbox);
+ return retval;
+}
+
+/* helper: free an ImapUserAclType */
+void
+imap_user_acl_free(ImapUserAclType *acl)
+{
+ if (acl)
+ g_free(acl->uid);
+ g_free(acl);
+}
+
+/* RFC 4314, sect. 3.6: "<mailbox> [[<uid> <rights>] <uid> <rights> ...]" */
+static ImapResponse
+ir_getacl(ImapMboxHandle *h)
+{
+ char *mbox;
+ char *mbx7;
+ ImapResponse retval;
+ int eol;
+
+ g_list_foreach(h->acls, (GFunc)imap_user_acl_free, NULL);
+ g_list_free(h->acls);
+ h->acls = NULL;
+
+ mbox = imap_get_astring(h->sio, &eol);
+ if (!mbox)
+ return IMR_NO;
+
+ mbx7 = imap_utf8_to_mailbox(h->mbox);
+ if (strcmp(mbox, mbx7)) {
+ fprintf(stderr, "expected ACL for %s, not for %s\n", mbx7, mbox);
+ retval = IMR_NO;
+ } else if (eol == '\n') {
+ retval = IMR_OK;
+ } else {
+ int c;
+ GString *uid;
+
+ retval = IMR_OK;
+ do {
+ ImapAclType acl_flags;
+ ImapUserAclType *acl;
+
+ uid = g_string_new("");
+ while ((c = sio_getc(h->sio)) != -1 && c != '\n' && c != ' ')
+ uid = g_string_append_c(uid, c);
+ if (c != ' ') {
+ g_string_free(uid, TRUE);
+ EAT_LINE(h, c);
+ retval = IMR_NO;
+ } else {
+ if (extract_acl(h, " \n", &acl_flags, &eol) != IMR_OK) {
+ g_string_free(uid, TRUE);
+ retval = IMR_NO;
+ } else {
+ acl = g_new(ImapUserAclType, 1);
+ acl->uid = g_string_free(uid, FALSE);
+ acl->acl = acl_flags;
+ h->acls = g_list_append(h->acls, acl);
+ }
+ }
+ } while (retval == IMR_OK && !eol);
+ }
+ free(mbox);
+ free(mbx7);
+ return retval;
+}
+
ImapAddress*
imap_address_new(gchar *name, gchar *addr_spec)
{
@@ -4064,7 +4277,11 @@ static const struct {
{ "SORT", 4, ir_sort },
{ "THREAD", 6, ir_thread },
{ "FLAGS", 5, ir_flags },
- { "FETCH", 5, ir_fetch }
+ { "FETCH", 5, ir_fetch },
+ { "MYRIGHTS", 8, ir_myrights },
+ { "ACL", 3, ir_getacl },
+ { "QUOTAROOT", 9, ir_quotaroot },
+ { "QUOTA", 5, ir_quota }
};
static const struct {
const gchar *response;
diff --git a/libbalsa/imap/imap-handle.h b/libbalsa/imap/imap-handle.h
index 02d94c0..340ce73 100644
--- a/libbalsa/imap/imap-handle.h
+++ b/libbalsa/imap/imap-handle.h
@@ -72,6 +72,7 @@ typedef enum
IMCAP_LOGINDISABLED, /* RFC 2595 */
IMCAP_MULTIAPPEND, /* RFC 3502 */
IMCAP_NAMESPACE, /* RFC 2342: IMAP4 Namespace */
+ IMCAP_QUOTA, /* RFC 2087 */
IMCAP_SASLIR, /* RFC 4959 */
IMCAP_SCAN, /* FIXME: RFC? */
IMCAP_STARTTLS, /* RFC 2595: STARTTLS */
diff --git a/libbalsa/imap/imap_private.h b/libbalsa/imap/imap_private.h
index cb748a6..7456648 100644
--- a/libbalsa/imap/imap_private.h
+++ b/libbalsa/imap/imap_private.h
@@ -143,6 +143,14 @@ struct _ImapMboxHandle {
unsigned enable_client_sort:1; /**< client side sorting allowed */
unsigned enable_compress:1; /**< enable compress extension */
unsigned enable_idle:1; /**< use IDLE - no problem with firewalls */
+ unsigned has_rights:1; /**< whether rights are up-to-date. */
+
+ ImapAclType rights; /**< my rights (RFC 4314) */
+ GList *acls; /**< acl's (RFC 4314) */
+
+ gulong quota_max_k; /**< max. available quota in kByte */
+ gulong quota_used_k; /**< used quota in kByte */
+ gchar *quota_root;
/* conditional stuff at the end for the safety. */
#ifdef USE_TLS
@@ -176,6 +184,8 @@ extern const char* imap_msg_flags[6];
ImapResponse imap_mbox_select_unlocked(ImapMboxHandle* handle, const char *mbox,
gboolean *readonly_mbox);
+ImapResponse imap_mbox_fetch_my_rights_unlocked(ImapMboxHandle* handle);
+
void imap_mbox_resize_cache(ImapMboxHandle *h, unsigned new_size);
ImapResponse imap_cmd_exec_cmdno(ImapMboxHandle* handle, const char* cmd,
diff --git a/libbalsa/imap/libimap.h b/libbalsa/imap/libimap.h
index c4a2376..00be2e0 100644
--- a/libbalsa/imap/libimap.h
+++ b/libbalsa/imap/libimap.h
@@ -277,4 +277,30 @@ size_t imap_serialized_message_size(void *data);
const char *lbi_strerror(ImapResult rc);
+/* RFC 4314: IMAP ACL's */
+typedef enum {
+ IMAP_ACL_NONE = 0,
+ IMAP_ACL_LOOKUP = 1<<0, /* 'l': visible to LIST, LSUB; SUBSCRIBE mailbox*/
+ IMAP_ACL_READ = 1<<1, /* 'r': SELECT the mailbox, perform STATUS */
+ IMAP_ACL_SEEN = 1<<2, /* 's': keep seen/unseen across sessions */
+ IMAP_ACL_WRITE = 1<<3, /* 'w': write */
+ IMAP_ACL_INSERT = 1<<4, /* 'i': APPEND, COPY into mailbox */
+ IMAP_ACL_POST = 1<<5, /* 'p': send mail to submission address */
+ IMAP_ACL_CREATE = 1<<6, /* 'k': CREATE, RENAME */
+ IMAP_ACL_DELETE = 1<<7, /* 'x': DELETE, RENAME */
+ IMAP_ACL_DELMSG = 1<<8, /* 't': delete messages (\DELETED flag) */
+ IMAP_ACL_EXPUNGE = 1<<9, /* 'e': EXPUNGE */
+ IMAP_ACL_ADMIN = 1<<10 /* 'a': administer (SETACL/DELETEACL/GETACL/LISTRIGHTS) */
+} ImapAclType;
+
+#define IMAP_ACL_CAN_WRITE (IMAP_ACL_WRITE | IMAP_ACL_INSERT | IMAP_ACL_CREATE | \
+ IMAP_ACL_DELETE | IMAP_ACL_DELMSG | IMAP_ACL_EXPUNGE)
+
+typedef struct {
+ gchar* uid;
+ ImapAclType acl;
+} ImapUserAclType;
+
+void imap_user_acl_free(ImapUserAclType *acl);
+
#endif /* __IMAP_H__ */
diff --git a/libbalsa/mailbox_imap.c b/libbalsa/mailbox_imap.c
index cb81137..a6c1578 100644
--- a/libbalsa/mailbox_imap.c
+++ b/libbalsa/mailbox_imap.c
@@ -82,6 +82,9 @@ struct _LibBalsaMailboxImap {
guint unread_update_id;
LibBalsaMailboxSortFields sort_field;
unsigned opened:1;
+
+ ImapAclType rights; /* RFC 4314 'myrights' */
+ GList *acls; /* RFC 4314 acl's */
};
struct _LibBalsaMailboxImapClass {
@@ -329,6 +332,9 @@ libbalsa_mailbox_imap_finalize(GObject * object)
mailbox->unread_update_id = 0;
}
+ g_list_foreach(mailbox->acls, (GFunc)imap_user_acl_free, NULL);
+ g_list_free(mailbox->acls);
+
if (G_OBJECT_CLASS(parent_class)->finalize)
G_OBJECT_CLASS(parent_class)->finalize(object);
}
@@ -364,6 +370,62 @@ libbalsa_mailbox_imap_set_path(LibBalsaMailboxImap* mailbox, const gchar* path)
libbalsa_mailbox_imap_update_url(mailbox);
}
+gboolean
+libbalsa_imap_get_quota(LibBalsaMailboxImap * mailbox,
+ gulong *max_kbyte, gulong *used_kbyte)
+{
+ g_return_val_if_fail(LIBBALSA_MAILBOX_IMAP(mailbox), FALSE);
+
+ return imap_mbox_get_quota(mailbox->handle, mailbox->path,
+ max_kbyte, used_kbyte) == IMR_OK;
+}
+
+/* converts ACL's to a standard RFC 4314 acl string */
+static char *
+imap_acl_to_str(ImapAclType acl)
+{
+ GString *rights;
+ static const char * flags = "lrswipkxtea";
+ int n;
+
+ rights = g_string_new("");
+ for (n = 0; n < 11; n++)
+ if (acl & (1 << n))
+ rights = g_string_append_c(rights, flags[n]);
+ return g_string_free(rights, FALSE);
+}
+
+gchar *
+libbalsa_imap_get_rights(LibBalsaMailboxImap * mailbox)
+{
+ g_return_val_if_fail(LIBBALSA_MAILBOX_IMAP(mailbox), NULL);
+
+ if (mailbox->rights == IMAP_ACL_NONE)
+ return NULL;
+ else
+ return imap_acl_to_str(mailbox->rights);
+}
+
+gchar **
+libbalsa_imap_get_acls(LibBalsaMailboxImap * mailbox)
+{
+ gchar ** acls;
+ guint n;
+ GList *p;
+
+ g_return_val_if_fail(LIBBALSA_MAILBOX_IMAP(mailbox), NULL);
+
+ if (!mailbox->acls)
+ return NULL;
+ acls = g_new0(char *, 2 * g_list_length(mailbox->acls) + 1);
+ n = 0;
+ for (p = g_list_first(mailbox->acls); p; p = g_list_next(p), n += 2) {
+ acls[n] = g_strdup(((ImapUserAclType *)p->data)->uid);
+ acls[n + 1] = imap_acl_to_str(((ImapUserAclType *)p->data)->acl);
+ }
+ return acls;
+}
+
const gchar*
libbalsa_mailbox_imap_get_path(LibBalsaMailboxImap * mailbox)
{
@@ -926,6 +988,16 @@ libbalsa_mailbox_imap_get_selected_handle(LibBalsaMailboxImap *mimap,
mimap->handle = NULL;
return NULL;
}
+
+ /* check if we have RFC 4314 acl's for the selected mailbox */
+ if (imap_mbox_get_my_rights(mimap->handle, &mimap->rights, FALSE) ==
+ IMR_OK) {
+ if ((mimap->rights & IMAP_ACL_CAN_WRITE) != IMAP_ACL_CAN_WRITE)
+ LIBBALSA_MAILBOX(mimap)->readonly = TRUE;
+ if (mimap->rights & IMAP_ACL_ADMIN)
+ imap_mbox_get_acl(mimap->handle, mimap->path, &mimap->acls);
+ }
+
/* test validity */
uidval = imap_mbox_handle_get_validity(mimap->handle);
if (mimap->uid_validity != uidval) {
diff --git a/libbalsa/mailbox_imap.h b/libbalsa/mailbox_imap.h
index 679f5f2..59caf70 100644
--- a/libbalsa/mailbox_imap.h
+++ b/libbalsa/mailbox_imap.h
@@ -77,6 +77,12 @@ gboolean libbalsa_imap_rename_subfolder(LibBalsaMailboxImap* mbox,
gboolean libbalsa_imap_delete_folder(LibBalsaMailboxImap * mailbox,
GError **err);
+gboolean libbalsa_imap_get_quota(LibBalsaMailboxImap * mailbox,
+ gulong *max_kbyte, gulong *used_kbyte);
+
+gchar *libbalsa_imap_get_rights(LibBalsaMailboxImap * mailbox);
+gchar **libbalsa_imap_get_acls(LibBalsaMailboxImap * mailbox);
+
gchar *libbalsa_imap_url(LibBalsaServer * server, const gchar * path);
void libbalsa_imap_set_cache_size(off_t cache_size);
diff --git a/src/folder-conf.c b/src/folder-conf.c
index 703d2f9..17e5139 100644
--- a/src/folder-conf.c
+++ b/src/folder-conf.c
@@ -837,11 +837,92 @@ folder_conf_imap_sub_node(BalsaMailboxNode * mn)
G_CALLBACK(validate_sub_folder),
sdd, 2, sdd->old_parent, label);
+ if (mn) {
+ static const char *std_acls[] = {
+ "lrs", N_("read-only"),
+ "lrswipkxte", N_("read-write"),
+ "lrswipkxtea", N_("admin"),
+ NULL, N_("special") };
+ GString *rights_str;
+ gchar * rights;
+ gchar * quotas;
+
+ label = libbalsa_create_label(_("Permissions:"), table, 3);
+
+ /* mailbox closed: no detailed permissions available */
+ if (!libbalsa_mailbox_imap_is_connected(LIBBALSA_MAILBOX_IMAP(mn->mailbox))) {
+ rights_str = g_string_new(std_acls[mn->mailbox->readonly ? 1 : 3]);
+ rights_str =
+ g_string_append(rights_str,
+ _("\ndetailed permissions are available only for open folders"));
+ } else {
+ rights = libbalsa_imap_get_rights(LIBBALSA_MAILBOX_IMAP(mn->mailbox));
+ if (!rights) {
+ rights_str = g_string_new(std_acls[mn->mailbox->readonly ? 1 : 3]);
+ rights_str =
+ g_string_append(rights_str,
+ _("\nthe server does not support ACL's"));
+ } else {
+ gint n;
+ gchar **acls;
+
+ /* my rights */
+ for (n = 0;
+ std_acls[n] && strcmp(std_acls[n], rights);
+ n += 2);
+ rights_str = g_string_new(_("mine: "));
+ g_string_append_printf(rights_str, "%s (%s)",
+ std_acls[n + 1], rights);
+
+ /* acl's - only available if I have admin privileges */
+ if ((acls =
+ libbalsa_imap_get_acls(LIBBALSA_MAILBOX_IMAP(mn->mailbox)))) {
+ int uid;
+
+ for (uid = 0; acls[uid]; uid += 2) {
+ for (n = 0;
+ std_acls[n] && strcmp(std_acls[n], acls[uid + 1]);
+ n += 2);
+ g_string_append_printf(rights_str,
+ "\nuid '%s': %s (%s)",
+ acls[uid], std_acls[n + 1],
+ acls[uid + 1]);
+ }
+ g_strfreev(acls);
+ }
+ g_free(rights);
+ }
+ }
+ rights = g_string_free(rights_str, FALSE);
+ gtk_table_attach(GTK_TABLE(table), gtk_label_new(rights), 1, 2, 3, 4,
+ GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 5);
+ g_free(rights);
+
+ label = libbalsa_create_label(_("Quota:"), table, 4);
+
+ /* mailbox closed: no quota available */
+ if (!libbalsa_mailbox_imap_is_connected(LIBBALSA_MAILBOX_IMAP(mn->mailbox)))
+ quotas = g_strdup(_("quota information available only for open folders"));
+ else {
+ gulong max, used;
+
+ if (!libbalsa_imap_get_quota(LIBBALSA_MAILBOX_IMAP(mn->mailbox), &max, &used))
+ quotas = g_strdup(_("the server does not support quotas"));
+ else if (max == 0 && used == 0)
+ quotas = g_strdup(_("no limits"));
+ else
+ quotas = g_strdup_printf(_("%lu kByte of %lu kbyte (%.1f%%) used"),
+ used, max,
+ 100.0 * (float) used / (float) max);
+ }
+ gtk_table_attach(GTK_TABLE(table), gtk_label_new(quotas), 1, 2, 4, 5,
+ GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 5);
+ g_free(quotas);
- if (mn)
sdd->mcv = mailbox_conf_view_new(mn->mailbox,
GTK_WINDOW(sdd->dialog),
- table, 3);
+ table, 5);
+ }
gtk_widget_show_all(GTK_WIDGET(sdd->dialog));
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]