diff options
Diffstat (limited to 'camel/providers/imap')
-rw-r--r-- | camel/providers/imap/camel-imap-folder.c | 96 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-folder.h | 2 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-store.c | 230 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-store.h | 5 |
4 files changed, 191 insertions, 142 deletions
diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index 9664dab008..96236d2374 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -93,7 +93,6 @@ static const CamelMessageInfo *imap_get_message_info (CamelFolder *folder, const static GPtrArray *imap_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex); /* flag methods */ -/*static guint32 imap_get_permanent_flags (CamelFolder *folder, CamelException *ex);*/ static guint32 imap_get_message_flags (CamelFolder *folder, const char *uid); static void imap_set_message_flags (CamelFolder *folder, const char *uid, guint32 flags, guint32 set); static gboolean imap_get_message_user_flag (CamelFolder *folder, const char *uid, const char *name); @@ -306,6 +305,7 @@ imap_get_message_count_internal (CamelFolder *folder, CamelException *ex) { CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); gchar *result, *msg_count, *folder_path; + GPtrArray *response; gint status, count = 0; g_return_val_if_fail (folder->can_hold_messages, 0); @@ -313,10 +313,10 @@ imap_get_message_count_internal (CamelFolder *folder, CamelException *ex) folder_path = camel_imap_store_folder_path (store, folder->full_name); if (store->has_status_capability) - status = camel_imap_command_extended (store, folder, &result, ex, + status = camel_imap_command_extended (store, folder, &response, ex, "STATUS \"%s\" (MESSAGES)", folder_path); else - status = camel_imap_command_extended (store, folder, &result, ex, + status = camel_imap_command_extended (store, folder, &response, ex, "EXAMINE \"%s\"", folder_path); g_free (folder_path); @@ -325,17 +325,22 @@ imap_get_message_count_internal (CamelFolder *folder, CamelException *ex) return 0; /* parse out the message count */ - if (result && *result == '*') { - if (store->has_status_capability) { - /* should come in the form: "* STATUS <folder> (MESSAGES <count>)" */ + if (store->has_status_capability) { + /* should come in the form: "* STATUS <folder> (MESSAGES <count>)" */ + result = camel_imap_response_extract (response, "STATUS", NULL); + if (result) { if ((msg_count = strstr (result, "MESSAGES")) != NULL) { msg_count = imap_next_word (msg_count); /* we should now be pointing to the message count */ count = atoi (msg_count); } - } else { - /* should come in the form: "* <count> EXISTS" */ + g_free (result); + } + } else { + /* should come in the form: "* <count> EXISTS" */ + result = camel_imap_response_extract (response, "EXISTS", NULL); + if (result) { if ((msg_count = strstr (result, "EXISTS")) != NULL) { for ( ; msg_count > result && *msg_count != '*'; msg_count--); @@ -344,9 +349,9 @@ imap_get_message_count_internal (CamelFolder *folder, CamelException *ex) /* we should now be pointing to the message count */ count = atoi (msg_count); } + g_free (result); } } - g_free (result); return count; } @@ -501,16 +506,16 @@ imap_get_subfolder_info_internal (CamelFolder *folder, CamelException *ex) { CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); - GPtrArray *listing; + GPtrArray *response, *listing; gboolean found_inbox = FALSE; - gint status; - gchar *result, *namespace; + gint status, i; + gchar *namespace; CamelFolderInfo *fi; g_return_val_if_fail (folder != NULL, g_ptr_array_new ()); namespace = camel_imap_store_folder_path (store, folder->full_name); - status = camel_imap_command_extended (store, NULL, &result, ex, + status = camel_imap_command_extended (store, NULL, &response, ex, "LIST \"\" \"%s%s*\"", namespace, *namespace ? store->dir_sep : ""); @@ -523,31 +528,20 @@ imap_get_subfolder_info_internal (CamelFolder *folder, CamelException *ex) /* parse out the subfolders */ listing = g_ptr_array_new (); - if (result) { - char *ptr = result; - - while (ptr && *ptr == '*') { - gchar *flags, *sep, *dir, *buf, *end; - - for (end = ptr; *end && *end != '\n'; end++); - buf = g_strndup (ptr, (gint)(end - ptr)); - ptr = end; - - if (!imap_parse_list_response (buf, namespace, &flags, &sep, &dir)) { - g_free (buf); + if (response) { + for (i = 0; i < response->len; i++) { + gchar *resp, *flags, *sep, *dir; + + resp = response->pdata[i]; + if (!imap_parse_list_response (resp, namespace, &flags, &sep, &dir)) { g_free (flags); g_free (sep); g_free (dir); - - if (*ptr == '\n') - ptr++; - continue; } - - g_free (buf); + g_free (flags); - + if (*dir) { d(fprintf (stderr, "adding folder: %s\n", dir)); fi = g_new0 (CamelFolderInfo, 1); @@ -563,12 +557,10 @@ imap_get_subfolder_info_internal (CamelFolder *folder, CamelException *ex) found_inbox = TRUE; g_ptr_array_add (listing, fi); } - + g_free (sep); - - if (*ptr == '\n') - ptr++; } + camel_imap_response_free (response); } if (!*folder->name && !found_inbox) { @@ -580,7 +572,6 @@ imap_get_subfolder_info_internal (CamelFolder *folder, CamelException *ex) g_ptr_array_add (listing, fi); } - g_free (result); g_free (namespace); imap_folder->lsub = listing; @@ -821,13 +812,12 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex) summary_specifier = imap_protocol_get_summary_specifier (store); - /* We use camel_imap_command_extended here because it's safe */ if (num == 1) { - status = camel_imap_command_extended (store, folder, &result, ex, - "FETCH 1 (%s)", summary_specifier); + status = camel_imap_fetch_command (store, folder, &result, ex, + "FETCH 1 (%s)", summary_specifier); } else { - status = camel_imap_command_extended (store, folder, &result, ex, - "FETCH 1:%d (%s)", num, summary_specifier); + status = camel_imap_fetch_command (store, folder, &result, ex, + "FETCH 1:%d (%s)", num, summary_specifier); } g_free (summary_specifier); @@ -986,9 +976,8 @@ imap_get_message_info_internal (CamelFolder *folder, guint id, CamelException *e /* we don't have a cached copy, so fetch it */ summary_specifier = imap_protocol_get_summary_specifier (store); - /* again, we use camel_imap_command_extended here because it's safe to do so */ - status = camel_imap_command_extended (store, folder, &result, ex, - "FETCH %d (%s)", id, summary_specifier); + status = camel_imap_fetch_command (store, folder, &result, ex, + "FETCH %d (%s)", id, summary_specifier); g_free (summary_specifier); @@ -1093,7 +1082,7 @@ imap_get_message_info (CamelFolder *folder, const char *uid) static GPtrArray * imap_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex) { - GPtrArray *uids = NULL; + GPtrArray *response, *uids = NULL; char *result, *sexp, *p; int status; @@ -1109,12 +1098,14 @@ imap_search_by_expression (CamelFolder *folder, const char *expression, CamelExc } status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, - &result, ex, "UID SEARCH %s", sexp); + &response, NULL, "UID SEARCH %s", sexp); + g_free (sexp); - if (status != CAMEL_IMAP_OK) { - g_free (sexp); + if (status != CAMEL_IMAP_OK) + return uids; + result = camel_imap_response_extract (response, "SEARCH", NULL); + if (!result) return uids; - } if ((p = strstr (result, "* SEARCH"))) { char *word; @@ -1136,7 +1127,6 @@ imap_search_by_expression (CamelFolder *folder, const char *expression, CamelExc } g_free (result); - g_free (sexp); return uids; } @@ -1178,7 +1168,7 @@ imap_set_message_user_flag (CamelFolder *folder, const char *uid, const char *na } void -camel_imap_folder_changed (CamelFolder *folder, gint recent, GPtrArray *expunged, CamelException *ex) +camel_imap_folder_changed (CamelFolder *folder, gint recent, GArray *expunged, CamelException *ex) { CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); @@ -1186,7 +1176,7 @@ camel_imap_folder_changed (CamelFolder *folder, gint recent, GPtrArray *expunged gint i, id; for (i = 0; i < expunged->len; i++) { - id = atoi (expunged->pdata[i]); + id = g_array_index (expunged, int, i); d(fprintf (stderr, "Expunging message %d from the summary (i = %d)\n", id + i, i)); if (id <= imap_folder->summary->len) { diff --git a/camel/providers/imap/camel-imap-folder.h b/camel/providers/imap/camel-imap-folder.h index 2589ab4d50..d4d960b2a8 100644 --- a/camel/providers/imap/camel-imap-folder.h +++ b/camel/providers/imap/camel-imap-folder.h @@ -64,7 +64,7 @@ typedef struct { /* public methods */ CamelFolder *camel_imap_folder_new (CamelStore *parent, const char *folder_name); -void camel_imap_folder_changed (CamelFolder *folder, gint recent, GPtrArray *expunged, +void camel_imap_folder_changed (CamelFolder *folder, gint recent, GArray *expunged, CamelException *ex); /* Standard Camel function */ diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c index b6748f62cc..698b2ed732 100644 --- a/camel/providers/imap/camel-imap-store.c +++ b/camel/providers/imap/camel-imap-store.c @@ -180,7 +180,8 @@ imap_connect (CamelService *service, CamelException *ex) { CamelImapStore *store = CAMEL_IMAP_STORE (service); CamelSession *session = camel_service_get_session (CAMEL_SERVICE (store)); - gchar *buf, *result, *errbuf = NULL; + gchar *result, *buf, *errbuf = NULL; + GPtrArray *response; gboolean authenticated = FALSE; gint status; @@ -244,12 +245,14 @@ imap_connect (CamelService *service, CamelException *ex) } /* Now lets find out the IMAP capabilities */ - status = camel_imap_command_extended (store, NULL, &result, ex, "CAPABILITY"); - - if (status != CAMEL_IMAP_OK) { - /* Non-fatal error... (ex is set) */ - } - + status = camel_imap_command_extended (store, NULL, &response, ex, "CAPABILITY"); + if (status != CAMEL_IMAP_OK) + return FALSE; + + result = camel_imap_response_extract (response, "CAPABILITY", ex); + if (!result) + return FALSE; + /* parse for capabilities here. */ if (e_strstrcase (result, "IMAP4REV1")) store->server_level = IMAP_LEVEL_IMAP4REV1; @@ -257,20 +260,22 @@ imap_connect (CamelService *service, CamelException *ex) store->server_level = IMAP_LEVEL_IMAP4; else store->server_level = IMAP_LEVEL_UNKNOWN; - - if ((store->server_level >= IMAP_LEVEL_IMAP4REV1) || (e_strstrcase (result, "STATUS"))) + + if ((store->server_level >= IMAP_LEVEL_IMAP4REV1) || + (e_strstrcase (result, "STATUS"))) store->has_status_capability = TRUE; else store->has_status_capability = FALSE; - g_free (result); - + /* We now need to find out which directory separator this daemon uses */ - status = camel_imap_command_extended (store, NULL, &result, ex, "LIST \"\" \"\""); - - if (status != CAMEL_IMAP_OK) { - /* Again, this is non-fatal */ - } else { + status = camel_imap_command_extended (store, NULL, &response, ex, "LIST \"\" \"\""); + if (status != CAMEL_IMAP_OK) + return FALSE; + result = camel_imap_response_extract (response, "LIST", ex); + if (!result) + return FALSE; + else { char *flags, *sep, *folder; if (imap_parse_list_response (result, "", &flags, &sep, &folder)) { @@ -283,9 +288,8 @@ imap_connect (CamelService *service, CamelException *ex) g_free (flags); g_free (sep); g_free (folder); + g_free (result); } - - g_free (result); camel_remote_store_refresh_folders (CAMEL_REMOTE_STORE (store), ex); @@ -330,8 +334,8 @@ camel_imap_store_folder_path (CamelImapStore *store, const char *name) static gboolean imap_folder_exists (CamelImapStore *store, const char *folder_path, gboolean *selectable, CamelException *ex) { - gchar *result; - char *flags, *sep, *dirname; + GPtrArray *response; + char *result, *flags, *sep, *dirname; gint status; if (!g_strcasecmp (folder_path, "INBOX")) { @@ -345,12 +349,13 @@ imap_folder_exists (CamelImapStore *store, const char *folder_path, gboolean *se *selectable = FALSE; status = camel_imap_command_extended (CAMEL_IMAP_STORE (store), NULL, - &result, ex, "LIST \"\" \"%s\"", folder_path); - if (status != CAMEL_IMAP_OK) { - g_free (result); + &response, ex, "LIST \"\" \"%s\"", folder_path); + if (status != CAMEL_IMAP_OK) return FALSE; - } - + result = camel_imap_response_extract (response, "LIST", ex); + if (!result) + return FALSE; + if (imap_parse_list_response (result, "", &flags, &sep, &dirname)) { if (selectable) *selectable = !e_strstrcase (flags, "NoSelect"); @@ -358,9 +363,11 @@ imap_folder_exists (CamelImapStore *store, const char *folder_path, gboolean *se g_free (flags); g_free (sep); g_free (dirname); + g_free (result); return TRUE; } + g_free (result); g_free (flags); g_free (sep); @@ -630,12 +637,12 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder, CamelException * **/ gint -camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char **ret, CamelException *ex, char *fmt, ...) +camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, GPtrArray **ret, CamelException *ex, char *fmt, ...) { gint status = CAMEL_IMAP_OK; - GPtrArray *data, *expunged; + GPtrArray *data; + GArray *expunged; gchar *respbuf, *cmdid; - guint32 len = 0; gint recent = 0; va_list ap; gint i; @@ -653,27 +660,24 @@ camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char ** } va_end (ap); - data = g_ptr_array_new (); - expunged = g_ptr_array_new (); + expunged = g_array_new (FALSE, FALSE, sizeof (int)); + if (ret) + data = g_ptr_array_new (); /* read multi-line response */ while (1) { if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), &respbuf, ex) < 0) { /* cleanup */ - for (i = 0; i < data->len; i++) - g_free (data->pdata[i]); - g_ptr_array_free (data, TRUE); - - for (i = 0; i < expunged->len; i++) - g_free (expunged->pdata[i]); - g_ptr_array_free (expunged, TRUE); + if (ret) { + for (i = 0; i < data->len; i++) + g_free (data->pdata[i]); + g_ptr_array_free (data, TRUE); + } + g_array_free (expunged, TRUE); return CAMEL_IMAP_FAIL; } - g_ptr_array_add (data, respbuf); - len += strlen (respbuf) + 1; - /* IMAPs multi-line response ends with the cmdid string at the beginning of the line */ if (!strncmp (respbuf, cmdid, strlen (cmdid))) { status = camel_imap_status (cmdid, respbuf); @@ -690,6 +694,8 @@ camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char ** rcnt = imap_next_word (respbuf); if (*rcnt >= '0' && *rcnt <= '9' && !strncmp ("RECENT", imap_next_word (rcnt), 6)) recent = atoi (rcnt); + g_free (respbuf); + continue; } else if (strstr (respbuf, "EXPUNGE")) { char *id_str; int id; @@ -699,33 +705,22 @@ camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char ** id_str = imap_next_word (respbuf); if (*id_str >= '0' && *id_str <= '9' && !strncmp ("EXPUNGE", imap_next_word (id_str), 7)) { id = atoi (id_str); - g_ptr_array_add (expunged, g_strdup_printf ("%d", id)); + g_array_append_val (expunged, id); } + g_free (respbuf); + continue; } } + if (ret) + g_ptr_array_add (data, respbuf); + else + g_free (respbuf); } - if (status == CAMEL_IMAP_OK && ret) { - gchar *p; - - /* populate the return buffer with the server response */ - *ret = g_new (char, len + 1); - p = *ret; - - for (i = 0; i < data->len; i++) { - char *datap; - - datap = (char *) data->pdata[i]; - if (*datap == '.') - datap++; - len = strlen (datap); - memcpy (p, datap, len); - p += len; - *p++ = '\n'; - } - - *p = '\0'; - } else if (status != CAMEL_IMAP_OK) { + if (status == CAMEL_IMAP_OK) { + if (ret) + *ret = data; + } else { /* command failed */ if (respbuf) { char *word; @@ -741,10 +736,16 @@ camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char ** "IMAP command failed: Unknown"); } - if (ret) - *ret = NULL; + if (ret) { + for (i = 0; i < data->len; i++) + g_free (data->pdata[i]); + g_ptr_array_free (data, TRUE); + } } + if (respbuf) + g_free (respbuf); + /* Update the summary */ if (folder && (recent > 0 || expunged->len > 0)) { CamelException dex; @@ -753,19 +754,81 @@ camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char ** camel_imap_folder_changed (folder, recent, expunged, &dex); camel_exception_clear (&dex); } - - for (i = 0; i < data->len; i++) - g_free (data->pdata[i]); - g_ptr_array_free (data, TRUE); - - for (i = 0; i < expunged->len; i++) - g_free (expunged->pdata[i]); - g_ptr_array_free (expunged, TRUE); + g_array_free (expunged, TRUE); return status; } /** + * camel_imap_response_free: + * @response: the result data returned from camel_imap_command_extended + * + * Frees the data. + **/ +void +camel_imap_response_free (GPtrArray *response) +{ + int i; + + for (i = 0; i < response->len; i++) + g_free (response->pdata[i]); + g_ptr_array_free (response, TRUE); +} + +/** + * camel_imap_response_extract: + * @response: the result data returned from camel_imap_command_extended + * @type: the response type to extract + * @ex: a CamelException + * + * This checks that @response contains a single untagged response of + * type @type and returns just that response data. If @response + * doesn't contain the right information, the function will set @ex and + * return %NULL. Either way, @response will be freed. + * + * Return value: the desired response string, which the caller must free. + **/ +char * +camel_imap_response_extract (GPtrArray *response, const char *type, + CamelException *ex) +{ + int len = strlen (type), i; + char *resp; + + for (i = 0; i < response->len; i++) { + resp = response->pdata[i]; + if (strncmp (resp, "* ", 2) != 0) { + g_free (resp); + continue; + } + + /* Skip inititial sequence number, if present */ + strtoul (resp + 2, &resp, 10); + if (*resp == ' ') + resp++; + + if (!g_strncasecmp (resp, type, len)) + break; + + g_free (resp); + } + + if (i < response->len) { + resp = response->pdata[i]; + for (i++; i < response->len; i++) + g_free (response->pdata[i]); + } else { + resp = NULL; + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + "IMAP server response did not contain " + "%s information", type); + } + + g_ptr_array_free (response, TRUE); + return resp; +} + +/** * camel_imap_fetch_command: Send a FETCH request to an IMAP server and get * a multi-line response. * @store: the IMAP store @@ -800,7 +863,8 @@ camel_imap_fetch_command (CamelImapStore *store, CamelFolder *folder, char **ret * determine whether we are actually reading server responses. */ gint status = CAMEL_IMAP_OK; - GPtrArray *data, *expunged; + GPtrArray *data; + GArray *expunged; gboolean is_notification; gchar *respbuf, *cmdid; guint32 len = 0; @@ -862,7 +926,7 @@ camel_imap_fetch_command (CamelImapStore *store, CamelFolder *folder, char **ret return CAMEL_IMAP_FAIL; } - expunged = g_ptr_array_new (); + expunged = g_array_new (FALSE, FALSE, sizeof (int)); /* read multi-line response */ while (1) { @@ -871,10 +935,7 @@ camel_imap_fetch_command (CamelImapStore *store, CamelFolder *folder, char **ret for (i = 0; i < data->len; i++) g_free (data->pdata[i]); g_ptr_array_free (data, TRUE); - - for (i = 0; i < expunged->len; i++) - g_free (expunged->pdata[i]); - g_ptr_array_free (expunged, TRUE); + g_array_free (expunged, TRUE); return CAMEL_IMAP_FAIL; } @@ -897,10 +958,8 @@ camel_imap_fetch_command (CamelImapStore *store, CamelFolder *folder, char **ret recent = 0; - for (i = 0; i < expunged->len; i++) { - g_free (expunged->pdata[i]); - g_ptr_array_remove_index (expunged, i); - } + for (i = 0; i < expunged->len; i++) + g_array_remove_index (expunged, i); } /* Check for a RECENT in the untagged response */ @@ -922,7 +981,7 @@ camel_imap_fetch_command (CamelImapStore *store, CamelFolder *folder, char **ret id_str = imap_next_word (respbuf); if (*id_str >= '0' && *id_str <= '9' && !strncmp ("EXPUNGE", imap_next_word (id_str), 7)) { id = atoi (id_str); - g_ptr_array_add (expunged, g_strdup_printf ("%d", id)); + g_array_append_val (expunged, id); } } } @@ -986,10 +1045,7 @@ camel_imap_fetch_command (CamelImapStore *store, CamelFolder *folder, char **ret for (i = 0; i < data->len; i++) g_free (data->pdata[i]); g_ptr_array_free (data, TRUE); - - for (i = 0; i < expunged->len; i++) - g_free (expunged->pdata[i]); - g_ptr_array_free (expunged, TRUE); + g_array_free (expunged, TRUE); return status; } diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h index fe7b9f2f78..1d9a07ff96 100644 --- a/camel/providers/imap/camel-imap-store.h +++ b/camel/providers/imap/camel-imap-store.h @@ -84,7 +84,10 @@ gint camel_imap_command (CamelImapStore *store, CamelFolder *folder, CamelException *ex, char *fmt, ...); gint camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, - char **ret, CamelException *ex, char *fmt, ...); + GPtrArray **ret, CamelException *ex, char *fmt, ...); +void camel_imap_response_free (GPtrArray *response); +char *camel_imap_response_extract (GPtrArray *response, const char *type, + CamelException *ex); gint camel_imap_fetch_command (CamelImapStore *store, CamelFolder *folder, char **ret, CamelException *ex, char *fmt, ...); |