[evolution-patches] First pass at IMAP quota support (RFC 2087)
- From: David Malcolm <dmalcolm redhat com>
- To: Evolution Patches <evolution-patches ximian com>
- Subject: [evolution-patches] First pass at IMAP quota support (RFC 2087)
- Date: Thu, 07 Oct 2004 12:43:31 -0400
Attached is a first attempt at IMAP quota support. A screenshot can be
seen here:
http://people.redhat.com/dmalcolm/ScreenshotOfIMAPQuota.png
It detects the QUOTA capability on an IMAP server. If present, when
getting folder information, it does a quota query on _every_ folder
returned by the server.
This is returned as a CamelImapQuotaRoot object, created by the
CamelProvider in its thread, owned by the CamelFolderInfo.
The UI thread examines these and converts to a percentage, or to
CAMEL_QUOTA_UNAVAILABLE, or to CAMEL_QUOTA_INHERIT_PARENT. It appends a
% usage figure to every mail folder for which data is available that
doesn't inhereit its quota from its parent. This means that for typical
usage you get a % full indicator on your INBOX.
Limitations so far:
- There are some hacks/incomplete bits in the RFC2087 parsing code
- Is the additional IMAP traffic too excessive?
- I haven't yet added GUI to the Folder Properties dialog
- There's a crash when I free up the quota structs; I believe I've
messed up somewhere - what are the ownership rules for CamelFolderInfo
structs? So for now I leak memory :-(
- This should be generalised to handle quotas on other types of mail
store e.g. for Exchange servers. I don't know the details of these;
suggestions are welcome.
Still it works (with the above caveats), and I wanted to get feedback.
Dave
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;
+ }
+}
+
/**
* 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)
+{
+ 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));
+ }
+
+ g_list_free (quota_root->resources);
+
+ g_free (quota_root);
+}
+
+int
+camel_imap_quota_root_get_worst_usage (CamelImapQuotaRoot *quota_root)
+{
+ /* 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;
+ }
+
+ 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,
+ "a_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);
+
+ 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;
+
+ in_str++;
+
+ if (!imap_parse_rfc2087_quota_resource (in_str, out_list_of_resource)) return FALSE;
+
+ 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);
+
+ 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)) {
+ /* 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
};
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, "a_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;
+ /* 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,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]