Re: [evolution-patches] First pass at IMAP quota support (RFC 2087)



a few comments below, I think the idea of putting the quota info on the
CamelFolderInfo is probably the right way, hopefully NotZed replies with
his comments on the design there.

few comments below, mostly stylistic/namespace related.

On Thu, 2004-10-07 at 12:43 -0400, David Malcolm wrote:
> Index: camel/camel-folder.h
> ===================================================================
> RCS file: /cvs/gnome/evolution/camel/camel-folder.h,v
> retrieving revision 1.124
> diff -u -p -r1.124 camel-folder.h
> --- camel/camel-folder.h        13 Apr 2004 15:58:56 -0000      1.124
> +++ camel/camel-folder.h        7 Oct 2004 16:19:40 -0000
> @@ -112,6 +112,9 @@ struct _CamelFolder
>  #define CAMEL_FOLDER_IS_JUNK                (1<<5)
>  #define CAMEL_FOLDER_FILTER_JUNK           (1<<6)
>  
> +#define CAMEL_QUOTA_UNAVAILABLE (-1)
> +#define CAMEL_QUOTA_INHERIT_PARENT (-2)
> +
>  typedef struct {
>         CamelObjectClass parent_class;
>  
> Index: camel/camel-store.c
> ===================================================================
> RCS file: /cvs/gnome/evolution/camel/camel-store.c,v
> retrieving revision 1.154
> diff -u -p -r1.154 camel-store.c
> --- camel/camel-store.c 20 Sep 2004 05:59:53 -0000      1.154
> +++ camel/camel-store.c 7 Oct 2004 16:19:41 -0000
> @@ -850,6 +850,12 @@ void
>  camel_folder_info_free (CamelFolderInfo *fi)
>  {
>         if (fi) {
> +               /* FIXME: disabled for now */
> +#if 0
> +               if (fi->quota_info) {
> +                       camel_imap_quota_root_free
> (fi->quota_info);    
> +               }
> +#endif
>                 camel_folder_info_free (fi->next);
>                 camel_folder_info_free (fi->child);
>                 g_free (fi->name);
> @@ -1025,6 +1031,9 @@ static CamelFolderInfo *folder_info_clon
>         else
>                 info->child = NULL;
>  
> +       /* Eventually do this with reference counting? */
> +       info->quota_info = camel_imap_quota_root_clone
> (fi->quota_info);
> +
>         return info;
>  }
>  
> @@ -1154,6 +1163,16 @@ camel_store_noop (CamelStore *store, Cam
>         CS_CLASS (store)->noop (store, ex);
>  }
>  
> +CamelImapQuotaRoot *
> +camel_store_get_quota_info (CamelStore *store, CamelFolderInfo *fi,
> CamelException *ex)
> +{
> +       if (CS_CLASS (store)->get_quota_info) {
> +               return CS_CLASS (store)->get_quota_info (store, fi,
> ex);
> +       } else {
> +               return NULL;
> +       }
> +}

a virtual method should always be defined. by default, the CamelStore
could implement a no-op implementation for this (which would just return
NULL).

then this function would be a simple 1-liner

> +
>  
>  /**
>   * camel_store_folder_uri_equal:
> @@ -1203,4 +1222,107 @@ camel_store_folder_uri_equal (CamelStore
>         camel_url_free (url1);
>         
>         return equal;
> +}
> +
> +void 
> +camel_imap_quota_root_free (CamelImapQuotaRoot *quota_root)

this should just be camel_quota_root_free(), keep the imap namespace out
of it (plus it's supposed to be generic anyway so don't name it imap)
probably just a leftover from earlier workings.

> +{
> +       GList *iter;
> +
> +       g_return_if_fail (quota_root);
> +
> +       g_free (quota_root->name);
> +
> +       for (iter=quota_root->resources; iter; iter=iter->next) {
> +               camel_quota_resource_free
> ((CamelQuotaResource*)(iter->data));

shouldn't need to cast here, but whatever :)

> +       }
> +
> +       g_list_free (quota_root->resources);
> +       
> +       g_free (quota_root);
> +}
> +
> +int 
> +camel_imap_quota_root_get_worst_usage (CamelImapQuotaRoot
> *quota_root)

probably just name it camel_quota_root_get_usage()

> +{
> +       /* Return most pessimistic usage information for display to
> the user: */        
> +       if (quota_root->resources) {
> +               GList *iter;
> +               int result = 0;
> +               for (iter = quota_root->resources; iter;
> iter=iter->next) {
> +                       CamelQuotaResource *qr = (CamelQuotaResource
> *)iter->data;
> +                       g_assert (qr);
> +                       
> +                       if (qr->limit>0) {
> +                               int percent =
> (qr->usage*100)/qr->limit;
> +                               
> +                               if (result<percent) {
> +                                       result = percent;
> +                               }
> +                       }
> +                       
> +                       camel_quota_resource_free (qr);
> +               }
> +               
> +               return result;          
> +       } else {
> +               return CAMEL_QUOTA_UNAVAILABLE;
> +       }
> +}
> +
> +CamelImapQuotaRoot *
> +camel_imap_quota_root_clone (CamelImapQuotaRoot *quota_root)
> +{
> +       CamelImapQuotaRoot *new_qr;
> +       GList *iter;
> +
> +       if (NULL==quota_root) {
> +               return NULL;
> +       }

as a general stylistic thing, if an if-statement only has 1-line, then
we just do:

if (foo)
	bar();

also, we use the convention:

if (quota_root == NULL)

> +
> +       new_qr = g_new0 (CamelImapQuotaRoot, 1);
> +       new_qr->name = g_strdup (quota_root->name);
> +
> +       for (iter = quota_root->resources; iter; iter=iter->next) {
> +               new_qr->resources = g_list_append (new_qr->resources,
> +
> camel_quota_resource_clone ((CamelQuotaResource*)iter->data));
> +       }
> +       
> +       return new_qr;
> +}
> +
> +CamelQuotaResource *
> +camel_quota_resource_new (const gchar *name, CamelQuotaAmount usage,
> CamelQuotaAmount limit)
> +{
> +       CamelQuotaResource *qr;
> +
> +       g_return_val_if_fail (name, NULL);
> +
> +       qr = g_new0 (CamelQuotaResource, 1);
> +       qr->name = g_strdup (name);
> +       qr->usage = usage;
> +       qr->limit = limit;
> +
> +       return qr;
> +}
> +
> +void
> +camel_quota_resource_free (CamelQuotaResource *qr)
> +{
> +       g_return_if_fail (qr);
> +       g_return_if_fail (qr->name);
> +
> +       /* FIXME: getting a crash here; looks like I'm messing up the
> lifetime/ownership of these objects between the threads */
> +#if 0
> +       g_free (qr->name);
> +       g_free (qr);
> +#endif
> +}
> +
> +CamelQuotaResource *
> +camel_quota_resource_clone (CamelQuotaResource *qr)
> +{
> +       g_return_val_if_fail (qr, NULL);
> +
> +       return camel_quota_resource_new (qr->name, qr->usage,
> qr->limit);
>  }
> Index: camel/camel-store.h
> ===================================================================
> RCS file: /cvs/gnome/evolution/camel/camel-store.h,v
> retrieving revision 1.69
> diff -u -p -r1.69 camel-store.h
> --- camel/camel-store.h 26 May 2004 04:24:01 -0000      1.69
> +++ camel/camel-store.h 7 Oct 2004 16:19:41 -0000
> @@ -42,6 +42,21 @@ enum {
>         CAMEL_STORE_ARG_FIRST  = CAMEL_SERVICE_ARG_FIRST + 100,
>  };
>  
> +typedef guint32 CamelQuotaAmount;
> +
> +/* struct designed to hold the result of an RFC-2087 quota_resource
> */
> +typedef struct _CamelQuotaResource {
> +       char *name;
> +       CamelQuotaAmount usage;
> +       CamelQuotaAmount limit; 
> +} CamelQuotaResource;
> +
> +/* Eventually generalise this into a base class, with
> provider-specific quota info ? */
> +typedef struct {
> +       char *name;
> +       GList *resources; /* list of CamelImapQuotaResource */
> +} CamelImapQuotaRoot;
> +
>  typedef struct _CamelFolderInfo {
>         struct _CamelFolderInfo *next;
>         struct _CamelFolderInfo *parent;
> @@ -54,6 +69,11 @@ typedef struct _CamelFolderInfo {
>         guint32 flags;
>         guint32 unread;
>         guint32 total;
> +
> +#if 1
> +       CamelImapQuotaRoot *quota_info;
> +#endif
> +       
>  } CamelFolderInfo;
>  
>  /* Note: these are abstractions (duh), its upto the provider to make
> them make sense */
> @@ -162,6 +182,10 @@ typedef struct {
>                                                      CamelException
> *ex);
>         void            (*noop)                     (CamelStore
> *store,
>                                                      CamelException
> *ex);
> +
> +       CamelImapQuotaRoot *(*get_quota_info)       (CamelStore
> *store,
> +                                                    CamelFolderInfo
> *fi,
> +                                                    CamelException
> *ex);
>  } CamelStoreClass;
>  
>  
> @@ -227,9 +251,25 @@ void             camel_store_unsubscribe
>  void             camel_store_noop                     (CamelStore
> *store,
>                                                        CamelException
> *ex);
>  
> +CamelImapQuotaRoot *camel_store_get_quota_info        (CamelStore
> *store,
> +                                                      CamelFolderInfo
> *fi,
> +                                                      CamelException
> *ex);
> +
>  int              camel_store_folder_uri_equal         (CamelStore
> *store,
>                                                        const char
> *uri0,
>                                                        const char
> *uri1);
> +GList *          camel_store_get_quota_resources      (CamelStore
> *store,
> +                                                      CamelException
> *ex);
> +
> +CamelQuotaResource *camel_quota_resource_new          (const gchar
> *name,
> +
> CamelQuotaAmount usage,
> +
> CamelQuotaAmount limit);
> +void                camel_quota_resource_free
> (CamelQuotaResource *qr);
> +CamelQuotaResource* camel_quota_resource_clone
> (CamelQuotaResource *qr);
> +
> +void                camel_imap_quota_root_free
> (CamelImapQuotaRoot *quota_root);
> +int                 camel_imap_quota_root_get_worst_usage
> (CamelImapQuotaRoot *quota_root);
> +CamelImapQuotaRoot *camel_imap_quota_root_clone
> (CamelImapQuotaRoot *quota_root);
>  
>  #ifdef __cplusplus
>  }
> Index: camel/providers/imap/camel-imap-folder.c
> ===================================================================
> RCS
> file: /cvs/gnome/evolution/camel/providers/imap/camel-imap-folder.c,v
> retrieving revision 1.338
> diff -u -p -r1.338 camel-imap-folder.c
> --- camel/providers/imap/camel-imap-folder.c    20 Sep 2004 05:59:53
> -0000      1.338
> +++ camel/providers/imap/camel-imap-folder.c    7 Oct 2004 16:19:41
> -0000
> @@ -2807,3 +2807,87 @@ parse_fetch_response (CamelImapFolder *i
>         return data;
>  }
>  
> +static void
> +getquotaroot_cb (char *response_str,
> +                CamelImapQuotaRoot *result)
> +{
> +       g_assert (response_str);
> +       g_assert (result);
> +
> +       g_message (response_str);
> +
> +       /* Expect lines of the form "* QUOTAROOT" and "* QUOTA": */
> +       /*   
> +   quota_list      ::= "(" #quota_resource ")"
> +
> +   quota_resource  ::= atom SP number SP number
> +
> +   quota_response  ::= "QUOTA" SP astring SP quota_list
> +       */
> +
> +       if (g_str_has_prefix(response_str, "* QUOTAROOT ")) {
> +               /* FIXME: get quotaroot name */
> +               if (result->name) {
> +                       g_free (result->name);
> +               }
> +               result->name = g_strdup ("fubar"); /* FIXME */
> +       }
> +
> +       if (g_str_has_prefix(response_str, "* QUOTA ")) {
> +               char *quota_name;               
> +               if (imap_parse_rfc2087_quota_response (response_str+2,
> +                                                      &quota_name,
> +
> &result->resources)) {
> +               }
> +       }
> +
> +}
> +
> +CamelImapQuotaRoot *
> +camel_imap_quota_root_new (CamelImapResponse *response)
> +{
> +       CamelImapQuotaRoot *result;
> +
> +       g_return_val_if_fail (response, NULL);
> +
> +       /* Expect a response of this form: */
> +
> +       /* 
> +          Result:     OK - getquota completed
> +          NO - getquota error: no such mailbox, permission denied
> +          BAD - command unknown or arguments invalid
> +
> +          The GETQUOTAROOT command takes the name of a mailbox and
> returns the
> +          list of quota roots for the mailbox in an untagged
> QUOTAROOT
> +          response.  For each listed quota root, it also returns the
> quota
> +          root's resource usage and limits in an untagged QUOTA
> response.
> +
> +   Example:    C: A003 GETQUOTAROOT INBOX
> +               S: * QUOTAROOT INBOX ""
> +               S: * QUOTA "" (STORAGE 10 512)
> +               S: A003 OK Getquota completed
> +       */
> +
> +       result = g_new0 (CamelImapQuotaRoot, 1);
> +       
> +       /* Handle the lines of the response: */
> +       g_ptr_array_foreach (response->untagged,
> +                            (GFunc)getquotaroot_cb,
> +                            result);
> +
> +       return result;
> +}
> +
> +CamelImapQuotaRoot *
> +camel_imap_folder_get_quota_root (CamelImapFolder *imap_folder,
> +                                 CamelException *ex)
> +{
> +       CamelFolder *folder = CAMEL_FOLDER (imap_folder);
> +       CamelImapStore *imap_store = CAMEL_IMAP_STORE
> (folder->parent_store);
> +
> +       return camel_imap_store_get_quota_root (imap_store,
> +                                               folder->full_name,
> +                                               ex);
> +}
> +
> +
> Index: camel/providers/imap/camel-imap-folder.h
> ===================================================================
> RCS
> file: /cvs/gnome/evolution/camel/providers/imap/camel-imap-folder.h,v
> retrieving revision 1.42
> diff -u -p -r1.42 camel-imap-folder.h
> --- camel/providers/imap/camel-imap-folder.h    14 Jan 2004 04:35:58
> -0000      1.42
> +++ camel/providers/imap/camel-imap-folder.h    7 Oct 2004 16:19:41
> -0000
> @@ -36,6 +36,7 @@ extern "C" {
>  #include "camel-imap-types.h"
>  #include <camel/camel-disco-folder.h>
>  #include <camel/camel-folder-search.h>
> +#include <camel/camel-store.h>
>  
>  #define CAMEL_IMAP_FOLDER_TYPE     (camel_imap_folder_get_type ())
>  #define CAMEL_IMAP_FOLDER(obj)     (CAMEL_CHECK_CAST((obj),
> CAMEL_IMAP_FOLDER_TYPE, CamelImapFolder))
> @@ -81,6 +82,11 @@ CamelStream *camel_imap_folder_fetch_dat
>                                            const char *section_text,
>                                            gboolean cache_only,
>                                            CamelException *ex);
> +
> +CamelImapQuotaRoot *camel_imap_folder_get_quota_root (CamelImapFolder
> *imap_folder,
> +                                                     CamelException
> *ex);
> +
> +CamelImapQuotaRoot *camel_imap_quota_root_new (CamelImapResponse
> *response);
>  
>  /* Standard Camel function */
>  CamelType camel_imap_folder_get_type (void);
> Index: camel/providers/imap/camel-imap-store.c
> ===================================================================
> RCS
> file: /cvs/gnome/evolution/camel/providers/imap/camel-imap-store.c,v
> retrieving revision 1.303
> diff -u -p -r1.303 camel-imap-store.c
> --- camel/providers/imap/camel-imap-store.c     27 Sep 2004 17:41:15
> -0000      1.303
> +++ camel/providers/imap/camel-imap-store.c     7 Oct 2004 16:19:41
> -0000
> @@ -73,6 +73,9 @@ static CamelDiscoStoreClass *parent_clas
>  
>  static char imap_tag_prefix = 'A';
>  
> +static void update_quota_info (CamelImapStore *imap_store,
> +                              CamelFolderInfo *fi);
> +
>  static void construct (CamelService *service, CamelSession *session,
>                        CamelProvider *provider, CamelURL *url,
>                        CamelException *ex);
> @@ -448,6 +451,7 @@ static struct {
>         { "UIDPLUS",            IMAP_CAPABILITY_UIDPLUS },
>         { "LITERAL+",           IMAP_CAPABILITY_LITERALPLUS },
>         { "STARTTLS",           IMAP_CAPABILITY_STARTTLS },
> +       { "QUOTA",              IMAP_CAPABILITY_QUOTA },
>         { NULL, 0 }
>  };
>  
> @@ -2394,6 +2398,8 @@ parse_list_response_as_folder_info (Came
>         if (flags & CAMEL_IMAP_FOLDER_UNMARKED)
>                 fi->unread = -1;
>  
> +       update_quota_info (imap_store, fi);
> +
>         return fi;
>  }
>  
> @@ -2904,6 +2910,32 @@ fail:
>         return NULL;
>  }
>  
> +static void
> +update_quota_info (CamelImapStore *imap_store,
> +                  CamelFolderInfo *fi)
> +{
> +       /* Query and fill in quota info for this folder: */
> +       char *folder_name;
> +
> +       CamelImapQuotaRoot *qr;
> +
> +       CAMEL_SERVICE_ASSERT_LOCKED (imap_store, connect_lock);
> +
> +       if (fi->quota_info) {
> +               camel_imap_quota_root_free (fi->quota_info);
> +               fi->quota_info = NULL;
> +       }
> +       
> +       folder_name = camel_imap_store_summary_path_to_full
> (imap_store->summary, fi->full_name, imap_store->dir_sep);
> +
> +       qr = camel_imap_store_get_quota_root (imap_store, 
> +                                             folder_name,
> +                                             NULL);
> +       g_free (folder_name);
> +
> +       fi->quota_info = qr;
> +}
> +
>  static CamelFolderInfo *
>  get_folder_info_online (CamelStore *store, const char *top, guint32
> flags, CamelException *ex)
>  {
> @@ -2937,6 +2969,8 @@ get_folder_info_online (CamelStore *stor
>  
>         d(dumpfi(tree));
>         camel_store_summary_save((CamelStoreSummary
> *)imap_store->summary);
> +
> +       update_quota_info (imap_store, tree);
>  done:
>         CAMEL_SERVICE_UNLOCK(store, connect_lock);
>  
> @@ -3208,4 +3242,48 @@ camel_imap_store_readline (CamelImapStor
>         g_byte_array_free (ba, FALSE);
>         
>         return nread;
> +}
> +
> +CamelImapQuotaRoot *
> +camel_imap_store_get_quota_root (CamelImapStore *imap_store,
> +                                const char *folder_name,
> +                                CamelException *ex)
> +{
> +       g_return_val_if_fail (imap_store, NULL);
> +       g_return_val_if_fail (folder_name, NULL);
> +
> +       CAMEL_SERVICE_LOCK (imap_store, connect_lock);
> +
> +       if (!imap_store->connected) {
> +               CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
> +               return NULL;
> +       }
> +
> +       if (imap_store->capabilities & IMAP_CAPABILITY_QUOTA) { 
> +               /* The server claimed to support RFC-2087: */
> +               CamelImapResponse *response;
> +
> +               /* FIXME FIXME FIXME: locking issues? */
> +               response = camel_imap_command (imap_store,
> +                                              NULL,
> +                                              ex,
> +                                              "GETQUOTAROOT \"%s\"",
> folder_name);

hmmm, not sure the format argument is correct here. you can't always
just quote the folder name string (it may contain quotes itself, or may
require being sent as a literal, etc)

I forget what the formatter is for folder names... probably %F?

> +
> +               if (response) {
> +                       CamelImapQuotaRoot *qr =
> camel_imap_quota_root_new (response);
> +
> +                       /* Free the resource, unlocking the store */
> +                       camel_imap_response_free (imap_store,
> +                                                 response);    
> +
> +                       CAMEL_SERVICE_UNLOCK (imap_store,
> connect_lock);
> +
> +                       return qr;
> +               }
> +       }
> +
> +       CAMEL_SERVICE_UNLOCK (imap_store, connect_lock);
> +
> +       return NULL;
> +
>  }
> Index: camel/providers/imap/camel-imap-store.h
> ===================================================================
> RCS
> file: /cvs/gnome/evolution/camel/providers/imap/camel-imap-store.h,v
> retrieving revision 1.60
> diff -u -p -r1.60 camel-imap-store.h
> --- camel/providers/imap/camel-imap-store.h     25 Mar 2004 23:02:40
> -0000      1.60
> +++ camel/providers/imap/camel-imap-store.h     7 Oct 2004 16:19:41
> -0000
> @@ -94,6 +94,7 @@ typedef enum {
>  #define IMAP_CAPABILITY_STARTTLS                (1 << 6)
>  #define IMAP_CAPABILITY_useful_lsub            (1 << 7)
>  #define IMAP_CAPABILITY_utf8_search            (1 << 8)
> +#define IMAP_CAPABILITY_QUOTA                          (1 << 9)
>  
>  #define IMAP_PARAM_OVERRIDE_NAMESPACE          (1 << 0)
>  #define IMAP_PARAM_CHECK_ALL                   (1 << 1)
> @@ -141,6 +142,10 @@ CamelType camel_imap_store_get_type (voi
>  gboolean camel_imap_store_connected (CamelImapStore *store,
> CamelException *ex);
>  
>  ssize_t camel_imap_store_readline (CamelImapStore *store, char
> **dest, CamelException *ex);
> +
> +CamelImapQuotaRoot *camel_imap_store_get_quota_root (CamelImapStore
> *imap_store,
> +                                                    const char
> *folder_name,
> +                                                    CamelException
> *ex);
>  
>  #ifdef __cplusplus
>  }
> Index: camel/providers/imap/camel-imap-utils.c
> ===================================================================
> RCS
> file: /cvs/gnome/evolution/camel/providers/imap/camel-imap-utils.c,v
> retrieving revision 1.73
> diff -u -p -r1.73 camel-imap-utils.c
> --- camel/providers/imap/camel-imap-utils.c     15 Apr 2004 16:11:40
> -0000      1.73
> +++ camel/providers/imap/camel-imap-utils.c     7 Oct 2004 16:19:41
> -0000
> @@ -1263,3 +1263,132 @@ imap_mailbox_decode (const unsigned char
>         
>         return camel_utf7_utf8 (buf);
>  }
> +
> +
> +
> +
> +/* From RFC 2087: 
> +   getquota        ::= "GETQUOTA" SP astring
> +*/
> +gboolean
> +imap_parse_rfc2087_getquota (const char *in_str)
> +{
> +       g_assert_not_reached ();
> +       return FALSE;
> +}
> +
> +/* From RFC 2087: 
> +   getquotaroot    ::= "GETQUOTAROOT" SP astring
> +*/
> +gboolean
> +imap_parse_rfc2087_getquotaroot (const char *in_str)
> +{
> +       g_assert_not_reached ();
> +       return FALSE;
> +}
> +
> +/* From RFC 2087: 
> +   quota_list      ::= "(" #quota_resource ")"
> +*/
> +gboolean
> +imap_parse_rfc2087_quota_list (const char *in_str,
> +                              GList **out_list_of_resource)
> +{      
> +       while (*in_str && *in_str!='(') {
> +               in_str++;
> +       }
> +
> +       if (*in_str!='(') return FALSE;

the return statement should be on it's own line (styleistically)

> +       
> +       in_str++;
> +
> +       if (!imap_parse_rfc2087_quota_resource (in_str,
> out_list_of_resource)) return FALSE;

same.

> +
> +       while (*in_str && *in_str!=')') {
> +               in_str++;
> +       }
> +
> +       if (*in_str!=')') return FALSE;
> +       
> +       return TRUE;
> +}
> +
> +/* From RFC 2087: 
> +   quota_resource  ::= atom SP number SP number
> +*/
> +gboolean
> +imap_parse_rfc2087_quota_resource (const char *in_str,
> +                                  GList **out_list_of_resource)
> +{
> +       size_t len;
> +       char *name = imap_parse_string_generic (&in_str, &len,
> IMAP_ASTRING);
> +       
> +       const char *usage = imap_next_word (in_str);
> +       const char *limit = imap_next_word (usage);
> +
> +       CamelQuotaResource *resource = camel_quota_resource_new (name,
> strtoul(usage, NULL, 10), strtoul(limit, NULL, 10));
> +
> +       *out_list_of_resource = g_list_append (*out_list_of_resource,
> +                                              resource);
> +
> +       g_free (name);
> +
> +       return TRUE;
> +}
> +
> +/* From RFC 2087: 
> +   quota_response  ::= "QUOTA" SP astring SP quota_list
> +*/
> +gboolean
> +imap_parse_rfc2087_quota_response (const char *in_str,
> +                                  char **out_name,
> +                                  GList **out_list_of_resource)
> +{
> +       const char *curs = in_str+6;
> +       size_t len;
> +               
> +       *out_name = imap_parse_string_generic (&curs, &len,
> IMAP_ASTRING);

probably just use the imap_parse_astring() macro

> +
> +       return imap_parse_rfc2087_quota_list (curs,
> out_list_of_resource);
> +}
> +
> +/* From RFC 2087: 
> +   quotaroot_response ::= "QUOTAROOT" SP astring *(SP astring)
> +*/
> +gboolean
> +imap_parse_rfc2087_quotaroot_response (const char *in_str)
> +{
> +       g_assert_not_reached ();
> +       return FALSE;
> +}
> +
> +/* From RFC 2087: 
> +   setquota        ::= "SETQUOTA" SP astring SP setquota_list
> +*/
> +gboolean
> +imap_parse_rfc2087_setquota (const char *in_str)
> +{
> +       g_assert_not_reached ();
> +       return FALSE;
> +}
> +
> +/* From RFC 2087: 
> +   setquota_list   ::= "(" 0#setquota_resource ")"
> +*/
> +gboolean
> +imap_parse_rfc2087_setquota_list (const char *in_str)
> +{
> +       g_assert_not_reached ();
> +       return FALSE;
> +}
> +
> +/* From RFC 2087: 
> +   setquota_resource ::= atom SP number
> +*/
> +gboolean
> +imap_parse_rfc2087_setquota_resource (const char *in_str)
> +{
> +       g_assert_not_reached ();
> +       return FALSE;
> +}
> +
> Index: camel/providers/imap/camel-imap-utils.h
> ===================================================================
> RCS
> file: /cvs/gnome/evolution/camel/providers/imap/camel-imap-utils.h,v
> retrieving revision 1.23
> diff -u -p -r1.23 camel-imap-utils.h
> --- camel/providers/imap/camel-imap-utils.h     15 Aug 2002 06:17:09
> -0000      1.23
> +++ camel/providers/imap/camel-imap-utils.h     7 Oct 2004 16:19:41
> -0000
> @@ -88,6 +88,30 @@ char *imap_namespace_concat (CamelImapSt
>  char *imap_mailbox_encode (const unsigned char *in, size_t inlen);
>  char *imap_mailbox_decode (const unsigned char *in, size_t inlen);
>  
> +/* RFC 2087 (IMAP quota) support: */
> +gboolean
> +imap_parse_rfc2087_getquota (const char *in_str);
> +gboolean
> +imap_parse_rfc2087_getquotaroot (const char *in_str);
> +gboolean
> +imap_parse_rfc2087_quota_list (const char *in_str,
> +                              GList **out_list_of_resource);
> +gboolean
> +imap_parse_rfc2087_quota_resource (const char *in_str,
> +                                  GList **out_list_of_resource);
> +gboolean
> +imap_parse_rfc2087_quota_response (const char *in_str,
> +                                  char **out_name,
> +                                  GList **out_list_of_resource);
> +gboolean
> +imap_parse_rfc2087_quotaroot_response (const char *in_str);
> +gboolean
> +imap_parse_rfc2087_setquota (const char *in_str);
> +gboolean
> +imap_parse_rfc2087_setquota_list (const char *in_str);
> +gboolean
> +imap_parse_rfc2087_setquota_resource (const char *in_str);
> +
>  #ifdef __cplusplus
>  }
>  #endif /* __cplusplus */
> Index: mail/em-folder-tree-model.c
> ===================================================================
> RCS file: /cvs/gnome/evolution/mail/em-folder-tree-model.c,v
> retrieving revision 1.64
> diff -u -p -r1.64 em-folder-tree-model.c
> --- mail/em-folder-tree-model.c 24 Sep 2004 04:23:29 -0000      1.64
> +++ mail/em-folder-tree-model.c 7 Oct 2004 16:19:43 -0000
> @@ -69,6 +69,7 @@ static GType col_types[] = {
>         G_TYPE_UINT,     /* flags */
>         G_TYPE_BOOLEAN,  /* is a store node */
>         G_TYPE_BOOLEAN,  /* has not-yet-loaded subfolders */
> +       G_TYPE_INT       /* percent of quota used (or
> EMFTM_QUOTA_UNAVAILABLE if not available) */
>  };
>  
>  /* GObject virtual method overrides */
> @@ -436,6 +438,7 @@ em_folder_tree_model_set_folder_info (EM
>         gboolean load = FALSE;
>         struct _CamelFolder *folder;
>         gboolean emitted = FALSE;
> +       int quota_usage = CAMEL_QUOTA_UNAVAILABLE;
>         const char *name;
>  
>         if (!fully_loaded)
> @@ -465,9 +468,29 @@ em_folder_tree_model_set_folder_info (EM
>                         
>                         unread = total > 0 ? total : 0;
>                 }
> +
>                 camel_object_unref(folder);
>         }
>  
> +
> +       {
> +               CamelImapQuotaRoot *quota_info = fi->quota_info;
> +
> +               if (quota_info) {
> +                       if (fi->parent) {
> +                               if (fi->parent->quota_info) {
> +                                       if (0==strcmp
> (quota_info->name, fi->parent->quota_info->name)) {

if (strcmp (...) == 0)

you could probably also combine a couple of the if's into  single
if-statement:

if (fi->parent && fi->parent->quota_info && strcmp...) {
   stuff();
}

one thing that bugs me about this logic here is what if a folder doesn't
share a quota root with it's immediate parent but does share a quota
root with another folder somewhere else? is this possible?

I haven't read the spec that closely so I might have missed something
but I dunno. this is more a note-to-self thing that hopefully I'll
remember to go check out later.

> +                                               /* Has the same quota
> root as parent; suppress output */
> +                                               quota_usage =
> CAMEL_QUOTA_INHERIT_PARENT;
> +                                       }
> +                               }
> +                       }
> +                       if (quota_usage != CAMEL_QUOTA_INHERIT_PARENT)
> {
> +                               quota_usage =
> camel_imap_quota_root_get_worst_usage (quota_info);
> +                       }
> +               }
> +       }
> +
>         if (emft_is_special_local_folder(si->store, fi->full_name))
>                 name = _(fi->name);
>         else
> @@ -482,6 +505,7 @@ em_folder_tree_model_set_folder_info (EM
>                             COL_UINT_FLAGS, fi->flags,
>                             COL_BOOL_IS_STORE, FALSE,
>                             COL_BOOL_LOAD_SUBDIRS, load,
> +                           COL_INT_QUOTA_USED, quota_usage,
>                             -1);
>         
>         if (load) {
> @@ -495,6 +519,7 @@ em_folder_tree_model_set_folder_info (EM
>                                     COL_BOOL_IS_STORE, FALSE,
>                                     COL_STRING_URI, NULL,
>                                     COL_UINT_UNREAD, 0,
> +                                   COL_INT_QUOTA_USED,
> CAMEL_QUOTA_UNAVAILABLE, 
>                                     -1);
>                 
>                 path = gtk_tree_model_get_path ((GtkTreeModel *)
> model, iter);
> @@ -764,7 +789,7 @@ em_folder_tree_model_add_store (EMFolder
>         uri = camel_url_to_string (((CamelService *) store)->url,
> CAMEL_URL_HIDE_ALL);
>         
>         account = mail_config_get_account_by_source_url (uri);
> -       
> +
>         /* add the store to the tree */
>         gtk_tree_store_append ((GtkTreeStore *) model, &iter, NULL);
>         gtk_tree_store_set ((GtkTreeStore *) model, &iter,
> @@ -773,7 +798,9 @@ em_folder_tree_model_add_store (EMFolder
>                             COL_STRING_FULL_NAME, NULL,
>                             COL_BOOL_LOAD_SUBDIRS, TRUE,
>                             COL_BOOL_IS_STORE, TRUE,
> -                           COL_STRING_URI, uri, -1);
> +                           COL_STRING_URI, uri,
> +                           COL_INT_QUOTA_USED,
> CAMEL_QUOTA_UNAVAILABLE,
> +                           -1);
>         
>         path = gtk_tree_model_get_path ((GtkTreeModel *) model,
> &iter);
>         row = gtk_tree_row_reference_new ((GtkTreeModel *) model,
> path);
> @@ -799,6 +826,7 @@ em_folder_tree_model_add_store (EMFolder
>                             COL_BOOL_IS_STORE, FALSE,
>                             COL_STRING_URI, NULL,
>                             COL_UINT_UNREAD, 0,
> +                           COL_INT_QUOTA_USED,
> CAMEL_QUOTA_UNAVAILABLE, 
>                             -1);
>         
>         g_free (uri);
> Index: mail/em-folder-tree-model.h
> ===================================================================
> RCS file: /cvs/gnome/evolution/mail/em-folder-tree-model.h,v
> retrieving revision 1.20
> diff -u -p -r1.20 em-folder-tree-model.h
> --- mail/em-folder-tree-model.h 10 Jun 2004 22:08:41 -0000      1.20
> +++ mail/em-folder-tree-model.h 7 Oct 2004 16:19:43 -0000
> @@ -61,6 +61,8 @@ enum {
>         COL_BOOL_LOAD_SUBDIRS,    /* %TRUE only if the store/folder
>                                    * has subfolders which have not yet
>                                    * been added to the tree */
> +
> +       COL_INT_QUOTA_USED,      /* percentage of quota used, or
> CAMEL_QUOTA_UNAVAILABLE if no quota information available */
>         NUM_COLUMNS
>  };

I wonder if the quota should rather be a float instead of int. we may
still want to render as int, but at some point we may want to display as
float or something. (or maybe the user would like an option to enable
display as float vs int)

>  
> Index: mail/em-folder-tree.c
> ===================================================================
> RCS file: /cvs/gnome/evolution/mail/em-folder-tree.c,v
> retrieving revision 1.131
> diff -u -p -r1.131 em-folder-tree.c
> --- mail/em-folder-tree.c       7 Oct 2004 01:32:09 -0000       1.131
> +++ mail/em-folder-tree.c       7 Oct 2004 16:19:43 -0000
> @@ -309,12 +309,15 @@ render_display_name (GtkTreeViewColumn *
>  {
>         gboolean is_store, bold;
>         unsigned int unread;
> +       int quota_used;
>         char *display;
>         char *name;
>         
>         gtk_tree_model_get (model, iter, COL_STRING_DISPLAY_NAME,
> &name,
>                             COL_BOOL_IS_STORE, &is_store,
> -                           COL_UINT_UNREAD, &unread, -1);
> +                           COL_UINT_UNREAD, &unread, 
> +                           COL_INT_QUOTA_USED, &quota_used,
> +                           -1);
>         
>         if (!(bold = is_store || unread)) {
>                 if (gtk_tree_model_iter_has_child (model, iter))
> @@ -324,8 +327,19 @@ render_display_name (GtkTreeViewColumn *
>         if (!is_store && unread) {
>                 display = g_strdup_printf ("%s (%u)", name, unread);
>                 g_free (name);
> -       } else
> +       } else {
>                 display = name;
> +       }
> +
> +       if (quota_used!=CAMEL_QUOTA_UNAVAILABLE) {
> +
> +               if (quota_used!=CAMEL_QUOTA_INHERIT_PARENT)
> {           
> +                       gchar *old_display = display;

use normal char type :)

ugh @ gint/gchar

> +                       /* Note to translators: this string will be
> used to display the name of an email folder, together with the
> percentage of the storage quota used appended; e.g. "INBOX (73% full)"
> */
> +                       display = g_strdup_printf (_("%s (%u%%
> full)"), display, quota_used);
> +                       g_free (old_display);
> +               }
> +       }
>         
>         g_object_set (renderer, "text", display,
>                       "weight", bold ? PANGO_WEIGHT_BOLD :
> PANGO_WEIGHT_NORMAL
-- 
Jeffrey Stedfast
Evolution Hacker - Novell, Inc.
fejj ximian com  - www.novell.com

Attachment: smime.p7s
Description: S/MIME cryptographic signature



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]