From 70f49bc0d7ce40521c4c99b7c9dbe6255db2c788 Mon Sep 17 00:00:00 2001 From: Meilof Veeningen Date: Mon, 12 Jan 2004 22:20:40 +0000 Subject: now based on discofolder, cache_message and append_message implemented, 2004-01-12 Meilof Veeningen * providers/nntp/camel-nntp-folder.[ch]: now based on discofolder, cache_message and append_message implemented, only retrieve messages when we are subscribed, some stubs * providers/nntp/camel-nntp-provider.c: newsgroup name display settings, password authentication, fix for check_equal where the protocols wouldn't be checked * providers/nntp/camel-nntp-store.[ch]: base on discostore with online/offline support, subscriptions, downloading changed parts of the newsgroup list, some stubs, authentication, automatic reconnect * providers/nntp/camel-nntp-store-summary.[ch]: NNTP store summary based on IMAP code * providers/nntp/camel-nntp-summary.c: save summary after xover * providers/nntp/camel-nntp-grouplist.h: added CamelNNTPGroupList structs * providers/nntp/Makefile.am: added store summary svn path=/trunk/; revision=24178 --- camel/providers/nntp/camel-nntp-store-summary.c | 430 ++++++++++++++++++++++++ 1 file changed, 430 insertions(+) create mode 100644 camel/providers/nntp/camel-nntp-store-summary.c (limited to 'camel/providers/nntp/camel-nntp-store-summary.c') diff --git a/camel/providers/nntp/camel-nntp-store-summary.c b/camel/providers/nntp/camel-nntp-store-summary.c new file mode 100644 index 0000000000..8cade2a5eb --- /dev/null +++ b/camel/providers/nntp/camel-nntp-store-summary.c @@ -0,0 +1,430 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2002 Ximian Inc. + * + * Authors: Michael Zucchi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* currently, this is just a straigt s/imap/nntp from the IMAP file*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "camel-nntp-store-summary.h" + +#include "camel-file-utils.h" + +#include "e-util/md5-utils.h" +#include "e-util/e-memory.h" + +#include "camel-private.h" +#include "camel-utf8.h" + +#define d(x) +#define io(x) /* io debug */ + +#define CAMEL_NNTP_STORE_SUMMARY_VERSION_0 (0) + +#define CAMEL_NNTP_STORE_SUMMARY_VERSION (0) + +#define _PRIVATE(o) (((CamelNNTPStoreSummary *)(o))->priv) + +static int summary_header_load(CamelStoreSummary *, FILE *); +static int summary_header_save(CamelStoreSummary *, FILE *); + +/*static CamelStoreInfo * store_info_new(CamelStoreSummary *, const char *);*/ +static CamelStoreInfo * store_info_load(CamelStoreSummary *, FILE *); +static int store_info_save(CamelStoreSummary *, FILE *, CamelStoreInfo *); +static void store_info_free(CamelStoreSummary *, CamelStoreInfo *); + +static const char *store_info_string(CamelStoreSummary *, const CamelStoreInfo *, int); +static void store_info_set_string(CamelStoreSummary *, CamelStoreInfo *, int, const char *); + +static void camel_nntp_store_summary_class_init (CamelNNTPStoreSummaryClass *klass); +static void camel_nntp_store_summary_init (CamelNNTPStoreSummary *obj); +static void camel_nntp_store_summary_finalise (CamelObject *obj); + +static CamelStoreSummaryClass *camel_nntp_store_summary_parent; + +static void +camel_nntp_store_summary_class_init (CamelNNTPStoreSummaryClass *klass) +{ + CamelStoreSummaryClass *ssklass = (CamelStoreSummaryClass *)klass; + + ssklass->summary_header_load = summary_header_load; + ssklass->summary_header_save = summary_header_save; + + /*ssklass->store_info_new = store_info_new;*/ + ssklass->store_info_load = store_info_load; + ssklass->store_info_save = store_info_save; + ssklass->store_info_free = store_info_free; + + ssklass->store_info_string = store_info_string; + ssklass->store_info_set_string = store_info_set_string; +} + +static void +camel_nntp_store_summary_init (CamelNNTPStoreSummary *s) +{ + /*struct _CamelNNTPStoreSummaryPrivate *p; + + p = _PRIVATE(s) = g_malloc0(sizeof(*p));*/ + + ((CamelStoreSummary *) s)->store_info_size = sizeof (CamelNNTPStoreInfo); + s->version = CAMEL_NNTP_STORE_SUMMARY_VERSION; + memset (&s->last_newslist, 0, sizeof (s->last_newslist)); +} + +static void +camel_nntp_store_summary_finalise (CamelObject *obj) +{ + /*struct _CamelNNTPStoreSummaryPrivate *p;*/ + /*CamelNNTPStoreSummary *s = (CamelNNTPStoreSummary *)obj;*/ + + /*p = _PRIVATE(obj); + g_free(p);*/ +} + +CamelType +camel_nntp_store_summary_get_type (void) +{ + static CamelType type = CAMEL_INVALID_TYPE; + + if (type == CAMEL_INVALID_TYPE) { + camel_nntp_store_summary_parent = (CamelStoreSummaryClass *)camel_store_summary_get_type(); + type = camel_type_register((CamelType)camel_nntp_store_summary_parent, "CamelNNTPStoreSummary", + sizeof (CamelNNTPStoreSummary), + sizeof (CamelNNTPStoreSummaryClass), + (CamelObjectClassInitFunc) camel_nntp_store_summary_class_init, + NULL, + (CamelObjectInitFunc) camel_nntp_store_summary_init, + (CamelObjectFinalizeFunc) camel_nntp_store_summary_finalise); + } + + return type; +} + +/** + * camel_nntp_store_summary_new: + * + * Create a new CamelNNTPStoreSummary object. + * + * Return value: A new CamelNNTPStoreSummary widget. + **/ +CamelNNTPStoreSummary * +camel_nntp_store_summary_new (void) +{ + return (CamelNNTPStoreSummary *) camel_object_new (camel_nntp_store_summary_get_type ()); +} + +/** + * camel_nntp_store_summary_full_name: + * @s: + * @path: + * + * Retrieve a summary item by full name. + * + * A referenced to the summary item is returned, which may be + * ref'd or free'd as appropriate. + * + * Return value: The summary item, or NULL if the @full_name name + * is not available. + * It must be freed using camel_store_summary_info_free(). + **/ +CamelNNTPStoreInfo * +camel_nntp_store_summary_full_name(CamelNNTPStoreSummary *s, const char *full_name) +{ + int count, i; + CamelNNTPStoreInfo *info; + + count = camel_store_summary_count ((CamelStoreSummary *) s); + for (i = 0; i < count; i++) { + info = (CamelNNTPStoreInfo *)camel_store_summary_index ((CamelStoreSummary *) s, i); + if (info) { + if (strcmp (info->full_name, full_name) == 0) + return info; + camel_store_summary_info_free ((CamelStoreSummary *) s, (CamelStoreInfo *)info); + } + } + + return NULL; +} + +char * +camel_nntp_store_summary_full_to_path (CamelNNTPStoreSummary *s, const char *full_name, char dir_sep) +{ + char *path, *p; + int c; + const char *f; + + if (dir_sep != '/') { + p = path = g_alloca (strlen (full_name) * 3 + 1); + f = full_name; + while ((c = *f++ & 0xff)) { + if (c == dir_sep) + *p++ = '/'; + else if (c == '/' || c == '%') + p += sprintf (p, "%%%02X", c); + else + *p++ = c; + } + *p = 0; + } else + path = (char *) full_name; + + return camel_utf7_utf8 (path); +} + +static guint32 +hexnib (guint32 c) +{ + if (c >= '0' && c <= '9') + return c-'0'; + else if (c >= 'A' && c <= 'Z') + return c - 'A' + 10; + else + return 0; +} + +char * +camel_nntp_store_summary_path_to_full (CamelNNTPStoreSummary *s, const char *path, char dir_sep) +{ + unsigned char *full, *f; + guint32 c, v = 0; + const char *p; + int state=0; + char *subpath, *last = NULL; + CamelStoreInfo *si; + + /* check to see if we have a subpath of path already defined */ + subpath = g_alloca (strlen (path) + 1); + strcpy (subpath, path); + do { + si = camel_store_summary_path ((CamelStoreSummary *) s, subpath); + if (si == NULL) { + last = strrchr (subpath, '/'); + if (last) + *last = 0; + } + } while (si == NULL && last); + + /* path is already present, use the raw version we have */ + if (si && strlen (subpath) == strlen (path)) { + f = g_strdup (camel_nntp_store_info_full_name (s, si)); + camel_store_summary_info_free ((CamelStoreSummary *) s, si); + return f; + } + + f = full = g_alloca (strlen (path)*2+1); + if (si) + p = path + strlen (subpath); + else + p = path; + + while ((c = camel_utf8_getc ((const unsigned char **) &p))) { + switch (state) { + case 0: + if (c == '%') { + state = 1; + } else { + if (c == '/') + c = dir_sep; + camel_utf8_putc(&f, c); + } + break; + case 1: + state = 2; + v = hexnib (c) << 4; + break; + case 2: + state = 0; + v |= hexnib (c); + camel_utf8_putc (&f, v); + break; + } + } + camel_utf8_putc (&f, c); + + /* merge old path part if required */ + f = camel_utf8_utf7 (full); + if (si) { + full = g_strdup_printf ("%s%s", camel_nntp_store_info_full_name (s, si), f); + g_free (f); + camel_store_summary_info_free ((CamelStoreSummary *) s, si); + f = full; + } + + return f; +} + +CamelNNTPStoreInfo * +camel_nntp_store_summary_add_from_full (CamelNNTPStoreSummary *s, const char *full, char dir_sep) +{ + CamelNNTPStoreInfo *info; + char *pathu8; + int len; + char *full_name; + + d(printf("adding full name '%s' '%c'\n", full, dir_sep)); + + len = strlen (full); + full_name = g_alloca (len+1); + strcpy(full_name, full); + if (full_name[len-1] == dir_sep) + full_name[len-1] = 0; + + info = camel_nntp_store_summary_full_name (s, full_name); + if (info) { + camel_store_summary_info_free ((CamelStoreSummary *) s, (CamelStoreInfo *) info); + d(printf(" already there\n")); + return info; + } + + pathu8 = camel_nntp_store_summary_full_to_path (s, full_name, dir_sep); + + info = (CamelNNTPStoreInfo *) camel_store_summary_add_from_path ((CamelStoreSummary *) s, pathu8); + if (info) { + d(printf(" '%s' -> '%s'\n", pathu8, full_name)); + camel_store_info_set_string((CamelStoreSummary *)s, (CamelStoreInfo *)info, CAMEL_NNTP_STORE_INFO_FULL_NAME, full_name); + } else + d(printf(" failed\n")); + + return info; +} + +static int +summary_header_load (CamelStoreSummary *s, FILE *in) +{ + CamelNNTPStoreSummary *is = (CamelNNTPStoreSummary *) s; + gint32 version, nil; + + if (camel_nntp_store_summary_parent->summary_header_load ((CamelStoreSummary *) s, in) == -1 + || camel_file_util_decode_fixed_int32 (in, &version) == -1) + return -1; + + is->version = version; + + if (version < CAMEL_NNTP_STORE_SUMMARY_VERSION_0) { + g_warning("Store summary header version too low"); + return -1; + } + + if (fread (is->last_newslist, 1, NNTP_DATE_SIZE, in) < NNTP_DATE_SIZE) + return -1; + + camel_file_util_decode_fixed_int32 (in, &nil); + + return 0; +} + +static int +summary_header_save (CamelStoreSummary *s, FILE *out) +{ + CamelNNTPStoreSummary *is = (CamelNNTPStoreSummary *) s; + + /* always write as latest version */ + if (camel_nntp_store_summary_parent->summary_header_save ((CamelStoreSummary *) s, out) == -1 + || camel_file_util_encode_fixed_int32 (out, CAMEL_NNTP_STORE_SUMMARY_VERSION) == -1 + || fwrite (is->last_newslist, 1, NNTP_DATE_SIZE, out) < NNTP_DATE_SIZE + || camel_file_util_encode_fixed_int32 (out, 0) == -1) + return -1; + + return 0; +} + +static CamelStoreInfo * +store_info_load (CamelStoreSummary *s, FILE *in) +{ + CamelNNTPStoreInfo *ni; + + ni = (CamelNNTPStoreInfo *) camel_nntp_store_summary_parent->store_info_load (s, in); + if (ni) { + if (camel_file_util_decode_string (in, &ni->full_name) == -1) { + camel_store_summary_info_free (s, (CamelStoreInfo *) ni); + ni = NULL; + } + /* set the URL */ + } + + return (CamelStoreInfo *) ni; +} + +static int +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) + return -1; + + return 0; +} + +static void +store_info_free (CamelStoreSummary *s, CamelStoreInfo *mi) +{ + CamelNNTPStoreInfo *nsi = (CamelNNTPStoreInfo *) mi; + + g_free (nsi->full_name); + camel_nntp_store_summary_parent->store_info_free (s, mi); +} + +static const char * +store_info_string(CamelStoreSummary *s, const CamelStoreInfo *mi, int type) +{ + CamelNNTPStoreInfo *nsi = (CamelNNTPStoreInfo *)mi; + + /* FIXME: Locks? */ + + g_assert (mi != NULL); + + switch (type) { + case CAMEL_NNTP_STORE_INFO_FULL_NAME: + return nsi->full_name; + default: + return camel_nntp_store_summary_parent->store_info_string(s, mi, type); + } +} + +static void +store_info_set_string(CamelStoreSummary *s, CamelStoreInfo *mi, int type, const char *str) +{ + CamelNNTPStoreInfo *nsi = (CamelNNTPStoreInfo *)mi; + + g_assert(mi != NULL); + + switch (type) { + case CAMEL_NNTP_STORE_INFO_FULL_NAME: + d(printf("Set full name %s -> %s\n", nsi->full_name, str)); + CAMEL_STORE_SUMMARY_LOCK(s, summary_lock); + g_free (nsi->full_name); + nsi->full_name = g_strdup (str); + CAMEL_STORE_SUMMARY_UNLOCK(s, summary_lock); + break; + default: + camel_nntp_store_summary_parent->store_info_set_string (s, mi, type, str); + break; + } +} -- cgit