diff options
author | Not Zed <NotZed@Ximian.com> | 2004-06-03 17:29:08 +0800 |
---|---|---|
committer | Michael Zucci <zucchi@src.gnome.org> | 2004-06-03 17:29:08 +0800 |
commit | 0a7400e900f9235cf6ef73a8978433178a5b8f0c (patch) | |
tree | 53f1ce1f63eff31afa5e3ef0c607a9af806cd441 /camel/providers/nntp/camel-nntp-store.c | |
parent | f60455997beaa2374f20921d2e874f70d08b4bb4 (diff) | |
download | gsoc2013-evolution-0a7400e900f9235cf6ef73a8978433178a5b8f0c.tar gsoc2013-evolution-0a7400e900f9235cf6ef73a8978433178a5b8f0c.tar.gz gsoc2013-evolution-0a7400e900f9235cf6ef73a8978433178a5b8f0c.tar.bz2 gsoc2013-evolution-0a7400e900f9235cf6ef73a8978433178a5b8f0c.tar.lz gsoc2013-evolution-0a7400e900f9235cf6ef73a8978433178a5b8f0c.tar.xz gsoc2013-evolution-0a7400e900f9235cf6ef73a8978433178a5b8f0c.tar.zst gsoc2013-evolution-0a7400e900f9235cf6ef73a8978433178a5b8f0c.zip |
only save the summary, don't update from server, thats what refresh info
2004-06-03 Not Zed <NotZed@Ximian.com>
* providers/nntp/camel-nntp-folder.c (nntp_folder_sync_online):
only save the summary, don't update from server, thats what
refresh info does.
(nntp_folder_download_message): fix exception handling.
(nntp_folder_cache_message): same.
(nntp_folder_get_message): ditto, plus major cleanup.
(nntp_folder_download_message): take combined uid so it can cache
and lookup properly. duh.
* providers/nntp/camel-nntp-store.c
(nntp_store_get_subscribed_folder_info): if not fast, then open
the folder, and update it. Yeah i've given up trying to worry
about performance vs usability.
* providers/nntp/camel-nntp-summary.c (camel_nntp_summary_check):
update the storesummary if we update the folder summary. Hmm,
isn't duplicated data meant to be a bad thing? :P
* providers/nntp/camel-nntp-store.c (camel_nntp_store_set_folder):
removed, now handled by nntp_command.
(nntp_connected): removed, now handled by nntp_command.
* camel-string-utils.c (camel_tolower): added ascii to-lower
function.
(camel_toupper): and upper, for completeness.
* camel-store-summary.c (CAMEL_STORE_SUMMARY_VERSION): bumped file
version by 1. This is a mess, version 1 files treated the
bitfield 'flags' with bit number values not bits. Messy.
* providers/nntp/camel-nntp-store-summary.c (store_info_save):
write last/first count.
(CAMEL_NNTP_STORE_SUMMARY_VERSION): bump version to 1.
(store_info_load): if we're loading >= version 1, then load
last/first counts.
* providers/nntp/camel-nntp-store.c
(nntp_store_get_folder_info_all): pass the whole line to
store_info_from_line, dont strip last/first info.
(nntp_store_info_update): renamed from info_new_from_line. only
add if not present. handle updates, try and handle unread counts
and readonly status.
2004-06-02 Not Zed <NotZed@Ximian.com>
* providers/nntp/camel-nntp-store.c: setup xover once we've
started.
* providers/nntp/camel-nntp-summary.c: (xover_setup): moved to
nntp store.
* providers/nntp/camel-nntp-folder.c (folder_check)
(folder_check_free, camel_nntp_folder_new): remove async summary
stuff.
* providers/nntp/camel-nntp-store.c (camel_nntp_command): take
exception argument again, and folder argument. do retry logic and
auth logic differently.
(camel_nntp_raw_command): raw command interface, dont try
reconnect or anything fancy. pass i/o errors straight out, etc.
(camel_nntp_try_authenticate): change to return return codes &
take exception.
* providers/nntp/camel-nntp-summary.c (camel_nntp_summary_new):
just take path argument.
(camel_nntp_summary_check): take a store, and a folder name.
(add_range_head, add_range_xover): remove the time based update
events, they never had any effect anyway. Take store argument.
(xover_setup): take store argument.
* camel-folder-search.c (search_match_threads): remove debug.
svn path=/trunk/; revision=26164
Diffstat (limited to 'camel/providers/nntp/camel-nntp-store.c')
-rw-r--r-- | camel/providers/nntp/camel-nntp-store.c | 494 |
1 files changed, 340 insertions, 154 deletions
diff --git a/camel/providers/nntp/camel-nntp-store.c b/camel/providers/nntp/camel-nntp-store.c index 26e825436b..a36a69634f 100644 --- a/camel/providers/nntp/camel-nntp-store.c +++ b/camel/providers/nntp/camel-nntp-store.c @@ -40,6 +40,9 @@ #include <camel/camel-tcp-stream-raw.h> #include <camel/camel-tcp-stream-ssl.h> +#include <camel/camel-stream-mem.h> +#include <camel/camel-data-cache.h> + #include <camel/camel-disco-store.h> #include <camel/camel-disco-diary.h> @@ -84,6 +87,72 @@ enum { USE_SSL_WHEN_POSSIBLE }; +static struct { + const char *name; + int type; +} headers[] = { + { "subject", 0 }, + { "from", 0 }, + { "date", 0 }, + { "message-id", 1 }, + { "references", 0 }, + { "bytes", 2 }, +}; + +static int +xover_setup(CamelNNTPStore *store, CamelException *ex) +{ + int ret, i; + char *line; + unsigned int len; + unsigned char c, *p; + struct _xover_header *xover, *last; + + /* manual override */ + if (store->xover || getenv("CAMEL_NNTP_DISABLE_XOVER") != NULL) + return 0; + + ret = camel_nntp_raw_command(store, ex, &line, "list overview.fmt"); + if (ret == -1) { + camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, + _("NNTP Command failed: %s"), g_strerror(errno)); + return -1; + } else if (ret != 215) + /* unsupported command? ignore */ + return 0; + + last = (struct _xover_header *)&store->xover; + + /* supported command */ + while ((ret = camel_nntp_stream_line(store->stream, (unsigned char **)&line, &len)) > 0) { + p = line; + xover = g_malloc0(sizeof(*xover)); + last->next = xover; + last = xover; + while ((c = *p++)) { + if (c == ':') { + p[-1] = 0; + for (i=0;i<sizeof(headers)/sizeof(headers[0]);i++) { + if (strcmp(line, headers[i].name) == 0) { + xover->name = headers[i].name; + if (strncmp(p, "full", 4) == 0) + xover->skip = strlen(xover->name)+1; + else + xover->skip = 0; + xover->type = headers[i].type; + break; + } + } + break; + } else { + p[-1] = camel_tolower(c); + } + } + } + + return ret; +} + static gboolean connect_to_server (CamelService *service, int ssl_mode, CamelException *ex) { @@ -176,12 +245,13 @@ connect_to_server (CamelService *service, int ssl_mode, CamelException *ex) goto fail; } - /* set 'reader' mode & ignore return code */ - if (camel_nntp_command (store, (char **) &buf, "mode reader") < 0 || - /* hack: inn seems to close connections if nothing is done within - the first ten seconds. a non-existent command is enough though */ - camel_nntp_command (store, (char **) &buf, "date") < 0) - goto fail; + /* set 'reader' mode & ignore return code, also ping the server, inn goes offline very quickly otherwise */ + if (camel_nntp_raw_command (store, ex, (char **) &buf, "mode reader") == -1 + || camel_nntp_raw_command (store, ex, (char **) &buf, "date") == -1) + goto fail; + + if (xover_setup(store, ex) == -1) + goto fail; path = g_build_filename (store->storage_path, ".ev-journal", NULL); disco_store->diary = camel_disco_diary_new (disco_store, path, ex); @@ -285,8 +355,10 @@ nntp_disconnect_online (CamelService *service, gboolean clean, CamelException *e CAMEL_NNTP_STORE_LOCK(store, command_lock); - if (clean) - camel_nntp_command (store, &line, "quit"); + if (clean) { + camel_nntp_raw_command (store, ex, &line, "quit"); + camel_exception_clear(ex); + } if (!service_class->disconnect (service, clean, ex)) { CAMEL_NNTP_STORE_UNLOCK(store, command_lock); @@ -399,7 +471,8 @@ nntp_folder_info_from_store_info (CamelNNTPStore *store, gboolean short_notation else fi->name = g_strdup (si->path); - fi->unread = -1; + fi->unread = si->unread; + fi->total = si->total; path = alloca(strlen(fi->full_name)+2); sprintf(path, "/%s", fi->full_name); url = camel_url_new_with_base (base_url, path); @@ -435,25 +508,69 @@ nntp_folder_info_from_name (CamelNNTPStore *store, gboolean short_notation, cons return fi; } -static CamelStoreInfo * -nntp_store_info_from_line (CamelNNTPStore *store, char *line) +/* handle list/newgroups response */ +static CamelNNTPStoreInfo * +nntp_store_info_update(CamelNNTPStore *store, char *line) { CamelStoreSummary *summ = (CamelStoreSummary *)store->summary; CamelURL *base_url = ((CamelService *)store)->url; - CamelNNTPStoreInfo *nsi = (CamelNNTPStoreInfo*)camel_store_summary_info_new(summ); - CamelStoreInfo *si = (CamelStoreInfo*)nsi; + CamelNNTPStoreInfo *si, *fsi; CamelURL *url; - char *relpath; - - relpath = g_strdup_printf ("/%s", line); - url = camel_url_new_with_base (base_url, relpath); - g_free (relpath); - si->uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); - camel_url_free (url); - - si->path = g_strdup (line); - nsi->full_name = g_strdup (line); - return (CamelStoreInfo*) si; + char *relpath, *tmp; + guint32 last = 0, first = 0, new = 0; + + tmp = strchr(line, ' '); + if (tmp) + *tmp++ = 0; + + fsi = si = (CamelNNTPStoreInfo *)camel_store_summary_path((CamelStoreSummary *)store->summary, line); + if (si == NULL) { + si = (CamelNNTPStoreInfo*)camel_store_summary_info_new(summ); + + relpath = g_alloca(strlen(line)+2); + sprintf(relpath, "/%s", line); + url = camel_url_new_with_base (base_url, relpath); + si->info.uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); + camel_url_free (url); + + si->info.path = g_strdup (line); + si->full_name = g_strdup (line); /* why do we keep this? */ + camel_store_summary_add((CamelStoreSummary *)store->summary, &si->info); + } else { + first = si->first; + last = si->last; + } + + if (tmp && *tmp >= '0' && *tmp <= '9') { + last = strtoul(tmp, &tmp, 10); + if (*tmp == ' ' && tmp[1] >= '0' && tmp[1] <= '9') { + first = strtoul(tmp+1, &tmp, 10); + if (*tmp == ' ' && tmp[1] != 'y') + si->info.flags |= CAMEL_STORE_INFO_FOLDER_READONLY; + } + } + + printf("store info update '%s' first '%d' last '%d'\n", line, first, last); + + if (si->last) { + if (last > si->last) + new = last-si->last; + } else { + if (last > first) + new = last - first; + } + + si->info.total = last > first?last-first:0; + si->info.unread += new; /* this is a _guess_ */ + si->last = last; + si->first = first; + + if (fsi) + camel_store_summary_info_free((CamelStoreSummary *)store->summary, &fsi->info); + else /* TODO see if we really did touch it */ + camel_store_summary_touch ((CamelStoreSummary *)store->summary); + + return si; } static CamelFolderInfo * @@ -468,10 +585,24 @@ nntp_store_get_subscribed_folder_info (CamelNNTPStore *store, const char *top, g return NULL; for (i=0;(si = camel_store_summary_index ((CamelStoreSummary *) store->summary, i));i++) { + if (si == NULL) + continue; + if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) { + /* slow mode? open and update the folder, always! this will implictly update + our storeinfo too; in a very round-about way */ + if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0) { + CamelNNTPFolder *folder; + char *line; + + folder = (CamelNNTPFolder *)camel_store_get_folder((CamelStore *)store, si->path, 0, ex); + if (folder) { + camel_nntp_command(store, ex, folder, &line, NULL); + camel_object_unref(folder); + } + camel_exception_clear(ex); + } fi = nntp_folder_info_from_store_info (store, store->do_short_folder_notation, si); - if (!fi) - continue; fi->flags |= CAMEL_FOLDER_NOINFERIORS | CAMEL_FOLDER_NOCHILDREN | CAMEL_FOLDER_SYSTEM; if (last) last->next = fi; @@ -552,12 +683,12 @@ nntp_store_get_cached_folder_info (CamelNNTPStore *store, const char *orig_top, /* retrieves the date from the NNTP server */ static gboolean -nntp_get_date(CamelNNTPStore *nntp_store) +nntp_get_date(CamelNNTPStore *nntp_store, CamelException *ex) { unsigned char *line; - int ret = camel_nntp_command(nntp_store, (char **)&line, "date"); + int ret = camel_nntp_command(nntp_store, ex, NULL, (char **)&line, "date"); char *ptr; - + nntp_store->summary->last_newslist[0] = 0; if (ret == 111) { @@ -573,6 +704,15 @@ nntp_get_date(CamelNNTPStore *nntp_store) return FALSE; } +static void +store_info_remove(void *key, void *value, void *data) +{ + CamelStoreSummary *summary = data; + CamelStoreInfo *si = value; + + camel_store_summary_remove(summary, si); +} + static gint store_info_sort (gconstpointer a, gconstpointer b) { @@ -583,9 +723,9 @@ static CamelFolderInfo * nntp_store_get_folder_info_all(CamelNNTPStore *nntp_store, const char *top, guint32 flags, gboolean online, CamelException *ex) { CamelNNTPStoreSummary *summary = nntp_store->summary; - CamelStoreInfo *si; + CamelNNTPStoreInfo *si; unsigned int len; - unsigned char *line, *space; + unsigned char *line; int ret = -1; if (top == NULL) @@ -600,53 +740,50 @@ nntp_store_get_folder_info_all(CamelNNTPStore *nntp_store, const char *top, guin memcpy(date + 7, summary->last_newslist + 8, 6); /* HHMMSS */ date[13] = '\0'; - nntp_get_date (nntp_store); + if (!nntp_get_date (nntp_store, ex)) + return NULL; - ret = camel_nntp_command (nntp_store, (char **) &line, "newgroups %s", date); - if (ret != 231) { + ret = camel_nntp_command (nntp_store, ex, NULL, (char **) &line, "newgroups %s", date); + if (ret == -1) + return NULL; + else if (ret != 231) { /* newgroups not supported :S so reload the complete list */ - ret = -1; - camel_store_summary_clear ((CamelStoreSummary*) summary); summary->last_newslist[0] = 0; goto do_complete_list; } - - while ((ret = camel_nntp_stream_line (nntp_store->stream, &line, &len)) > 0) { - if ((space = strchr(line, ' '))) - *space = '\0'; - - si = camel_store_summary_path ((CamelStoreSummary *) nntp_store->summary, line); - if (si) { - camel_store_summary_info_free ((CamelStoreSummary *) nntp_store->summary, si); - } else { - si = nntp_store_info_from_line (nntp_store, line); - camel_store_summary_add ((CamelStoreSummary*) nntp_store->summary, si); - } - } + + while ((ret = camel_nntp_stream_line (nntp_store->stream, &line, &len)) > 0) + nntp_store_info_update(nntp_store, line); } else { + GHashTable *all; + int i; + do_complete_list: /* seems we do need a complete list */ /* at first, we do a DATE to find out the last load occasion */ - nntp_get_date (nntp_store); + if (!nntp_get_date (nntp_store, ex)) + goto error; - ret = camel_nntp_command (nntp_store, (char **)&line, "list"); - if (ret != 215) { - if (ret < 0) - line = _("Stream error"); - ret = -1; + ret = camel_nntp_command (nntp_store, ex, NULL, (char **)&line, "list"); + if (ret == -1) + return NULL; + else if (ret != 215) { camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_INVALID, _("Error retrieving newsgroups:\n\n%s"), line); goto error; } - + + all = g_hash_table_new(g_str_hash, g_str_equal); + for (i = 0; (si = (CamelNNTPStoreInfo *)camel_store_summary_index ((CamelStoreSummary *)nntp_store->summary, i)); i++) + g_hash_table_insert(all, si->info.path, si); + while ((ret = camel_nntp_stream_line(nntp_store->stream, &line, &len)) > 0) { - if ((space = strchr(line, ' '))) - *space = '\0'; - - si = nntp_store_info_from_line (nntp_store, line); - camel_store_summary_add ((CamelStoreSummary*) nntp_store->summary, si); - /* check to see if it answers our current query */ + si = nntp_store_info_update(nntp_store, line); + g_hash_table_remove(all, si->info.path); } + + g_hash_table_foreach(all, store_info_remove, nntp_store->summary); + g_hash_table_destroy(all); } /* sort the list */ @@ -810,6 +947,7 @@ nntp_store_finalize (CamelObject *object) /* call base finalize */ CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (object); struct _CamelNNTPStorePrivate *p = nntp_store->priv; + struct _xover_header *xover, *xn; camel_service_disconnect ((CamelService *)object, TRUE, NULL); @@ -827,6 +965,13 @@ nntp_store_finalize (CamelObject *object) g_free (nntp_store->base_url); if (nntp_store->storage_path) g_free (nntp_store->storage_path); + + xover = nntp_store->xover; + while (xover) { + xn = xover->next; + g_free(xover); + xover = xn; + } e_mutex_destroy(p->command_lock); @@ -955,110 +1100,66 @@ camel_nntp_store_get_type (void) return camel_nntp_store_type; } -/* enter owning lock */ -int -camel_nntp_store_set_folder (CamelNNTPStore *store, CamelFolder *folder, CamelFolderChangeInfo *changes, CamelException *ex) -{ - int ret; - - if (store->current_folder && strcmp (folder->full_name, store->current_folder) == 0) - return 0; - - /* FIXME: Do something with changeinfo */ - ret = camel_nntp_summary_check ((CamelNNTPSummary *) folder->summary, changes, ex); - - g_free (store->current_folder); - store->current_folder = g_strdup (folder->full_name); - - return ret; -} - -static gboolean -camel_nntp_try_authenticate (CamelNNTPStore *store) +static int +camel_nntp_try_authenticate (CamelNNTPStore *store, CamelException *ex) { CamelService *service = (CamelService *) store; CamelSession *session = camel_service_get_session (service); int ret; char *line; - if (!service->url->user) - return FALSE; + if (!service->url->user) { + camel_exception_setv(ex, CAMEL_EXCEPTION_INVALID_PARAM, + _("Authentication requested but not username provided")); + return -1; + } /* if nessecary, prompt for the password */ if (!service->url->passwd) { - CamelException ex; char *prompt; prompt = g_strdup_printf (_("Please enter the NNTP password for %s@%s"), service->url->user, service->url->host); - - camel_exception_init (&ex); - service->url->passwd = camel_session_get_password (session, service, NULL, - prompt, "password", CAMEL_SESSION_PASSWORD_SECRET, &ex); - camel_exception_clear (&ex); + prompt, "password", CAMEL_SESSION_PASSWORD_SECRET, ex); g_free (prompt); if (!service->url->passwd) - return FALSE; + return -1; } /* now, send auth info (currently, only authinfo user/pass is supported) */ - ret = camel_nntp_command(store, &line, "authinfo user %s", service->url->user); - if (ret == NNTP_AUTH_ACCEPTED) { - return TRUE; - } else if (ret == NNTP_AUTH_CONTINUE) { - ret = camel_nntp_command (store, &line, "authinfo pass %s", service->url->passwd); - if (ret == NNTP_AUTH_ACCEPTED) - return TRUE; - else - return FALSE; - } else - return FALSE; -} - -static gboolean -nntp_connected (CamelNNTPStore *store, CamelException *ex) -{ - if (((CamelDiscoStore *)store)->status == CAMEL_DISCO_STORE_OFFLINE) { - g_warning("Trying to talk to nntp session whilst offline"); - return FALSE; + ret = camel_nntp_raw_command(store, ex, &line, "authinfo user %s", service->url->user); + if (ret == NNTP_AUTH_CONTINUE) + ret = camel_nntp_raw_command(store, ex, &line, "authinfo pass %s", service->url->passwd); + + if (ret != NNTP_AUTH_ACCEPTED) { + if (ret != -1) + camel_exception_setv(ex, CAMEL_EXCEPTION_SERVICE_CANT_AUTHENTICATE, + _("Cannot authenticate to server: %s"), line); + return -1; } - if (store->stream == NULL) - return camel_service_connect (CAMEL_SERVICE (store), ex); - - return TRUE; + return ret; } /* Enter owning lock */ int -camel_nntp_command (CamelNNTPStore *store, char **line, const char *fmt, ...) +camel_nntp_raw_commandv (CamelNNTPStore *store, CamelException *ex, char **line, const char *fmt, va_list ap) { const unsigned char *p, *ps; unsigned char c; - va_list ap; char *s; int d; unsigned int u, u2; e_mutex_assert_locked(store->priv->command_lock); - - if (!nntp_connected (store, NULL)) - return -1; - - /* Check for unprocessed data, ! */ - if (store->stream->mode == CAMEL_NNTP_STREAM_DATA) { - g_warning("Unprocessed data left in stream, flushing"); - while (camel_nntp_stream_getd(store->stream, (unsigned char **)&p, &u) > 0) - ; - } + g_assert(store->stream->mode != CAMEL_NNTP_STREAM_DATA); + camel_nntp_stream_set_mode(store->stream, CAMEL_NNTP_STREAM_LINE); - command_begin_send: - va_start(ap, fmt); ps = p = fmt; while ((c = *p++)) { switch (c) { @@ -1102,42 +1203,127 @@ camel_nntp_command (CamelNNTPStore *store, char **line, const char *fmt, ...) dd(printf("NNTP_COMMAND: '%.*s'\n", (int)store->mem->buffer->len, store->mem->buffer->data)); camel_stream_write ((CamelStream *) store->mem, "\r\n", 2); - if (camel_stream_write ((CamelStream *) store->stream, store->mem->buffer->data, store->mem->buffer->len) == -1 && errno != EINTR) { - camel_stream_reset ((CamelStream *) store->mem); - /* FIXME: hack */ - g_byte_array_set_size (store->mem->buffer, 0); - - reconnect: - /* some error, re-connect */ - camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); - - if (!nntp_connected (store, NULL)) - return -1; - - goto command_begin_send; - } - - camel_stream_reset ((CamelStream *) store->mem); + if (camel_stream_write((CamelStream *) store->stream, store->mem->buffer->data, store->mem->buffer->len) == -1) + goto ioerror; + /* FIXME: hack */ + camel_stream_reset ((CamelStream *) store->mem); g_byte_array_set_size (store->mem->buffer, 0); if (camel_nntp_stream_line (store->stream, (unsigned char **) line, &u) == -1) - return -1; + goto ioerror; u = strtoul (*line, NULL, 10); - /* Check for 'authentication required' codes */ - if (u == NNTP_AUTH_REQUIRED && - camel_nntp_try_authenticate(store)) - goto command_begin_send; - - /* the server doesn't like us anymore, but we still like her! */ - if (u == 401 || u == 503) - goto reconnect; - /* Handle all switching to data mode here, to make callers job easier */ if (u == 215 || (u >= 220 && u <=224) || (u >= 230 && u <= 231)) camel_nntp_stream_set_mode(store->stream, CAMEL_NNTP_STREAM_DATA); return u; + +ioerror: + if (errno == EINTR) + camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled.")); + else + camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("NNTP Command failed: %s"), g_strerror(errno)); + return -1; +} + +int +camel_nntp_raw_command(CamelNNTPStore *store, CamelException *ex, char **line, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = camel_nntp_raw_commandv(store, ex, line, fmt, ap); + va_end(ap); + + return ret; +} + +int +camel_nntp_command (CamelNNTPStore *store, CamelException *ex, CamelNNTPFolder *folder, char **line, const char *fmt, ...) +{ + const unsigned char *p; + va_list ap; + int ret, retry; + unsigned int u; + + e_mutex_assert_locked(store->priv->command_lock); + + if (((CamelDiscoStore *)store)->status == CAMEL_DISCO_STORE_OFFLINE) { + camel_exception_setv(ex, CAMEL_EXCEPTION_SERVICE_NOT_CONNECTED, + _("Not connected.")); + return -1; + } + + /* Check for unprocessed data, ! */ + if (store->stream->mode == CAMEL_NNTP_STREAM_DATA) { + g_warning("Unprocessed data left in stream, flushing"); + while (camel_nntp_stream_getd(store->stream, (unsigned char **)&p, &u) > 0) + ; + } + camel_nntp_stream_set_mode(store->stream, CAMEL_NNTP_STREAM_LINE); + + retry = 0; + do { + retry ++; + + if (store->stream == NULL + && !camel_service_connect (CAMEL_SERVICE (store), ex)) + return -1; + + if (folder != NULL + && (store->current_folder == NULL || strcmp(store->current_folder, ((CamelFolder *)folder)->full_name) != 0)) { + ret = camel_nntp_raw_command(store, ex, line, "group %s", ((CamelFolder *)folder)->full_name); + if (ret == 211) { + g_free(store->current_folder); + store->current_folder = g_strdup(((CamelFolder *)folder)->full_name); + camel_nntp_folder_selected(folder, *line, ex); + if (camel_exception_is_set(ex)) + return -1; + } else { + goto error; + } + } + + /* dummy fmt, we just wanted to select the folder */ + if (fmt == NULL) + return 0; + + va_start(ap, fmt); + ret = camel_nntp_raw_commandv(store, ex, line, fmt, ap); + va_end(ap); + error: + switch (ret) { + case NNTP_AUTH_REQUIRED: + if (camel_nntp_try_authenticate(store, ex) != NNTP_AUTH_ACCEPTED) + return -1; + continue; + case 411: /* no such group */ + camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID, + _("No such folder: %s"), line); + return -1; + case 400: /* service discontinued */ + case 401: /* wrong client state - this should quit but this is what the old code did */ + case 503: /* information not available - this should quit but this is what the old code did (?) */ + camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); + continue; + case -1: /* i/o error */ + if (camel_exception_get_id(ex) == CAMEL_EXCEPTION_USER_CANCEL) + return -1; + camel_exception_clear(ex); + break; + } + } while (ret == -1 && retry < 3); + + if (ret == -1) { + if (errno == EINTR) + camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled.")); + else + camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("NNTP Command failed: %s"), g_strerror(errno)); + } + + return ret; } |