diff options
Diffstat (limited to 'camel/providers/imap')
-rw-r--r-- | camel/providers/imap/Makefile.am | 3 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-command.c | 49 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-folder.c | 386 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-store.h | 1 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-utils.c | 357 |
5 files changed, 203 insertions, 593 deletions
diff --git a/camel/providers/imap/Makefile.am b/camel/providers/imap/Makefile.am index dbee888f39..bf183aa3ce 100644 --- a/camel/providers/imap/Makefile.am +++ b/camel/providers/imap/Makefile.am @@ -9,6 +9,7 @@ INCLUDES = -I.. \ -I$(srcdir)/.. \ -I$(top_srcdir)/camel \ -I$(top_srcdir)/intl \ + -I$(top_srcdir)/libibex \ -I$(top_srcdir)/e-util \ -I$(top_srcdir) \ -I$(includedir) \ @@ -39,7 +40,7 @@ libcamelimapinclude_HEADERS = \ camel-imap-utils.h \ camel-imap-wrapper.h -libcamelimap_la_LDFLAGS = -avoid-version -module +libcamelimap_la_LDFLAGS = -version-info 0:0:0 noinst_HEADERS = \ camel-imap-private.h diff --git a/camel/providers/imap/camel-imap-command.c b/camel/providers/imap/camel-imap-command.c index 6a2382b3c8..f6fb0dde8e 100644 --- a/camel/providers/imap/camel-imap-command.c +++ b/camel/providers/imap/camel-imap-command.c @@ -267,25 +267,18 @@ camel_imap_command_response (CamelImapStore *store, char **response, switch (*respbuf) { case '*': - if (!g_strncasecmp (respbuf, "* BYE", 5)) { + type = CAMEL_IMAP_RESPONSE_UNTAGGED; + + /* Read the rest of the response if it is multi-line. */ + respbuf = imap_read_untagged (store, respbuf, ex); + if (!respbuf) + type = CAMEL_IMAP_RESPONSE_ERROR; + else if (!g_strncasecmp (respbuf, "* BYE", 5)) { /* Connection was lost, no more data to fetch */ - camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Server unexpectedly disconnected: %s"), - _("Unknown error")); /* g_strerror (104)); FIXME after 1.0 is released */ store->connected = FALSE; g_free (respbuf); - respbuf = NULL; type = CAMEL_IMAP_RESPONSE_ERROR; - break; } - - /* Read the rest of the response. */ - type = CAMEL_IMAP_RESPONSE_UNTAGGED; - respbuf = imap_read_untagged (store, respbuf, ex); - if (!respbuf) - type = CAMEL_IMAP_RESPONSE_ERROR; - break; case '+': type = CAMEL_IMAP_RESPONSE_CONTINUATION; @@ -299,7 +292,6 @@ camel_imap_command_response (CamelImapStore *store, char **response, if (type == CAMEL_IMAP_RESPONSE_ERROR || type == CAMEL_IMAP_RESPONSE_TAGGED) CAMEL_IMAP_STORE_UNLOCK (store, command_lock); - return type; } @@ -406,16 +398,17 @@ imap_read_untagged (CamelImapStore *store, char *line, CamelException *ex) str->str + 1, length); if (nread == -1) { if (errno == EINTR) - camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Operation cancelled")); + camel_exception_set(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Operation cancelled")); else - camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, g_strerror (errno)); + camel_exception_set(ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, strerror(errno)); camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); goto lose; } if (nread < length) { - camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Server response ended too soon.")); - camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + _("Server response ended too soon.")); + camel_service_disconnect (CAMEL_SERVICE (store), + FALSE, NULL); goto lose; } str->str[length + 1] = '\0'; @@ -588,14 +581,12 @@ camel_imap_response_extract (CamelImapStore *store, int len = strlen (type), i; char *resp; - len = strlen (type); - for (i = 0; i < response->untagged->len; i++) { resp = response->untagged->pdata[i]; /* Skip "* ", and initial sequence number, if present */ strtoul (resp + 2, &resp, 10); if (*resp == ' ') - resp = (char *) imap_next_word (resp); + resp = imap_next_word (resp); if (!g_strncasecmp (resp, type, len)) break; @@ -702,7 +693,7 @@ imap_command_strdup_vprintf (CamelImapStore *store, const char *fmt, len += arglen * 2; start = p + 1; break; - + case '%': start = p; break; @@ -743,14 +734,8 @@ imap_command_strdup_vprintf (CamelImapStore *store, const char *fmt, case 'S': case 'F': string = args->pdata[i++]; - if (*p == 'F') { - char *mailbox; - - mailbox = imap_namespace_concat (store, string); - string = imap_mailbox_encode (mailbox, strlen (mailbox)); - g_free (mailbox); - } - + if (*p == 'F') + string = imap_namespace_concat (store, string); if (store->capabilities & IMAP_CAPABILITY_LITERALPLUS) { op += sprintf (op, "{%d+}\r\n%s", strlen (string), string); diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index 811533d25a..45dad9f6b0 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -64,11 +64,6 @@ #include "camel-stream.h" #include "string-utils.h" - -/* set to -1 for infinite size */ -#define UID_SET_LIMIT (4096) - - #define CF_CLASS(o) (CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(o))) static CamelDiscoFolderClass *disco_folder_class = NULL; @@ -231,8 +226,6 @@ camel_imap_folder_new (CamelStore *parent, const char *folder_name, !g_strcasecmp (folder_name, "INBOX")) folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT; - imap_folder->search = camel_imap_search_new(folder_dir); - return folder; } @@ -453,8 +446,7 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex) CamelImapMessageInfo *iinfo; GArray *removed; gboolean ok; - CamelFolderChangeInfo *changes = NULL; - + CAMEL_IMAP_STORE_ASSERT_LOCKED (store, command_lock); imap_folder->need_rescan = FALSE; @@ -544,20 +536,15 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex) info->flags = (info->flags | server_set) & ~server_cleared; iinfo->server_flags = new[i].flags; - - if (changes == NULL) - changes = camel_folder_change_info_new(); - camel_folder_change_info_change_uid(changes, new[i].uid); + + camel_object_trigger_event (CAMEL_OBJECT (folder), + "message_changed", + new[i].uid); } camel_folder_summary_info_free (folder->summary, info); g_free (new[i].uid); } - - if (changes) { - camel_object_trigger_event(CAMEL_OBJECT (folder), "folder_changed", changes); - camel_folder_change_info_free(changes); - } seq = i + 1; @@ -578,14 +565,11 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex) g_array_free (removed, TRUE); } -/* the max number of chars that an unsigned 32-bit int can be is 10 chars plus 1 for a possible : */ -#define UID_SET_FULL(setlen, maxlen) (maxlen > 0 ? setlen + 11 >= maxlen : FALSE) - /* Find all messages in @folder with flags matching @flags and @mask. * If no messages match, returns %NULL. Otherwise, returns an array of * CamelMessageInfo and sets *@set to a message set corresponding the - * UIDs of the matched messages (up to @UID_SET_LIMIT bytes). The - * caller must free the infos, the array, and the set string. + * UIDs of the matched messages. The caller must free the infos, the + * array, and the set string. */ static GPtrArray * get_matching (CamelFolder *folder, guint32 flags, guint32 mask, char **set) @@ -594,12 +578,12 @@ get_matching (CamelFolder *folder, guint32 flags, guint32 mask, char **set) CamelMessageInfo *info; int i, max, range; GString *gset; - + matches = g_ptr_array_new (); gset = g_string_new (""); max = camel_folder_summary_count (folder->summary); range = -1; - for (i = 0; i < max && !UID_SET_FULL (gset->len, UID_SET_LIMIT); i++) { + for (i = 0; i < max; i++) { info = camel_folder_summary_index (folder->summary, i); if (!info) continue; @@ -614,7 +598,7 @@ get_matching (CamelFolder *folder, guint32 flags, guint32 mask, char **set) } continue; } - + g_ptr_array_add (matches, info); if (range != -1) continue; @@ -623,12 +607,11 @@ get_matching (CamelFolder *folder, guint32 flags, guint32 mask, char **set) g_string_append_c (gset, ','); g_string_sprintfa (gset, "%s", camel_message_info_uid (info)); } - if (range != -1 && range != max - 1) { info = matches->pdata[matches->len - 1]; g_string_sprintfa (gset, ":%s", camel_message_info_uid (info)); } - + if (matches->len) { *set = gset->str; g_string_free (gset, FALSE); @@ -674,19 +657,14 @@ imap_sync_online (CamelFolder *folder, CamelException *ex) } /* Note: Cyrus is broken and will not accept an - empty-set of flags so... if this is true then we - want to unset the previously set flags.*/ + empty-set of flags so... if this is true then we + want to unset the previously set flags.*/ unset = !(info->flags & CAMEL_IMAP_SERVER_FLAGS); /* FIXME: since we don't know the previously set - flags, if unset is TRUE then just unset all the flags? */ + flags, if unset is TRUE then just unset all the flags? */ flaglist = imap_create_flag_list (unset ? CAMEL_IMAP_SERVER_FLAGS : info->flags); - /* Note: get_matching() uses UID_SET_LIMIT to limit - the size of the uid-set string. We don't have to - loop here to flush all the matching uids because - they will be scooped up later by our parent loop (I - think?). -- Jeff */ matches = get_matching (folder, info->flags & (CAMEL_IMAP_SERVER_FLAGS | CAMEL_MESSAGE_FOLDER_FLAGGED), CAMEL_IMAP_SERVER_FLAGS | CAMEL_MESSAGE_FOLDER_FLAGGED, &set); camel_folder_summary_info_free (folder->summary, info); @@ -751,34 +729,28 @@ imap_expunge_uids_online (CamelFolder *folder, GPtrArray *uids, CamelException * { CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); CamelImapResponse *response; - int uid = 0; char *set; + set = imap_uid_array_to_set (folder->summary, uids); CAMEL_IMAP_STORE_LOCK (store, command_lock); - - while (uid < uids->len) { - set = imap_uid_array_to_set (folder->summary, uids, uid, UID_SET_LIMIT, &uid); - response = camel_imap_command (store, folder, ex, - "UID STORE %s +FLAGS.SILENT \\Deleted", - set); - if (response) - camel_imap_response_free (store, response); - if (camel_exception_is_set (ex)) { - CAMEL_IMAP_STORE_UNLOCK (store, command_lock); - g_free (set); - return; - } - - if (store->capabilities & IMAP_CAPABILITY_UIDPLUS) { - response = camel_imap_command (store, folder, ex, - "UID EXPUNGE %s", set); - } else - response = camel_imap_command (store, folder, ex, "EXPUNGE"); - - if (response) - camel_imap_response_free (store, response); + response = camel_imap_command (store, folder, ex, + "UID STORE %s +FLAGS.SILENT \\Deleted", + set); + if (response) + camel_imap_response_free (store, response); + if (camel_exception_is_set (ex)) { + CAMEL_IMAP_STORE_UNLOCK (store, command_lock); + g_free (set); + return; } + if (store->capabilities & IMAP_CAPABILITY_UIDPLUS) { + response = camel_imap_command (store, folder, ex, + "UID EXPUNGE %s", set); + } else + response = camel_imap_command (store, folder, ex, "EXPUNGE"); + if (response) + camel_imap_response_free (store, response); CAMEL_IMAP_STORE_UNLOCK (store, command_lock); } @@ -802,21 +774,20 @@ static void imap_expunge_uids_resyncing (CamelFolder *folder, GPtrArray *uids, CamelException *ex) { CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); - GPtrArray *keep_uids, *mark_uids; CamelImapResponse *response; - char *result; + char *result, *keep_uidset, *mark_uidset; if (store->capabilities & IMAP_CAPABILITY_UIDPLUS) { imap_expunge_uids_online (folder, uids, ex); return; } - + /* If we don't have UID EXPUNGE we need to avoid expunging any * of the wrong messages. So we search for deleted messages, * and any that aren't in our to-expunge list get temporarily * marked un-deleted. */ - + CAMEL_IMAP_STORE_LOCK (store, command_lock); response = camel_imap_command (store, folder, ex, "UID SEARCH DELETED"); if (!response) { @@ -828,125 +799,100 @@ imap_expunge_uids_resyncing (CamelFolder *folder, GPtrArray *uids, CamelExceptio CAMEL_IMAP_STORE_UNLOCK (store, command_lock); return; } - + + keep_uidset = mark_uidset = NULL; if (result[8] == ' ') { + GPtrArray *keep_uids, *mark_uids; char *uid, *lasts = NULL; unsigned long euid, kuid; int ei, ki; - + keep_uids = g_ptr_array_new (); mark_uids = g_ptr_array_new (); - + /* Parse SEARCH response */ for (uid = strtok_r (result + 9, " ", &lasts); uid; uid = strtok_r (NULL, " ", &lasts)) g_ptr_array_add (keep_uids, uid); qsort (keep_uids->pdata, keep_uids->len, sizeof (void *), uid_compar); - + /* Fill in "mark_uids", empty out "keep_uids" as needed */ for (ei = ki = 0; ei < uids->len; ei++) { euid = strtoul (uids->pdata[ei], NULL, 10); - + for (kuid = 0; ki < keep_uids->len; ki++) { kuid = strtoul (keep_uids->pdata[ki], NULL, 10); - + if (kuid >= euid) break; } - + if (euid == kuid) g_ptr_array_remove_index (keep_uids, ki); else g_ptr_array_add (mark_uids, uids->pdata[ei]); } + + if (keep_uids->len) + keep_uidset = imap_uid_array_to_set (folder->summary, keep_uids); + g_ptr_array_free (keep_uids, TRUE); + + if (mark_uids->len) + mark_uidset = imap_uid_array_to_set (folder->summary, mark_uids); + g_ptr_array_free (mark_uids, TRUE); } else { /* Empty SEARCH result, meaning nothing is marked deleted * on server. */ - - keep_uids = NULL; - mark_uids = NULL; + mark_uidset = imap_uid_array_to_set (folder->summary, uids); } - g_free (result); - + /* Unmark messages to be kept */ - if (keep_uids) { - char *uidset; - int uid = 0; - - while (uid < keep_uids->len) { - uidset = imap_uid_array_to_set (folder->summary, keep_uids, uid, UID_SET_LIMIT, &uid); - - response = camel_imap_command (store, folder, ex, - "UID STORE %s -FLAGS.SILENT \\Deleted", - uidset); - - g_free (uidset); - - if (!response) { - g_ptr_array_free (keep_uids, TRUE); - g_ptr_array_free (mark_uids, TRUE); - CAMEL_IMAP_STORE_UNLOCK (store, command_lock); - return; - } - camel_imap_response_free (store, response); + if (keep_uidset) { + response = camel_imap_command (store, folder, ex, + "UID STORE %s -FLAGS.SILENT \\Deleted", + keep_uidset); + if (!response) { + g_free (keep_uidset); + g_free (mark_uidset); + CAMEL_IMAP_STORE_UNLOCK (store, command_lock); + return; } + camel_imap_response_free (store, response); } - + /* Mark any messages that still need to be marked */ - if (mark_uids) { - char *uidset; - int uid = 0; - - while (uid < mark_uids->len) { - uidset = imap_uid_array_to_set (folder->summary, mark_uids, uid, UID_SET_LIMIT, &uid); - - response = camel_imap_command (store, folder, ex, - "UID STORE %s +FLAGS.SILENT \\Deleted", - uidset); - - g_free (uidset); - - if (!response) { - g_ptr_array_free (keep_uids, TRUE); - g_ptr_array_free (mark_uids, TRUE); - CAMEL_IMAP_STORE_UNLOCK (store, command_lock); - return; - } - camel_imap_response_free (store, response); + if (mark_uidset) { + response = camel_imap_command (store, folder, ex, + "UID STORE %s +FLAGS.SILENT \\Deleted", + mark_uidset); + g_free (mark_uidset); + if (!response) { + g_free (keep_uidset); + CAMEL_IMAP_STORE_UNLOCK (store, command_lock); + return; } - - g_ptr_array_free (mark_uids, TRUE); + camel_imap_response_free (store, response); } - + /* Do the actual expunging */ response = camel_imap_command (store, folder, ex, "EXPUNGE"); if (response) camel_imap_response_free (store, response); - + /* And fix the remaining messages if we mangled them */ - if (keep_uids) { - char *uidset; - int uid = 0; - - while (uid < keep_uids->len) { - uidset = imap_uid_array_to_set (folder->summary, keep_uids, uid, UID_SET_LIMIT, &uid); - - /* Don't pass ex if it's already been set */ - response = camel_imap_command (store, folder, - camel_exception_is_set (ex) ? NULL : ex, - "UID STORE %s +FLAGS.SILENT \\Deleted", - uidset); - - g_free (uidset); - if (response) - camel_imap_response_free (store, response); - } - - g_ptr_array_free (keep_uids, TRUE); + if (keep_uidset) { + /* Don't pass ex if it's already been set */ + response = camel_imap_command (store, folder, + camel_exception_is_set (ex) ? NULL : ex, + "UID STORE %s +FLAGS.SILENT \\Deleted", + keep_uidset); + g_free (keep_uidset); + if (response) + camel_imap_response_free (store, response); } - + CAMEL_IMAP_STORE_UNLOCK (store, command_lock); } @@ -1240,22 +1186,16 @@ do_copy (CamelFolder *source, GPtrArray *uids, { CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store); CamelImapResponse *response; - char *uidset; - int uid = 0; - - while (uid < uids->len && !camel_exception_is_set (ex)) { - uidset = imap_uid_array_to_set (source->summary, uids, uid, UID_SET_LIMIT, &uid); - - response = camel_imap_command (store, source, ex, "UID COPY %s %F", - uidset, destination->full_name); - - g_free (uidset); - - if (response && (store->capabilities & IMAP_CAPABILITY_UIDPLUS)) - handle_copyuid (response, source, destination); - - camel_imap_response_free (store, response); - } + char *set; + + set = imap_uid_array_to_set (source->summary, uids); + response = camel_imap_command (store, source, ex, "UID COPY %s %F", + set, destination->full_name); + if (response && (store->capabilities & IMAP_CAPABILITY_UIDPLUS)) + handle_copyuid (response, source, destination); + + camel_imap_response_free (store, response); + g_free (set); } static void @@ -1374,6 +1314,9 @@ imap_search_by_expression (CamelFolder *folder, const char *expression, CamelExc command channel too */ CAMEL_IMAP_FOLDER_LOCK(folder, search_lock); + if (!imap_folder->search) + imap_folder->search = camel_imap_search_new (); + camel_folder_search_set_folder (imap_folder->search, folder); summary = camel_folder_get_summary(folder); camel_folder_search_set_summary(imap_folder->search, summary); @@ -1410,6 +1353,9 @@ imap_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids CAMEL_IMAP_FOLDER_LOCK(folder, search_lock); + if (imap_folder->search == NULL) + imap_folder->search = camel_imap_search_new(); + camel_folder_search_set_folder(imap_folder->search, folder); camel_folder_search_set_summary(imap_folder->search, summary); @@ -1465,7 +1411,6 @@ get_content (CamelImapFolder *imap_folder, const char *uid, body_mp = camel_multipart_new (); camel_data_wrapper_set_mime_type_field ( CAMEL_DATA_WRAPPER (body_mp), ci->type); - camel_multipart_set_boundary (body_mp, NULL); speclen = strlen (part_spec); @@ -1505,7 +1450,7 @@ get_content (CamelImapFolder *imap_folder, const char *uid, camel_object_unref (CAMEL_OBJECT (content)); camel_multipart_add_part (body_mp, part); camel_object_unref (CAMEL_OBJECT (part)); - + ci = ci->next; } g_free (child_spec); @@ -1731,7 +1676,7 @@ add_message_from_data (CamelFolder *folder, GPtrArray *messages, if (seq - first >= messages->len) g_ptr_array_set_size (messages, seq - first + 1); - + msg = camel_mime_message_new (); if (camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (msg), stream) == -1) { camel_object_unref (CAMEL_OBJECT (msg)); @@ -1813,13 +1758,13 @@ imap_update_summary (CamelFolder *folder, int exists, g_free (resp); if (!data) continue; - + seq = GPOINTER_TO_INT (g_datalist_get_data (&data, "SEQUENCE")); if (seq < first) { g_datalist_clear (&data); continue; } - + if (g_datalist_get_data (&data, "FLAGS")) got += IMAP_PRETEND_SIZEOF_FLAGS; if (g_datalist_get_data (&data, "RFC822.SIZE")) @@ -1827,22 +1772,22 @@ imap_update_summary (CamelFolder *folder, int exists, stream = g_datalist_get_data (&data, "BODY_PART_STREAM"); if (stream) { got += IMAP_PRETEND_SIZEOF_HEADERS; - + /* Use the stream now so we don't tie up many * many fds if we're fetching many many messages. */ add_message_from_data (folder, messages, first, data); g_datalist_set_data (&data, "BODY_PART_STREAM", NULL); } - + camel_operation_progress (NULL, got * 100 / size); g_ptr_array_add (fetch_data, data); } camel_operation_end (NULL); - + if (type == CAMEL_IMAP_RESPONSE_ERROR) goto lose; - + /* Figure out which headers we still need to fetch. */ needheaders = g_ptr_array_new (); size = got = 0; @@ -1850,67 +1795,55 @@ imap_update_summary (CamelFolder *folder, int exists, data = fetch_data->pdata[i]; if (g_datalist_get_data (&data, "BODY_PART_LEN")) continue; - + uid = g_datalist_get_data (&data, "UID"); if (uid) { g_ptr_array_add (needheaders, uid); size += IMAP_PRETEND_SIZEOF_HEADERS; } } - + /* And fetch them */ if (needheaders->len) { - char *uidset; - int uid = 0; - - qsort (needheaders->pdata, needheaders->len, - sizeof (void *), uid_compar); - + char *set; + + /* FIXME: sort needheaders */ + set = imap_uid_array_to_set (folder->summary, needheaders); + g_ptr_array_free (needheaders, TRUE); + if (!camel_imap_command_start (store, folder, ex, + "UID FETCH %s BODY.PEEK[%s]", + set, header_spec)) { + g_free (set); + goto lose; + } + g_free (set); + camel_operation_start (NULL, _("Fetching summary information for new messages")); - - while (uid < needheaders->len) { - uidset = imap_uid_array_to_set (folder->summary, needheaders, uid, UID_SET_LIMIT, &uid); - if (!camel_imap_command_start (store, folder, ex, - "UID FETCH %s BODY.PEEK[%s]", - uidset, header_spec)) { - g_ptr_array_free (needheaders, TRUE); - camel_operation_end (NULL); - g_free (uidset); - goto lose; - } - g_free (uidset); - - while ((type = camel_imap_command_response (store, &resp, ex)) - == CAMEL_IMAP_RESPONSE_UNTAGGED) { - data = parse_fetch_response (imap_folder, resp); - g_free (resp); - if (!data) - continue; - - stream = g_datalist_get_data (&data, "BODY_PART_STREAM"); - if (stream) { - add_message_from_data (folder, messages, first, data); - got += IMAP_PRETEND_SIZEOF_HEADERS; - camel_operation_progress (NULL, got * 100 / size); - } - g_datalist_clear (&data); - } - - if (type == CAMEL_IMAP_RESPONSE_ERROR) { - g_ptr_array_free (needheaders, TRUE); - camel_operation_end (NULL); - goto lose; + while ((type = camel_imap_command_response (store, &resp, ex)) + == CAMEL_IMAP_RESPONSE_UNTAGGED) { + data = parse_fetch_response (imap_folder, resp); + g_free (resp); + if (!data) + continue; + + stream = g_datalist_get_data (&data, "BODY_PART_STREAM"); + if (stream) { + add_message_from_data (folder, messages, first, data); + got += IMAP_PRETEND_SIZEOF_HEADERS; + camel_operation_progress (NULL, got * 100 / size); } + g_datalist_clear (&data); } - - g_ptr_array_free (needheaders, TRUE); camel_operation_end (NULL); + + if (type == CAMEL_IMAP_RESPONSE_ERROR) + goto lose; } - + /* Now finish up summary entries (fix UIDs, set flags and size) */ for (i = 0; i < fetch_data->len; i++) { data = fetch_data->pdata[i]; - + seq = GPOINTER_TO_INT (g_datalist_get_data (&data, "SEQUENCE")); if (seq >= first + messages->len) { g_datalist_clear (&data); @@ -1939,11 +1872,7 @@ imap_update_summary (CamelFolder *folder, int exists, break; } - if (pmi == NULL) { - /* Server response is *really* fucked up, - I guess we just pretend it never happened? */ - continue; - } + g_assert (pmi); mi = camel_message_info_new (); camel_message_info_dup_to (pmi, mi); @@ -1963,11 +1892,11 @@ imap_update_summary (CamelFolder *folder, int exists, size = GPOINTER_TO_INT (g_datalist_get_data (&data, "RFC822.SIZE")); if (size) mi->size = size; - + g_datalist_clear (&data); } g_ptr_array_free (fetch_data, TRUE); - + /* And add the entries to the summary, etc. */ for (i = 0; i < messages->len; i++) { mi = messages->pdata[i]; @@ -1977,30 +1906,13 @@ imap_update_summary (CamelFolder *folder, int exists, } camel_folder_summary_add (folder->summary, mi); camel_folder_change_info_add_uid (changes, camel_message_info_uid (mi)); - + if ((mi->flags & CAMEL_IMAP_MESSAGE_RECENT)) camel_folder_change_info_recent_uid(changes, camel_message_info_uid (mi)); } g_ptr_array_free (messages, TRUE); - - /* Kludge around Microsoft Exchange 5.5 IMAP - See bug #5348 for details */ - if (camel_folder_summary_count (folder->summary) != exists) { - CamelImapStore *imap_store = (CamelImapStore *) folder->parent_store; - CamelImapResponse *response; - - /* forget the currently selected folder */ - if (imap_store->current_folder) { - camel_object_unref (CAMEL_OBJECT (imap_store->current_folder)); - imap_store->current_folder = NULL; - } - - /* now re-select it and process the EXISTS response */ - response = camel_imap_command (imap_store, folder, ex, NULL); - camel_imap_response_free (imap_store, response); - } - return; - + lose: if (fetch_data) { for (i = 0; i < fetch_data->len; i++) { @@ -2109,7 +2021,7 @@ camel_imap_folder_fetch_data (CamelImapFolder *imap_folder, const char *uid, CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock); CAMEL_IMAP_STORE_UNLOCK (store, command_lock); return stream; - } + } if (camel_disco_store_status (CAMEL_DISCO_STORE (store)) == CAMEL_DISCO_STORE_OFFLINE) { camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h index 9a6c6655ad..43c9b8e1f0 100644 --- a/camel/providers/imap/camel-imap-store.h +++ b/camel/providers/imap/camel-imap-store.h @@ -71,7 +71,6 @@ typedef enum { #define IMAP_CAPABILITY_UIDPLUS (1 << 4) #define IMAP_CAPABILITY_LITERALPLUS (1 << 5) #define IMAP_CAPABILITY_useful_lsub (1 << 6) -#define IMAP_CAPABILITY_utf8_search (1 << 7) #define IMAP_PARAM_OVERRIDE_NAMESPACE (1 << 0) #define IMAP_PARAM_CHECK_ALL (1 << 1) diff --git a/camel/providers/imap/camel-imap-utils.c b/camel/providers/imap/camel-imap-utils.c index 91d2efb702..d5466bf9ac 100644 --- a/camel/providers/imap/camel-imap-utils.c +++ b/camel/providers/imap/camel-imap-utils.c @@ -24,7 +24,6 @@ #include <stdio.h> #include <string.h> #include <time.h> -#include <iconv.h> #include "camel-imap-utils.h" #include "camel-imap-summary.h" @@ -33,13 +32,13 @@ #define d(x) x -const char * +char * imap_next_word (const char *buf) { - const char *word; + char *word; /* skip over current word */ - for (word = buf; *word && *word != ' '; word++); + for (word = (char *)buf; *word && *word != ' '; word++); /* skip over white space */ for ( ; *word && *word == ' '; word++); @@ -63,8 +62,8 @@ imap_next_word (const char *buf) gboolean imap_parse_list_response (CamelImapStore *store, const char *buf, int *flags, char *sep, char **folder) { - const char *word; - size_t len; + char *word; + int len; if (*buf != '*') return FALSE; @@ -117,34 +116,22 @@ imap_parse_list_response (CamelImapStore *store, const char *buf, int *flags, ch return FALSE; if (folder) { - char *astring, *mailbox; - size_t nlen; + char *real_name; + int n_len; /* get the folder name */ word = imap_next_word (word); - astring = imap_parse_astring ((char **) &word, &len); - if (!astring) - return FALSE; - - mailbox = imap_mailbox_decode (astring, strlen (astring)); - g_free (astring); - if (!mailbox) - return FALSE; - - nlen = strlen (store->namespace); - - if (!strncmp (mailbox, store->namespace, nlen)) { - /* strip off the namespace */ - if (nlen > 0) - memmove (mailbox, mailbox + nlen, (len - nlen) + 1); - *folder = mailbox; - } else if (!g_strcasecmp (mailbox, "INBOX")) { - *folder = mailbox; + real_name = imap_parse_astring (&word, &len); + n_len = strlen (store->namespace); + if (!strncmp (real_name, store->namespace, n_len)) + *folder = g_strdup (real_name + n_len); + else if (!g_strcasecmp (real_name, "INBOX")) { + *folder = g_strdup (real_name); } else { - g_warning ("IMAP folder name \"%s\" does not begin with \"%s\"", mailbox, store->namespace); - *folder = mailbox; + g_warning ("IMAP folder name \"%s\" does not begin with \"%s\"", real_name, store->namespace); + *folder = g_strdup (real_name); } - + g_free (real_name); return *folder != NULL; } @@ -286,7 +273,7 @@ static char imap_atom_specials[128] = { /** * imap_parse_string_generic: * @str_p: a pointer to a string - * @len: a pointer to a size_t to return the length in + * @len: a pointer to an int to return the length in * @type: type of string (#IMAP_STRING, #IMAP_ASTRING, or #IMAP_NSTRING) * to parse. * @@ -305,7 +292,7 @@ static char imap_atom_specials[128] = { * latter, it will point to the character after the NIL.) **/ char * -imap_parse_string_generic (char **str_p, size_t *len, int type) +imap_parse_string_generic (char **str_p, int *len, int type) { char *str = *str_p; char *out; @@ -314,7 +301,7 @@ imap_parse_string_generic (char **str_p, size_t *len, int type) return NULL; else if (*str == '"') { char *p; - size_t size; + int size; str++; size = strcspn (str, "\"") + 1; @@ -486,7 +473,7 @@ imap_parse_body (char **body_p, CamelFolder *folder, char *body = *body_p; CamelMessageContentInfo *child; CamelContentType *type; - size_t len; + int len; if (!body || *body++ != '(') { *body_p = NULL; @@ -543,7 +530,7 @@ imap_parse_body (char **body_p, CamelFolder *folder, /* single part */ char *main_type, *subtype; char *id, *description, *encoding; - guint32 size = 0; + guint32 size; main_type = imap_parse_string (&body, &len); skip_char (&body, ' '); @@ -661,54 +648,44 @@ get_summary_uid_numeric (CamelFolderSummary *summary, int index) return uid; } -/* the max number of chars that an unsigned 32-bit int can be is 10 chars plus 1 for a possible : */ -#define UID_SET_FULL(setlen, maxlen) (maxlen > 0 ? setlen + 11 >= maxlen : FALSE) - /** * imap_uid_array_to_set: * @summary: summary for the folder the UIDs come from * @uids: a (sorted) array of UIDs - * @uid: uid index to start at - * @maxlen: max length of the set string (or -1 for infinite) - * @lastuid: index offset of the last uid used * - * Creates an IMAP "set" up to @maxlen bytes long, covering the listed - * UIDs starting at index @uid and not covering any UIDs that are in - * @summary but not in @uids. It doesn't actually require that all (or - * any) of the UIDs be in @summary. - * - * After calling, @lastuid will be set the index of the first uid - * *not* included in the returned set string. + * Creates an IMAP "set" covering the listed UIDs and not covering + * any UIDs that are in @summary but not in @uids. It doesn't + * actually require that all (or any) of the UIDs be in @summary. * * Return value: the set, which the caller must free with g_free() **/ char * -imap_uid_array_to_set (CamelFolderSummary *summary, GPtrArray *uids, int uid, ssize_t maxlen, int *lastuid) +imap_uid_array_to_set (CamelFolderSummary *summary, GPtrArray *uids) { + int ui, si, scount; unsigned long last_uid, next_summary_uid, this_uid; gboolean range = FALSE; - int si, scount; GString *gset; char *set; - g_return_val_if_fail (uids->len > uid, NULL); + g_return_val_if_fail (uids->len > 0, NULL); - gset = g_string_new (uids->pdata[uid]); - last_uid = strtoul (uids->pdata[uid], NULL, 10); + gset = g_string_new (uids->pdata[0]); + last_uid = strtoul (uids->pdata[0], NULL, 10); next_summary_uid = 0; scount = camel_folder_summary_count (summary); - for (uid++, si = 0; uid < uids->len && !UID_SET_FULL (gset->len, maxlen); uid++) { + for (ui = 1, si = 0; ui < uids->len; ui++) { /* Find the next UID in the summary after the one we * just wrote out. */ - for ( ; last_uid >= next_summary_uid && si < scount; si++) + for (; last_uid >= next_summary_uid && si < scount; si++) next_summary_uid = get_summary_uid_numeric (summary, si); if (last_uid >= next_summary_uid) next_summary_uid = (unsigned long) -1; /* Now get the next UID from @uids */ - this_uid = strtoul (uids->pdata[uid], NULL, 10); + this_uid = strtoul (uids->pdata[ui], NULL, 10); if (this_uid == next_summary_uid || this_uid == last_uid + 1) range = TRUE; else { @@ -725,8 +702,6 @@ imap_uid_array_to_set (CamelFolderSummary *summary, GPtrArray *uids, int uid, ss if (range) g_string_sprintfa (gset, ":%lu", last_uid); - *lastuid = uid; - set = gset->str; g_string_free (gset, FALSE); @@ -825,7 +800,7 @@ imap_uid_array_free (GPtrArray *arr) char * imap_concat (CamelImapStore *imap_store, const char *prefix, const char *suffix) { - size_t len; + int len; len = strlen (prefix); if (len == 0 || prefix[len - 1] == imap_store->dir_sep) @@ -843,7 +818,7 @@ imap_namespace_concat (CamelImapStore *store, const char *name) else return g_strdup (""); } - + if (!g_strcasecmp (name, "INBOX")) return g_strdup ("INBOX"); @@ -851,268 +826,6 @@ imap_namespace_concat (CamelImapStore *store, const char *name) g_warning ("Trying to concat NULL namespace to \"%s\"!", name); return g_strdup (name); } - - return imap_concat (store, store->namespace, name); -} - - -#define UTF8_TO_UTF7_LEN(len) ((len * 3) + 8) -#define UTF7_TO_UTF8_LEN(len) (len) - -enum { - MODE_USASCII, - MODE_AMPERSAND, - MODE_MODUTF7 -}; - -#define is_usascii(c) (((c) >= 0x20 && (c) <= 0x25) || ((c) >= 0x27 && (c) <= 0x7e)) -#define encode_mode(c) (is_usascii (c) ? MODE_USASCII : (c) == '&' ? MODE_AMPERSAND : MODE_MODUTF7) - -char * -imap_mailbox_encode (const unsigned char *in, size_t inlen) -{ - const unsigned char *start, *inptr, *inend; - unsigned char *mailbox, *m, *mend; - size_t inleft, outleft, conv; - char *inbuf, *outbuf; - iconv_t cd; - int mode; - - cd = (iconv_t) -1; - m = mailbox = g_malloc (UTF8_TO_UTF7_LEN (inlen) + 1); - mend = mailbox + UTF8_TO_UTF7_LEN (inlen); - - start = inptr = in; - inend = in + inlen; - mode = MODE_USASCII; - - while (inptr < inend) { - int new_mode; - - new_mode = encode_mode (*inptr); - - if (new_mode != mode) { - switch (mode) { - case MODE_USASCII: - memcpy (m, start, inptr - start); - m += (inptr - start); - break; - case MODE_AMPERSAND: - while (start < inptr) { - *m++ = '&'; - *m++ = '-'; - start++; - } - break; - case MODE_MODUTF7: - inbuf = (char *) start; - inleft = inptr - start; - outbuf = (char *) m; - outleft = mend - m; - - if (cd == (iconv_t) -1) - cd = iconv_open ("UTF-7", "UTF-8"); - - conv = iconv (cd, &inbuf, &inleft, &outbuf, &outleft); - if (conv == (size_t) -1) { - g_warning ("error converting mailbox to UTF-7!"); - } - iconv (cd, NULL, NULL, &outbuf, &outleft); - - /* shift into modified UTF-7 mode (overwrite UTF-7's '+' shift)... */ - *m++ = '&'; - - while (m < (unsigned char *) outbuf) { - /* replace '/' with ',' */ - if (*m == '/') - *m = ','; - - m++; - } - - break; - } - - mode = new_mode; - start = inptr; - } - - inptr++; - } - - switch (mode) { - case MODE_USASCII: - memcpy (m, start, inptr - start); - m += (inptr - start); - break; - case MODE_AMPERSAND: - while (start < inptr) { - *m++ = '&'; - *m++ = '-'; - start++; - } - break; - case MODE_MODUTF7: - inbuf = (char *) start; - inleft = inptr - start; - outbuf = (char *) m; - outleft = mend - m; - - if (cd == (iconv_t) -1) - cd = iconv_open ("UTF-7", "UTF-8"); - - conv = iconv (cd, &inbuf, &inleft, &outbuf, &outleft); - if (conv == (size_t) -1) { - g_warning ("error converting mailbox to UTF-7!"); - } - iconv (cd, NULL, NULL, &outbuf, &outleft); - - /* shift into modified UTF-7 mode (overwrite UTF-7's '+' shift)... */ - *m++ = '&'; - - while (m < (unsigned char *) outbuf) { - /* replace '/' with ',' */ - if (*m == '/') - *m = ','; - - m++; - } - - break; - } - - *m = '\0'; - - if (cd != (iconv_t) -1) - iconv_close (cd); - - return mailbox; -} - -char * -imap_mailbox_decode (const unsigned char *in, size_t inlen) -{ - const unsigned char *start, *inptr, *inend; - unsigned char *mailbox, *m, *mend; - unsigned char mode_switch; - iconv_t cd; - - cd = (iconv_t) -1; - m = mailbox = g_malloc (UTF7_TO_UTF8_LEN (inlen) + 1); - mend = mailbox + UTF7_TO_UTF8_LEN (inlen); - - start = inptr = in; - inend = in + inlen; - mode_switch = '&'; - - while (inptr < inend) { - if (*inptr == mode_switch) { - if (mode_switch == '&') { - /* mode switch from US-ASCII to UTF-7 */ - mode_switch = '-'; - memcpy (m, start, inptr - start); - m += (inptr - start); - start = inptr; - } else if (mode_switch == '-') { - /* mode switch from UTF-7 to US-ASCII or an ampersand (&) */ - mode_switch = '&'; - start++; - if (start == inptr) { - /* we had the sequence "&-" which becomes "&" when decoded */ - *m++ = '&'; - } else { - char *buffer, *inbuf, *outbuf; - size_t buflen, outleft, conv; - - buflen = (inptr - start) + 2; - inbuf = buffer = alloca (buflen); - *inbuf++ = '+'; - while (start < inptr) { - *inbuf++ = *start == ',' ? '/' : *start; - start++; - } - *inbuf = '-'; - - inbuf = buffer; - outbuf = (char *) m; - outleft = mend - m; - - if (cd == (iconv_t) -1) - cd = iconv_open ("UTF-8", "UTF-7"); - - conv = iconv (cd, &inbuf, &buflen, &outbuf, &outleft); - if (conv == (size_t) -1) { - g_warning ("error decoding mailbox: %.*s", inlen, in); - } - iconv (cd, NULL, NULL, NULL, NULL); - - m = (unsigned char *) outbuf; - } - - /* point to the char after the '-' */ - start = inptr + 1; - } - } - - inptr++; - } - - if (*inptr == mode_switch) { - if (mode_switch == '&') { - /* the remaining text is US-ASCII */ - memcpy (m, start, inptr - start); - m += (inptr - start); - start = inptr; - } else if (mode_switch == '-') { - /* We've got encoded UTF-7 or else an ampersand */ - start++; - if (start == inptr) { - /* we had the sequence "&-" which becomes "&" when decoded */ - *m++ = '&'; - } else { - char *buffer, *inbuf, *outbuf; - size_t buflen, outleft, conv; - - buflen = (inptr - start) + 2; - inbuf = buffer = alloca (buflen); - *inbuf++ = '+'; - while (start < inptr) { - *inbuf++ = *start == ',' ? '/' : *start; - start++; - } - *inbuf = '-'; - - inbuf = buffer; - outbuf = (char *) m; - outleft = mend - m; - - if (cd == (iconv_t) -1) - cd = iconv_open ("UTF-8", "UTF-7"); - - conv = iconv (cd, &inbuf, &buflen, &outbuf, &outleft); - if (conv == (size_t) -1) { - g_warning ("error decoding mailbox: %.*s", inlen, in); - } - iconv (cd, NULL, NULL, NULL, NULL); - - m = (unsigned char *) outbuf; - } - } - } else { - if (mode_switch == '-') { - /* illegal encoded mailbox... */ - g_warning ("illegal mailbox name encountered: %.*s", inlen, in); - } - - memcpy (m, start, inptr - start); - m += (inptr - start); - } - - *m = '\0'; - - if (cd != (iconv_t) -1) - iconv_close (cd); - - return mailbox; + return imap_concat (store, store->namespace, name); } |