aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/nntp/camel-nntp-folder.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/nntp/camel-nntp-folder.c')
-rw-r--r--camel/providers/nntp/camel-nntp-folder.c386
1 files changed, 243 insertions, 143 deletions
diff --git a/camel/providers/nntp/camel-nntp-folder.c b/camel/providers/nntp/camel-nntp-folder.c
index e3b4da6b40..47d3111a01 100644
--- a/camel/providers/nntp/camel-nntp-folder.c
+++ b/camel/providers/nntp/camel-nntp-folder.c
@@ -1,10 +1,10 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* camel-nntp-folder.c : Abstract class for an email folder */
-
-/*
- * Author : Chris Toshok <toshok@ximian.com>
+/* camel-nntp-folder.c : Class for a news folder
+ *
+ * Authors : Chris Toshok <toshok@ximian.com>
+ * Michael Zucchi <notzed@ximian.com>
*
- * Copyright (C) 2000 Ximian .
+ * Copyright (C) 2001 Ximian .
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
@@ -33,21 +33,20 @@
#include <string.h>
#include <fcntl.h>
-#include "camel-folder-summary.h"
-#include "camel-nntp-resp-codes.h"
+#include "camel/string-utils.h"
+#include "camel/camel-stream-mem.h"
+#include "camel/camel-data-wrapper.h"
+#include "camel/camel-mime-message.h"
+#include "camel/camel-folder-search.h"
+#include "camel/camel-exception.h"
+#include "camel/camel-session.h"
+#include "camel/camel-data-cache.h"
+
+#include "camel-nntp-summary.h"
#include "camel-nntp-store.h"
#include "camel-nntp-folder.h"
#include "camel-nntp-store.h"
-#include "camel-nntp-utils.h"
-
-#include "string-utils.h"
-#include "camel-stream-mem.h"
-#include "camel-data-wrapper.h"
-#include "camel-mime-message.h"
-#include "camel-folder-summary.h"
-#include "camel-folder-search.h"
-
-#include "camel-exception.h"
+#include "camel-nntp-private.h"
static CamelFolderClass *parent_class=NULL;
@@ -56,131 +55,131 @@ static CamelFolderClass *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))
-
static void
-nntp_folder_sync (CamelFolder *folder, gboolean expunge,
- CamelException *ex)
+nntp_folder_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
{
- CamelNNTPStore *store;
+ CamelNNTPStore *nntp_store;
+ CamelFolderChangeInfo *changes = NULL;
+ CamelNNTPFolder *nntp_folder;
- camel_folder_summary_save (folder->summary);
+ nntp_store = (CamelNNTPStore *)folder->parent_store;
+ nntp_folder = (CamelNNTPFolder *)folder;
- store = CAMEL_NNTP_STORE (camel_folder_get_parent_store (folder));
+ CAMEL_NNTP_STORE_LOCK(nntp_store, command_lock);
- if (store->newsrc)
- camel_nntp_newsrc_write (store->newsrc);
+ 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);
+ }
}
static void
-nntp_folder_set_message_flags (CamelFolder *folder, const char *uid,
- guint32 flags, guint32 set)
+nntp_folder_set_message_flags(CamelFolder *folder, const char *uid, guint32 flags, guint32 set)
{
((CamelFolderClass *)parent_class)->set_message_flags(folder, uid, flags, set);
-
- if (flags & set & CAMEL_MESSAGE_SEEN) {
- int article_num;
- CamelNNTPStore *nntp_store = CAMEL_NNTP_STORE (camel_folder_get_parent_store (folder));
-
- sscanf (uid, "%d", &article_num);
-
- camel_nntp_newsrc_mark_article_read (nntp_store->newsrc,
- folder->name,
- article_num);
- }
}
static CamelMimeMessage *
-nntp_folder_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
+nntp_folder_get_message (CamelFolder *folder, const char *uid, CamelException *ex)
{
- CamelStream *message_stream = NULL;
CamelMimeMessage *message = NULL;
- CamelStore *parent_store;
- char *buf;
- int buf_len;
- int buf_alloc;
- int status;
- gboolean done;
- char *message_id;
-
- /* get the parent store */
- parent_store = camel_folder_get_parent_store (folder);
-
- message_id = strchr (uid, ',');
- if (message_id) {
- message_id++;
- status = camel_nntp_command (CAMEL_NNTP_STORE( parent_store ), ex, NULL, "ARTICLE %s", message_id);
+ CamelNNTPStore *nntp_store;
+ CamelFolderChangeInfo *changes;
+ CamelNNTPFolder *nntp_folder;
+ CamelStream *stream = NULL;
+ int ret;
+ char *line;
+ const char *msgid;
+
+ nntp_store = (CamelNNTPStore *)folder->parent_store;
+ nntp_folder = (CamelNNTPFolder *)folder;
+
+ CAMEL_NNTP_STORE_LOCK(nntp_store, command_lock);
+
+ msgid = strchr(uid, ',');
+ if (msgid == 0) {
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Internal error: uid in invalid format: %s"), uid);
+ goto fail;
}
-
- /* if the message_id was not found, raise an exception and return */
- if (message_id == NULL || status == NNTP_NO_SUCH_ARTICLE) {
- camel_exception_setv (ex,
- CAMEL_EXCEPTION_FOLDER_INVALID_UID,
- _("Message %s not found."),
- uid);
- return NULL;
- }
- else if (status != NNTP_ARTICLE_FOLLOWS) {
- /* XXX */
- g_warning ("weird nntp error %d\n", status);
- return NULL;
+ msgid++;
+
+ /* 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);
+ if (stream == NULL) {
+ /* Not in cache, retrieve and put in cache */
+ if (camel_nntp_store_set_folder(nntp_store, folder, nntp_folder->changes, ex) == -1)
+ goto fail;
+
+ ret = camel_nntp_command(nntp_store, &line, "article %s", msgid);
+ if (ret == -1)
+ goto error;
+
+ if (ret == 220) {
+ stream = camel_data_cache_add(nntp_store->cache, "cache", msgid, NULL);
+ if (stream) {
+ if (camel_stream_write_to_stream((CamelStream *)nntp_store->stream, stream) == -1)
+ goto error;
+ if (camel_stream_reset(stream) == -1)
+ goto error;
+ } else {
+ stream = (CamelStream *)nntp_store->stream;
+ camel_object_ref((CamelObject *)stream);
+ }
+ }
}
- /* this could probably done fairly easily with an nntp stream that
- returns eof after '.' */
+ if (stream) {
+ message = camel_mime_message_new();
+ if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)message, stream) == -1)
+ goto error;
- /* XXX ick ick ick. read the entire message into a buffer and
- then create a stream_mem for it. */
- buf_alloc = 2048;
- buf_len = 0;
- buf = g_malloc(buf_alloc);
- done = FALSE;
+ CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock);
- buf[0] = 0;
+ camel_object_unref((CamelObject *)stream);
+ return message;
+ }
- while (!done) {
- int line_length;
- char *line;
+ camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot get message %s: %s"), uid, line);
- if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (parent_store), &line, ex) < 0) {
- g_warning ("recv_line failed while building message\n");
- break;
- }
+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, strerror(errno));
- /* XXX check exception */
+fail:
+ if (message)
+ camel_object_unref((CamelObject *)message);
- line_length = strlen ( line );
+ if (stream)
+ camel_object_unref((CamelObject *)stream);
- if (!strcmp(line, ".")) {
- done = TRUE;
- g_free (line);
- }
- else {
- if (buf_len + line_length > buf_alloc) {
- buf_alloc *= 2;
- buf = g_realloc (buf, buf_alloc);
- }
- strcat(buf, line);
- strcat(buf, "\n");
- buf_len += strlen(line) + 1;
- g_free (line);
- }
+ if (camel_folder_change_info_changed(nntp_folder->changes)) {
+ changes = nntp_folder->changes;
+ nntp_folder->changes = camel_folder_change_info_new();
+ } else {
+ changes = NULL;
}
- /* create a stream bound to the message */
- message_stream = camel_stream_mem_new_with_buffer(buf, buf_len);
-
- message = camel_mime_message_new ();
- camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER(message), message_stream);
-
- camel_object_unref (CAMEL_OBJECT (message_stream));
+ CAMEL_NNTP_STORE_UNLOCK(nntp_store, command_lock);
-#if 0
- gtk_signal_connect (CAMEL_OBJECT (message), "message_changed", message_changed, folder);
-#endif
-
- g_free (buf);
+ if (changes) {
+ camel_object_trigger_event((CamelObject *)folder, "folder_changed", changes);
+ camel_folder_change_info_free(changes);
+ }
- return message;
+ return NULL;
}
static GPtrArray*
@@ -188,7 +187,9 @@ nntp_folder_search_by_expression (CamelFolder *folder, const char *expression, C
{
CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (folder);
GPtrArray *matches, *summary;
-
+
+ CAMEL_NNTP_FOLDER_LOCK(nntp_folder, search_lock);
+
if(nntp_folder->search == NULL)
nntp_folder->search = camel_folder_search_new();
@@ -198,11 +199,54 @@ nntp_folder_search_by_expression (CamelFolder *folder, const char *expression, C
matches = camel_folder_search_execute_expression(nntp_folder->search, expression, ex);
+ CAMEL_NNTP_FOLDER_UNLOCK(nntp_folder, search_lock);
+
camel_folder_free_summary(folder, summary);
return matches;
}
+static GPtrArray *
+nntp_folder_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex)
+{
+ CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER(folder);
+ GPtrArray *summary, *matches;
+ int i;
+
+ /* NOTE: could get away without the search lock by creating a new
+ search object each time */
+
+ summary = g_ptr_array_new();
+ for (i=0;i<uids->len;i++) {
+ CamelMessageInfo *info;
+
+ info = camel_folder_get_message_info(folder, uids->pdata[i]);
+ if (info)
+ g_ptr_array_add(summary, info);
+ }
+
+ if (summary->len == 0)
+ return summary;
+
+ CAMEL_NNTP_FOLDER_LOCK(folder, search_lock);
+
+ if (nntp_folder->search == NULL)
+ nntp_folder->search = camel_folder_search_new();
+
+ camel_folder_search_set_folder(nntp_folder->search, folder);
+ camel_folder_search_set_summary(nntp_folder->search, summary);
+
+ matches = camel_folder_search_execute_expression(nntp_folder->search, expression, ex);
+
+ CAMEL_NNTP_FOLDER_UNLOCK(folder, search_lock);
+
+ for (i=0;i<summary->len;i++)
+ camel_folder_free_message_info(folder, summary->pdata[i]);
+ g_ptr_array_free(summary, TRUE);
+
+ return matches;
+}
+
static void
nntp_folder_search_free(CamelFolder *folder, GPtrArray *result)
{
@@ -213,15 +257,19 @@ nntp_folder_search_free(CamelFolder *folder, GPtrArray *result)
}
static void
-nntp_folder_finalize (CamelObject *object)
+nntp_folder_init(CamelNNTPFolder *nntp_folder, CamelNNTPFolderClass *klass)
{
- CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (object);
+ nntp_folder->changes = camel_folder_change_info_new();
+}
- g_free (nntp_folder->summary_file_path);
+static void
+nntp_folder_finalise (CamelNNTPFolder *nntp_folder)
+{
+ g_free(nntp_folder->storage_path);
}
static void
-camel_nntp_folder_class_init (CamelNNTPFolderClass *camel_nntp_folder_class)
+nntp_folder_class_init (CamelNNTPFolderClass *camel_nntp_folder_class)
{
CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS (camel_nntp_folder_class);
@@ -234,6 +282,7 @@ camel_nntp_folder_class_init (CamelNNTPFolderClass *camel_nntp_folder_class)
camel_folder_class->set_message_flags = nntp_folder_set_message_flags;
camel_folder_class->get_message = nntp_folder_get_message;
camel_folder_class->search_by_expression = nntp_folder_search_by_expression;
+ camel_folder_class->search_by_uids = nntp_folder_search_by_uids;
camel_folder_class->search_free = nntp_folder_search_free;
}
@@ -246,46 +295,97 @@ camel_nntp_folder_get_type (void)
camel_nntp_folder_type = camel_type_register (CAMEL_FOLDER_TYPE, "CamelNNTPFolder",
sizeof (CamelNNTPFolder),
sizeof (CamelNNTPFolderClass),
- (CamelObjectClassInitFunc) camel_nntp_folder_class_init,
+ (CamelObjectClassInitFunc) nntp_folder_class_init,
NULL,
- (CamelObjectInitFunc) NULL,
- (CamelObjectFinalizeFunc) nntp_folder_finalize);
+ (CamelObjectInitFunc) nntp_folder_init,
+ (CamelObjectFinalizeFunc) nntp_folder_finalise);
}
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((CamelObject *)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)
{
- CamelFolder *folder = CAMEL_FOLDER (camel_object_new (CAMEL_NNTP_FOLDER_TYPE));
- CamelNNTPFolder *nntp_folder = CAMEL_NNTP_FOLDER (folder);
- const gchar *root_dir_path;
+ CamelFolder *folder;
+ CamelNNTPFolder *nntp_folder;
+ char *root;
+ CamelService *service;
+#ifdef ASYNC_SUMMARY
+ struct _folder_check_msg *m;
+#endif
- camel_folder_construct (folder, parent, folder_name, folder_name);
- folder->folder_flags |= (CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY |
- CAMEL_FOLDER_HAS_SEARCH_CAPABILITY);
+ service = (CamelService *)parent;
+ root = camel_session_get_storage_path(service->session, service, ex);
+ if (root == NULL)
+ return NULL;
+
+ /* If this doesn't work, stuff wont save, but let it continue anyway */
+ (void) camel_mkdir_hier(root, 0777);
+
+ folder = (CamelFolder *) camel_object_new (CAMEL_NNTP_FOLDER_TYPE);
+ nntp_folder = (CamelNNTPFolder *)folder;
- root_dir_path = camel_nntp_store_get_toplevel_dir (CAMEL_NNTP_STORE(folder->parent_store));
- nntp_folder->summary_file_path = g_strdup_printf ("%s/%s-ev-summary",
- root_dir_path,
- folder->name);
+ camel_folder_construct (folder, parent, folder_name, folder_name);
+ folder->folder_flags |= CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY|CAMEL_FOLDER_HAS_SEARCH_CAPABILITY;
- folder->summary = camel_folder_summary_new ();
- camel_folder_summary_set_filename (folder->summary,
- nntp_folder->summary_file_path);
+ nntp_folder->storage_path = g_strdup_printf("%s/%s", root, folder->full_name);
+ g_free(root);
+ folder->summary = (CamelFolderSummary *)camel_nntp_summary_new(nntp_folder);
camel_folder_summary_load (folder->summary);
-
- camel_nntp_get_headers (CAMEL_FOLDER( folder )->parent_store,
- nntp_folder, ex);
- if (camel_exception_get_id (ex)) {
- camel_object_unref (CAMEL_OBJECT (folder));
- return NULL;
+#ifdef ASYNC_SUMMARY
+ m = camel_session_thread_msg_new(service->session, &folder_check_ops, sizeof(*m));
+ m->folder = nntp_folder;
+ camel_object_ref((CamelObject *)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_object_unref((CamelObject *)folder);
+ folder = NULL;
}
+#endif
- /* XXX check return value */
- camel_folder_summary_save (folder->summary);
-
return folder;
}