diff options
Diffstat (limited to 'camel/providers')
22 files changed, 796 insertions, 859 deletions
diff --git a/camel/providers/groupwise/camel-gw-listener.c b/camel/providers/groupwise/camel-gw-listener.c index 1f6eaf6267..9da66d6b6d 100644 --- a/camel/providers/groupwise/camel-gw-listener.c +++ b/camel/providers/groupwise/camel-gw-listener.c @@ -162,7 +162,7 @@ lookup_account_info (const char *key) #define SELECTED_TASKS "/apps/evolution/calendar/tasks/selected_tasks" static void -add_esource (const char *conf_key, const char *group_name, const char *source_name, CamelURL *url) +add_esource (const char *conf_key, const char *group_name, const char* source_name, const char *username, const char* relative_uri, const char *soap_port, const char *use_ssl) { ESourceList *source_list; ESourceGroup *group; @@ -170,45 +170,20 @@ add_esource (const char *conf_key, const char *group_name, const char *source_n GConfClient* client; GSList *ids, *temp ; char *source_selection_key; - char *relative_uri; - const char *soap_port; - const char * use_ssl; - const char *poa_address; - const char *offline_sync; - - - poa_address = camel_url_get_param (url, "poa"); - if (!poa_address || strlen (poa_address) ==0) - return; - soap_port = camel_url_get_param (url, "soap_port"); - - if (!soap_port || strlen (soap_port) == 0) - soap_port = "7181"; - use_ssl = camel_url_get_param (url, "soap_ssl"); - if (use_ssl) - use_ssl = "always"; - else - use_ssl = NULL; - - offline_sync = camel_url_get_param (url, "offline_sync"); - client = gconf_client_get_default(); source_list = e_source_list_new_for_gconf (client, conf_key); group = e_source_group_new (group_name, GROUPWISE_URI_PREFIX); - if (!e_source_list_add_group (source_list, group, -1)) + if ( !e_source_list_add_group (source_list, group, -1)) return; - relative_uri = g_strdup_printf ("%s@%s/", url->user, poa_address); - + source = e_source_new (source_name, relative_uri); e_source_set_property (source, "auth", "1"); - e_source_set_property (source, "username", url->user); - e_source_set_property (source, "port", camel_url_get_param (url, "soap_port")); + e_source_set_property (source, "username", username); + e_source_set_property (source, "port", soap_port); e_source_set_property (source, "auth-domain", "Groupwise"); - e_source_set_property (source, "use_ssl", camel_url_get_param (url, "use_ssl")); - e_source_set_property (source, "offline_sync", offline_sync); - // e_source_set_property (source, "offline_sync", ); + e_source_set_property (source, "use_ssl", use_ssl); e_source_group_add_source (group, source, -1); e_source_list_sync (source_list, NULL); @@ -231,7 +206,6 @@ add_esource (const char *conf_key, const char *group_name, const char *source_n g_object_unref (group); g_object_unref (source_list); g_object_unref (client); - g_free (relative_uri); } @@ -308,7 +282,7 @@ remove_esource (const char *conf_key, const char *group_name, char* source_name, /* looks up for e-source with having same info as old_account_info and changes its values passed in new values */ static void -modify_esource (const char* conf_key, GwAccountInfo *old_account_info, const char* new_group_name, CamelURL *new_url) +modify_esource (const char* conf_key, GwAccountInfo *old_account_info, const char* new_group_name, const char *username, const char* new_relative_uri, const char *soap_port, const char *use_ssl) { ESourceList *list; ESourceGroup *group; @@ -320,15 +294,11 @@ modify_esource (const char* conf_key, GwAccountInfo *old_account_info, const cha gboolean found_group; GConfClient* client; const char *poa_address; - char *new_relative_uri; - const char *new_poa_address; - + url = camel_url_new (old_account_info->source_url, NULL); poa_address = camel_url_get_param (url, "poa"); if (!poa_address || strlen (poa_address) ==0) return; - new_poa_address = camel_url_get_param (new_url, "poa"); - old_relative_uri = g_strdup_printf ("%s@%s/", url->user, poa_address); client = gconf_client_get_default (); list = e_source_list_new_for_gconf (client, conf_key); @@ -351,16 +321,13 @@ modify_esource (const char* conf_key, GwAccountInfo *old_account_info, const cha if (strcmp (e_source_peek_relative_uri (source), old_relative_uri) == 0) { - new_relative_uri = g_strdup_printf ("%s@%s/", new_url->user, new_poa_address); e_source_group_set_name (group, new_group_name); e_source_set_relative_uri (source, new_relative_uri); - e_source_set_property (source, "username", new_url->user); - e_source_set_property (source, "port", camel_url_get_param (new_url,"soap_port")); - e_source_set_property (source, "use_ssl", camel_url_get_param (url, "soap_ssl")); - e_source_set_property (source, "offline_sync", camel_url_get_param (url, "offline_sync")); + e_source_set_property (source, "username", username); + e_source_set_property (source, "port", soap_port); + e_source_set_property (source, "use_ssl", use_ssl); e_source_list_sync (list, NULL); found_group = TRUE; - g_free (new_relative_uri); break; } } @@ -371,7 +338,6 @@ modify_esource (const char* conf_key, GwAccountInfo *old_account_info, const cha g_object_unref (client); camel_url_free (url); g_free (old_relative_uri); - } /* add sources for calendar and tasks if the account added is groupwise account @@ -402,8 +368,8 @@ add_calendar_tasks_sources (GwAccountInfo *info) use_ssl = NULL; relative_uri = g_strdup_printf ("%s@%s/", url->user, poa_address); - add_esource ("/apps/evolution/calendar/sources", info->name, _("Calendar"), url); - add_esource ("/apps/evolution/tasks/sources", info->name, _("Tasks"), url); + add_esource ("/apps/evolution/calendar/sources", info->name, _("Calendar"), url->user, relative_uri, soap_port, use_ssl); + add_esource ("/apps/evolution/tasks/sources", info->name, _("Tasks"), url->user, relative_uri, soap_port, use_ssl); camel_url_free (url); g_free (relative_uri); @@ -551,7 +517,7 @@ add_addressbook_sources (EAccount *account) e_source_set_property (source, "auth-domain", "Groupwise"); e_source_set_property (source, "port", soap_port); e_source_set_property(source, "user", url->user); - e_source_set_property (source, "offline_sync", camel_url_get_param (url, "offline_sync")); + if (!e_gw_container_get_is_writable (E_GW_CONTAINER(temp_list->data))) e_source_set_property (source, "completion", "true"); if (e_gw_container_get_is_frequent_contacts (E_GW_CONTAINER(temp_list->data))) @@ -593,7 +559,6 @@ modify_addressbook_sources ( EAccount *account, GwAccountInfo *existing_account_ ESource *source; GConfClient *client; const char *poa_address; - url = camel_url_new (existing_account_info->source_url, NULL); if (url == NULL) { @@ -766,6 +731,7 @@ account_changed (EAccountList *account_listener, EAccount *account) { gboolean is_gw_account; CamelURL *old_url, *new_url; + char *relative_uri; const char *old_soap_port, *new_soap_port; GwAccountInfo *existing_account_info; const char *old_use_ssl, *new_use_ssl; @@ -833,9 +799,11 @@ account_changed (EAccountList *account_listener, EAccount *account) account_added (account_listener, account); } else if (strcmp (existing_account_info->name, account->name)) { - modify_esource ("/apps/evolution/calendar/sources", existing_account_info, account->name, new_url); - modify_esource ("/apps/evolution/tasks/sources", existing_account_info, account->name, new_url); + relative_uri = g_strdup_printf ("%s@%s/", new_url->user, new_poa_address); + modify_esource ("/apps/evolution/calendar/sources", existing_account_info, account->name, new_url->user, relative_uri, new_soap_port, new_use_ssl); + modify_esource ("/apps/evolution/tasks/sources", existing_account_info, account->name, new_url->user, relative_uri, new_soap_port, new_use_ssl); modify_addressbook_sources (account, existing_account_info); + g_free (relative_uri); } diff --git a/camel/providers/imap/camel-imap-command.c b/camel/providers/imap/camel-imap-command.c index eeb3ecd302..fdba581fbb 100644 --- a/camel/providers/imap/camel-imap-command.c +++ b/camel/providers/imap/camel-imap-command.c @@ -43,7 +43,7 @@ #include <camel/camel-private.h> #include <camel/camel-utf8.h> #include <camel/camel-session.h> -#include "camel-i18n.h" + extern int camel_verbose_debug; @@ -499,10 +499,16 @@ imap_read_untagged (CamelImapStore *store, char *line, CamelException *ex) fulllen += str->len; g_ptr_array_add (data, str); - + /* Read the next line. */ - if (camel_imap_store_readline (store, &line, ex) < 0) - goto lose; + do { + if (camel_imap_store_readline (store, &line, ex) < 0) + goto lose; + + /* MAJOR HACK ALERT, gropuwise sometimes sends an extra blank line after literals, check that here */ + if (line[0] == 0) + g_warning("Server sent empty line after a literal, assuming in error"); + } while (line[0] == 0); } /* Now reassemble the data. */ diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index 6cdd96bcf7..d592b819f1 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -23,6 +23,7 @@ * USA */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -37,8 +38,8 @@ #include <fcntl.h> #include <ctype.h> -/*#include "libedataserver/e-path.h"*/ -#include "libedataserver/e-time-utils.h" +#include "e-util/e-path.h" +#include "e-util/e-time-utils.h" #include "camel-imap-folder.h" #include "camel-imap-command.h" @@ -69,7 +70,6 @@ #include "camel-string-utils.h" #include "camel-file-utils.h" #include "camel-debug.h" -#include "camel-i18n.h" #define d(x) @@ -237,7 +237,7 @@ camel_imap_folder_new (CamelStore *parent, const char *folder_name, camel_folder_construct (folder, parent, folder_name, short_name); summary_file = g_strdup_printf ("%s/summary", folder_dir); - folder->summary = camel_imap_summary_new (folder, summary_file); + folder->summary = camel_imap_summary_new (summary_file); g_free (summary_file); if (!folder->summary) { camel_object_unref (CAMEL_OBJECT (folder)); @@ -387,7 +387,7 @@ camel_imap_folder_selected (CamelFolder *folder, CamelImapResponse *response, info = camel_folder_summary_index (folder->summary, count - 1); val = strtoul (camel_message_info_uid (info), NULL, 10); - camel_message_info_free(info); + camel_folder_summary_info_free (folder->summary, info); if (uid == 0 || uid != val) imap_folder->need_rescan = TRUE; } @@ -470,7 +470,7 @@ imap_rename (CamelFolder *folder, const char *new) char *folders; folders = g_strconcat (imap_store->storage_path, "/folders", NULL); - folder_dir = imap_path_to_physical (folders, new); + folder_dir = e_path_to_physical (folders, new); g_free (folders); summary_path = g_strdup_printf("%s/summary", folder_dir); @@ -575,7 +575,7 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex) ok = camel_imap_command_start (store, folder, ex, "UID FETCH 1:%s (FLAGS)", camel_message_info_uid (info)); - camel_message_info_free(info); + camel_folder_summary_info_free (folder->summary, info); if (!ok) { camel_operation_end (NULL); return; @@ -632,7 +632,7 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex) iinfo = (CamelImapMessageInfo *)info; if (strcmp (camel_message_info_uid (info), new[i].uid) != 0) { - camel_message_info_free(info); + camel_folder_summary_info_free(folder->summary, info); seq = i + 1; g_array_append_val (removed, seq); i--; @@ -646,8 +646,8 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex) server_set = new[i].flags & ~iinfo->server_flags; server_cleared = iinfo->server_flags & ~new[i].flags; - - iinfo->info.flags = (iinfo->info.flags | server_set) & ~server_cleared; + + info->flags = (info->flags | server_set) & ~server_cleared; iinfo->server_flags = new[i].flags; if (changes == NULL) @@ -655,7 +655,7 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex) camel_folder_change_info_change_uid(changes, new[i].uid); } - camel_message_info_free(info); + camel_folder_summary_info_free (folder->summary, info); g_free (new[i].uid); } @@ -697,7 +697,7 @@ static GPtrArray * get_matching (CamelFolder *folder, guint32 flags, guint32 mask, char **set) { GPtrArray *matches; - CamelImapMessageInfo *info; + CamelMessageInfo *info; int i, max, range; GString *gset; @@ -706,11 +706,11 @@ get_matching (CamelFolder *folder, guint32 flags, guint32 mask, char **set) max = camel_folder_summary_count (folder->summary); range = -1; for (i = 0; i < max && !UID_SET_FULL (gset->len, UID_SET_LIMIT); i++) { - info = (CamelImapMessageInfo *)camel_folder_summary_index (folder->summary, i); + info = camel_folder_summary_index (folder->summary, i); if (!info) continue; - if ((info->info.flags & mask) != flags) { - camel_message_info_free((CamelMessageInfo *)info); + if ((info->flags & mask) != flags) { + camel_folder_summary_info_free (folder->summary, info); if (range != -1) { if (range != i - 1) { info = matches->pdata[matches->len - 1]; @@ -758,7 +758,7 @@ imap_sync_online (CamelFolder *folder, CamelException *ex) { CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); CamelImapResponse *response = NULL; - CamelImapMessageInfo *info; + CamelMessageInfo *info; CamelException local_ex; GPtrArray *matches; char *set, *flaglist; @@ -779,33 +779,33 @@ imap_sync_online (CamelFolder *folder, CamelException *ex) */ max = camel_folder_summary_count (folder->summary); for (i = 0; i < max; i++) { - if (!(info = (CamelImapMessageInfo *)camel_folder_summary_index (folder->summary, i))) + if (!(info = camel_folder_summary_index (folder->summary, i))) continue; - if (!(info->info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) { - camel_message_info_free((CamelMessageInfo *)info); + if (!(info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) { + camel_folder_summary_info_free (folder->summary, info); continue; } /* 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.*/ - unset = !(info->info.flags & folder->permanent_flags); + unset = !(info->flags & folder->permanent_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->info.flags & (folder->permanent_flags | CAMEL_MESSAGE_FOLDER_FLAGGED), + matches = get_matching (folder, info->flags & (folder->permanent_flags | CAMEL_MESSAGE_FOLDER_FLAGGED), folder->permanent_flags | CAMEL_MESSAGE_FOLDER_FLAGGED, &set); - camel_message_info_free(info); + camel_folder_summary_info_free (folder->summary, info); if (matches == NULL) continue; /* FIXME: since we don't know the previously set flags, if unset is TRUE then just unset all the flags? */ - flaglist = imap_create_flag_list (unset ? folder->permanent_flags : info->info.flags & folder->permanent_flags); + flaglist = imap_create_flag_list (unset ? folder->permanent_flags : info->flags & folder->permanent_flags); /* Note: to `unset' flags, use -FLAGS.SILENT (<flag list>) */ response = camel_imap_command (store, folder, &local_ex, @@ -820,15 +820,16 @@ imap_sync_online (CamelFolder *folder, CamelException *ex) if (!camel_exception_is_set (&local_ex)) { for (j = 0; j < matches->len; j++) { info = matches->pdata[j]; - info->info.flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED; - ((CamelImapMessageInfo *) info)->server_flags = info->info.flags & CAMEL_IMAP_SERVER_FLAGS; + info->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED; + ((CamelImapMessageInfo *) info)->server_flags = + info->flags & CAMEL_IMAP_SERVER_FLAGS; } camel_folder_summary_touch (folder->summary); } for (j = 0; j < matches->len; j++) { info = matches->pdata[j]; - camel_message_info_free(&info->info); + camel_folder_summary_info_free (folder->summary, info); } g_ptr_array_free (matches, TRUE); @@ -1166,11 +1167,10 @@ do_append (CamelFolder *folder, CamelMimeMessage *message, CamelStreamFilter *streamfilter; GByteArray *ba; char *flagstr, *end; - guint32 flags; - - flags = camel_message_info_flags(info); - if (flags) - flagstr = imap_create_flag_list (flags); + + /* create flag string param */ + if (info && info->flags) + flagstr = imap_create_flag_list (info->flags); else flagstr = NULL; @@ -1357,7 +1357,7 @@ imap_transfer_offline (CamelFolder *source, GPtrArray *uids, camel_imap_summary_add_offline_uncached (dest->summary, destuid, mi); camel_imap_message_cache_copy (sc, uid, dc, destuid, ex); - camel_message_info_free(mi); + camel_folder_summary_info_free (source->summary, mi); camel_folder_change_info_add_uid (changes, destuid); if (transferred_uids) @@ -1968,12 +1968,12 @@ imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex) { CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store); - CamelImapMessageInfo *mi; + CamelMessageInfo *mi; CamelMimeMessage *msg = NULL; CamelStream *stream = NULL; int retry; - mi = (CamelImapMessageInfo *)camel_folder_summary_uid (folder->summary, uid); + mi = camel_folder_summary_uid (folder->summary, uid); if (mi == NULL) { camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, _("Cannot get message: %s\n %s"), uid, _("No such message")); @@ -2001,11 +2001,11 @@ imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex) /* If the message is small or only 1 part, or server doesn't do 4v1 (properly) fetch it in one piece. */ if (store->server_level < IMAP_LEVEL_IMAP4REV1 || store->braindamaged - || mi->info.size < IMAP_SMALL_BODY_SIZE - || (!content_info_incomplete(mi->info.content) && !mi->info.content->childs)) { + || mi->size < IMAP_SMALL_BODY_SIZE + || (!content_info_incomplete(mi->content) && !mi->content->childs)) { msg = get_message_simple (imap_folder, uid, NULL, ex); } else { - if (content_info_incomplete (mi->info.content)) { + if (content_info_incomplete (mi->content)) { /* For larger messages, fetch the structure and build a message * with offline parts. (We check mi->content->type rather than * mi->content because camel_folder_summary_info_new always creates @@ -2038,7 +2038,7 @@ imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex) } if (body) - imap_parse_body ((const char **) &body, folder, mi->info.content); + imap_parse_body ((const char **) &body, folder, mi->content); if (fetch_data) g_datalist_clear (&fetch_data); @@ -2049,7 +2049,7 @@ imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex) if (camel_debug_start("imap:folder")) { printf("Folder get message '%s' folder info ->\n", uid); - camel_message_info_dump((CamelMessageInfo *)mi); + camel_message_info_dump(mi); camel_debug_end(); } @@ -2059,10 +2059,10 @@ imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex) * fall back to fetching the entire thing and * let the mailer's "bad MIME" code handle it. */ - if (content_info_incomplete (mi->info.content)) + if (content_info_incomplete (mi->content)) msg = get_message_simple (imap_folder, uid, NULL, ex); else - msg = get_message (imap_folder, uid, mi->info.content, ex); + msg = get_message (imap_folder, uid, mi->content, ex); } } while (msg == NULL && retry < 2 @@ -2072,7 +2072,7 @@ done: /* FIXME, this shouldn't be done this way. */ if (msg) camel_medium_set_header (CAMEL_MEDIUM (msg), "X-Evolution-Source", store->base_url); fail: - camel_message_info_free(&mi->info); + camel_folder_summary_info_free (folder->summary, mi); return msg; } @@ -2201,7 +2201,7 @@ add_message_from_data (CamelFolder *folder, GPtrArray *messages, { CamelMimeMessage *msg; CamelStream *stream; - CamelImapMessageInfo *mi; + CamelMessageInfo *mi; const char *idate; int seq; @@ -2221,14 +2221,14 @@ add_message_from_data (CamelFolder *folder, GPtrArray *messages, return; } - mi = (CamelImapMessageInfo *)camel_folder_summary_info_new_from_message (folder->summary, msg); + mi = camel_folder_summary_info_new_from_message (folder->summary, msg); camel_object_unref (CAMEL_OBJECT (msg)); if ((idate = g_datalist_get_data (&data, "INTERNALDATE"))) - mi->info.date_received = decode_internaldate (idate); + mi->date_received = decode_internaldate (idate); - if (mi->info.date_received == -1) - mi->info.date_received = mi->info.date_sent; + if (mi->date_received == -1) + mi->date_received = mi->date_sent; messages->pdata[seq - first] = mi; } @@ -2253,7 +2253,7 @@ imap_update_summary (CamelFolder *folder, int exists, int i, seq, first, size, got; CamelImapResponseType type; const char *header_spec; - CamelImapMessageInfo *mi, *info; + CamelMessageInfo *mi, *info; CamelStream *stream; char *uid, *resp; GData *data; @@ -2272,9 +2272,9 @@ imap_update_summary (CamelFolder *folder, int exists, seq = camel_folder_summary_count (folder->summary); first = seq + 1; if (seq > 0) { - mi = (CamelImapMessageInfo *)camel_folder_summary_index (folder->summary, seq - 1); + mi = camel_folder_summary_index (folder->summary, seq - 1); uidval = strtoul(camel_message_info_uid (mi), NULL, 10); - camel_message_info_free(&mi->info); + camel_folder_summary_info_free (folder->summary, mi); } else uidval = 0; @@ -2433,23 +2433,24 @@ imap_update_summary (CamelFolder *folder, int exists, continue; } - mi = (CamelImapMessageInfo *)camel_message_info_clone(pmi); + mi = camel_message_info_new (); + camel_message_info_dup_to (pmi, mi); } uid = g_datalist_get_data (&data, "UID"); if (uid) - mi->info.uid = g_strdup (uid); + camel_message_info_set_uid (mi, g_strdup (uid)); flags = GPOINTER_TO_INT (g_datalist_get_data (&data, "FLAGS")); if (flags) { ((CamelImapMessageInfo *)mi)->server_flags = flags; /* "or" them in with the existing flags that may * have been set by summary_info_new_from_message. */ - mi->info.flags |= flags; + mi->flags |= flags; } size = GPOINTER_TO_INT (g_datalist_get_data (&data, "RFC822.SIZE")); if (size) - mi->info.size = size; + mi->size = size; g_datalist_clear (&data); } @@ -2473,7 +2474,7 @@ imap_update_summary (CamelFolder *folder, int exists, i + first); break; } - info = (CamelImapMessageInfo *)camel_folder_summary_uid(folder->summary, uid); + info = camel_folder_summary_uid(folder->summary, uid); if (info) { for (seq = 0; seq < camel_folder_summary_count (folder->summary); seq++) { if (folder->summary->messages->pdata[seq] == info) @@ -2485,20 +2486,20 @@ imap_update_summary (CamelFolder *folder, int exists, _("Unexpected server response: Identical UIDs provided for messages %d and %d"), seq + 1, i + first); - camel_message_info_free(&info->info); + camel_folder_summary_info_free(folder->summary, info); break; } - camel_folder_summary_add (folder->summary, (CamelMessageInfo *)mi); + camel_folder_summary_add (folder->summary, mi); camel_folder_change_info_add_uid (changes, camel_message_info_uid (mi)); - if ((mi->info.flags & CAMEL_IMAP_MESSAGE_RECENT)) + if ((mi->flags & CAMEL_IMAP_MESSAGE_RECENT)) camel_folder_change_info_recent_uid(changes, camel_message_info_uid (mi)); } for ( ; i < messages->len; i++) { if ((mi = messages->pdata[i])) - camel_message_info_free(&mi->info); + camel_folder_summary_info_free(folder->summary, mi); } g_ptr_array_free (messages, TRUE); @@ -2516,7 +2517,7 @@ imap_update_summary (CamelFolder *folder, int exists, if (messages) { for (i = 0; i < messages->len; i++) { if (messages->pdata[i]) - camel_message_info_free(messages->pdata[i]); + camel_folder_summary_info_free (folder->summary, messages->pdata[i]); } g_ptr_array_free (messages, TRUE); } @@ -2552,7 +2553,7 @@ camel_imap_folder_changed (CamelFolder *folder, int exists, camel_imap_message_cache_remove (imap_folder->cache, camel_message_info_uid (info)); CAMEL_IMAP_FOLDER_UNLOCK (imap_folder, cache_lock); camel_folder_summary_remove (folder->summary, info); - camel_message_info_free(info); + camel_folder_summary_info_free(folder->summary, info); } } diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c index 5811b0f691..3f92c2f40a 100644 --- a/camel/providers/imap/camel-imap-store.c +++ b/camel/providers/imap/camel-imap-store.c @@ -24,6 +24,7 @@ * */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -34,6 +35,8 @@ #include <unistd.h> #include <errno.h> +#include "e-util/e-path.h" + #include "camel-imap-store.h" #include "camel-imap-store-summary.h" #include "camel-imap-folder.h" @@ -56,11 +59,11 @@ #include "camel-sasl.h" #include "camel-utf8.h" #include "camel-string-utils.h" + #include "camel-imap-private.h" #include "camel-private.h" + #include "camel-debug.h" -#include "camel-i18n.h" -#include "camel-net-utils.h" #define d(x) @@ -502,52 +505,87 @@ imap_get_capability (CamelService *service, CamelException *ex) } enum { - MODE_CLEAR, - MODE_SSL, - MODE_TLS, + USE_SSL_NEVER, + USE_SSL_ALWAYS, + USE_SSL_WHEN_POSSIBLE }; #define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3) #define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS) static gboolean -connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, CamelException *ex) +connect_to_server (CamelService *service, int ssl_mode, int try_starttls, CamelException *ex) { CamelImapStore *store = (CamelImapStore *) service; CamelImapResponse *response; CamelStream *tcp_stream; CamelSockOptData sockopt; gboolean force_imap4 = FALSE; - int clean_quit, ret; + int clean_quit; + int ret; char *buf; + struct addrinfo *ai, hints = { 0 }; + char *serv; + const char *port = NULL; + + /* FIXME: this connect stuff is duplicated everywhere */ + + if (service->url->port) { + serv = g_alloca(16); + sprintf(serv, "%d", service->url->port); + } else { + serv = "imap"; + port = IMAP_PORT; + } - if (ssl_mode != MODE_CLEAR) { + if (ssl_mode != USE_SSL_NEVER) { #ifdef HAVE_SSL - if (ssl_mode == MODE_TLS) { + if (try_starttls) { tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS); } else { + if (service->url->port == 0) { + serv = "imaps"; + port = IMAPS_PORT; + } tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS); } #else - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s: %s"), - service->url->host, _("SSL unavailable")); + if (!try_starttls && service->url->port == 0) { + serv = "imaps"; + port = IMAPS_PORT; + } + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + _("Could not connect to %s (port %s): %s"), + service->url->host, serv, + _("SSL unavailable")); return FALSE; #endif /* HAVE_SSL */ } else { tcp_stream = camel_tcp_stream_raw_new (); } + + hints.ai_socktype = SOCK_STREAM; + ai = camel_getaddrinfo(service->url->host, serv, &hints, ex); + if (ai == NULL && port != NULL && camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) { + camel_exception_clear(ex); + ai = camel_getaddrinfo(service->url->host, port, &hints, ex); + } + if (ai == NULL) { + camel_object_unref(tcp_stream); + return FALSE; + } - if ((ret = camel_tcp_stream_connect ((CamelTcpStream *) tcp_stream, ai)) == -1) { + ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai); + camel_freeaddrinfo(ai); + if (ret == -1) { if (errno == EINTR) camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Connection cancelled")); else camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s: %s"), - service->url->host, - g_strerror (errno)); + _("Could not connect to %s (port %s): %s"), + service->url->host, serv, g_strerror (errno)); camel_object_unref (tcp_stream); @@ -591,7 +629,7 @@ connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, Cam if (!strncmp(buf, "* PREAUTH", 9)) store->preauthed = TRUE; - if (strstr (buf, "Courier-IMAP")) { + if (strstr (buf, "Courier-IMAP") || getenv("CAMEL_IMAP_BRAINDAMAGED")) { /* Courier-IMAP is braindamaged. So far this flag only * works around the fact that Courier-IMAP is known to * give invalid BODY responses seemingly because its @@ -642,18 +680,32 @@ connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, Cam store->server_level = IMAP_LEVEL_IMAP4; } - if (ssl_mode != MODE_TLS) { - /* we're done */ - return TRUE; +#ifdef HAVE_SSL + if (ssl_mode == USE_SSL_WHEN_POSSIBLE) { + if (store->capabilities & IMAP_CAPABILITY_STARTTLS) + goto starttls; + } else if (ssl_mode == USE_SSL_ALWAYS) { + if (try_starttls) { + if (store->capabilities & IMAP_CAPABILITY_STARTTLS) { + /* attempt to toggle STARTTLS mode */ + goto starttls; + } else { + /* server doesn't support STARTTLS, abort */ + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Failed to connect to IMAP server %s in secure mode: %s"), + service->url->host, _("SSL/TLS extension not supported.")); + /* we have the possibility of quitting cleanly here */ + clean_quit = TRUE; + goto exception; + } + } } +#endif /* HAVE_SSL */ - if (!(store->capabilities & IMAP_CAPABILITY_STARTTLS)) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to connect to IMAP server %s in secure mode: %s"), - service->url->host, _("STARTTLS not supported")); - - goto exception; - } + return TRUE; + +#ifdef HAVE_SSL + starttls: /* as soon as we send a STARTTLS command, all hope is lost of a clean QUIT if problems arise */ clean_quit = FALSE; @@ -718,6 +770,7 @@ connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, Cam store->connected = FALSE; return FALSE; +#endif /* HAVE_SSL */ } static gboolean @@ -865,70 +918,60 @@ connect_to_server_process (CamelService *service, const char *cmd, CamelExceptio static struct { char *value; - char *serv; - char *port; int mode; } ssl_options[] = { - { "", "imaps", IMAPS_PORT, MODE_SSL }, /* really old (1.x) */ - { "always", "imaps", IMAPS_PORT, MODE_SSL }, - { "when-possible", "imap", IMAP_PORT, MODE_TLS }, - { "never", "imap", IMAP_PORT, MODE_CLEAR }, - { NULL, "imap", IMAP_PORT, MODE_CLEAR }, + { "", USE_SSL_ALWAYS }, + { "always", USE_SSL_ALWAYS }, + { "when-possible", USE_SSL_WHEN_POSSIBLE }, + { "never", USE_SSL_NEVER }, + { NULL, USE_SSL_NEVER }, }; static gboolean connect_to_server_wrapper (CamelService *service, CamelException *ex) { - const char *command, *ssl_mode; - struct addrinfo hints, *ai; - int mode, ret, i; - char *serv; - const char *port; - - if ((command = camel_url_get_param (service->url, "command"))) + const char *command; +#ifdef HAVE_SSL + const char *use_ssl; + int i, ssl_mode; +#endif + command = camel_url_get_param (service->url, "command"); + if (command) return connect_to_server_process (service, command, ex); - - if ((ssl_mode = camel_url_get_param (service->url, "use_ssl"))) { + +#ifdef HAVE_SSL + use_ssl = camel_url_get_param (service->url, "use_ssl"); + if (use_ssl) { for (i = 0; ssl_options[i].value; i++) - if (!strcmp (ssl_options[i].value, ssl_mode)) + if (!strcmp (ssl_options[i].value, use_ssl)) break; - mode = ssl_options[i].mode; - serv = ssl_options[i].serv; - port = ssl_options[i].port; + ssl_mode = ssl_options[i].mode; + } else + ssl_mode = USE_SSL_NEVER; + + if (ssl_mode == USE_SSL_ALWAYS) { + /* First try the ssl port */ + if (!connect_to_server (service, ssl_mode, FALSE, ex)) { + if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE) { + /* The ssl port seems to be unavailable, lets try STARTTLS */ + camel_exception_clear (ex); + return connect_to_server (service, ssl_mode, TRUE, ex); + } else { + return FALSE; + } + } + + return TRUE; + } else if (ssl_mode == USE_SSL_WHEN_POSSIBLE) { + /* If the server supports STARTTLS, use it */ + return connect_to_server (service, ssl_mode, TRUE, ex); } else { - mode = MODE_CLEAR; - serv = "imap"; - port = IMAP_PORT; - } - - if (service->url->port) { - serv = g_alloca (16); - sprintf (serv, "%d", service->url->port); - port = NULL; - } - - memset (&hints, 0, sizeof (hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = PF_UNSPEC; - ai = camel_getaddrinfo(service->url->host, serv, &hints, ex); - if (ai == NULL && port != NULL && camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) { - camel_exception_clear (ex); - ai = camel_getaddrinfo(service->url->host, port, &hints, ex); - } - if (ai == NULL) - return FALSE; - - if (!(ret = connect_to_server (service, ai, mode, ex)) && mode == MODE_SSL) { - camel_exception_clear (ex); - ret = connect_to_server (service, ai, MODE_TLS, ex); - } else if (!ret && mode == MODE_TLS) { - camel_exception_clear (ex); - ret = connect_to_server (service, ai, MODE_CLEAR, ex); + /* User doesn't care about SSL */ + return connect_to_server (service, ssl_mode, FALSE, ex); } - - camel_freeaddrinfo (ai); - - return ret; +#else + return connect_to_server (service, USE_SSL_NEVER, FALSE, ex); +#endif } extern CamelServiceAuthType camel_imap_password_authtype; @@ -1041,7 +1084,7 @@ imap_forget_folder (CamelImapStore *imap_store, const char *folder_name, CamelEx name = folder_name; storage_path = g_strdup_printf ("%s/folders", imap_store->storage_path); - folder_dir = imap_path_to_physical (storage_path, folder_name); + folder_dir = e_path_to_physical (storage_path, folder_name); g_free (storage_path); if (access (folder_dir, F_OK) != 0) { g_free (folder_dir); @@ -1049,7 +1092,7 @@ imap_forget_folder (CamelImapStore *imap_store, const char *folder_name, CamelEx } summary_file = g_strdup_printf ("%s/summary", folder_dir); - summary = camel_imap_summary_new (NULL, summary_file); + summary = camel_imap_summary_new (summary_file); if (!summary) { g_free (summary_file); g_free (folder_dir); @@ -1599,17 +1642,14 @@ imap_disconnect_online (CamelService *service, gboolean clean, CamelException *e static gboolean imap_summary_is_dirty (CamelFolderSummary *summary) { - CamelImapMessageInfo *info; + CamelMessageInfo *info; int max, i; - int found = FALSE; - + max = camel_folder_summary_count (summary); - for (i = 0; i < max && !found; i++) { - info = (CamelImapMessageInfo *)camel_folder_summary_index (summary, i); - if (info) { - found = info->info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED; - camel_message_info_free(info); - } + for (i = 0; i < max; i++) { + info = camel_folder_summary_index (summary, i); + if (info && (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) + return TRUE; } return FALSE; @@ -1982,7 +2022,7 @@ get_folder_online (CamelStore *store, const char *folder_name, guint32 flags, Ca } storage_path = g_strdup_printf("%s/folders", imap_store->storage_path); - folder_dir = imap_path_to_physical (storage_path, folder_name); + folder_dir = e_path_to_physical (storage_path, folder_name); g_free(storage_path); new_folder = camel_imap_folder_new (store, folder_name, folder_dir, ex); g_free (folder_dir); @@ -2025,7 +2065,7 @@ get_folder_offline (CamelStore *store, const char *folder_name, folder_name = "INBOX"; storage_path = g_strdup_printf("%s/folders", imap_store->storage_path); - folder_dir = imap_path_to_physical (storage_path, folder_name); + folder_dir = e_path_to_physical (storage_path, folder_name); g_free(storage_path); if (!folder_dir || access (folder_dir, F_OK) != 0) { g_free (folder_dir); @@ -2195,8 +2235,8 @@ rename_folder (CamelStore *store, const char *old_name, const char *new_name_in, manage_subscriptions(store, new_name_in, TRUE); storage_path = g_strdup_printf("%s/folders", imap_store->storage_path); - oldpath = imap_path_to_physical (storage_path, old_name); - newpath = imap_path_to_physical (storage_path, new_name_in); + oldpath = e_path_to_physical (storage_path, old_name); + newpath = e_path_to_physical (storage_path, new_name_in); g_free(storage_path); /* So do we care if this didn't work? Its just a cache? */ @@ -2631,7 +2671,7 @@ fill_fi(CamelStore *store, CamelFolderInfo *fi, guint32 flags) /* This is a lot of work for one path! */ storage_path = g_strdup_printf("%s/folders", ((CamelImapStore *)store)->storage_path); - folder_dir = imap_path_to_physical(storage_path, fi->full_name); + folder_dir = e_path_to_physical(storage_path, fi->full_name); path = g_strdup_printf("%s/summary", folder_dir); s = (CamelFolderSummary *)camel_object_new(camel_imap_summary_get_type()); camel_folder_summary_set_build_content(s, TRUE); @@ -3037,7 +3077,7 @@ get_folder_info_offline (CamelStore *store, const char *top, /* A kludge to avoid having to pass a struct to the callback */ g_ptr_array_add (folders, imap_store); storage_path = g_strdup_printf("%s/folders", imap_store->storage_path); - if (!imap_path_find_folders (storage_path, get_one_folder_offline, folders)) { + if (!e_path_find_folders (storage_path, get_one_folder_offline, folders)) { camel_disco_store_check_online (CAMEL_DISCO_STORE (imap_store), ex); fi = NULL; } else { diff --git a/camel/providers/imap4/camel-imap4-engine.c b/camel/providers/imap4/camel-imap4-engine.c index d6f17532ee..adbf862747 100644 --- a/camel/providers/imap4/camel-imap4-engine.c +++ b/camel/providers/imap4/camel-imap4-engine.c @@ -28,7 +28,6 @@ #include <camel/camel-sasl.h> #include <camel/camel-stream-buffer.h> -#include <camel/camel-i18n.h> #include "camel-imap4-summary.h" #include "camel-imap4-command.h" @@ -115,6 +114,22 @@ camel_imap4_engine_init (CamelIMAP4Engine *engine, CamelIMAP4EngineClass *klass) } static void +imap4_namespace_clear (CamelIMAP4Namespace **namespace) +{ + CamelIMAP4Namespace *node, *next; + + node = *namespace; + while (node != NULL) { + next = node->next; + g_free (node->path); + g_free (node); + node = next; + } + + *namespace = NULL; +} + +static void camel_imap4_engine_finalize (CamelObject *object) { CamelIMAP4Engine *engine = (CamelIMAP4Engine *) object; @@ -129,9 +144,9 @@ camel_imap4_engine_finalize (CamelObject *object) g_hash_table_foreach (engine->authtypes, (GHFunc) g_free, NULL); g_hash_table_destroy (engine->authtypes); - camel_imap4_namespace_clear (&engine->namespaces.personal); - camel_imap4_namespace_clear (&engine->namespaces.other); - camel_imap4_namespace_clear (&engine->namespaces.shared); + imap4_namespace_clear (&engine->namespaces.personal); + imap4_namespace_clear (&engine->namespaces.other); + imap4_namespace_clear (&engine->namespaces.shared); if (engine->folder) camel_object_unref (engine->folder); @@ -148,7 +163,6 @@ camel_imap4_engine_finalize (CamelObject *object) /** * camel_imap4_engine_new: * @service: service - * @reconnect: reconnect callback function * * Returns a new imap4 engine **/ @@ -334,16 +348,6 @@ camel_imap4_engine_namespace (CamelIMAP4Engine *engine, CamelException *ex) } -/** - * camel_imap4_engine_select_folder: - * @engine: IMAP4 engine - * @folder: folder to select - * @ex: exception - * - * Convenience function to select @folder. - * - * Returns 0 on success or -1 on fail. - **/ int camel_imap4_engine_select_folder (CamelIMAP4Engine *engine, CamelFolder *folder, CamelException *ex) { @@ -435,15 +439,11 @@ static struct { { "IMAP4", CAMEL_IMAP4_CAPABILITY_IMAP4 }, { "IMAP4REV1", CAMEL_IMAP4_CAPABILITY_IMAP4REV1 }, { "STATUS", CAMEL_IMAP4_CAPABILITY_STATUS }, - { "NAMESPACE", CAMEL_IMAP4_CAPABILITY_NAMESPACE }, /* rfc2342 */ - { "UIDPLUS", CAMEL_IMAP4_CAPABILITY_UIDPLUS }, /* rfc2359 */ - { "LITERAL+", CAMEL_IMAP4_CAPABILITY_LITERALPLUS }, /* rfc2088 */ + { "NAMESPACE", CAMEL_IMAP4_CAPABILITY_NAMESPACE }, + { "UIDPLUS", CAMEL_IMAP4_CAPABILITY_UIDPLUS }, + { "LITERAL+", CAMEL_IMAP4_CAPABILITY_LITERALPLUS }, { "LOGINDISABLED", CAMEL_IMAP4_CAPABILITY_LOGINDISABLED }, { "STARTTLS", CAMEL_IMAP4_CAPABILITY_STARTTLS }, - { "QUOTA", CAMEL_IMAP4_CAPABILITY_QUOTA }, /* rfc2087 */ - { "ACL", CAMEL_IMAP4_CAPABILITY_ACL }, /* rfc2086 */ - { "IDLE", CAMEL_IMAP4_CAPABILITY_IDLE }, /* rfc2177 */ - { "MULTIAPPEND", CAMEL_IMAP4_CAPABILITY_MULTIAPPEND }, /* rfc3502 */ { NULL, 0 } }; @@ -469,7 +469,7 @@ engine_parse_capability (CamelIMAP4Engine *engine, int sentinel, CamelException return -1; while (token.token == CAMEL_IMAP4_TOKEN_ATOM) { - if (!g_ascii_strncasecmp ("AUTH=", token.v.atom, 5)) { + if (!strncasecmp ("AUTH=", token.v.atom, 5)) { CamelServiceAuthType *auth; if ((auth = camel_sasl_authtype (token.v.atom + 5)) != NULL) @@ -563,9 +563,9 @@ engine_parse_namespace (CamelIMAP4Engine *engine, CamelException *ex) camel_imap4_token_t token; int i, n = 0; - camel_imap4_namespace_clear (&engine->namespaces.personal); - camel_imap4_namespace_clear (&engine->namespaces.other); - camel_imap4_namespace_clear (&engine->namespaces.shared); + imap4_namespace_clear (&engine->namespaces.personal); + imap4_namespace_clear (&engine->namespaces.other); + imap4_namespace_clear (&engine->namespaces.shared); if (camel_imap4_engine_next_token (engine, &token, ex) == -1) return -1; @@ -604,19 +604,8 @@ engine_parse_namespace (CamelIMAP4Engine *engine, CamelException *ex) goto exception; } - switch (token.token) { - case CAMEL_IMAP4_TOKEN_NIL: - node->sep = '\0'; - break; - case CAMEL_IMAP4_TOKEN_QSTRING: - if (strlen (token.v.qstring) == 1) { - node->sep = *token.v.qstring; - break; - } else { - /* invalid, fall thru */ - } - default: - d(fprintf (stderr, "Expected to find a nil or a valid qstring token as second element in NAMESPACE pair\n")); + if (token.token != CAMEL_IMAP4_TOKEN_QSTRING || strlen (token.v.qstring) > 1) { + d(fprintf (stderr, "Expected to find a qstring token as second element in NAMESPACE pair\n")); camel_imap4_utils_set_unexpected_token_error (ex, engine, &token); g_free (node->path); g_free (node); @@ -624,6 +613,7 @@ engine_parse_namespace (CamelIMAP4Engine *engine, CamelException *ex) goto exception; } + node->sep = *token.v.qstring; tail->next = node; tail = node; @@ -682,7 +672,7 @@ engine_parse_namespace (CamelIMAP4Engine *engine, CamelException *ex) exception: for (i = 0; i <= n; i++) - camel_imap4_namespace_clear (&namespaces[i]); + imap4_namespace_clear (&namespaces[i]); return -1; } @@ -723,15 +713,6 @@ static struct { }; -/** - * camel_imap4_engine_parse_resp_code: - * @engine: IMAP4 engine - * @ex: exception - * - * Parses a RESP-CODE - * - * Returns 0 on success or -1 on fail. - **/ int camel_imap4_engine_parse_resp_code (CamelIMAP4Engine *engine, CamelException *ex) { @@ -900,34 +881,26 @@ camel_imap4_engine_parse_resp_code (CamelIMAP4Engine *engine, CamelException *ex if (camel_imap4_engine_next_token (engine, &token, ex) == -1) return -1; - if (token.token != CAMEL_IMAP4_TOKEN_ATOM && token.token != CAMEL_IMAP4_TOKEN_NUMBER) { - d(fprintf (stderr, "Expected an atom or numeric token as the second argument to the COPYUID RESP-CODE\n")); + if (token.token != CAMEL_IMAP4_TOKEN_ATOM) { + d(fprintf (stderr, "Expected an atom token as the second argument to the COPYUID RESP-CODE\n")); camel_imap4_utils_set_unexpected_token_error (ex, engine, &token); goto exception; } - if (resp != NULL) { - if (token.token == CAMEL_IMAP4_TOKEN_NUMBER) - resp->v.copyuid.srcset = g_strdup_printf ("%u", token.v.number); - else - resp->v.copyuid.srcset = g_strdup (token.v.atom); - } + if (resp != NULL) + resp->v.copyuid.srcset = g_strdup (token.v.atom); if (camel_imap4_engine_next_token (engine, &token, ex) == -1) return -1; - if (token.token != CAMEL_IMAP4_TOKEN_ATOM && token.token != CAMEL_IMAP4_TOKEN_NUMBER) { - d(fprintf (stderr, "Expected an atom or numeric token as the third argument to the APPENDUID RESP-CODE\n")); + if (token.token != CAMEL_IMAP4_TOKEN_ATOM) { + d(fprintf (stderr, "Expected an atom token as the third argument to the APPENDUID RESP-CODE\n")); camel_imap4_utils_set_unexpected_token_error (ex, engine, &token); goto exception; } - if (resp != NULL) { - if (token.token == CAMEL_IMAP4_TOKEN_NUMBER) - resp->v.copyuid.destset = g_strdup_printf ("%u", token.v.number); - else - resp->v.copyuid.destset = g_strdup (token.v.atom); - } + if (resp != NULL) + resp->v.copyuid.destset = g_strdup (token.v.atom); break; default: @@ -986,17 +959,8 @@ camel_imap4_engine_parse_resp_code (CamelIMAP4Engine *engine, CamelException *ex } -/** - * camel_imap4_engine_handle_untagged_1: - * @engine: IMAP4 engine - * @token: IMAP4 token - * @ex: exception - * - * Handles a single untagged response - * - * Returns -1 on error or one of - * CAMEL_IMAP4_UNTAGGED_[OK,NO,BAD,PREAUTH,HANDLED] on success - **/ + +/* returns -1 on error, or one of CAMEL_IMAP4_UNTAGGED_[OK,NO,BAD,PREAUTH,HANDLED] on success */ int camel_imap4_engine_handle_untagged_1 (CamelIMAP4Engine *engine, camel_imap4_token_t *token, CamelException *ex) { @@ -1149,13 +1113,6 @@ camel_imap4_engine_handle_untagged_1 (CamelIMAP4Engine *engine, camel_imap4_toke } -/** - * camel_imap4_engine_handle_untagged: - * @engine: IMAP4 engine - * @ex: exception - * - * Handle a stream of untagged responses. - **/ void camel_imap4_engine_handle_untagged (CamelIMAP4Engine *engine, CamelException *ex) { @@ -1254,7 +1211,6 @@ engine_state_change (CamelIMAP4Engine *engine, CamelIMAP4Command *ic) return retval; } - /** * camel_imap4_engine_iterate: * @engine: IMAP4 engine @@ -1421,13 +1377,6 @@ camel_imap4_engine_prequeue (CamelIMAP4Engine *engine, CamelFolder *folder, cons } -/** - * camel_imap4_engine_dequeue: - * @engine: IMAP4 engine - * @ic: IMAP4 command - * - * Removes @ic from the processing queue. - **/ void camel_imap4_engine_dequeue (CamelIMAP4Engine *engine, CamelIMAP4Command *ic) { @@ -1444,18 +1393,6 @@ camel_imap4_engine_dequeue (CamelIMAP4Engine *engine, CamelIMAP4Command *ic) } -/** - * camel_imap4_engine_next_token: - * @engine: IMAP4 engine - * @token: IMAP4 token - * @ex: exception - * - * Wraps camel_imap4_stream_next_token() to set an exception on - * failure and updates the engine state to DISCONNECTED if the stream - * gets disconencted. - * - * Returns 0 on success or -1 on fail. - **/ int camel_imap4_engine_next_token (CamelIMAP4Engine *engine, camel_imap4_token_t *token, CamelException *ex) { @@ -1473,15 +1410,6 @@ camel_imap4_engine_next_token (CamelIMAP4Engine *engine, camel_imap4_token_t *to } -/** - * camel_imap4_engine_eat_line: - * @engine: IMAP4 engine - * @ex: exception - * - * Gobbles up the remainder of the response line. - * - * Returns 0 on success or -1 on fail - **/ int camel_imap4_engine_eat_line (CamelIMAP4Engine *engine, CamelException *ex) { @@ -1514,19 +1442,6 @@ camel_imap4_engine_eat_line (CamelIMAP4Engine *engine, CamelException *ex) } -/** - * camel_imap4_engine_line: - * @engine: IMAP4 engine - * @line: line pointer - * @len: length pointer - * @ex: exception - * - * Reads in a single line of input from the IMAP4 server and updates - * @line to point to the line buffer. @len is set to the length of the - * line buffer. @line must be free'd using g_free(). - * - * Returns 0 on success or -1 on fail - **/ int camel_imap4_engine_line (CamelIMAP4Engine *engine, unsigned char **line, size_t *len, CamelException *ex) { @@ -1569,20 +1484,6 @@ camel_imap4_engine_line (CamelIMAP4Engine *engine, unsigned char **line, size_t } -/** - * camel_imap4_engine_literal: - * @engine: IMAP4 engine - * @literal: literal pointer - * @len: len pointer - * @ex: exception - * - * Reads in an entire literal string and updates @literal to point to - * it. @len is set to the length of the literal. @literal will also - * conveniently be terminated with a nul-byte. @literal must be free'd - * using g_free(). - * - * Returns 0 on success or -1 on fail. - **/ int camel_imap4_engine_literal (CamelIMAP4Engine *engine, unsigned char **literal, size_t *len, CamelException *ex) { @@ -1626,55 +1527,6 @@ camel_imap4_engine_literal (CamelIMAP4Engine *engine, unsigned char **literal, s } -/** - * camel_imap4_engine_nstring: - * @engine: IMAP4 engine - * @nstring: nstring pointer - * @ex: exception - * - * Reads in an nstring (NIL, atom, qstring or literal) and updates - * @nstring to point to it. @nstring must be free'd using g_free(). - * - * Returns 0 on success or -1 on fail. - **/ -int -camel_imap4_engine_nstring (CamelIMAP4Engine *engine, unsigned char **nstring, CamelException *ex) -{ - camel_imap4_token_t token; - size_t n; - - if (camel_imap4_engine_next_token (engine, &token, ex) == -1) - return -1; - - switch (token.token) { - case CAMEL_IMAP4_TOKEN_NIL: - *nstring = NULL; - break; - case CAMEL_IMAP4_TOKEN_ATOM: - *nstring = g_strdup (token.v.atom); - break; - case CAMEL_IMAP4_TOKEN_QSTRING: - *nstring = g_strdup (token.v.qstring); - break; - case CAMEL_IMAP4_TOKEN_LITERAL: - if (camel_imap4_engine_literal (engine, nstring, &n, ex) == -1) - return -1; - break; - default: - camel_imap4_utils_set_unexpected_token_error (ex, engine, &token); - return -1; - } - - return 0; -} - - -/** - * camel_imap4_resp_code_free: - * @rcode: RESP-CODE - * - * Free's the RESP-CODE - **/ void camel_imap4_resp_code_free (CamelIMAP4RespCode *rcode) { diff --git a/camel/providers/imap4/camel-imap4-store.c b/camel/providers/imap4/camel-imap4-store.c index 2e7308d75d..0d33f43c5d 100644 --- a/camel/providers/imap4/camel-imap4-store.c +++ b/camel/providers/imap4/camel-imap4-store.c @@ -34,9 +34,6 @@ #include <camel/camel-private.h> -#include <camel/camel-i18n.h> -#include <camel/camel-net-utils.h> - #include "camel-imap4-store.h" #include "camel-imap4-engine.h" #include "camel-imap4-folder.h" @@ -44,9 +41,7 @@ #include "camel-imap4-command.h" #include "camel-imap4-utils.h" #include "camel-imap4-summary.h" -#include "camel-imap4-store-summary.h" -#define d(x) x static void camel_imap4_store_class_init (CamelIMAP4StoreClass *klass); static void camel_imap4_store_init (CamelIMAP4Store *store, CamelIMAP4StoreClass *klass); @@ -148,7 +143,6 @@ static void camel_imap4_store_init (CamelIMAP4Store *store, CamelIMAP4StoreClass *klass) { store->engine = NULL; - store->summary = NULL; } static void @@ -156,11 +150,6 @@ camel_imap4_store_finalize (CamelObject *object) { CamelIMAP4Store *store = (CamelIMAP4Store *) object; - if (store->summary) { - camel_store_summary_save ((CamelStoreSummary *) store->summary); - camel_object_unref (store->summary); - } - if (store->engine) camel_object_unref (store->engine); @@ -172,7 +161,6 @@ static void imap4_construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex) { CamelIMAP4Store *store = (CamelIMAP4Store *) service; - char *buf; CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex); if (camel_exception_is_set (ex)) @@ -180,20 +168,6 @@ imap4_construct (CamelService *service, CamelSession *session, CamelProvider *pr store->storage_path = camel_session_get_storage_path (session, service, ex); store->engine = camel_imap4_engine_new (service, imap4_reconnect); - - /* setup/load the summary */ - buf = g_alloca (strlen (store->storage_path) + 32); - sprintf (buf, "%s/.summary", store->storage_path); - store->summary = camel_imap4_store_summary_new (); - camel_store_summary_set_filename ((CamelStoreSummary *) store->summary, buf); - - buf = camel_url_to_string (service->url, CAMEL_URL_HIDE_ALL); - url = camel_url_new (buf, NULL); - g_free (buf); - camel_store_summary_set_uri_base ((CamelStoreSummary *) store->summary, url); - camel_url_free (url); - - camel_store_summary_load ((CamelStoreSummary *) store->summary); } static char * @@ -226,7 +200,7 @@ connect_to_server (CamelIMAP4Engine *engine, struct addrinfo *ai, int ssl_mode, if (ssl_mode != MODE_CLEAR) { #ifdef HAVE_SSL if (ssl_mode == MODE_TLS) { - tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS); + tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, STARTTLS_FLAGS); } else { tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS); } @@ -262,8 +236,6 @@ connect_to_server (CamelIMAP4Engine *engine, struct addrinfo *ai, int ssl_mode, if (camel_imap4_engine_capability (engine, ex) == -1) return FALSE; - camel_imap4_store_summary_set_capabilities (((CamelIMAP4Store *) service)->summary, engine->capa); - if (ssl_mode != MODE_TLS) { /* we're done */ return TRUE; @@ -320,9 +292,9 @@ connect_to_server_wrapper (CamelIMAP4Engine *engine, CamelException *ex) struct addrinfo *ai, hints; const char *ssl_mode; int mode, ret, i; - const char *port; char *serv; - + const char *port; + if ((ssl_mode = camel_url_get_param (service->url, "use_ssl"))) { for (i = 0; ssl_options[i].value; i++) if (!strcmp (ssl_options[i].value, ssl_mode)) @@ -353,13 +325,7 @@ connect_to_server_wrapper (CamelIMAP4Engine *engine, CamelException *ex) if (ai == NULL) return FALSE; - if (!(ret = connect_to_server (engine, ai, mode, ex)) && mode == MODE_SSL) { - camel_exception_clear (ex); - ret = connect_to_server (engine, ai, MODE_TLS, ex); - } else if (!ret && mode == MODE_TLS) { - camel_exception_clear (ex); - ret = connect_to_server (engine, ai, MODE_CLEAR, ex); - } + ret = connect_to_server (engine, ai, mode, ex); camel_freeaddrinfo (ai); @@ -389,7 +355,7 @@ sasl_auth (CamelIMAP4Engine *engine, CamelIMAP4Command *ic, const unsigned char if (!(challenge = camel_sasl_challenge_base64 (sasl, (const char *) linebuf, ex))) return -1; - d(fprintf (stderr, "sending : %s\r\n", challenge)); + fprintf (stderr, "sending : %s\r\n", challenge); if (camel_stream_printf (engine->ostream, "%s\r\n", challenge) == -1) { g_free (challenge); @@ -437,7 +403,7 @@ imap4_try_authenticate (CamelIMAP4Engine *engine, gboolean reprompt, const char CamelServiceAuthType *mech; mech = g_hash_table_lookup (engine->authtypes, service->url->authmech); - sasl = camel_sasl_new ("imap", mech->authproto, service); + sasl = camel_sasl_new ("imap4", mech->authproto, service); ic = camel_imap4_engine_prequeue (engine, NULL, "AUTHENTICATE %s\r\n", service->url->authmech); ic->plus = sasl_auth; @@ -501,8 +467,6 @@ imap4_reconnect (CamelIMAP4Engine *engine, CamelException *ex) g_free (errmsg); errmsg = g_strdup (lex.desc); camel_exception_clear (&lex); - g_free (service->url->passwd); - service->url->passwd = NULL; reprompt = TRUE; } g_free (errmsg); @@ -515,25 +479,16 @@ imap4_reconnect (CamelIMAP4Engine *engine, CamelException *ex) if (camel_imap4_engine_namespace (engine, ex) == -1) return FALSE; - camel_imap4_store_summary_set_namespaces (((CamelIMAP4Store *) service)->summary, &engine->namespaces); - return TRUE; } static gboolean imap4_connect (CamelService *service, CamelException *ex) { - CamelIMAP4Store *store = (CamelIMAP4Store *) service; gboolean retval; - if (!camel_session_is_online (service->session)) - return TRUE; - CAMEL_SERVICE_LOCK (service, connect_lock); - if (store->engine->state == CAMEL_IMAP4_ENGINE_DISCONNECTED) - retval = imap4_reconnect (store->engine, ex); - else - retval = TRUE; + retval = imap4_reconnect (((CamelIMAP4Store *) service)->engine, ex); CAMEL_SERVICE_UNLOCK (service, connect_lock); return retval; @@ -546,18 +501,13 @@ imap4_disconnect (CamelService *service, gboolean clean, CamelException *ex) CamelIMAP4Command *ic; int id; - if (!camel_session_is_online (service->session)) - return TRUE; - - CAMEL_SERVICE_LOCK (store, connect_lock); - if (clean && store->engine->state != CAMEL_IMAP4_ENGINE_DISCONNECTED) { + if (clean && !store->engine->istream->disconnected) { ic = camel_imap4_engine_queue (store->engine, NULL, "LOGOUT\r\n"); while ((id = camel_imap4_engine_iterate (store->engine)) < ic->id && id != -1) ; camel_imap4_command_unref (ic); } - CAMEL_SERVICE_UNLOCK (store, connect_lock); return 0; } @@ -572,9 +522,6 @@ imap4_query_auth_types (CamelService *service, CamelException *ex) GList *sasl_types, *t, *next; gboolean connected; - if (!camel_session_is_online (service->session)) - return NULL; - CAMEL_SERVICE_LOCK (store, connect_lock); connected = connect_to_server_wrapper (store->engine, ex); CAMEL_SERVICE_UNLOCK (store, connect_lock); @@ -595,30 +542,83 @@ imap4_query_auth_types (CamelService *service, CamelException *ex) return g_list_prepend (sasl_types, &camel_imap4_password_authtype); } + +static char +imap4_get_path_delim (CamelIMAP4Engine *engine, const char *full_name) +{ + /* FIXME: move this to utils so imap4-folder.c can share */ + CamelIMAP4Namespace *namespace; + const char *slash; + size_t len; + char *top; + + if ((slash = strchr (full_name, '/'))) + len = (slash - full_name); + else + len = strlen (full_name); + + top = g_alloca (len + 1); + memcpy (top, full_name, len); + top[len] = '\0'; + + if (!g_ascii_strcasecmp (top, "INBOX")) + top = "INBOX"; + + retry: + namespace = engine->namespaces.personal; + while (namespace != NULL) { + if (!strcmp (namespace->path, top)) + return namespace->sep; + namespace = namespace->next; + } + + namespace = engine->namespaces.other; + while (namespace != NULL) { + if (!strcmp (namespace->path, top)) + return namespace->sep; + namespace = namespace->next; + } + + namespace = engine->namespaces.shared; + while (namespace != NULL) { + if (!strcmp (namespace->path, top)) + return namespace->sep; + namespace = namespace->next; + } + + if (top[0] != '\0') { + /* look for a default namespace? */ + top[0] = '\0'; + goto retry; + } + + return '/'; +} + static char * imap4_folder_utf7_name (CamelStore *store, const char *folder_name, char wildcard) { char *real_name, *p; - char sep = '\0'; + char sep; int len; - if (*folder_name) { - sep = camel_imap4_get_path_delim (((CamelIMAP4Store *) store)->summary, folder_name); - - if (sep != '/') { - p = real_name = g_alloca (strlen (folder_name) + 1); - strcpy (real_name, folder_name); - while (*p != '\0') { - if (*p == '/') - *p = sep; - p++; - } - - folder_name = real_name; + sep = imap4_get_path_delim (((CamelIMAP4Store *) store)->engine, folder_name); + + if (sep != '/') { + p = real_name = g_alloca (strlen (folder_name) + 1); + strcpy (real_name, folder_name); + while (*p != '\0') { + if (*p == '/') + *p = sep; + p++; } + folder_name = real_name; + } + + if (*folder_name) real_name = camel_utf8_utf7 (folder_name); - } else + else real_name = g_strdup (""); if (wildcard) { @@ -639,7 +639,6 @@ static CamelFolder * imap4_get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex) { CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine; - CamelSession *session = ((CamelService *) store)->session; CamelFolder *folder = NULL; camel_imap4_list_t *list; CamelIMAP4Command *ic; @@ -651,18 +650,6 @@ imap4_get_folder (CamelStore *store, const char *folder_name, guint32 flags, Cam CAMEL_SERVICE_LOCK (store, connect_lock); - if (!camel_session_is_online (session)) { - if ((flags & CAMEL_STORE_FOLDER_CREATE) != 0) { - camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create IMAP folders in offline mode.")); - } else { - folder = camel_imap4_folder_new (store, folder_name, ex); - } - - CAMEL_SERVICE_UNLOCK (store, connect_lock); - - return folder; - } - /* make sure the folder exists - try LISTing it? */ utf7_name = imap4_folder_utf7_name (store, folder_name, '\0'); ic = camel_imap4_engine_queue (engine, NULL, "LIST \"\" %S\r\n", utf7_name); @@ -740,7 +727,6 @@ imap4_create_folder (CamelStore *store, const char *parent_name, const char *fol * contain subfolders - delete them and re-create with the * proper hint */ CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine; - CamelSession *session = ((CamelService *) store)->session; CamelFolderInfo *fi = NULL; CamelIMAP4Command *ic; char *utf7_name; @@ -750,7 +736,7 @@ imap4_create_folder (CamelStore *store, const char *parent_name, const char *fol char sep; int id; - sep = camel_imap4_get_path_delim (((CamelIMAP4Store *) store)->summary, parent_name); + sep = imap4_get_path_delim (engine, parent_name); c = folder_name; while (*c != '\0') { @@ -765,11 +751,6 @@ imap4_create_folder (CamelStore *store, const char *parent_name, const char *fol c++; } - if (!camel_session_is_online (session)) { - camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create IMAP folders in offline mode.")); - return NULL; - } - if (parent_name != NULL && *parent_name) name = g_strdup_printf ("%s/%s", parent_name, folder_name); else @@ -807,8 +788,6 @@ imap4_create_folder (CamelStore *store, const char *parent_name, const char *fol fi->unread = -1; fi->total = -1; - camel_imap4_store_summary_note_info (((CamelIMAP4Store *) store)->summary, fi); - camel_object_trigger_event (store, "folder_created", fi); break; case CAMEL_IMAP4_RESULT_NO: @@ -841,7 +820,6 @@ static void imap4_delete_folder (CamelStore *store, const char *folder_name, CamelException *ex) { CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine; - CamelSession *session = ((CamelService *) store)->session; CamelFolder *selected = (CamelFolder *) engine->folder; CamelIMAP4Command *ic, *ic0 = NULL; CamelFolderInfo *fi; @@ -858,11 +836,6 @@ imap4_delete_folder (CamelStore *store, const char *folder_name, CamelException return; } - if (!camel_session_is_online (session)) { - camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot delete IMAP folders in offline mode.")); - return; - } - CAMEL_SERVICE_LOCK (store, connect_lock); if (selected && !strcmp (folder_name, selected->full_name)) @@ -909,8 +882,6 @@ imap4_delete_folder (CamelStore *store, const char *folder_name, CamelException fi->unread = -1; fi->total = -1; - camel_imap4_store_summary_unnote_info (((CamelIMAP4Store *) store)->summary, fi); - camel_object_trigger_event (store, "folder_deleted", fi); camel_folder_info_free (fi); @@ -937,7 +908,6 @@ static void imap4_rename_folder (CamelStore *store, const char *old_name, const char *new_name, CamelException *ex) { CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine; - CamelSession *session = ((CamelService *) store)->session; char *old_uname, *new_uname; CamelIMAP4Command *ic; int id; @@ -950,11 +920,6 @@ imap4_rename_folder (CamelStore *store, const char *old_name, const char *new_na return; } - if (!camel_session_is_online (session)) { - camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot rename IMAP folders in offline mode.")); - return; - } - CAMEL_SERVICE_LOCK (store, connect_lock); old_uname = imap4_folder_utf7_name (store, old_name, '\0'); @@ -977,7 +942,6 @@ imap4_rename_folder (CamelStore *store, const char *old_name, const char *new_na switch (ic->result) { case CAMEL_IMAP4_RESULT_OK: /* FIXME: need to update state on the renamed folder object */ - /* FIXME: need to update cached summary info too */ break; case CAMEL_IMAP4_RESULT_NO: /* FIXME: would be good to save the NO reason into the err message */ @@ -1091,11 +1055,6 @@ imap4_build_folder_info (CamelStore *store, const char *top, guint32 flags, GPtr url = camel_url_copy (engine->url); - if (!strcmp (top, "") && (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)) { - /* clear the folder-info cache */ - camel_store_summary_clear ((CamelStoreSummary *) ((CamelIMAP4Store *) store)->summary); - } - for (i = 0; i < array->len; i++) { list = array->pdata[i]; fi = g_malloc0 (sizeof (CamelFolderInfo)); @@ -1116,20 +1075,34 @@ imap4_build_folder_info (CamelStore *store, const char *top, guint32 flags, GPtr fi->flags = list->flags; fi->unread = -1; fi->total = -1; - - /* SELECTED folder, just get it from the folder */ - if (folder && !strcmp (folder->full_name, fi->full_name)) { - camel_object_get(folder, NULL, CAMEL_FOLDER_TOTAL, &fi->total, CAMEL_FOLDER_UNREAD, &fi->unread, 0); - } else if (!(flags & CAMEL_STORE_FOLDER_INFO_FAST)) { - imap4_status (store, fi); + + if (!(flags & CAMEL_STORE_FOLDER_INFO_FAST)) { + if (folder && !strcmp (folder->full_name, fi->full_name)) { + /* can't STATUS this folder since it is SELECTED, besides - it would be wasteful */ + CamelMessageInfo *info; + int index; + + fi->total = camel_folder_summary_count (folder->summary); + + fi->unread = 0; + for (index = 0; index < fi->total; index++) { + if (!(info = camel_folder_summary_index (folder->summary, index))) + continue; + + if ((info->flags & CAMEL_MESSAGE_SEEN) == 0) + fi->unread++; + + camel_folder_summary_info_free (folder->summary, info); + } + } else { + imap4_status (store, fi); + } } g_free (list->name); g_free (list); array->pdata[i] = fi; - - camel_imap4_store_summary_note_info (((CamelIMAP4Store *) store)->summary, fi); } fi = camel_folder_info_build (array, top, '/', TRUE); @@ -1138,8 +1111,6 @@ imap4_build_folder_info (CamelStore *store, const char *top, guint32 flags, GPtr g_ptr_array_free (array, TRUE); - camel_store_summary_save ((CamelStoreSummary *) ((CamelIMAP4Store *) store)->summary); - return fi; } @@ -1147,7 +1118,6 @@ static CamelFolderInfo * imap4_get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex) { CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine; - CamelSession *session = ((CamelService *) store)->session; CamelIMAP4Command *ic, *ic0 = NULL; CamelFolderInfo *fi = NULL; camel_imap4_list_t *list; @@ -1157,30 +1127,23 @@ imap4_get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelE char wildcard; int id, i; - if (top == NULL) - top = ""; - CAMEL_SERVICE_LOCK (store, connect_lock); - if (!camel_session_is_online (session) || engine->state == CAMEL_IMAP4_ENGINE_DISCONNECTED) { - fi = camel_imap4_store_summary_get_folder_info (((CamelIMAP4Store *) store)->summary, top, flags); - if (fi == NULL && camel_session_is_online (session)) { - /* folder info hasn't yet been cached and the store hasn't been - * connected yet, but the network is available so we can connect - * and query the server. */ - goto check_online; - } - CAMEL_SERVICE_UNLOCK (store, connect_lock); - return fi; + if (engine->state == CAMEL_IMAP4_ENGINE_DISCONNECTED) { + if (!camel_service_connect ((CamelService *) store, ex)) + return NULL; + + engine = ((CamelIMAP4Store *) store)->engine; } - check_online: - if (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) cmd = "LSUB"; else cmd = "LIST"; + if (top == NULL) + top = ""; + wildcard = (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) ? '*' : '%'; pattern = imap4_folder_utf7_name (store, top, wildcard); array = g_ptr_array_new (); @@ -1268,7 +1231,6 @@ static void imap4_subscribe_folder (CamelStore *store, const char *folder_name, CamelException *ex) { CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine; - CamelSession *session = ((CamelService *) store)->session; CamelIMAP4Command *ic; CamelFolderInfo *fi; char *utf7_name; @@ -1276,11 +1238,6 @@ imap4_subscribe_folder (CamelStore *store, const char *folder_name, CamelExcepti const char *p; int id; - if (!camel_session_is_online (session)) { - camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot subscribe to IMAP folders in offline mode.")); - return; - } - CAMEL_SERVICE_LOCK (store, connect_lock); utf7_name = imap4_folder_utf7_name (store, folder_name, '\0'); @@ -1314,8 +1271,6 @@ imap4_subscribe_folder (CamelStore *store, const char *folder_name, CamelExcepti fi->unread = -1; fi->total = -1; - camel_imap4_store_summary_note_info (((CamelIMAP4Store *) store)->summary, fi); - camel_object_trigger_event (store, "folder_subscribed", fi); camel_folder_info_free (fi); break; @@ -1341,7 +1296,6 @@ static void imap4_unsubscribe_folder (CamelStore *store, const char *folder_name, CamelException *ex) { CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine; - CamelSession *session = ((CamelService *) store)->session; CamelIMAP4Command *ic; CamelFolderInfo *fi; char *utf7_name; @@ -1349,11 +1303,6 @@ imap4_unsubscribe_folder (CamelStore *store, const char *folder_name, CamelExcep const char *p; int id; - if (!camel_session_is_online (session)) { - camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot unsubscribe from IMAP folders in offline mode.")); - return; - } - CAMEL_SERVICE_LOCK (store, connect_lock); utf7_name = imap4_folder_utf7_name (store, folder_name, '\0'); @@ -1387,8 +1336,6 @@ imap4_unsubscribe_folder (CamelStore *store, const char *folder_name, CamelExcep fi->unread = -1; fi->total = -1; - camel_imap4_store_summary_unnote_info (((CamelIMAP4Store *) store)->summary, fi); - camel_object_trigger_event (store, "folder_unsubscribed", fi); camel_folder_info_free (fi); break; @@ -1414,14 +1361,10 @@ static void imap4_noop (CamelStore *store, CamelException *ex) { CamelIMAP4Engine *engine = ((CamelIMAP4Store *) store)->engine; - CamelSession *session = ((CamelService *) store)->session; CamelFolder *folder = (CamelFolder *) engine->folder; CamelIMAP4Command *ic; int id; - if (!camel_session_is_online (session)) - return; - CAMEL_SERVICE_LOCK (store, connect_lock); if (folder) { diff --git a/camel/providers/imapp/camel-imapp-store.c b/camel/providers/imapp/camel-imapp-store.c index 03f835da7a..c1c9f50649 100644 --- a/camel/providers/imapp/camel-imapp-store.c +++ b/camel/providers/imapp/camel-imapp-store.c @@ -48,7 +48,6 @@ #ifdef HAVE_SSL #include "camel/camel-tcp-stream-ssl.h" #endif -#include "camel/camel-i18n.h" #include "camel-imapp-store-summary.h" #include "camel-imapp-store.h" @@ -57,7 +56,6 @@ #include "camel-imapp-exception.h" #include "camel-imapp-utils.h" #include "camel-imapp-driver.h" -#include "camel-net-utils.h" /* Specified in RFC 2060 section 2.1 */ #define IMAP_PORT 143 @@ -811,7 +809,7 @@ static int store_resp_fetch(CamelIMAPPEngine *ie, guint32 id, void *data) if (strcmp(finfo->uid, camel_message_info_uid(info)) != 0) { printf("summary at index %d has uid %s expected %s\n", id, camel_message_info_uid(info), finfo->uid); /* uid mismatch??? try do it based on uid instead? try to reorder? i dont know? */ - camel_message_info_free(info); + camel_folder_summary_info_free(((CamelFolder *)istore->selected)->summary, info); info = camel_folder_summary_uid(((CamelFolder *)istore->selected)->summary, finfo->uid); } } @@ -860,7 +858,7 @@ static int store_resp_fetch(CamelIMAPPEngine *ie, guint32 id, void *data) CamelMimeParser *mp; if (pending == NULL) - camel_message_info_free(info); + camel_folder_summary_info_free(((CamelFolder *)istore->selected)->summary, info); mp = camel_mime_parser_new(); camel_mime_parser_init_with_stream(mp, finfo->header); info = camel_folder_summary_info_new_from_parser(((CamelFolder *)istore->selected)->summary, mp); @@ -873,7 +871,7 @@ static int store_resp_fetch(CamelIMAPPEngine *ie, guint32 id, void *data) /* FIXME: use a dlist */ e_dlist_remove((EDListNode *)pending); g_hash_table_remove(istore->pending_fetch_table, camel_message_info_uid(pending->info)); - camel_message_info_free(pending->info); + camel_folder_summary_info_free(((CamelFolder *)istore->selected)->summary, pending->info); /*e_memchunk_free(istore->pending_fetch_chunks, pending);*/ } } else if (finfo->got & FETCH_FLAGS) { @@ -885,7 +883,7 @@ static int store_resp_fetch(CamelIMAPPEngine *ie, guint32 id, void *data) } } else { if (pending == NULL) - camel_message_info_free(info); + camel_folder_summary_info_free(((CamelFolder *)istore->selected)->summary, info); printf("got unexpected fetch response?\n"); imap_dump_fetch(finfo); } @@ -975,7 +973,7 @@ camel_imapp_store_folder_selected(CamelIMAPPStore *store, CamelIMAPPFolder *fold if (info) { printf("message info [%d] =\n", i); camel_message_info_dump(info); - camel_message_info_free(info); + camel_folder_summary_info_free(((CamelFolder *)istore->selected)->summary, info); } } } CAMEL_CATCH (e) { diff --git a/camel/providers/local/camel-local-folder.c b/camel/providers/local/camel-local-folder.c index 70673d9687..b86d23221a 100644 --- a/camel/providers/local/camel-local-folder.c +++ b/camel/providers/local/camel-local-folder.c @@ -20,6 +20,7 @@ * */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -47,7 +48,6 @@ #include "camel-stream-filter.h" #include "camel-mime-filter-from.h" #include "camel-exception.h" -#include "camel-i18n.h" #include "camel-local-private.h" diff --git a/camel/providers/local/camel-maildir-folder.c b/camel/providers/local/camel-maildir-folder.c index b74f6e5ace..ba42b75f28 100644 --- a/camel/providers/local/camel-maildir-folder.c +++ b/camel/providers/local/camel-maildir-folder.c @@ -39,7 +39,6 @@ #include "camel-data-wrapper.h" #include "camel-mime-message.h" #include "camel-exception.h" -#include "camel-i18n.h" #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ @@ -153,7 +152,7 @@ camel_maildir_folder_new(CamelStore *parent_store, const char *full_name, guint3 static CamelLocalSummary *maildir_create_summary(CamelLocalFolder *lf, const char *path, const char *folder, CamelIndex *index) { - return (CamelLocalSummary *)camel_maildir_summary_new((CamelFolder *)lf, path, folder, index); + return (CamelLocalSummary *)camel_maildir_summary_new(path, folder, index); } static void @@ -251,7 +250,7 @@ static CamelMimeMessage *maildir_get_message(CamelFolder * folder, const gchar * /* what do we do if the message flags (and :info data) changes? filename mismatch - need to recheck I guess */ name = g_strdup_printf("%s/cur/%s", lf->folder_path, camel_maildir_info_filename(mdi)); - camel_message_info_free(info); + camel_folder_summary_info_free(folder->summary, info); if ((message_stream = camel_stream_fs_new_with_name(name, O_RDONLY, 0)) == NULL) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, diff --git a/camel/providers/local/camel-mbox-folder.c b/camel/providers/local/camel-mbox-folder.c index d213b444fc..fa8f0b645d 100644 --- a/camel/providers/local/camel-mbox-folder.c +++ b/camel/providers/local/camel-mbox-folder.c @@ -42,7 +42,6 @@ #include "camel-stream-filter.h" #include "camel-mime-filter-from.h" #include "camel-exception.h" -#include "camel-i18n.h" #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ @@ -56,6 +55,13 @@ static CamelLocalFolderClass *parent_class = NULL; static int mbox_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex); static void mbox_unlock(CamelLocalFolder *lf); +#ifdef STATUS_PINE +static gboolean mbox_set_message_flags(CamelFolder *folder, const char *uid, guint32 flags, guint32 set); +#endif + +static void mbox_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value); +static void mbox_set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value); + static void mbox_append_message(CamelFolder *folder, CamelMimeMessage * message, const CamelMessageInfo * info, char **appended_uid, CamelException *ex); static CamelMimeMessage *mbox_get_message(CamelFolder *folder, const gchar * uid, CamelException *ex); static CamelLocalSummary *mbox_create_summary(CamelLocalFolder *lf, const char *path, const char *folder, CamelIndex *index); @@ -76,6 +82,12 @@ camel_mbox_folder_class_init(CamelMboxFolderClass * camel_mbox_folder_class) camel_folder_class->append_message = mbox_append_message; camel_folder_class->get_message = mbox_get_message; +#ifdef STATUS_PINE + camel_folder_class->set_message_flags = mbox_set_message_flags; +#endif + camel_folder_class->set_message_user_flag = mbox_set_message_user_flag; + camel_folder_class->set_message_user_tag = mbox_set_message_user_tag; + lclass->get_full_path = camel_mbox_folder_get_full_path; lclass->get_meta_path = camel_mbox_folder_get_meta_path; lclass->create_summary = mbox_create_summary; @@ -194,7 +206,7 @@ camel_mbox_folder_get_meta_path (CamelLocalFolder *lf, const char *toplevel_dir, static CamelLocalSummary *mbox_create_summary(CamelLocalFolder *lf, const char *path, const char *folder, CamelIndex *index) { - return (CamelLocalSummary *)camel_mbox_summary_new((CamelFolder *)lf, path, folder, index); + return (CamelLocalSummary *)camel_mbox_summary_new(path, folder, index); } static int mbox_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex) @@ -408,7 +420,7 @@ retry: g_assert(info->frompos != -1); frompos = info->frompos; - camel_message_info_free((CamelMessageInfo *)info); + camel_folder_summary_info_free(folder->summary, (CamelMessageInfo *)info); /* we use an fd instead of a normal stream here - the reason is subtle, camel_mime_part will cache the whole message in memory if the stream is non-seekable (which it is when built from a parser @@ -480,3 +492,66 @@ fail: return message; } + +#ifdef STATUS_PINE +static gboolean +mbox_set_message_flags(CamelFolder *folder, const char *uid, guint32 flags, guint32 set) +{ + /* Basically, if anything could change the Status line, presume it does */ + if (((CamelMboxSummary *)folder->summary)->xstatus + && (flags & (CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_FLAGGED|CAMEL_MESSAGE_ANSWERED|CAMEL_MESSAGE_DELETED))) { + flags |= CAMEL_MESSAGE_FOLDER_XEVCHANGE|CAMEL_MESSAGE_FOLDER_FLAGGED; + set |= CAMEL_MESSAGE_FOLDER_XEVCHANGE|CAMEL_MESSAGE_FOLDER_FLAGGED; + } + + return ((CamelFolderClass *)parent_class)->set_message_flags(folder, uid, flags, set); +} +#endif + +static void +mbox_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value) +{ + CamelMessageInfo *info; + + g_return_if_fail(folder->summary != NULL); + + info = camel_folder_summary_uid(folder->summary, uid); + if (info == NULL) + return; + + if (camel_flag_set(&info->user_flags, name, value)) { + CamelFolderChangeInfo *changes = camel_folder_change_info_new(); + + info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED|CAMEL_MESSAGE_FOLDER_XEVCHANGE; + camel_folder_summary_touch(folder->summary); + + camel_folder_change_info_change_uid(changes, uid); + camel_object_trigger_event(folder, "folder_changed", changes); + camel_folder_change_info_free(changes); + } + camel_folder_summary_info_free(folder->summary, info); +} + +static void +mbox_set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value) +{ + CamelMessageInfo *info; + + g_return_if_fail(folder->summary != NULL); + + info = camel_folder_summary_uid(folder->summary, uid); + if (info == NULL) + return; + + if (camel_tag_set(&info->user_tags, name, value)) { + CamelFolderChangeInfo *changes = camel_folder_change_info_new(); + + info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED|CAMEL_MESSAGE_FOLDER_XEVCHANGE; + camel_folder_summary_touch(folder->summary); + + camel_folder_change_info_change_uid(changes, uid); + camel_object_trigger_event (folder, "folder_changed", changes); + camel_folder_change_info_free(changes); + } + camel_folder_summary_info_free(folder->summary, info); +} diff --git a/camel/providers/local/camel-mbox-store.c b/camel/providers/local/camel-mbox-store.c index a9e581cdd7..1277407dbb 100644 --- a/camel/providers/local/camel-mbox-store.c +++ b/camel/providers/local/camel-mbox-store.c @@ -37,7 +37,6 @@ #include "camel-text-index.h" #include "camel-exception.h" #include "camel-url.h" -#include "camel-i18n.h" #define d(x) @@ -618,7 +617,7 @@ fill_fi(CamelStore *store, CamelFolderInfo *fi, guint32 flags) path = camel_mbox_folder_get_meta_path(NULL, root, fi->full_name, ".ev-summary"); folderpath = camel_mbox_folder_get_full_path(NULL, root, fi->full_name); - mbs = (CamelMboxSummary *)camel_mbox_summary_new(NULL, path, folderpath, NULL); + mbs = (CamelMboxSummary *)camel_mbox_summary_new(path, folderpath, NULL); if (camel_folder_summary_header_load((CamelFolderSummary *)mbs) != -1) { fi->unread = ((CamelFolderSummary *)mbs)->unread_count; fi->total = ((CamelFolderSummary *)mbs)->saved_count; diff --git a/camel/providers/local/camel-mh-folder.c b/camel/providers/local/camel-mh-folder.c index 1b054a4547..78456b6daf 100644 --- a/camel/providers/local/camel-mh-folder.c +++ b/camel/providers/local/camel-mh-folder.c @@ -39,7 +39,6 @@ #include "camel-data-wrapper.h" #include "camel-mime-message.h" #include "camel-exception.h" -#include "camel-i18n.h" #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ @@ -117,7 +116,7 @@ camel_mh_folder_new(CamelStore *parent_store, const char *full_name, guint32 fla static CamelLocalSummary *mh_create_summary(CamelLocalFolder *lf, const char *path, const char *folder, CamelIndex *index) { - return (CamelLocalSummary *)camel_mh_summary_new((CamelFolder *)lf, path, folder, index); + return (CamelLocalSummary *)camel_mh_summary_new(path, folder, index); } static void @@ -205,7 +204,7 @@ static CamelMimeMessage *mh_get_message(CamelFolder * folder, const gchar * uid, } /* we only need it to check the message exists */ - camel_message_info_free(info); + camel_folder_summary_info_free(folder->summary, info); name = g_strdup_printf("%s/%s", lf->folder_path, uid); if ((message_stream = camel_stream_fs_new_with_name(name, O_RDONLY, 0)) == NULL) { diff --git a/camel/providers/local/camel-spool-folder.c b/camel/providers/local/camel-spool-folder.c index c4c7da91b6..6a1bbf798a 100644 --- a/camel/providers/local/camel-spool-folder.c +++ b/camel/providers/local/camel-spool-folder.c @@ -44,8 +44,8 @@ #include "camel-session.h" #include "camel-file-utils.h" #include "camel-lock-client.h" + #include "camel-local-private.h" -#include "camel-i18n.h" #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ @@ -160,7 +160,7 @@ spool_get_meta_path(CamelLocalFolder *lf, const char *toplevel_dir, const char * static CamelLocalSummary * spool_create_summary(CamelLocalFolder *lf, const char *path, const char *folder, CamelIndex *index) { - return (CamelLocalSummary *)camel_spool_summary_new((CamelFolder *)lf, folder); + return (CamelLocalSummary *)camel_spool_summary_new(folder); } static int diff --git a/camel/providers/local/camel-spool-store.c b/camel/providers/local/camel-spool-store.c index 3dc21886c8..2e3d9ea777 100644 --- a/camel/providers/local/camel-spool-store.c +++ b/camel/providers/local/camel-spool-store.c @@ -41,7 +41,6 @@ #include "camel-exception.h" #include "camel-url.h" #include "camel-private.h" -#include "camel-i18n.h" #define d(x) diff --git a/camel/providers/nntp/camel-nntp-folder.c b/camel/providers/nntp/camel-nntp-folder.c index de0f4cd222..ffb1b29742 100644 --- a/camel/providers/nntp/camel-nntp-folder.c +++ b/camel/providers/nntp/camel-nntp-folder.c @@ -49,7 +49,6 @@ #include "camel/camel-multipart.h" #include "camel/camel-mime-part.h" #include "camel/camel-stream-buffer.h" -#include "camel/camel-i18n.h" #include "camel/camel-private.h" #include "camel-nntp-summary.h" @@ -511,7 +510,7 @@ camel_nntp_folder_new (CamelStore *parent, const char *folder_name, CamelExcepti g_free(root); root = g_strdup_printf("%s.ev-summary", nntp_folder->storage_path); - folder->summary = (CamelFolderSummary *) camel_nntp_summary_new (folder, root); + folder->summary = (CamelFolderSummary *) camel_nntp_summary_new (root); g_free(root); camel_folder_summary_load (folder->summary); diff --git a/camel/providers/nntp/camel-nntp-private.h b/camel/providers/nntp/camel-nntp-private.h index 520c9db134..253d4e2031 100644 --- a/camel/providers/nntp/camel-nntp-private.h +++ b/camel/providers/nntp/camel-nntp-private.h @@ -35,7 +35,7 @@ extern "C" { #include <config.h> #endif -#include "libedataserver/e-msgport.h" +#include "e-util/e-msgport.h" struct _CamelNNTPStorePrivate { int dummy; diff --git a/camel/providers/nntp/camel-nntp-store.c b/camel/providers/nntp/camel-nntp-store.c index f9daad8515..3e911ec1c5 100644 --- a/camel/providers/nntp/camel-nntp-store.c +++ b/camel/providers/nntp/camel-nntp-store.c @@ -53,8 +53,6 @@ #include "camel-nntp-folder.h" #include "camel-nntp-private.h" #include "camel-nntp-resp-codes.h" -#include "camel-i18n.h" -#include "camel-net-utils.h" #define w(x) #define dd(x) (camel_debug("nntp")?(x):0) @@ -85,6 +83,12 @@ nntp_can_work_offline(CamelDiscoStore *store) return TRUE; } +enum { + USE_SSL_NEVER, + USE_SSL_ALWAYS, + USE_SSL_WHEN_POSSIBLE +}; + static struct { const char *name; int type; @@ -149,17 +153,8 @@ xover_setup(CamelNNTPStore *store, CamelException *ex) return ret; } -enum { - MODE_CLEAR, - MODE_SSL, - MODE_TLS, -}; - -#define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3) -#define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS) - static gboolean -connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, CamelException *ex) +connect_to_server (CamelService *service, int ssl_mode, CamelException *ex) { CamelNNTPStore *store = (CamelNNTPStore *) service; CamelDiscoStore *disco_store = (CamelDiscoStore*) service; @@ -169,6 +164,9 @@ connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, Cam unsigned int len; int ret; char *path; + struct addrinfo *ai, hints = { 0 }; + char *serv; + const char *port = NULL; CAMEL_SERVICE_LOCK(store, connect_lock); @@ -185,34 +183,50 @@ connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, Cam camel_data_cache_set_expire_age (store->cache, 60*60*24*14); camel_data_cache_set_expire_access (store->cache, 60*60*24*5); } + + if (service->url->port) { + serv = g_alloca(16); + sprintf(serv, "%d", service->url->port); + } else { + serv = "nntp"; + port = NNTP_PORT; + } - if (ssl_mode != MODE_CLEAR) { #ifdef HAVE_SSL - if (ssl_mode == MODE_TLS) { - tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, STARTTLS_FLAGS); - } else { - tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS); + if (ssl_mode != USE_SSL_NEVER) { + if (service->url->port == 0) { + serv = "nntps"; + port = NNTPS_PORT; } -#else - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s: %s"), - service->url->host, _("SSL unavailable")); - - goto fail; -#endif /* HAVE_SSL */ + tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3); } else { tcp_stream = camel_tcp_stream_raw_new (); } +#else + tcp_stream = camel_tcp_stream_raw_new (); +#endif /* HAVE_SSL */ + + hints.ai_socktype = SOCK_STREAM; + ai = camel_getaddrinfo(service->url->host, serv, &hints, ex); + if (ai == NULL && port != NULL && camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) { + camel_exception_clear(ex); + ai = camel_getaddrinfo(service->url->host, port, &hints, ex); + } + if (ai == NULL) { + camel_object_unref(tcp_stream); + goto fail; + } - if ((ret = camel_tcp_stream_connect ((CamelTcpStream *) tcp_stream, ai)) == -1) { + ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai); + camel_freeaddrinfo(ai); + if (ret == -1) { if (errno == EINTR) camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Connection cancelled")); else camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s: %s"), - service->url->host, - g_strerror (errno)); + _("Could not connect to %s (port %s): %s"), + service->url->host, serv, g_strerror (errno)); camel_object_unref (tcp_stream); @@ -254,11 +268,11 @@ connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, Cam if (service->url->user != NULL && camel_nntp_try_authenticate(store, ex) != NNTP_AUTH_ACCEPTED) goto fail; - - /* set 'reader' mode & ignore return code, also ping the server, inn goes offline very quickly otherwise */ + + /* set 'reader' mode & ignore return code, also ping the server, inn goes offline very quickly otherwise */ if (camel_nntp_raw_command_auth (store, ex, (char **) &buf, "mode reader") == -1 || camel_nntp_raw_command_auth (store, ex, (char **) &buf, "date") == -1) - goto fail; + goto fail; if (xover_setup(store, ex) == -1) goto fail; @@ -279,61 +293,54 @@ connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, Cam static struct { char *value; - char *serv; - char *port; int mode; } ssl_options[] = { - { "", "nntps", NNTPS_PORT, MODE_SSL }, /* really old (1.x) */ - { "always", "nntps", NNTPS_PORT, MODE_SSL }, - { "when-possible", "nntp", NNTP_PORT, MODE_TLS }, - { "never", "nntp", NNTP_PORT, MODE_CLEAR }, - { NULL, "nntp", NNTP_PORT, MODE_CLEAR }, + { "", USE_SSL_ALWAYS }, + { "always", USE_SSL_ALWAYS }, + { "when-possible", USE_SSL_WHEN_POSSIBLE }, + { "never", USE_SSL_NEVER }, + { NULL, USE_SSL_NEVER }, }; static gboolean nntp_connect_online (CamelService *service, CamelException *ex) { - struct addrinfo hints, *ai; - const char *ssl_mode; - int mode, ret, i; - char *serv; - const char *port; +#ifdef HAVE_SSL + const char *use_ssl; + int i, ssl_mode; - if ((ssl_mode = camel_url_get_param (service->url, "use_ssl"))) { + use_ssl = camel_url_get_param (service->url, "use_ssl"); + if (use_ssl) { for (i = 0; ssl_options[i].value; i++) - if (!strcmp (ssl_options[i].value, ssl_mode)) + if (!strcmp (ssl_options[i].value, use_ssl)) break; - mode = ssl_options[i].mode; - serv = ssl_options[i].serv; - port = ssl_options[i].port; + ssl_mode = ssl_options[i].mode; + } else + ssl_mode = USE_SSL_NEVER; + + if (ssl_mode == USE_SSL_ALWAYS) { + /* Connect via SSL */ + return connect_to_server (service, ssl_mode, ex); + } else if (ssl_mode == USE_SSL_WHEN_POSSIBLE) { + /* If the server supports SSL, use it */ + if (!connect_to_server (service, ssl_mode, ex)) { + if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE) { + /* The ssl port seems to be unavailable, fall back to plain NNTP */ + camel_exception_clear (ex); + return connect_to_server (service, USE_SSL_NEVER, ex); + } else { + return FALSE; + } + } + + return TRUE; } else { - mode = MODE_CLEAR; - serv = "nntp"; - port = NNTP_PORT; + /* User doesn't care about SSL */ + return connect_to_server (service, ssl_mode, ex); } - - if (service->url->port) { - serv = g_alloca (16); - sprintf (serv, "%d", service->url->port); - port = NULL; - } - - memset (&hints, 0, sizeof (hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = PF_UNSPEC; - ai = camel_getaddrinfo(service->url->host, serv, &hints, ex); - if (ai == NULL && port != NULL && camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) { - camel_exception_clear (ex); - ai = camel_getaddrinfo(service->url->host, port, &hints, ex); - } - if (ai == NULL) - return FALSE; - - ret = connect_to_server (service, ai, mode, ex); - - camel_freeaddrinfo (ai); - - return ret; +#else + return connect_to_server (service, USE_SSL_NEVER, ex); +#endif } static gboolean diff --git a/camel/providers/nntp/camel-nntp-stream.c b/camel/providers/nntp/camel-nntp-stream.c index 244b67acb1..74bee9ced5 100644 --- a/camel/providers/nntp/camel-nntp-stream.c +++ b/camel/providers/nntp/camel-nntp-stream.c @@ -60,8 +60,6 @@ stream_fill(CamelNNTPStream *is) is->end[0] = '\n'; return is->end - is->ptr; } else { - if (left == 0) - errno = ECONNRESET; dd(printf("NNTP_STREAM_FILL(ERROR): %d - '%s'\n", left, strerror(errno))); return -1; } diff --git a/camel/providers/nntp/camel-nntp-summary.c b/camel/providers/nntp/camel-nntp-summary.c index e6c02b95af..02589e632e 100644 --- a/camel/providers/nntp/camel-nntp-summary.c +++ b/camel/providers/nntp/camel-nntp-summary.c @@ -36,7 +36,6 @@ #include "camel/camel-stream-null.h" #include "camel/camel-operation.h" #include "camel/camel-data-cache.h" -#include "camel/camel-i18n.h" #include "camel/camel-debug.h" #include "camel-nntp-summary.h" @@ -60,7 +59,7 @@ struct _CamelNNTPSummaryPrivate { #define _PRIVATE(o) (((CamelNNTPSummary *)(o))->priv) -static CamelMessageInfo * message_info_new_from_header (CamelFolderSummary *, struct _camel_header_raw *); +static CamelMessageInfo * message_info_new (CamelFolderSummary *, struct _camel_header_raw *); static int summary_header_load(CamelFolderSummary *, FILE *); static int summary_header_save(CamelFolderSummary *, FILE *); @@ -94,7 +93,7 @@ camel_nntp_summary_class_init(CamelNNTPSummaryClass *klass) camel_nntp_summary_parent = CAMEL_FOLDER_SUMMARY_CLASS(camel_type_get_global_classfuncs(camel_folder_summary_get_type())); - sklass->message_info_new_from_header = message_info_new_from_header; + sklass->message_info_new = message_info_new; sklass->summary_header_load = summary_header_load; sklass->summary_header_save = summary_header_save; } @@ -108,7 +107,7 @@ camel_nntp_summary_init(CamelNNTPSummary *obj) p = _PRIVATE(obj) = g_malloc0(sizeof(*p)); /* subclasses need to set the right instance data sizes */ - s->message_info_size = sizeof(CamelMessageInfoBase); + s->message_info_size = sizeof(CamelMessageInfo); s->content_info_size = sizeof(CamelMessageContentInfo); /* and a unique file version */ @@ -124,12 +123,10 @@ camel_nntp_summary_finalise(CamelObject *obj) } CamelNNTPSummary * -camel_nntp_summary_new(struct _CamelFolder *folder, const char *path) +camel_nntp_summary_new(const char *path) { CamelNNTPSummary *cns = (CamelNNTPSummary *)camel_object_new(camel_nntp_summary_get_type()); - ((CamelFolderSummary *)cns)->folder = folder; - camel_folder_summary_set_filename((CamelFolderSummary *)cns, path); camel_folder_summary_set_build_content((CamelFolderSummary *)cns, FALSE); @@ -137,9 +134,9 @@ camel_nntp_summary_new(struct _CamelFolder *folder, const char *path) } static CamelMessageInfo * -message_info_new_from_header(CamelFolderSummary *s, struct _camel_header_raw *h) +message_info_new(CamelFolderSummary *s, struct _camel_header_raw *h) { - CamelMessageInfoBase *mi; + CamelMessageInfo *mi; CamelNNTPSummary *cns = (CamelNNTPSummary *)s; /* error to call without this setup */ @@ -149,13 +146,13 @@ message_info_new_from_header(CamelFolderSummary *s, struct _camel_header_raw *h) /* we shouldn't be here if we already have this uid */ g_assert(camel_folder_summary_uid(s, cns->priv->uid) == NULL); - mi = (CamelMessageInfoBase *)((CamelFolderSummaryClass *)camel_nntp_summary_parent)->message_info_new_from_header(s, h); + mi = ((CamelFolderSummaryClass *)camel_nntp_summary_parent)->message_info_new(s, h); if (mi) { - mi->uid = g_strdup(cns->priv->uid); + camel_message_info_set_uid(mi, cns->priv->uid); cns->priv->uid = NULL; } - return (CamelMessageInfo *)mi; + return mi; } static int @@ -209,7 +206,7 @@ static int add_range_xover(CamelNNTPSummary *cns, CamelNNTPStore *store, unsigned int high, unsigned int low, CamelFolderChangeInfo *changes, CamelException *ex) { CamelFolderSummary *s; - CamelMessageInfoBase *mi; + CamelMessageInfo *mi; struct _camel_header_raw *headers = NULL; char *line, *tab; int len, ret; @@ -273,16 +270,16 @@ add_range_xover(CamelNNTPSummary *cns, CamelNNTPStore *store, unsigned int high, /* truncated line? ignore? */ if (xover == NULL) { - mi = (CamelMessageInfoBase *)camel_folder_summary_uid(s, cns->priv->uid); + mi = camel_folder_summary_uid(s, cns->priv->uid); if (mi == NULL) { - mi = (CamelMessageInfoBase *)camel_folder_summary_add_from_header(s, headers); + mi = camel_folder_summary_add_from_header(s, headers); if (mi) { mi->size = size; cns->high = n; camel_folder_change_info_add_uid(changes, camel_message_info_uid(mi)); } } else { - camel_message_info_free(mi); + camel_folder_summary_info_free(s, mi); } } @@ -354,7 +351,7 @@ add_range_head(CamelNNTPSummary *cns, CamelNNTPStore *store, unsigned int high, camel_folder_change_info_add_uid(changes, camel_message_info_uid(mi)); } else { /* already have, ignore */ - camel_message_info_free(mi); + camel_folder_summary_info_free(s, mi); } if (cns->priv->uid) { g_free(cns->priv->uid); @@ -447,7 +444,7 @@ camel_nntp_summary_check(CamelNNTPSummary *cns, CamelNNTPStore *store, char *lin i--; } - camel_message_info_free(mi); + camel_folder_summary_info_free(s, mi); } } cns->low = f; @@ -475,12 +472,12 @@ update: count = camel_folder_summary_count(s); for (i = 0; i < count; i++) { - CamelMessageInfoBase *mi = (CamelMessageInfoBase *)camel_folder_summary_index(s, i); + CamelMessageInfo *mi = camel_folder_summary_index(s, i); if (mi) { if ((mi->flags & CAMEL_MESSAGE_SEEN) == 0) unread++; - camel_message_info_free(mi); + camel_folder_summary_info_free(s, mi); } } diff --git a/camel/providers/pop3/camel-pop3-store.c b/camel/providers/pop3/camel-pop3-store.c index 46a1fd3fe6..f7117b1b31 100644 --- a/camel/providers/pop3/camel-pop3-store.c +++ b/camel/providers/pop3/camel-pop3-store.c @@ -45,7 +45,7 @@ #include "camel-session.h" #include "camel-exception.h" #include "camel-url.h" -#include "libedataserver/md5-utils.h" +#include "e-util/md5-utils.h" #include "camel-pop3-engine.h" #include "camel-sasl.h" #include "camel-data-cache.h" @@ -54,12 +54,9 @@ #ifdef HAVE_SSL #include "camel-tcp-stream-ssl.h" #endif -#include "camel-i18n.h" -#include "camel-net-utils.h" /* Specified in RFC 1939 */ -#define POP3_PORT "110" -#define POP3S_PORT "995" +#define POP3_PORT 110 static CamelStoreClass *parent_class = NULL; @@ -137,16 +134,16 @@ finalize (CamelObject *object) } enum { - MODE_CLEAR, - MODE_SSL, - MODE_TLS, + USE_SSL_NEVER, + USE_SSL_ALWAYS, + USE_SSL_WHEN_POSSIBLE }; #define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3) #define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS) static gboolean -connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, CamelException *ex) +connect_to_server (CamelService *service, int ssl_mode, int try_starttls, CamelException *ex) { CamelPOP3Store *store = CAMEL_POP3_STORE (service); CamelStream *tcp_stream; @@ -154,34 +151,67 @@ connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, Cam guint32 flags = 0; int clean_quit; int ret; - - if (ssl_mode != MODE_CLEAR) { + struct addrinfo *ai, hints = { 0 }; + char *serv; + const char *port = NULL; + + if (service->url->port) { + serv = g_alloca(16); + sprintf(serv, "%d", service->url->port); + } else { + serv = "pop3"; + port = "110"; + } + + if (ssl_mode != USE_SSL_NEVER) { #ifdef HAVE_SSL - if (ssl_mode == MODE_TLS) { + if (try_starttls) { tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS); } else { + if (service->url->port == 0) { + serv = "pop3s"; + port = "995"; + } tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS); } #else + if (!try_starttls && service->url->port == 0) { + serv = "pop3s"; + port = "995"; + } + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s: %s"), - service->url->host, _("SSL unavailable")); + _("Could not connect to %s (port %s): %s"), + service->url->host, serv, + _("SSL unavailable")); return FALSE; #endif /* HAVE_SSL */ } else { tcp_stream = camel_tcp_stream_raw_new (); } + + hints.ai_socktype = SOCK_STREAM; + ai = camel_getaddrinfo(service->url->host, serv, &hints, ex); + if (ai == NULL && port != NULL && camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) { + camel_exception_clear(ex); + ai = camel_getaddrinfo(service->url->host, port, &hints, ex); + } + if (ai == NULL) { + camel_object_unref(tcp_stream); + return FALSE; + } - if ((ret = camel_tcp_stream_connect ((CamelTcpStream *) tcp_stream, ai)) == -1) { + ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai); + camel_freeaddrinfo(ai); + if (ret == -1) { if (errno == EINTR) camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Connection cancelled")); else camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s: %s"), - service->url->host, - g_strerror (errno)); + _("Could not connect to POP server %s (port %s): %s"), + service->url->host, serv, g_strerror (errno)); camel_object_unref (tcp_stream); @@ -199,24 +229,41 @@ connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, Cam if (!(store->engine = camel_pop3_engine_new (tcp_stream, flags))) { camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to read a valid greeting from POP server %s"), - service->url->host); - camel_object_unref (tcp_stream); + _("Failed to read a valid greeting from POP server %s (port %s)"), + service->url->host, serv); return FALSE; } - if (ssl_mode != MODE_TLS) { - camel_object_unref (tcp_stream); - return TRUE; +#ifdef HAVE_SSL + if (store->engine) { + if (ssl_mode == USE_SSL_WHEN_POSSIBLE) { + if (store->engine->capa & CAMEL_POP3_CAP_STLS) + goto starttls; + } else if (ssl_mode == USE_SSL_ALWAYS) { + if (try_starttls) { + if (store->engine->capa & CAMEL_POP3_CAP_STLS) { + /* attempt to toggle STARTTLS mode */ + goto starttls; + } else { + /* server doesn't support STARTTLS, abort */ + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Failed to connect to POP server %s in secure mode: %s"), + service->url->host, _("SSL/TLS extension not supported.")); + /* we have the possibility of quitting cleanly here */ + clean_quit = TRUE; + goto stls_exception; + } + } + } } +#endif /* HAVE_SSL */ - if (!(store->engine->capa & CAMEL_POP3_CAP_STLS)) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to connect to POP server %s in secure mode: %s"), - service->url->host, _("STLS not supported")); - goto stls_exception; - } + camel_object_unref (tcp_stream); + return store->engine != NULL; + +#ifdef HAVE_SSL + starttls: /* as soon as we send a STLS command, all hope is lost of a clean QUIT if problems arise */ clean_quit = FALSE; @@ -237,6 +284,8 @@ connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, Cam /* Okay, now toggle SSL/TLS mode */ ret = camel_tcp_stream_ssl_enable_ssl (CAMEL_TCP_STREAM_SSL (tcp_stream)); + camel_object_unref (CAMEL_OBJECT (tcp_stream)); + if (ret == -1) { camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to connect to POP server %s in secure mode: %s"), @@ -244,8 +293,6 @@ connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, Cam goto stls_exception; } - camel_object_unref (tcp_stream); - /* rfc2595, section 4 states that after a successful STLS command, the client MUST discard prior CAPA responses */ camel_pop3_engine_reget_capabilities (store->engine); @@ -266,71 +313,59 @@ connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, Cam store->engine = NULL; return FALSE; +#endif /* HAVE_SSL */ } static struct { char *value; - char *serv; - char *port; int mode; } ssl_options[] = { - { "", "pop3s", POP3S_PORT, MODE_SSL }, /* really old (1.x) */ - { "always", "pop3s", POP3S_PORT, MODE_SSL }, - { "when-possible", "pop3", POP3_PORT, MODE_TLS }, - { "never", "pop3", POP3_PORT, MODE_CLEAR }, - { NULL, "pop3", POP3_PORT, MODE_CLEAR }, + { "", USE_SSL_ALWAYS }, + { "always", USE_SSL_ALWAYS }, + { "when-possible", USE_SSL_WHEN_POSSIBLE }, + { "never", USE_SSL_NEVER }, + { NULL, USE_SSL_NEVER }, }; static gboolean connect_to_server_wrapper (CamelService *service, CamelException *ex) { - struct addrinfo hints, *ai; - const char *ssl_mode; - int mode, ret, i; - char *serv; - const char *port; - - if ((ssl_mode = camel_url_get_param (service->url, "use_ssl"))) { +#ifdef HAVE_SSL + const char *use_ssl; + int i, ssl_mode; + + use_ssl = camel_url_get_param (service->url, "use_ssl"); + if (use_ssl) { for (i = 0; ssl_options[i].value; i++) - if (!strcmp (ssl_options[i].value, ssl_mode)) + if (!strcmp (ssl_options[i].value, use_ssl)) break; - mode = ssl_options[i].mode; - serv = ssl_options[i].serv; - port = ssl_options[i].port; + ssl_mode = ssl_options[i].mode; + } else + ssl_mode = USE_SSL_NEVER; + + if (ssl_mode == USE_SSL_ALWAYS) { + /* First try the ssl port */ + if (!connect_to_server (service, ssl_mode, FALSE, ex)) { + if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE) { + /* The ssl port seems to be unavailable, lets try STARTTLS */ + camel_exception_clear (ex); + return connect_to_server (service, ssl_mode, TRUE, ex); + } else { + return FALSE; + } + } + + return TRUE; + } else if (ssl_mode == USE_SSL_WHEN_POSSIBLE) { + /* If the server supports STARTTLS, use it */ + return connect_to_server (service, ssl_mode, TRUE, ex); } else { - mode = MODE_CLEAR; - serv = "pop3"; - port = POP3S_PORT; + /* User doesn't care about SSL */ + return connect_to_server (service, ssl_mode, FALSE, ex); } - - if (service->url->port) { - serv = g_alloca (16); - sprintf (serv, "%d", service->url->port); - port = NULL; - } - - memset (&hints, 0, sizeof (hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = PF_UNSPEC; - ai = camel_getaddrinfo(service->url->host, serv, &hints, ex); - if (ai == NULL && port != NULL && camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) { - camel_exception_clear (ex); - ai = camel_getaddrinfo(service->url->host, port, &hints, ex); - } - if (ai == NULL) - return FALSE; - - if (!(ret = connect_to_server (service, ai, mode, ex)) && mode == MODE_SSL) { - camel_exception_clear (ex); - ret = connect_to_server (service, ai, MODE_TLS, ex); - } else if (!ret && mode == MODE_TLS) { - camel_exception_clear (ex); - ret = connect_to_server (service, ai, MODE_CLEAR, ex); - } - - camel_freeaddrinfo (ai); - - return ret; +#else + return connect_to_server (service, USE_SSL_NEVER, FALSE, ex); +#endif } extern CamelServiceAuthType camel_pop3_password_authtype; diff --git a/camel/providers/smtp/camel-smtp-transport.c b/camel/providers/smtp/camel-smtp-transport.c index 065d79fdac..ea8ca26e49 100644 --- a/camel/providers/smtp/camel-smtp-transport.c +++ b/camel/providers/smtp/camel-smtp-transport.c @@ -55,15 +55,13 @@ #include "camel-session.h" #include "camel-exception.h" #include "camel-sasl.h" -#include "camel-i18n.h" -#include "camel-net-utils.h" + extern int camel_verbose_debug; #define d(x) (camel_verbose_debug ? (x) : 0) /* Specified in RFC 821 */ -#define SMTP_PORT "25" -#define SMTPS_PORT "465" +#define SMTP_PORT 25 /* camel smtp transport class prototypes */ static gboolean smtp_send_to (CamelTransport *transport, CamelMimeMessage *message, @@ -147,7 +145,18 @@ smtp_construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex) { + CamelSmtpTransport *smtp_transport = CAMEL_SMTP_TRANSPORT (service); + const char *use_ssl; + CAMEL_SERVICE_CLASS (parent_class)->construct (service, session, provider, url, ex); + + if ((use_ssl = camel_url_get_param (url, "use_ssl"))) { + /* Note: previous versions would use "" to toggle use_ssl to 'on' */ + if (!*use_ssl || !strcmp (use_ssl, "always")) + smtp_transport->flags |= CAMEL_SMTP_TRANSPORT_USE_SSL_ALWAYS; + else if (!strcmp (use_ssl, "when-possible")) + smtp_transport->flags |= CAMEL_SMTP_TRANSPORT_USE_SSL_WHEN_POSSIBLE; + } } static const char * @@ -219,56 +228,82 @@ smtp_error_string (int error) } } -enum { - MODE_CLEAR, - MODE_SSL, - MODE_TLS, -}; - #define SSL_PORT_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3) #define STARTTLS_FLAGS (CAMEL_TCP_STREAM_SSL_ENABLE_TLS) static gboolean -connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, CamelException *ex) +connect_to_server (CamelService *service, int try_starttls, CamelException *ex) { CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service); CamelStream *tcp_stream; char *respbuf = NULL; int ret; + struct addrinfo *ai, hints = { 0 }; + char *serv; + const char *port = NULL; if (!CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex)) return FALSE; /* set some smtp transport defaults */ - transport->flags = 0; + transport->flags &= CAMEL_SMTP_TRANSPORT_USE_SSL; /* reset all but ssl flags */ transport->authtypes = NULL; + + if (service->url->port) { + serv = g_alloca(16); + sprintf(serv, "%d", service->url->port); + } else { + serv = "smtp"; + port = "25"; + } - if (ssl_mode != MODE_CLEAR) { + if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL) { #ifdef HAVE_SSL - if (ssl_mode == MODE_TLS) { - tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, STARTTLS_FLAGS); + if (try_starttls) { + tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS); } else { + if (service->url->port == 0) { + serv = "smtps"; + port = "465"; + } tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS); } #else - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s: %s"), - service->url->host, _("SSL unavailable")); + if (!try_starttls && service->url->port == 0) { + serv = "smtps"; + port = "465"; + } + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + _("Could not connect to %s (port %s): %s"), + service->url->host, serv, + _("SSL unavailable")); + return FALSE; #endif /* HAVE_SSL */ } else { tcp_stream = camel_tcp_stream_raw_new (); } + + hints.ai_socktype = SOCK_STREAM; + ai = camel_getaddrinfo(service->url->host, serv, &hints, ex); + /* fallback to numerical port if the system is misconfigured */ + if (ai == NULL && port != NULL && camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) { + camel_exception_clear(ex); + ai = camel_getaddrinfo(service->url->host, port, &hints, ex); + } + if (ai == NULL) { + camel_object_unref(tcp_stream); + return FALSE; + } - if ((ret = camel_tcp_stream_connect ((CamelTcpStream *) tcp_stream, ai)) == -1) { - if (errno == EINTR) - camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, - _("Connection cancelled")); - else - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - _("Could not connect to %s: %s"), - service->url->host, g_strerror (errno)); + ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai); + camel_freeaddrinfo(ai); + if (ret == -1) { + camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + _("Could not connect to %s (port %s): %s"), + service->url->host, serv, + g_strerror (errno)); camel_object_unref (tcp_stream); @@ -312,19 +347,30 @@ connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, Cam /* clear any EHLO/HELO exception and assume that any SMTP errors encountered were non-fatal */ camel_exception_clear (ex); - if (ssl_mode != MODE_TLS) { - /* we're done */ - return TRUE; +#ifdef HAVE_SSL + if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL_WHEN_POSSIBLE) { + /* try_starttls is always TRUE here */ + if (transport->flags & CAMEL_SMTP_TRANSPORT_STARTTLS) + goto starttls; + } else if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL_ALWAYS) { + if (try_starttls) { + if (transport->flags & CAMEL_SMTP_TRANSPORT_STARTTLS) { + goto starttls; + } else { + /* server doesn't support STARTTLS, abort */ + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Failed to connect to SMTP server %s in secure mode: %s"), + service->url->host, _("server does not appear to support SSL")); + goto exception_cleanup; + } + } } +#endif /* HAVE_SSL */ - if (!(transport->flags & CAMEL_SMTP_TRANSPORT_STARTTLS)) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Failed to connect to SMTP server %s in secure mode: %s"), - service->url->host, _("STARTTLS not supported")); - - goto exception_cleanup; - } + return TRUE; +#ifdef HAVE_SSL + starttls: d(fprintf (stderr, "sending : STARTTLS\r\n")); if (camel_stream_write (tcp_stream, "STARTTLS\r\n", 10) == -1) { camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SYSTEM, @@ -374,68 +420,38 @@ connect_to_server (CamelService *service, struct addrinfo *ai, int ssl_mode, Cam transport->connected = FALSE; return FALSE; +#endif /* HAVE_SSL */ } -static struct { - char *value; - char *serv; - char *port; - int mode; -} ssl_options[] = { - { "", "smtps", SMTPS_PORT, MODE_SSL }, /* really old (1.x) */ - { "always", "smtps", SMTPS_PORT, MODE_SSL }, - { "when-possible", "smtp", SMTP_PORT, MODE_TLS }, - { "never", "smtp", SMTP_PORT, MODE_CLEAR }, - { NULL, "smtp", SMTP_PORT, MODE_CLEAR }, -}; - static gboolean connect_to_server_wrapper (CamelService *service, CamelException *ex) { - struct addrinfo hints, *ai; - const char *ssl_mode; - int mode, ret, i; - char *serv; - const char *port; - - if ((ssl_mode = camel_url_get_param (service->url, "use_ssl"))) { - for (i = 0; ssl_options[i].value; i++) - if (!strcmp (ssl_options[i].value, ssl_mode)) - break; - mode = ssl_options[i].mode; - serv = ssl_options[i].serv; - port = ssl_options[i].port; - } else { - mode = MODE_CLEAR; - serv = "smtp"; - port = SMTP_PORT; - } - - if (service->url->port) { - serv = g_alloca (16); - sprintf (serv, "%d", service->url->port); - port = NULL; - } +#ifdef HAVE_SSL + CamelSmtpTransport *transport = (CamelSmtpTransport *) service; - memset (&hints, 0, sizeof (hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = PF_UNSPEC; - ai = camel_getaddrinfo(service->url->host, serv, &hints, ex); - if (ai == NULL && port != NULL && camel_exception_get_id(ex) != CAMEL_EXCEPTION_USER_CANCEL) { - camel_exception_clear (ex); - ai = camel_getaddrinfo(service->url->host, port, &hints, ex); + if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL_ALWAYS) { + /* First try connecting to the SSL port */ + if (!connect_to_server (service, FALSE, ex)) { + if (camel_exception_get_id (ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE) { + /* Seems the SSL port is unavailable, lets try STARTTLS */ + camel_exception_clear (ex); + return connect_to_server (service, TRUE, ex); + } else { + return FALSE; + } + } + + return TRUE; + } else if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL_WHEN_POSSIBLE) { + /* If the server supports STARTTLS, use it */ + return connect_to_server (service, TRUE, ex); + } else { + /* User doesn't care about SSL */ + return connect_to_server (service, FALSE, ex); } - if (ai == NULL) - return FALSE; - - if (!(ret = connect_to_server (service, ai, mode, ex)) && mode == MODE_SSL) - ret = connect_to_server (service, ai, MODE_TLS, ex); - else if (!ret && mode == MODE_TLS) - ret = connect_to_server (service, ai, MODE_CLEAR, ex); - - camel_freeaddrinfo (ai); - - return ret; +#else + return connect_to_server (service, FALSE, ex); +#endif } static gboolean diff --git a/camel/providers/smtp/camel-smtp-transport.h b/camel/providers/smtp/camel-smtp-transport.h index 7b5ad88f12..87fcafb58b 100644 --- a/camel/providers/smtp/camel-smtp-transport.h +++ b/camel/providers/smtp/camel-smtp-transport.h @@ -43,7 +43,13 @@ extern "C" { #define CAMEL_SMTP_TRANSPORT_ENHANCEDSTATUSCODES (1 << 2) #define CAMEL_SMTP_TRANSPORT_STARTTLS (1 << 3) -#define CAMEL_SMTP_TRANSPORT_AUTH_EQUAL (1 << 4) /* set if we are using authtypes from a broken AUTH= */ +#define CAMEL_SMTP_TRANSPORT_USE_SSL_ALWAYS (1 << 4) +#define CAMEL_SMTP_TRANSPORT_USE_SSL_WHEN_POSSIBLE (1 << 5) + +#define CAMEL_SMTP_TRANSPORT_USE_SSL (CAMEL_SMTP_TRANSPORT_USE_SSL_ALWAYS | \ + CAMEL_SMTP_TRANSPORT_USE_SSL_WHEN_POSSIBLE) + +#define CAMEL_SMTP_TRANSPORT_AUTH_EQUAL (1 << 6) /* set if we are using authtypes from a broken AUTH= */ typedef struct { CamelTransport parent_object; |