only save the summary, don't update from server, thats what refresh info
authorNot Zed <NotZed@Ximian.com>
Thu, 3 Jun 2004 09:29:08 +0000 (09:29 +0000)
committerMichael Zucci <zucchi@src.gnome.org>
Thu, 3 Jun 2004 09:29:08 +0000 (09:29 +0000)
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.

15 files changed:
camel/ChangeLog
camel/camel-folder-search.c
camel/camel-store-summary.c
camel/camel-store-summary.h
camel/camel-string-utils.c
camel/camel-string-utils.h
camel/providers/nntp/camel-nntp-folder.c
camel/providers/nntp/camel-nntp-folder.h
camel/providers/nntp/camel-nntp-grouplist.c
camel/providers/nntp/camel-nntp-store-summary.c
camel/providers/nntp/camel-nntp-store-summary.h
camel/providers/nntp/camel-nntp-store.c
camel/providers/nntp/camel-nntp-store.h
camel/providers/nntp/camel-nntp-summary.c
camel/providers/nntp/camel-nntp-summary.h

index 465c177..a95bda9 100644 (file)
@@ -1,3 +1,77 @@
+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.
+
 2004-06-01  Not Zed  <NotZed@Ximian.com>
 
        ** A few fixes for better rfc compliance, and cleaner code.
index 26e7899..ab901f3 100644 (file)
@@ -780,7 +780,6 @@ search_match_threads(struct _ESExp *f, int argc, struct _ESExpTerm **argv, Camel
                r = e_sexp_term_eval(f, argv[i]);
        }
 
-       printf("match-threads, result %d\n", r==NULL?-1:r->type);
        if (r == NULL || r->type != ESEXP_RES_ARRAY_PTR)
                e_sexp_fatal_error(f, _("(match-threads) expects an array result"));
 
index 86e42fc..982d0ed 100644 (file)
 
 /* possible versions, for versioning changes */
 #define CAMEL_STORE_SUMMARY_VERSION_0 (1)
+#define CAMEL_STORE_SUMMARY_VERSION_2 (2)
 
 /* current version */
-#define CAMEL_STORE_SUMMARY_VERSION (1)
+#define CAMEL_STORE_SUMMARY_VERSION (2)
 
 #define _PRIVATE(o) (((CamelStoreSummary *)(o))->priv)
 
@@ -822,6 +823,23 @@ store_info_load(CamelStoreSummary *s, FILE *in)
        camel_file_util_decode_uint32(in, &mi->unread);
        camel_file_util_decode_uint32(in, &mi->total);
 
+       /* Ok, brown paper bag bug - prior to version 2 of the file, flags are
+          stored using the bit number, not the bit. Try to recover as best we can */
+       if (s->version < CAMEL_STORE_SUMMARY_VERSION_2) {
+               guint32 flags = 0;
+
+               if (mi->flags & 1)
+                       flags |= CAMEL_STORE_INFO_FOLDER_NOSELECT;
+               if (mi->flags & 2)
+                       flags |= CAMEL_STORE_INFO_FOLDER_READONLY;
+               if (mi->flags & 3)
+                       flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+               if (mi->flags & 4)
+                       flags |= CAMEL_STORE_INFO_FOLDER_FLAGGED;
+
+               mi->flags = flags;
+       }
+
        if (!ferror(in))
                return mi;
 
index dbcd611..e512cc3 100644 (file)
@@ -46,10 +46,10 @@ typedef struct _CamelStoreSummaryClass CamelStoreSummaryClass;
 typedef struct _CamelStoreInfo CamelStoreInfo;
 
 enum _CamelStoreInfoFlags {
-       CAMEL_STORE_INFO_FOLDER_NOSELECT,
-       CAMEL_STORE_INFO_FOLDER_READONLY,
-       CAMEL_STORE_INFO_FOLDER_SUBSCRIBED,
-       CAMEL_STORE_INFO_FOLDER_FLAGGED,
+       CAMEL_STORE_INFO_FOLDER_NOSELECT = 1<<0,
+       CAMEL_STORE_INFO_FOLDER_READONLY = 1<<1,
+       CAMEL_STORE_INFO_FOLDER_SUBSCRIBED = 1<<2,
+       CAMEL_STORE_INFO_FOLDER_FLAGGED = 1<<3,
 };
 
 #define CAMEL_STORE_INFO_FOLDER_UNKNOWN (~0)
index d9927d6..6949a9a 100644 (file)
@@ -108,3 +108,36 @@ camel_strdown (char *str)
        
        return str;
 }
+
+/**
+ * camel_tolower:
+ * @c: 
+ * 
+ * ASCII to-lower function.
+ * 
+ * Return value: 
+ **/
+char camel_tolower(char c)
+{
+       if (c >= 'A' && c <= 'Z')
+               c |= 0x20;
+
+       return c;
+}
+
+/**
+ * camel_toupper:
+ * @c: 
+ * 
+ * ASCII to-upper function.
+ * 
+ * Return value: 
+ **/
+char camel_toupper(char c)
+{
+       if (c >= 'a' && c <= 'z')
+               c &= ~0x20;
+
+       return c;
+}
+
index 54cbad3..e8a5bf3 100644 (file)
@@ -39,6 +39,7 @@ void camel_string_list_free (GList *string_list);
 char *camel_strstrcase (const char *haystack, const char *needle);
 
 const char *camel_strdown (char *str);
+char camel_tolower(char c);
 
 #ifdef __cplusplus
 }
index 411cc34..04855a2 100644 (file)
@@ -65,21 +65,29 @@ static CamelDiscoFolderClass *parent_class = NULL;
 #define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
 #define CNNTPS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so))
 
