aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/nntp/camel-nntp-store.c
diff options
context:
space:
mode:
authorNot Zed <NotZed@Ximian.com>2004-06-03 17:29:08 +0800
committerMichael Zucci <zucchi@src.gnome.org>2004-06-03 17:29:08 +0800
commit0a7400e900f9235cf6ef73a8978433178a5b8f0c (patch)
tree53f1ce1f63eff31afa5e3ef0c607a9af806cd441 /camel/providers/nntp/camel-nntp-store.c
parentf60455997beaa2374f20921d2e874f70d08b4bb4 (diff)
downloadgsoc2013-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.c494
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;
}