[balsa] Implement QUOTA, MYRIGHTS and GETACL commands.



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]