+void
+camel_nntp_folder_selected(CamelNNTPFolder *folder, char *line, CamelException *ex)
+{
+       camel_nntp_summary_check((CamelNNTPSummary *)((CamelFolder *)folder)->summary,
+                                (CamelNNTPStore *)((CamelFolder *)folder)->parent_store,
+                                line, folder->changes, ex);
+}
+
 static void
 nntp_folder_refresh_info_online (CamelFolder *folder, CamelException *ex)
 {
        CamelNNTPStore *nntp_store;
        CamelFolderChangeInfo *changes = NULL;
        CamelNNTPFolder *nntp_folder;
-       
+       char *line;
+
        nntp_store = (CamelNNTPStore *) folder->parent_store;
        nntp_folder = (CamelNNTPFolder *) folder;
        
        CAMEL_NNTP_STORE_LOCK(nntp_store, command_lock);
-       
-       if (camel_nntp_summary_check ((CamelNNTPSummary *) folder->summary, nntp_folder->changes, ex) != -1)
-               camel_folder_summary_save (folder->summary);
-       
+
+       camel_nntp_command(nntp_store, ex, nntp_folder, &line, NULL);
+
        if (camel_folder_change_info_changed(nntp_folder->changes)) {
                changes = nntp_folder->changes;
                nntp_folder->changes = camel_folder_change_info_new();
@@ -96,35 +104,17 @@ nntp_folder_refresh_info_online (CamelFolder *folder, CamelException *ex)
 static void
 nntp_folder_sync_online (CamelFolder *folder, CamelException *ex)
 {
-       CamelNNTPStore *nntp_store;
-       CamelFolderChangeInfo *changes = NULL;
-       CamelNNTPFolder *nntp_folder;
-       
-       nntp_store = (CamelNNTPStore *) folder->parent_store;
-       nntp_folder = (CamelNNTPFolder *) folder;
-       
-       CAMEL_NNTP_STORE_LOCK(nntp_store, command_lock);
-       
-       if (camel_nntp_summary_check ((CamelNNTPSummary *) folder->summary, nntp_folder->changes, ex) != -1)
-               camel_folder_summary_save (folder->summary);
-       
-       if (camel_folder_change_info_changed(nntp_folder->changes)) {
-               changes = nntp_folder->changes;
-               nntp_folder->changes = camel_folder_change_info_new();
-       }
-       
-       CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock);
-       
-       if (changes) {
-               camel_object_trigger_event ((CamelObject *) folder, "folder_changed", changes);
-               camel_folder_change_info_free (changes);
-       }
+       CAMEL_NNTP_STORE_LOCK(folder->parent_store, command_lock);
+       camel_folder_summary_save (folder->summary);
+       CAMEL_NNTP_STORE_UNLOCK(folder->parent_store, command_lock);
 }
 
 static void
 nntp_folder_sync_offline (CamelFolder *folder, CamelException *ex)
 {
+       CAMEL_NNTP_STORE_LOCK(folder->parent_store, command_lock);
        camel_folder_summary_save (folder->summary);
+       CAMEL_NNTP_STORE_UNLOCK(folder->parent_store, command_lock);
 }
 
 static gboolean
@@ -134,20 +124,14 @@ nntp_folder_set_message_flags (CamelFolder *folder, const char *uid, guint32 fla
 }
 
 static CamelStream *
-nntp_folder_download_message (CamelNNTPFolder *nntp_folder, const char *msgid, CamelException *ex)
+nntp_folder_download_message (CamelNNTPFolder *nntp_folder, const char *id, const char *msgid, CamelException *ex)
 {
        CamelNNTPStore *nntp_store = (CamelNNTPStore *) ((CamelFolder *) nntp_folder)->parent_store;
        CamelStream *stream = NULL;
        int ret;
        char *line;
-       
-       if (camel_nntp_store_set_folder (nntp_store, (CamelFolder *) nntp_folder, nntp_folder->changes, ex) == -1)
-               return NULL;
-       
-       ret = camel_nntp_command (nntp_store, &line, "article %s", msgid);
-       if (ret == -1)
-               goto fail;
-       
+
+       ret = camel_nntp_command (nntp_store, ex, nntp_folder, &line, "article %s", id);
        if (ret == 220) {
                stream = camel_data_cache_add (nntp_store->cache, "cache", msgid, NULL);
                if (stream) {
@@ -159,6 +143,10 @@ nntp_folder_download_message (CamelNNTPFolder *nntp_folder, const char *msgid, C
                        stream = (CamelStream *) nntp_store->stream;
                        camel_object_ref (stream);
                }
+       } else if (ret == 423 || ret == 430) {
+               camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, _("Cannot get message %s: %s"), msgid, line);
+       } else if (ret != -1) {
+               camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot get message %s: %s"), msgid, line);
        }
        
        return stream;
@@ -192,15 +180,10 @@ nntp_folder_cache_message (CamelDiscoFolder *disco_folder, const char *uid, Came
        
        CAMEL_NNTP_STORE_LOCK(nntp_store, command_lock);
        
-       stream = nntp_folder_download_message ((CamelNNTPFolder *) disco_folder, article, ex);
-       if (stream) {
+       stream = nntp_folder_download_message ((CamelNNTPFolder *) disco_folder, article, msgid, ex);
+       if (stream)
                camel_object_unref (stream);
-       } else {
-               /* failed to download message! */
-               camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-                                     _("Could not get article %s from NNTP server"), uid);
-       }
-       
+
        CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock);
 }
 
@@ -212,23 +195,22 @@ nntp_folder_get_message (CamelFolder *folder, const char *uid, CamelException *e
        CamelFolderChangeInfo *changes;
        CamelNNTPFolder *nntp_folder;
        CamelStream *stream = NULL;
-       char *line = NULL;
        char *article, *msgid;
 
        nntp_store = (CamelNNTPStore *) folder->parent_store;
        nntp_folder = (CamelNNTPFolder *) folder;
        
-       CAMEL_NNTP_STORE_LOCK(nntp_store, command_lock);
-
        article = alloca(strlen(uid)+1);
        strcpy(article, uid);
        msgid = strchr (article, ',');
        if (msgid == NULL) {
                camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
                                      _("Internal error: uid in invalid format: %s"), uid);
-               goto fail;
+               return NULL;
        }
        *msgid++ = 0;
+
+       CAMEL_NNTP_STORE_LOCK(nntp_store, command_lock);
        
        /* Lookup in cache, NEWS is global messageid's so use a global cache path */
        stream = camel_data_cache_get (nntp_store->cache, "cache", msgid, NULL);
@@ -239,38 +221,23 @@ nntp_folder_get_message (CamelFolder *folder, const char *uid, CamelException *e
                        goto fail;
                }
 
-               stream = nntp_folder_download_message (nntp_folder, article, ex);
+               stream = nntp_folder_download_message (nntp_folder, article, msgid, ex);
                if (stream == NULL)
                        goto fail;
        }
        
-       if (stream) {
-               message = camel_mime_message_new ();
-               if (camel_data_wrapper_construct_from_stream ((CamelDataWrapper *) message, stream) == -1)
-                       goto error;
-               
-               CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock);
-               
-               camel_object_unref (stream);
-               
-               return message;
+       message = camel_mime_message_new ();
+       if (camel_data_wrapper_construct_from_stream ((CamelDataWrapper *) message, stream) == -1) {
+               if (errno == EINTR)
+                       camel_exception_setv (ex, CAMEL_EXCEPTION_USER_CANCEL, _("User cancelled"));
+               else
+                       camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot get message %s: %s"), uid, g_strerror (errno));
+               camel_object_unref(message);
+               message = NULL;
        }
-       
-       camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot get message %s: %s"), uid, line);
-       
- error:
-       if (errno == EINTR)
-               camel_exception_setv (ex, CAMEL_EXCEPTION_USER_CANCEL, _("User cancelled"));
-       else
-               camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot get message %s: %s"), uid, g_strerror (errno));
-       
- fail:
-       if (message)
-               camel_object_unref (message);
-       
-       if (stream)
-               camel_object_unref (stream);
-       
+
+       camel_object_unref (stream);
+fail:
        if (camel_folder_change_info_changed (nntp_folder->changes)) {
                changes = nntp_folder->changes;
                nntp_folder->changes = camel_folder_change_info_new ();
@@ -284,8 +251,8 @@ nntp_folder_get_message (CamelFolder *folder, const char *uid, CamelException *e
                camel_object_trigger_event ((CamelObject *) folder, "folder_changed", changes);
                camel_folder_change_info_free (changes);
        }
-       
-       return NULL;
+               
+       return message;
 }
 
 static GPtrArray*
@@ -349,33 +316,25 @@ nntp_folder_append_message_online (CamelFolder *folder, CamelMimeMessage *mime_m
        int ret;
        unsigned int u;
        struct _camel_header_raw *header, *savedhdrs, *n, *tail;
-       unsigned char *line;
-       char *cmdbuf = NULL, *respbuf = NULL;
+       char *group, *line;
        
        CAMEL_NNTP_STORE_LOCK(nntp_store, command_lock);
        
        /* send 'POST' command */
-       ret = camel_nntp_command (nntp_store, (char **) &line, "post");
-       
+       ret = camel_nntp_command (nntp_store, ex, NULL, &line, "post");
        if (ret != 340) {
-               camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
-                                     _("Posting not allowed by news server"));
+               if (ret == 440)
+                       camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
+                                             _("Posting failed: %s"), line);
+               else if (ret != -1)
+                       camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+                                             _("Posting failed: %s"), line);
                CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock);
                return;
        }
        
-       /* send the 'Newsgroups: ' header */
-       cmdbuf = g_strdup_printf ("Newsgroups: %s\r\n", folder->full_name);
-       
-       if (camel_stream_write (stream, cmdbuf, strlen (cmdbuf)) == -1) {
-               g_free (cmdbuf);
-               camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-                                     _("Failed to send newsgroups header: %s: message not posted"),
-                                     g_strerror (errno));
-               CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock);
-               return;
-       }
-       g_free (cmdbuf);
+       /* the 'Newsgroups: ' header */
+       group = g_strdup_printf ("Newsgroups: %s\r\n", folder->full_name);
        
        /* setup stream filtering */
        crlffilter = camel_mime_filter_crlf_new (CAMEL_MIME_FILTER_CRLF_ENCODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_DOTS);
@@ -403,46 +362,23 @@ nntp_folder_append_message_online (CamelFolder *folder, CamelMimeMessage *mime_m
        }
        
        /* write the message */
-       ret = camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (mime_message), CAMEL_STREAM (filtered_stream));
-       
-       /* restore the mail headers */
-       header->next = savedhdrs;
-       
-       if (ret == -1) {
-               camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-                                     _("Error posting to newsgroup: %s: message not posted"),
-                                     g_strerror (errno));
-               camel_object_unref (filtered_stream);
-               CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock);
-               return;
-       }
-       
-       camel_stream_flush (CAMEL_STREAM (filtered_stream));
-       camel_object_unref (filtered_stream);
-       
-       /* terminate the message body */
-       if (camel_stream_write (stream, "\r\n.\r\n", 5) == -1) {
-               camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-                                     _("Error posting to newsgroup: %s: message not posted"),
-                                     g_strerror (errno));
-               CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock);
-               return;
-       }
-       
-       if (camel_nntp_stream_line (nntp_store->stream, (unsigned char **) &respbuf, &u) == -1)
-               respbuf = NULL;
-       
-       if (!respbuf || strncmp (respbuf, "240", 3)) {
-               if (!respbuf)
-                       camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-                                             _("Error reading response to posted message: message not posted"));
+       if (camel_stream_write(stream, group, strlen(group)) == -1
+           || camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (mime_message), CAMEL_STREAM (filtered_stream)) == -1
+           || camel_stream_flush (CAMEL_STREAM (filtered_stream)) == -1
+           || camel_stream_write (stream, "\r\n.\r\n", 5) == -1
+           || (ret = camel_nntp_stream_line (nntp_store->stream, (unsigned char **)&line, &u)) == -1) {
+               if (errno == EINTR)
+                       camel_exception_setv (ex, CAMEL_EXCEPTION_USER_CANCEL, _("User cancelled"));
                else
-                       camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-                                             _("Error posting message: %s: message not posted"), respbuf);
-               CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock);
-               return;
+                       camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Posting failed: %s"), g_strerror (errno));
+       } else if (atoi(line) != 240) {
+               camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Posting failed: %s"), line);
        }
-       
+
+       camel_object_unref (filtered_stream);
+       g_free(group);
+       header->next = savedhdrs;
+
        CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock);
        
        return;
@@ -541,47 +477,6 @@ camel_nntp_folder_get_type (void)
        return camel_nntp_folder_type;
 }
 
-
-/* not yet */
-/* Idea is we update in stages, but this requires a different xover command, etc */
-#ifdef ASYNC_SUMMARY
-struct _folder_check_msg {
-       CamelSessionThreadMsg msg;
-       CamelNNTPFolder *folder;
-};
-
-static void
-folder_check(CamelSession *session, CamelSessionThreadMsg *msg)
-{
-       struct _folder_check_msg *m = (struct _folder_check_msg *)msg;
-       CamelException *ex;
-       CamelNNTPStore *nntp_store;
-       
-       nntp_store = (CamelNNTPStore *) m->folder->parent.parent_store;
-       
-       CAMEL_NNTP_STORE_LOCK(nntp_store, command_lock);
-       
-       ex = camel_exception_new ();
-       camel_nntp_summary_check ((CamelNNTPSummary *) m->folder->parent.summary, m->folder->changes, ex);
-       camel_exception_free (ex);
-       
-       CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock);
-}
-
-static void
-folder_check_free(CamelSession *session, CamelSessionThreadMsg *msg)
-{
-       struct _folder_check_msg *m = (struct _folder_check_msg *)msg;
-       
-       camel_object_unref (m->folder);
-}
-
-static CamelSessionThreadOps folder_check_ops = {
-       folder_check,
-       folder_check_free,
-};
-#endif
-
 CamelFolder *
 camel_nntp_folder_new (CamelStore *parent, const char *folder_name, CamelException *ex)
 {
@@ -589,9 +484,6 @@ camel_nntp_folder_new (CamelStore *parent, const char *folder_name, CamelExcepti
        CamelNNTPFolder *nntp_folder;
        char *root;
        CamelService *service;
-#ifdef ASYNC_SUMMARY
-       struct _folder_check_msg *m;
-#endif
        CamelStoreInfo *si;
        gboolean subscribed = TRUE;
        
@@ -617,7 +509,9 @@ camel_nntp_folder_new (CamelStore *parent, const char *folder_name, CamelExcepti
        camel_object_state_read(nntp_folder);
        g_free(root);
 
-       folder->summary = (CamelFolderSummary *) camel_nntp_summary_new (nntp_folder);
+       root = g_strdup_printf("%s.ev-summary", nntp_folder->storage_path);
+       folder->summary = (CamelFolderSummary *) camel_nntp_summary_new (root);
+       g_free(root);
        camel_folder_summary_load (folder->summary);
        
        si = camel_store_summary_path ((CamelStoreSummary *) ((CamelNNTPStore*) parent)->summary, folder_name);
@@ -627,17 +521,11 @@ camel_nntp_folder_new (CamelStore *parent, const char *folder_name, CamelExcepti
        }
        
        if (subscribed) {
-#ifdef ASYNC_SUMMARY
-               m = camel_session_thread_msg_new (service->session, &folder_check_ops, sizeof(*m));
-               m->folder = nntp_folder;
-               camel_object_ref (folder);
-               camel_session_thread_queue (service->session, &m->msg, 0);
-#else
-               if (camel_nntp_summary_check ((CamelNNTPSummary *) folder->summary, nntp_folder->changes, ex) == -1) {
+               camel_folder_refresh_info(folder, ex);
+               if (camel_exception_is_set(ex)) {
                        camel_object_unref (folder);
                        folder = NULL;
                }
-#endif
         }
        
        return folder;
index 378fee6..0914ee4 100644 (file)
@@ -66,6 +66,8 @@ CamelType camel_nntp_folder_get_type (void);
 
 CamelFolder *camel_nntp_folder_new (CamelStore *parent, const char *folder_name, CamelException *ex);
 
+void camel_nntp_folder_selected(CamelNNTPFolder *folder, char *line, CamelException *ex);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
index 7f3850f..cbcf2b3 100644 (file)
@@ -37,8 +37,7 @@ camel_nntp_get_grouplist_from_server (CamelNNTPStore *store, CamelException *ex)
        CamelNNTPGroupList *list;
 
        CAMEL_NNTP_STORE_LOCK(store);
-       status = camel_nntp_command (store, ex, NULL,
-                                    "LIST");
+       status = camel_nntp_command (store, ex, NULL, &line, "LIST");
 
        if (status != NNTP_LIST_FOLLOWS) {
                camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
index 8cade2a..7dbcd89 100644 (file)
@@ -19,8 +19,6 @@
  * Boston, MA 02111-1307, USA.
  */
 
-/* currently, this is just a straigt s/imap/nntp from the IMAP file*/ 
-
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
@@ -45,8 +43,9 @@
 #define io(x)                  /* io debug */
 
 #define CAMEL_NNTP_STORE_SUMMARY_VERSION_0 (0)
+#define CAMEL_NNTP_STORE_SUMMARY_VERSION_1 (1)
 
-#define CAMEL_NNTP_STORE_SUMMARY_VERSION (0)
+#define CAMEL_NNTP_STORE_SUMMARY_VERSION (1)
 
 #define _PRIVATE(o) (((CamelNNTPStoreSummary *)(o))->priv)
 
@@ -362,7 +361,14 @@ store_info_load (CamelStoreSummary *s, FILE *in)
        if (ni) {
                if (camel_file_util_decode_string (in, &ni->full_name) == -1) {
                        camel_store_summary_info_free (s, (CamelStoreInfo *) ni);
-                       ni = NULL;
+                       return NULL;
+               }
+               if (((CamelNNTPStoreSummary *)s)->version >= CAMEL_NNTP_STORE_SUMMARY_VERSION_1) {
+                       if (camel_file_util_decode_uint32(in, &ni->first) == -1
+                           || camel_file_util_decode_uint32(in, &ni->last) == -1) {
+                               camel_store_summary_info_free (s, (CamelStoreInfo *) ni);
+                               return NULL;
+                       }
                }
                /* set the URL */
        }
@@ -376,7 +382,9 @@ store_info_save (CamelStoreSummary *s, FILE *out, CamelStoreInfo *mi)
        CamelNNTPStoreInfo *isi = (CamelNNTPStoreInfo *)mi;
        
        if (camel_nntp_store_summary_parent->store_info_save (s, out, mi) == -1
-           || camel_file_util_encode_string (out, isi->full_name) == -1)
+           || camel_file_util_encode_string (out, isi->full_name) == -1
+           || camel_file_util_encode_uint32(out, isi->first) == -1
+           || camel_file_util_encode_uint32(out, isi->last) == -1)
                return -1;
        
        return 0;
index cf0401f..2e442a8 100644 (file)
@@ -50,6 +50,8 @@ enum {
 struct _CamelNNTPStoreInfo {
        CamelStoreInfo info;
        char *full_name;
+       guint32 first;          /* from LIST or NEWGROUPS return */
+       guint32 last;
 };
 
 #define NNTP_DATE_SIZE 14
index 26e8254..a36a696 100644 (file)
@@ -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;
 }
index 10a56dc..0e68f4a 100644 (file)
@@ -30,18 +30,14 @@ extern "C" {
 #pragma }
 #endif /* __cplusplus */
 
-#include <camel/camel-store.h>
-#include <camel/camel-stream-mem.h>
-#include <camel/camel-data-cache.h>
-#include <camel/camel-exception.h>
-#include <camel/camel-folder.h>
-
 #include <camel/camel-disco-store.h>
-#include <camel/camel-disco-folder.h>
 
 #include "camel-nntp-stream.h"
 #include "camel-nntp-store-summary.h"
 
+struct _CamelNNTPFolder;
+struct _CamelException;
+
 #define CAMEL_NNTP_STORE_TYPE     (camel_nntp_store_get_type ())
 #define CAMEL_NNTP_STORE(obj)     (CAMEL_CHECK_CAST((obj), CAMEL_NNTP_STORE_TYPE, CamelNNTPStore))
 #define CAMEL_NNTP_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_NNTP_STORE_TYPE, CamelNNTPStoreClass))
@@ -59,6 +55,20 @@ extern "C" {
 typedef struct _CamelNNTPStore CamelNNTPStore;
 typedef struct _CamelNNTPStoreClass CamelNNTPStoreClass;
 
+enum _xover_t {
+       XOVER_STRING = 0,
+       XOVER_MSGID,
+       XOVER_SIZE,
+};
+
+struct _xover_header {
+       struct _xover_header *next;
+
+       const char *name;
+       unsigned int skip:8;
+       enum _xover_t type:8;
+};
+
 struct _CamelNNTPStore {
        CamelDiscoStore parent_object;  
        
@@ -66,17 +76,20 @@ struct _CamelNNTPStore {
        
        guint32 extensions;
        
-       gboolean posting_allowed;
-       gboolean do_short_folder_notation, folder_hierarchy_relative;
+       unsigned int posting_allowed:1;
+       unsigned int do_short_folder_notation:1;
+       unsigned int folder_hierarchy_relative:1;
 
-       CamelNNTPStoreSummary *summary;
+       struct _CamelNNTPStoreSummary *summary;
        
-       CamelNNTPStream *stream;
-       CamelStreamMem *mem;
+       struct _CamelNNTPStream *stream;
+       struct _CamelStreamMem *mem;
        
-       CamelDataCache *cache;
+       struct _CamelDataCache *cache;
        
        char *current_folder, *storage_path, *base_url;
+
+       struct _xover_header *xover;
 };
 
 struct _CamelNNTPStoreClass {
@@ -87,8 +100,9 @@ struct _CamelNNTPStoreClass {
 /* Standard Camel function */
 CamelType camel_nntp_store_get_type (void);
 
-int camel_nntp_command(CamelNNTPStore *store, char **line, const char *fmt, ...);
-int camel_nntp_store_set_folder(CamelNNTPStore *store, CamelFolder *folder, CamelFolderChangeInfo *changes, CamelException *ex);
+int camel_nntp_raw_commandv (CamelNNTPStore *store, struct _CamelException *ex, char **line, const char *fmt, va_list ap);
+int camel_nntp_raw_command(CamelNNTPStore *store, struct _CamelException *ex, char **line, const char *fmt, ...);
+int camel_nntp_command (CamelNNTPStore *store, struct _CamelException *ex, struct _CamelNNTPFolder *folder, char **line, const char *fmt, ...);
 
 #ifdef __cplusplus
 }
index d897db2..d30fdc6 100644 (file)
@@ -50,24 +50,6 @@ extern int camel_verbose_debug;
 
 #define CAMEL_NNTP_SUMMARY_VERSION (1)
 
-static int xover_setup(CamelNNTPSummary *cns, CamelException *ex);
-static int add_range_xover(CamelNNTPSummary *cns, unsigned int high, unsigned int low, CamelFolderChangeInfo *changes, CamelException *ex);
-static int add_range_head(CamelNNTPSummary *cns, unsigned int high, unsigned int low, CamelFolderChangeInfo *changes, CamelException *ex);
-
-enum _xover_t {
-       XOVER_STRING = 0,
-       XOVER_MSGID,
-       XOVER_SIZE,
-};
-
-struct _xover_header {
-       struct _xover_header *next;
-
-       const char *name;
-       unsigned int skip:8;
-       enum _xover_t type:8;
-};
-
 struct _CamelNNTPSummaryPrivate {
        char *uid;
 
@@ -136,29 +118,16 @@ static void
 camel_nntp_summary_finalise(CamelObject *obj)
 {
        CamelNNTPSummary *cns = CAMEL_NNTP_SUMMARY(obj);
-       struct _xover_header *xover, *xn;
-
-       xover = cns->priv->xover;
-       while (xover) {
-               xn = xover->next;
-               g_free(xover);
-               xover = xn;
-       }
 
        g_free(cns->priv);
 }
 
 CamelNNTPSummary *
-camel_nntp_summary_new(CamelNNTPFolder *folder)
+camel_nntp_summary_new(const char *path)
 {
        CamelNNTPSummary *cns = (CamelNNTPSummary *)camel_object_new(camel_nntp_summary_get_type());
-       char *path;
 
-       cns->folder = folder;
-       path = g_strdup_printf ("%s%s", folder->storage_path, ".ev-summary");
        camel_folder_summary_set_filename((CamelFolderSummary *)cns, path);
-       g_free(path);
-
        camel_folder_summary_set_build_content((CamelFolderSummary *)cns, FALSE);
        
        return cns;
@@ -230,198 +199,12 @@ summary_header_save(CamelFolderSummary *s, FILE *out)
        return 0;
 }
 
-/* Assumes we have the stream */
-int
-camel_nntp_summary_check(CamelNNTPSummary *cns, CamelFolderChangeInfo *changes, CamelException *ex)
-{
-       CamelNNTPStore *store;
-       CamelFolder *folder;
-       CamelFolderSummary *s;
-       int ret, i;
-       char *line;
-       unsigned int n, f, l;
-       int count;
-
-       folder = (CamelFolder *)cns->folder;
-       store = (CamelNNTPStore *)folder->parent_store;
-
-       if (((CamelDiscoStore *)store)->status == CAMEL_DISCO_STORE_OFFLINE)
-               return 0;
-
-       if (xover_setup (cns, ex) == -1) {
-               camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-                                     _("Connection error: %s"), strerror(errno));
-               return -1;
-       }
-
-       s = (CamelFolderSummary *)cns;
-
-       ret = camel_nntp_command(store, &line, "group %s", folder->full_name);
-       if (ret == 411) {
-               camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID,
-                                    _("No such folder: %s"), line);
-               return -1;
-       } else if (ret != 211) {
-               if (ret < 0)
-                       line = "";
-               camel_exception_setv(ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-                                    _("Could not get group: %s"), line);
-               return -1;
-       }
-
-       line +=3;
-       n = strtoul(line, &line, 10);
-       f = strtoul(line, &line, 10);
-       l = strtoul(line, &line, 10);
-
-       if (cns->low == f && cns->high == l) {
-               dd(printf("nntp_summary: no work to do!\n"));
-               return 0;
-       }
-
-       /* Need to work out what to do with our messages */
-
-       /* Check for messages no longer on the server */
-       if (cns->low != f) {
-               count = camel_folder_summary_count(s);
-               for (i = 0; i < count; i++) {
-                       CamelMessageInfo *mi = camel_folder_summary_index(s, i);
-
-                       if (mi) {
-                               const char *uid = camel_message_info_uid(mi);
-                               const char *msgid;
-
-                               n = strtoul(uid, NULL, 10);
-                               if (n < f || n > l) {
-                                       dd(printf("nntp_summary: %u is lower/higher than lowest/highest article, removed\n", n));
-                                       /* Since we use a global cache this could prematurely remove
-                                          a cached message that might be in another folder - not that important as
-                                          it is a true cache */
-                                       msgid = strchr(uid, ',');
-                                       if (msgid)
-                                               camel_data_cache_remove(store->cache, "cache", msgid+1, NULL);
-                                       camel_folder_change_info_remove_uid(changes, uid);
-                                       camel_folder_summary_remove(s, mi);
-                                       count--;
-                                       i--;
-                               }
-                               
-                               camel_folder_summary_info_free(s, mi);
-                       }
-               }
-               cns->low = f;
-       }
-
-       if (cns->high < l) {
-               if (cns->high < f)
-                       cns->high = f-1;
-
-               if (cns->priv->xover) {
-                       ret = add_range_xover(cns, l, cns->high+1, changes, ex);
-               } else {
-                       ret = add_range_head(cns, l, cns->high+1, changes, ex);
-               }
-       }
-
-
-       /* TODO: not from here */
-       camel_folder_summary_touch(s);
-       camel_folder_summary_save(s);
-
-       if (ret < 0)
-               camel_exception_setv(ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-                                    _("Could not get messages: unspecified error"));
-
-       return ret;
-}
-
-static struct {
-       const char *name;
-       int type;
-} headers[] = {
-       { "subject", 0 },
-       { "from", 0 },
-       { "date", 0 },
-       { "message-id", 1 },
-       { "references", 0 },
-       { "bytes", 2 },
-};
+/* ********************************************************************** */
 
+/* Note: This will be called from camel_nntp_command, so only use camel_nntp_raw_command */
 static int
-xover_setup(CamelNNTPSummary *cns, CamelException *ex)
+add_range_xover(CamelNNTPSummary *cns, CamelNNTPStore *store, unsigned int high, unsigned int low, CamelFolderChangeInfo *changes, CamelException *ex)
 {
-       CamelNNTPStore *store;
-       CamelFolder *folder;
-       CamelFolderSummary *s;
-       int ret, i;
-       char *line;
-       unsigned int len;
-       unsigned char c, *p;
-       struct _xover_header *xover, *last;
-
-       if (cns->priv->xover_setup)
-               return 0;
-
-       /* manual override */
-       if (getenv("CAMEL_NNTP_DISABLE_XOVER") != NULL) {
-               cns->priv->xover_setup = TRUE;
-               return 0;
-       }
-
-       folder = (CamelFolder *)cns->folder;
-       store = (CamelNNTPStore *)folder->parent_store;
-       s = (CamelFolderSummary *)cns;
-
-       ret = camel_nntp_command(store, &line, "list overview.fmt");
-       if (ret == -1) {
-               camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
-                                    _("NNTP Command failed: %s"), strerror(errno));
-               return -1;
-       }
-
-       cns->priv->xover_setup = TRUE;
-
-       /* unsupported command? */
-       if (ret != 215)
-               return 0;
-
-       last = (struct _xover_header *)&cns->priv->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] = tolower(c);
-                       }
-               }
-       }
-
-       return ret;
-}
-
-static int
-add_range_xover(CamelNNTPSummary *cns, unsigned int high, unsigned int low, CamelFolderChangeInfo *changes, CamelException *ex)
-{
-       CamelNNTPStore *store;
-       CamelFolder *folder;
        CamelFolderSummary *s;
        CamelMessageInfo *mi;
        struct _camel_header_raw *headers = NULL;
@@ -429,21 +212,20 @@ add_range_xover(CamelNNTPSummary *cns, unsigned int high, unsigned int low, Came
        int len, ret;
        unsigned int n, count, total, size;
        struct _xover_header *xover;
-       time_t last, now;
 
-       folder = (CamelFolder *)cns->folder;
-       store = (CamelNNTPStore *)folder->parent_store;
        s = (CamelFolderSummary *)cns;
 
        camel_operation_start(NULL, _("%s: Scanning new messages"), ((CamelService *)store)->url->host);
 
-       ret = camel_nntp_command(store, &line, "xover %r", low, high);
+       ret = camel_nntp_raw_command(store, ex, &line, "xover %r", low, high);
        if (ret != 224) {
                camel_operation_end(NULL);
+               if (ret != -1)
+                       camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+                                            _("Unexpected server response from xover: %s"), line);
                return -1;
        }
 
-       last = time(0);
        count = 0;
        total = high-low+1;
        while ((ret = camel_nntp_stream_line(store->stream, (unsigned char **)&line, &len)) > 0) {
@@ -453,7 +235,7 @@ add_range_xover(CamelNNTPSummary *cns, unsigned int high, unsigned int low, Came
                if (*tab != '\t')
                        continue;
                tab++;
-               xover = cns->priv->xover;
+               xover = store->xover;
                size = 0;
                for (;tab[0] && xover;xover = xover->next) {
                        line = tab;
@@ -507,13 +289,6 @@ add_range_xover(CamelNNTPSummary *cns, unsigned int high, unsigned int low, Came
                }
 
                camel_header_raw_clear(&headers);
-
-               now = time(0);
-               if (last + 2 < now) {
-                       camel_object_trigger_event((CamelObject *)folder, "folder_changed", changes);
-                       camel_folder_change_info_clear(changes);
-                       last = now;
-               }
        }
 
        camel_operation_end(NULL);
@@ -521,41 +296,36 @@ add_range_xover(CamelNNTPSummary *cns, unsigned int high, unsigned int low, Came
        return ret;
 }
 
+/* Note: This will be called from camel_nntp_command, so only use camel_nntp_raw_command */
 static int
-add_range_head(CamelNNTPSummary *cns, unsigned int high, unsigned int low, CamelFolderChangeInfo *changes, CamelException *ex)
+add_range_head(CamelNNTPSummary *cns, CamelNNTPStore *store, unsigned int high, unsigned int low, CamelFolderChangeInfo *changes, CamelException *ex)
 {
-       CamelNNTPStore *store;
-       CamelFolder *folder;
        CamelFolderSummary *s;
        int i, ret = -1;
        char *line, *msgid;
        unsigned int n, count, total;
        CamelMessageInfo *mi;
        CamelMimeParser *mp;
-       time_t now, last;
 
-       folder = (CamelFolder *)cns->folder;
-       store = (CamelNNTPStore *)folder->parent_store;
        s = (CamelFolderSummary *)cns;
 
        mp = camel_mime_parser_new();
 
        camel_operation_start(NULL, _("%s: Scanning new messages"), ((CamelService *)store)->url->host);
 
-       last = time(0);
        count = 0;
        total = high-low+1;
        for (i=low;i<high+1;i++) {
                camel_operation_progress(NULL, (count * 100) / total);
                count++;
-               ret = camel_nntp_command(store, &line, "head %u", i);
+               ret = camel_nntp_raw_command(store, ex, &line, "head %u", i);
                /* unknown article, ignore */
                if (ret == 423)
                        continue;
                else if (ret == -1)
-                       goto error;
+                       goto ioerror;
                else if (ret != 221) {
-                       camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Unknown server response: %s"), line);
+                       camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Unexpected server response from head: %s"), line);
                        goto ioerror;
                }
                line += 3;
@@ -588,13 +358,6 @@ add_range_head(CamelNNTPSummary *cns, unsigned int high, unsigned int low, Camel
                                cns->priv->uid = NULL;
                        }
                }
-
-               now = time(0);
-               if (last + 2 < now) {
-                       camel_object_trigger_event((CamelObject *)folder, "folder_changed", changes);
-                       camel_folder_change_info_clear(changes);
-                       last = now;
-               }
        }
 
        ret = 0;
@@ -618,3 +381,124 @@ ioerror:
 
        return ret;
 }
+
+/* Assumes we have the stream */
+/* Note: This will be called from camel_nntp_command, so only use camel_nntp_raw_command */
+int
+camel_nntp_summary_check(CamelNNTPSummary *cns, CamelNNTPStore *store, char *line, CamelFolderChangeInfo *changes, CamelException *ex)
+{
+       CamelFolderSummary *s;
+       int ret = 0, i;
+       unsigned int n, f, l;
+       int count;
+       char *folder = NULL;
+       CamelNNTPStoreInfo *si;
+
+       s = (CamelFolderSummary *)cns;
+
+       line +=3;
+       n = strtoul(line, &line, 10);
+       f = strtoul(line, &line, 10);
+       l = strtoul(line, &line, 10);
+       if (line[0] == ' ') {
+               char *tmp;
+
+               folder = line+1;
+               tmp = strchr(folder, ' ');
+               if (tmp)
+                       *tmp = 0;
+               tmp = g_alloca(strlen(folder)+1);
+               strcpy(tmp, folder);
+               folder = tmp;
+       }
+
+       if (cns->low == f && cns->high == l) {
+               dd(printf("nntp_summary: no work to do!\n"));
+               goto update;
+       }
+
+       /* Need to work out what to do with our messages */
+
+       /* Check for messages no longer on the server */
+       if (cns->low != f) {
+               count = camel_folder_summary_count(s);
+               for (i = 0; i < count; i++) {
+                       CamelMessageInfo *mi = camel_folder_summary_index(s, i);
+
+                       if (mi) {
+                               const char *uid = camel_message_info_uid(mi);
+                               const char *msgid;
+
+                               n = strtoul(uid, NULL, 10);
+                               if (n < f || n > l) {
+                                       dd(printf("nntp_summary: %u is lower/higher than lowest/highest article, removed\n", n));
+                                       /* Since we use a global cache this could prematurely remove
+                                          a cached message that might be in another folder - not that important as
+                                          it is a true cache */
+                                       msgid = strchr(uid, ',');
+                                       if (msgid)
+                                               camel_data_cache_remove(store->cache, "cache", msgid+1, NULL);
+                                       camel_folder_change_info_remove_uid(changes, uid);
+                                       camel_folder_summary_remove(s, mi);
+                                       count--;
+                                       i--;
+                               }
+                               
+                               camel_folder_summary_info_free(s, mi);
+                       }
+               }
+               cns->low = f;
+       }
+
+       if (cns->high < l) {
+               if (cns->high < f)
+                       cns->high = f-1;
+
+               if (store->xover) {
+                       ret = add_range_xover(cns, store, l, cns->high+1, changes, ex);
+               } else {
+                       ret = add_range_head(cns, store, l, cns->high+1, changes, ex);
+               }
+       }
+
+       /* TODO: not from here */
+       camel_folder_summary_touch(s);
+       camel_folder_summary_save(s);
+update:
+       /* update store summary if we have it */
+       if (folder
+           && (si = (CamelNNTPStoreInfo *)camel_store_summary_path((CamelStoreSummary *)store->summary, folder))) {
+               int unread = 0;
+
+               count = camel_folder_summary_count(s);
+               for (i = 0; i < count; i++) {
+                       CamelMessageInfo *mi = camel_folder_summary_index(s, i);
+
+                       if (mi) {
+                               if ((mi->flags & CAMEL_MESSAGE_SEEN) == 0)
+                                       unread++;
+                               camel_folder_summary_info_free(s, mi);
+                       }
+               }
+               
+               if (si->info.unread != unread
+                   || si->info.total != count
+                   || si->first != f
+                   || si->last != l) {
+                       si->info.unread = unread;
+                       si->info.total = count;
+                       si->first = f;
+                       si->last = l;
+                       camel_store_summary_touch((CamelStoreSummary *)store->summary);
+                       camel_store_summary_save((CamelStoreSummary *)store->summary);
+               }
+               camel_store_summary_info_free ((CamelStoreSummary *)store->summary, (CamelStoreInfo *)si);
+       } else {
+               if (folder)
+                       g_warning("Group '%s' not present in summary", folder);
+               else
+                       g_warning("Missing group from group response");
+       }
+
+       return ret;
+}
index b89ffe9..fb58cea 100644 (file)
 #define _CAMEL_NNTP_SUMMARY_H
 
 #include <camel/camel-folder-summary.h>
-#include <camel/camel-folder.h>
-#include <camel/camel-exception.h>
+
+struct _CamelNNTPStore;
+struct _CamelFolderChangeInfo;
+struct _CamelException;
 
 #define CAMEL_NNTP_SUMMARY(obj)         CAMEL_CHECK_CAST (obj, camel_nntp_summary_get_type (), CamelNNTPSummary)
 #define CAMEL_NNTP_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_nntp_summary_get_type (), CamelNNTPSummaryClass)
@@ -37,8 +39,6 @@ struct _CamelNNTPSummary {
 
        struct _CamelNNTPSummaryPrivate *priv;
 
-       struct _CamelNNTPFolder *folder;
-
        guint32 version;
        guint32 high, low;
 };
@@ -48,20 +48,9 @@ struct _CamelNNTPSummaryClass {
 };
 
 CamelType      camel_nntp_summary_get_type     (void);
-CamelNNTPSummary *camel_nntp_summary_new(struct _CamelNNTPFolder *folder);
-
-int camel_nntp_summary_check(CamelNNTPSummary *cns, CamelFolderChangeInfo *, CamelException *ex);
+CamelNNTPSummary *camel_nntp_summary_new(const char *path);
 
-#if 0
-/* load/check the summary */
-int camel_nntp_summary_load(CamelNNTPSummary *cls, CamelException *ex);
-/* check for new/removed messages */
-int camel_nntp_summary_check(CamelNNTPSummary *cls, CamelFolderChangeInfo *, CamelException *ex);
-/* perform a folder sync or expunge, if needed */
-int camel_nntp_summary_sync(CamelNNTPSummary *cls, gboolean expunge, CamelFolderChangeInfo *, CamelException *ex);
-/* add a new message to the summary */
-CamelMessageInfo *camel_nntp_summary_add(CamelNNTPSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *, CamelException *ex);
-#endif
+int camel_nntp_summary_check(CamelNNTPSummary *cns, struct _CamelNNTPStore *store, char *line, struct _CamelFolderChangeInfo *changes, struct _CamelException *ex);
 
 #endif /* ! _CAMEL_NNTP_SUMMARY_H */