aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/mbox/camel-mbox-summary.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/mbox/camel-mbox-summary.c')
-rw-r--r--camel/providers/mbox/camel-mbox-summary.c1556
1 files changed, 1197 insertions, 359 deletions
diff --git a/camel/providers/mbox/camel-mbox-summary.c b/camel/providers/mbox/camel-mbox-summary.c
index e15bb13b03..11f1c5779a 100644
--- a/camel/providers/mbox/camel-mbox-summary.c
+++ b/camel/providers/mbox/camel-mbox-summary.c
@@ -1,420 +1,1258 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-
-/*
- * Author : Bertrand Guiheneuf <bertrand@helixcode.com>
+/*
+ * Copyright (C) 2000 Helix Code Inc.
*
- * Copyright (C) 1999 - 2000 Helix Code .
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
+ * Authors: Michael Zucchi <notzed@helixcode.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
*
- * 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.
+ * 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 Library 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
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
-#include <config.h>
-
-#include "camel-exception.h"
-#include "camel-mbox-folder.h"
-#include "camel-mbox-summary.h"
-#include "md5-utils.h"
-
-
-#include <sys/stat.h>
-#include <unistd.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <fcntl.h>
-#include <dirent.h>
+#include <unistd.h>
+#include <sys/uio.h>
+
#include <stdio.h>
#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include <camel/camel-mime-parser.h>
+#include <camel/camel-mime-filter.h>
+#include <camel/camel-mime-filter-basic.h>
+#include <camel/camel-mime-filter-charset.h>
+#include <camel/camel-mime-filter-index.h>
+
+#include <camel/camel-mime-utils.h>
+
+#include "camel-mbox-summary.h"
+
#include <errno.h>
+#include <ctype.h>
#include <netinet/in.h>
-static CamelFolderSummaryClass *parent_class = NULL;
+#define d(x)
-static int count_messages (CamelFolderSummary *summary);
-static int count_subfolders (CamelFolderSummary *summary);
-static GPtrArray *get_subfolder_info (CamelFolderSummary *summary,
- int first, int count);
-static GPtrArray *get_message_info (CamelFolderSummary *summary,
- int first, int count);
-static void finalize (GtkObject *object);
+#define CAMEL_MBOX_SUMMARY_VERSION 2
-static void
-camel_mbox_summary_class_init (CamelMboxSummaryClass *camel_mbox_summary_class)
+static int safe_write(int fd, char *buffer, size_t towrite);
+static void camel_mbox_summary_add(CamelMboxSummary *s, CamelMboxMessageInfo *info);
+
+/*
+ Disk file format?
+
+ message uid
+message-block
+ date:
+ date received?
+
+ subject: (unicode encoded)
+ from: (unicode encoded)
+ to: (unicode)
+
+ content-block
+
+content-block
+ content-type: ; params;
+ content-id:
+ content-description:
+ content-transfer-encoding:
+ message-start:
+ header-size:
+ body-size:
+
+ message-block
+ multipart-block
+
+ */
+
+/* pah, i dont care, its almost no code and it works, dont need a glist */
+struct _node {
+ struct _node *next;
+};
+
+static struct _node *
+my_list_append(struct _node **list, struct _node *n)
+{
+ struct _node *ln = (struct _node *)list;
+ while (ln->next)
+ ln = ln->next;
+ n->next = 0;
+ ln->next = n;
+ return n;
+}
+
+static int
+my_list_size(struct _node **list)
+{
+ int len = 0;
+ struct _node *ln = (struct _node *)list;
+ while (ln->next) {
+ ln = ln->next;
+ len++;
+ }
+ return len;
+}
+
+/* low-level io functions */
+static int
+encode_int (FILE *out, gint32 value)
+{
+ int i;
+
+ for (i=28;i>0;i-=7) {
+ if (value >= (1<<i)) {
+ unsigned int c = (value>>i) & 0x7f;
+ if (fputc(c, out) == -1)
+ return -1;
+ }
+ }
+ return fputc(value | 0x80, out);
+}
+
+static gint32
+decode_int (FILE *in)
{
- GtkObjectClass *gtk_object_class =
- GTK_OBJECT_CLASS (camel_mbox_summary_class);
- CamelFolderSummaryClass *camel_folder_summary_class =
- CAMEL_FOLDER_SUMMARY_CLASS (camel_mbox_summary_class);
+ gint32 value=0, v;
- parent_class = gtk_type_class (camel_folder_summary_get_type ());
+ /* until we get the last byte, keep decoding 7 bits at a time */
+ while ( ((v = fgetc(in)) & 0x80) == 0 && v!=EOF) {
+ value |= v;
+ value <<= 7;
+ }
+ value |= (v&0x7f);
+ return value;
+}
- /* virtual method override */
- camel_folder_summary_class->count_messages = count_messages;
- camel_folder_summary_class->count_subfolders = count_subfolders;
- camel_folder_summary_class->get_subfolder_info = get_subfolder_info;
- camel_folder_summary_class->get_message_info = get_message_info;
+static int
+encode_fixed_int (FILE *out, gint32 value)
+{
+ guint32 save;
- gtk_object_class->finalize = finalize;
+ save = htonl(value);
+ return fwrite(&save, sizeof(save), 1, out);
}
+static gint32
+decode_fixed_int (FILE *out)
+{
+ guint32 save;
-GtkType
-camel_mbox_summary_get_type (void)
+ if (fread(&save, sizeof(save), 1, out) != -1) {
+ return ntohl(save);
+ } else {
+ return -1;
+ }
+}
+
+/* should be sorted, for binary search */
+/* This is a tokenisation mechanism for strings written to the
+ summary - to save space.
+ This list can have at most 31 words. */
+static char * tokens[] = {
+ "7bit",
+ "8bit",
+ "alternative",
+ "application",
+ "base64",
+ "boundary",
+ "charset",
+ "filename",
+ "html",
+ "image",
+ "iso-8859-1",
+ "iso-8859-8",
+ "message",
+ "mixed",
+ "multipart",
+ "name",
+ "octet-stream",
+ "parallel",
+ "plain",
+ "quoted-printable",
+ "rfc822",
+ "text",
+ "us-ascii", /* 23 words */
+};
+
+#define tokens_len (sizeof(tokens)/sizeof(tokens[0]))
+
+/* baiscally ...
+ 0 = null
+ 1-tokens_len == tokens[id-1]
+ >=32 string, length = n-32
+*/
+
+static int
+encode_string (FILE *out, char *str)
{
- static GtkType camel_mbox_summary_type = 0;
+ if (str == NULL) {
+ return encode_int(out, 0);
+ } else {
+ int len = strlen(str);
+ int i, token=-1;
+
+ if (len <= 16) {
+ char lower[32];
+
+ for (i=0;i<len;i++)
+ lower[i] = tolower(str[i]);
+ lower[i] = 0;
+ for (i=0;i<tokens_len;i++) {
+ if (!strcmp(tokens[i], lower)) {
+ token = i;
+ break;
+ }
+ }
+ }
+ if (token != -1) {
+ return encode_int(out, token+1);
+ } else {
+ if (encode_int(out, len+32) == -1)
+ return -1;
+ return fwrite(str, len, 1, out);
+ }
+ }
+ return 0;
+}
- if (!camel_mbox_summary_type) {
- GtkTypeInfo camel_mbox_summary_info =
- {
- "CamelMboxSummary",
- sizeof (CamelMboxSummary),
- sizeof (CamelMboxSummaryClass),
- (GtkClassInitFunc) camel_mbox_summary_class_init,
- (GtkObjectInitFunc) NULL,
- /* reserved_1 */ NULL,
- /* reserved_2 */ NULL,
- (GtkClassInitFunc) NULL,
- };
+static char *
+decode_string (FILE *in)
+{
+ char *ret;
+ int len;
+
+ len = decode_int(in);
- camel_mbox_summary_type = gtk_type_unique (camel_folder_summary_get_type (), &camel_mbox_summary_info);
+ if (len<32) {
+ if (len <= 0) {
+ ret = NULL;
+ } else if (len<= tokens_len) {
+ ret = g_strdup(tokens[len-1]);
+ } else {
+ g_warning("Invalid token encountered: %d", len);
+ ret = NULL;
+ }
+ } else if (len > 10240) {
+ g_warning("Got broken string header length: %d bytes", len);
+ ret = NULL;
+ } else {
+ len -= 32;
+ ret = g_malloc(len+1);
+ if (fread(ret, len, 1, in) == -1) {
+ g_free(ret);
+ return NULL;
+ }
+ ret[len]=0;
}
- return camel_mbox_summary_type;
+ return ret;
}
+
+
+/* allocation functions */
+
static void
-finalize (GtkObject *object)
+body_part_dump(CamelMboxMessageContentInfo *bs, int depth)
{
- CamelMboxSummary *summary = CAMEL_MBOX_SUMMARY (object);
- CamelMboxSummaryInformation *info;
- int i;
+ CamelMboxMessageContentInfo *c;
+ char *prefix;
- for (i = 0; i < summary->message_info->len; i++) {
- info = &(((CamelMboxSummaryInformation *)summary->message_info->data)[i]);
- g_free (info->headers.subject);
- g_free (info->headers.sender);
- g_free (info->headers.to);
- g_free (info->headers.sent_date);
- g_free (info->headers.received_date);
- g_free (info->headers.uid);
+ if (bs == NULL)
+ return;
+
+ prefix = alloca(depth*2+1);
+ memset(prefix, ' ', depth*2);
+ prefix[depth*2]=0;
+ printf("%scontent-range: %d %d %d\n", prefix, (int)bs->pos, (int)bs->bodypos, (int)bs->endpos);
+ printf("%scontent-type: %s/%s\n", prefix, bs->info.type?bs->info.type->type:"?", bs->info.type?bs->info.type->subtype:"?");
+ printf("%scontent-id: %s\n", prefix, bs->info.id);
+ printf("%scontent-description: %s\n", prefix, bs->info.description);
+ printf("%scontent-transfer-encoding: %s\n", prefix, bs->info.encoding);
+ c = (CamelMboxMessageContentInfo *)bs->info.childs;
+ while (c) {
+ printf("%s -- \n", prefix);
+ body_part_dump(c, depth+1);
+ c = (CamelMboxMessageContentInfo *)c->info.next;
}
- g_array_free (summary->message_info, TRUE);
+}
- GTK_OBJECT_CLASS (parent_class)->finalize (object);
-}
+static void
+message_struct_dump(CamelMboxMessageInfo *ms)
+{
+ char *tmp;
-static int
-count_messages (CamelFolderSummary *summary)
+ if (ms == NULL) {
+ printf("Empty message?\n");
+ return;
+ }
+
+ printf("Subject: %s\n", ms->info.subject);
+ printf("From: %s\n", ms->info.from);
+ printf("To: %s\n", ms->info.to);
+ tmp = header_format_date(ms->info.date_sent, 0);
+ printf("Date: %s\n", tmp);
+ g_free(tmp);
+ tmp = header_format_date(ms->info.date_received, 0);
+ printf("Date-Received: %s\n", tmp);
+ g_free(tmp);
+ printf("UID: %08x-%04x\n", atoi(ms->info.uid), ms->info.flags);
+ printf(" -- content ->\n");
+ body_part_dump((CamelMboxMessageContentInfo *)ms->info.content, 1);
+}
+
+static CamelMboxMessageContentInfo *
+body_part_new(CamelMimeParser *mp, CamelMboxMessageContentInfo *parent, int start, int body)
{
- return CAMEL_MBOX_SUMMARY (summary)->nb_message;
+ CamelMboxMessageContentInfo *bs;
+
+ bs = g_malloc0(sizeof(*bs));
+
+ bs->info.parent = (CamelMessageContentInfo *)parent;
+
+ bs->info.type = camel_mime_parser_content_type(mp);
+ header_content_type_ref(bs->info.type);
+
+ bs->info.id = header_msgid_decode(camel_mime_parser_header(mp, "content-id", NULL));
+ bs->info.description = header_decode_string(camel_mime_parser_header(mp, "content-description", NULL));
+ bs->info.encoding = header_content_encoding_decode(camel_mime_parser_header(mp, "content-transfer-encoding", NULL));
+
+ /* not sure what to set here? */
+ bs->pos = start;
+ bs->bodypos = body;
+ bs->endpos = -1;
+
+ if (parent)
+ my_list_append((struct _node **)&parent->info.childs, (struct _node *)bs);
+
+ return bs;
+}
+
+static CamelMboxMessageInfo *
+message_struct_new(CamelMimeParser *mp, CamelMboxMessageContentInfo *parent, int start, int body, off_t xev_offset)
+{
+ CamelMboxMessageInfo *ms;
+
+ ms = g_malloc0(sizeof(*ms));
+
+ /* FIXME: what about cc, sender vs from? */
+ ms->info.subject = g_strdup(camel_mime_parser_header(mp, "subject", NULL));
+ ms->info.from = g_strdup(camel_mime_parser_header(mp, "from", NULL));
+ ms->info.to = g_strdup(camel_mime_parser_header(mp, "to", NULL));
+
+ ms->info.date_sent = header_decode_date(camel_mime_parser_header(mp, "date", NULL), NULL);
+ ms->info.date_received = 0;
+
+ ms->info.content = (CamelMessageContentInfo *)body_part_new(mp, parent, start, body);
+ ms->xev_offset = xev_offset;
+ return ms;
+}
+
+static void
+body_part_free(CamelMboxMessageContentInfo *bs)
+{
+ CamelMboxMessageContentInfo *c, *cn;
+
+ c = (CamelMboxMessageContentInfo *)bs->info.childs;
+ while (c) {
+ cn = (CamelMboxMessageContentInfo *)c->info.next;
+ body_part_free(c);
+ c = cn;
+ }
+ g_free(bs->info.id);
+ g_free(bs->info.description);
+ g_free(bs->info.encoding);
+ header_content_type_unref(bs->info.type);
+ g_free(bs);
+}
+
+static void
+message_struct_free(CamelMboxMessageInfo *ms)
+{
+ g_free(ms->info.subject);
+ g_free(ms->info.to);
+ g_free(ms->info.from);
+ body_part_free((CamelMboxMessageContentInfo *)ms->info.content);
+ g_free(ms);
+}
+
+
+/* IO functions */
+static CamelMboxMessageContentInfo *
+body_part_load(FILE *in)
+{
+ CamelMboxMessageContentInfo *bs = NULL, *c;
+ struct _header_content_type *ct;
+ char *type;
+ char *subtype;
+ int i, count;
+
+ d(printf("got content-block\n"));
+ bs = g_malloc0(sizeof(*bs));
+ bs->pos = decode_int(in);
+ bs->bodypos = bs->pos + decode_int(in);
+ bs->endpos = bs->pos + decode_int(in);
+
+ /* do content type */
+ d(printf("got content-type\n"));
+ type = decode_string(in);
+ subtype = decode_string(in);
+
+ ct = header_content_type_new(type, subtype);
+ bs->info.type = ct;
+ count = decode_int(in);
+ d(printf("getting %d params\n", count));
+ for (i=0;i<count;i++) {
+ char *name = decode_string(in);
+ char *value = decode_string(in);
+
+ d(printf(" %s = \"%s\"\n", name, value));
+
+ header_content_type_set_param(ct, name, value);
+ /* FIXME: do this so we dont have to double alloc/free */
+ g_free(name);
+ g_free(value);
+ }
+
+ d(printf("got content-id\n"));
+ bs->info.id = decode_string(in);
+ d(printf("got content-description\n"));
+ bs->info.description = decode_string(in);
+ d(printf("got content-encoding\n"));
+ bs->info.encoding = decode_string(in);
+
+ count = decode_int(in);
+ d(printf("got children, %d\n", count));
+ for (i=0;i<count;i++) {
+ c = body_part_load(in);
+ if (c) {
+ my_list_append((struct _node **)&bs->info.childs, (struct _node *)c);
+ c->info.parent = (CamelMessageContentInfo *)bs;
+ } else {
+ printf("Cannot load child\n");
+ }
+ }
+
+ return bs;
}
static int
-count_subfolders (CamelFolderSummary *summary)
+body_part_save(FILE *out, CamelMboxMessageContentInfo *bs)
{
- /* XXX */
- g_warning ("CamelMboxSummary::count_subfolders not implemented");
+ CamelMboxMessageContentInfo *c, *cn;
+ struct _header_content_type *ct;
+ struct _header_param *hp;
+
+ encode_int(out, bs->pos);
+ encode_int(out, bs->bodypos - bs->pos);
+ encode_int(out, bs->endpos - bs->pos);
+
+ ct = bs->info.type;
+ if (ct) {
+ encode_string(out, ct->type);
+ encode_string(out, ct->subtype);
+ encode_int(out, my_list_size((struct _node **)&ct->params));
+ hp = ct->params;
+ while (hp) {
+ encode_string(out, hp->name);
+ encode_string(out, hp->value);
+ hp = hp->next;
+ }
+ } else {
+ encode_string(out, NULL);
+ encode_string(out, NULL);
+ encode_int(out, 0);
+ }
+ encode_string(out, bs->info.id);
+ encode_string(out, bs->info.description);
+ encode_string(out, bs->info.encoding);
+
+ encode_int(out, my_list_size((struct _node **)&bs->info.childs));
+
+ c = (CamelMboxMessageContentInfo *)bs->info.childs;
+ while (c) {
+ cn = (CamelMboxMessageContentInfo *)c->info.next;
+ body_part_save(out, c);
+ c = cn;
+ }
+
return 0;
}
-static GPtrArray *
-get_subfolder_info (CamelFolderSummary *summary, int first, int count)
+static CamelMboxMessageInfo *
+message_struct_load(FILE *in)
{
- /* XXX */
- g_warning ("CamelMboxSummary::count_subfolders not implemented");
+ CamelMboxMessageInfo *ms;
+
+ ms = g_malloc0(sizeof(*ms));
+
+ ms->info.uid = g_strdup_printf("%u", decode_int(in));
+ ms->info.flags = decode_int(in);
+ ms->info.date_sent = decode_int(in);
+ ms->info.date_received = decode_int(in);
+ ms->xev_offset = decode_int(in);
+ ms->info.subject = decode_string(in);
+ ms->info.from = decode_string(in);
+ ms->info.to = decode_string(in);
+ ms->info.content = (CamelMessageContentInfo *)body_part_load(in);
+
+ return ms;
+}
+
+static int
+message_struct_save(FILE *out, CamelMboxMessageInfo *ms)
+{
+ encode_int(out, strtoul(ms->info.uid, NULL, 10));
+ encode_int(out, ms->info.flags);
+ encode_int(out, ms->info.date_sent);
+ encode_int(out, ms->info.date_received);
+ encode_int(out, ms->xev_offset);
+ encode_string(out, ms->info.subject);
+ encode_string(out, ms->info.from);
+ encode_string(out, ms->info.to);
+ body_part_save(out, (CamelMboxMessageContentInfo *)ms->info.content);
+
return 0;
}
-static GPtrArray *
-get_message_info (CamelFolderSummary *summary, int first, int count)
+static unsigned int
+header_evolution_decode(const char *in, unsigned int *uid, unsigned int *flags)
{
- CamelMboxSummary *mbox_summary = CAMEL_MBOX_SUMMARY (summary);
- CamelMboxSummaryInformation *info;
- GPtrArray *arr;
+ char *header;
+ if (in
+ && (header = header_decode_token(&in))) {
+ if (strlen(header) == strlen("00000000-0000")
+ && sscanf(header, "%08x-%04x", uid, flags) == 2) {
+ g_free(header);
+ return *uid;
+ }
+ g_free(header);
+ }
- /* XXX bounds check */
+ return ~0;
+}
+
+static int
+safe_write(int fd, char *buffer, size_t towrite)
+{
+ size_t donelen;
+ size_t len;
- arr = g_ptr_array_new ();
- for (; count; count--) {
- info = &((CamelMboxSummaryInformation *)mbox_summary->message_info->data)[first++];
- g_ptr_array_add (arr, info);
+ donelen = 0;
+ while (donelen < towrite) {
+ len = write(fd, buffer + donelen, towrite - donelen);
+ if (len == -1) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ }
+ donelen += len;
}
+ return donelen;
+}
- return arr;
-}
-
-/**
- * camel_mbox_summary_save:
- * @summary:
- * @filename:
- * @ex:
- *
- * save the summary into a file
- **/
-void
-camel_mbox_summary_save (CamelMboxSummary *summary, const gchar *filename,
- CamelException *ex)
-{
- CamelMboxSummaryInformation *msg_info;
- guint cur_msg;
- guint field_length;
- gint fd;
- gint write_result; /* XXX use this */
- guint32 data;
-
- fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC,
- S_IRUSR | S_IWUSR);
- if (fd == -1) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
- "could not create the mbox summary "
- "file\n\t%s\nFull error is : %s\n",
- filename,
- strerror (errno));
- return;
+static int
+header_write(int fd, struct _header_raw *header, unsigned int uid, unsigned int flags)
+{
+ struct iovec iv[3];
+ int outlen = 0;
+
+ iv[1].iov_base = ":";
+ iv[1].iov_len = 1;
+
+ while (header) {
+ if (strcasecmp(header->name, "x-evolution")) {
+ int len;
+
+ iv[0].iov_base = header->name;
+ iv[0].iov_len = strlen(header->name);
+ iv[2].iov_base = header->value;
+ iv[2].iov_len = strlen(header->value);
+
+ do {
+ len = writev(fd, iv, 3);
+ } while (len == -1 && errno == EINTR);
+
+ if (len == -1)
+ return -1;
+ outlen += len;
+ }
+ header = header->next;
}
- /* We write the file out in network byte order, not because
- * that makes sense, but because it's easy.
- */
-
- data = htonl (CAMEL_MBOX_SUMMARY_VERSION);
- write (fd, &data, sizeof (data));
-
- data = htonl (summary->nb_message);
- write (fd, &data, sizeof (data));
- data = htonl (summary->next_uid);
- write (fd, &data, sizeof (data));
- data = htonl (summary->mbox_file_size);
- write (fd, &data, sizeof (data));
- data = htonl (summary->mbox_modtime);
- write (fd, &data, sizeof (data));
-
- for (cur_msg = 0; cur_msg < summary->nb_message; cur_msg++) {
- msg_info = (CamelMboxSummaryInformation *)
- (summary->message_info->data) + cur_msg;
-
- /* Write meta-info. */
- data = htonl (msg_info->position);
- write (fd, &data, sizeof (data));
- data = htonl (msg_info->size);
- write (fd, &data, sizeof (data));
- data = htonl (msg_info->x_evolution_offset);
- write (fd, &data, sizeof (data));
- data = htonl (msg_info->uid);
- write (fd, &data, sizeof (data));
- write (fd, &msg_info->status, 1);
-
- /* Write subject. */
- if (msg_info->headers.subject)
- field_length = strlen (msg_info->headers.subject);
- else
- field_length = 0;
- data = htonl (field_length);
- write (fd, &data, sizeof (data));
- if (msg_info->headers.subject)
- write (fd, msg_info->headers.subject, field_length);
-
- /* Write sender. */
- if (msg_info->headers.sender)
- field_length = strlen (msg_info->headers.sender);
- else
- field_length = 0;
- data = htonl (field_length);
- write (fd, &data, sizeof (data));
- if (msg_info->headers.sender)
- write (fd, msg_info->headers.sender, field_length);
-
- /* Write to. */
- if (msg_info->headers.to)
- field_length = strlen (msg_info->headers.to);
- else
- field_length = 0;
- data = htonl (field_length);
- write (fd, &data, sizeof (data));
- if (msg_info->headers.to)
- write (fd, msg_info->headers.to, field_length);
-
- /* Write sent date. */
- if (msg_info->headers.sent_date)
- field_length = strlen (msg_info->headers.sent_date);
- else
- field_length = 0;
- data = htonl (field_length);
- write (fd, &data, sizeof (data));
- if (msg_info->headers.sent_date)
- write (fd, msg_info->headers.sent_date, field_length);
-
- /* Write received date. */
- if (msg_info->headers.received_date)
- field_length = strlen (msg_info->headers.received_date);
+ return outlen;
+}
+
+/* returns -1 on error, else number of bytes written */
+int
+camel_mbox_summary_copy_block(int fromfd, int tofd, off_t readpos, size_t bytes)
+{
+ char buffer[4096];
+ int written = 0;
+ off_t pos, newpos;
+
+ pos = lseek(fromfd, 0, SEEK_CUR);
+ if (pos == -1)
+ return -1;
+
+ newpos = lseek(fromfd, readpos, SEEK_SET);
+ if (newpos == -1 || newpos != readpos)
+ goto error;
+
+ d(printf("oldpos = %d; copying %d from %d\n", (int)pos, (int)bytes, (int)readpos));
+
+ while (bytes>0) {
+ int toread, towrite, donelen;
+
+ toread = bytes;
+ if (bytes>4096)
+ toread = 4096;
else
- field_length = 0;
- data = htonl (field_length);
- write (fd, &data, sizeof (data));
- if (msg_info->headers.received_date)
- write (fd, msg_info->headers.received_date, field_length);
+ toread = bytes;
+ reread:
+ towrite = read(fromfd, buffer, toread);
+ if (towrite == -1) {
+ if (errno == EINTR || errno == EAGAIN)
+ goto reread;
+ goto error;
+ }
+
+ /* check for 'end of file' */
+ if (towrite == 0)
+ break;
+
+ if ( (donelen = safe_write(tofd, buffer, towrite)) == -1)
+ goto error;
+
+ written += donelen;
+ bytes -= donelen;
+ }
+
+ d(printf("written %d bytes\n", written));
+
+ newpos = lseek(fromfd, pos, SEEK_SET);
+ if (newpos == -1 || newpos != pos);
+ return -1;
+
+ return written;
+
+error:
+ lseek(fromfd, pos, SEEK_SET);
+ return -1;
+}
+
+#define SAVEIT
+
+static int index_folder(CamelMboxSummary *s, int startoffset)
+{
+ CamelMimeParser *mp;
+ int fd;
+ int fdout;
+ int state;
+
+ int toplevel = FALSE;
+ const char *xev;
+ char *data;
+ int datalen;
+
+ int enc_id=-1;
+ int chr_id=-1;
+ int idx_id=-1;
+ struct _header_content_type *ct;
+ int doindex=FALSE;
+ CamelMimeFilterCharset *mfc = NULL;
+ CamelMimeFilterIndex *mfi = NULL;
+ CamelMimeFilterBasic *mf64 = NULL, *mfqp = NULL;
+
+ CamelMboxMessageContentInfo *body = NULL, *parent = NULL;
+ CamelMboxMessageInfo *message = NULL;
+
+ int from_end = 0; /* start of message */
+ int from = 0; /* start of headers */
+ int last_write = 0; /* last written position */
+ int eof;
+ int write_offset = 0; /* how much does the dest differ from the source pos */
+ int old_offset = 0;
+
+ guint32 newuid;
+ off_t xevoffset = -1;
+
+ char *tmpname;
+
+ printf("indexing %s (%s) from %d\n", s->folder_path, s->summary_path, startoffset);
+
+ fd = open(s->folder_path, O_RDONLY);
+ if (fd==-1) {
+ perror("Can't open folder");
+ return -1;
}
- close (fd);
-}
-
-
-
-/**
- * camel_mbox_summary_load:
- * @filename:
- * @ex:
- *
- * load the summary from a file
- *
- * Return value:
- **/
-CamelMboxSummary *
-camel_mbox_summary_load (const gchar *filename, CamelException *ex)
-{
- CamelMboxSummaryInformation *msg_info;
- guint cur_msg;
- guint field_length;
- gint fd;
- CamelMboxSummary *summary;
- gint read_result;
- guint32 data;
-
- fd = open (filename, O_RDONLY);
- if (fd == -1) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INSUFFICIENT_PERMISSION,
- "could not open the mbox summary file\n"
- "\t%s\nFull error is : %s\n",
- filename, strerror (errno));
- return NULL;
+ tmpname = g_strdup_printf("%s.tmp", s->folder_path);
+
+ fdout = open(tmpname, O_WRONLY|O_CREAT|O_TRUNC, 0600);
+ if (fdout==-1) {
+ perror("Can't open output");
+ g_free(tmpname);
+ return -1;
}
- /* Verify version number. */
- read (fd, &data, sizeof(data));
- data = ntohl (data);
-
- if (data != CAMEL_MBOX_SUMMARY_VERSION) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_SUMMARY_INVALID,
- "This folder summary was written by "
- "%s version of this software.",
- data < CAMEL_MBOX_SUMMARY_VERSION ?
- "an older" : "a newer");
- return NULL;
+ mp = camel_mime_parser_new();
+ camel_mime_parser_init_with_fd(mp, fd);
+ camel_mime_parser_scan_from(mp, TRUE);
+
+ /* FIXME: cleaner fail code */
+ if (startoffset > 0) {
+ if (camel_mime_parser_seek(mp, startoffset, SEEK_SET) != startoffset) {
+ g_free(tmpname);
+ gtk_object_unref((GtkObject *)mp);
+ return -1;
+ }
}
- summary = CAMEL_MBOX_SUMMARY (gtk_object_new (camel_mbox_summary_get_type (), NULL));
-
- read (fd, &data, sizeof(data));
- summary->nb_message = ntohl (data);
- read (fd, &data, sizeof(data));
- summary->next_uid = ntohl (data);
- read (fd, &data, sizeof(data));
- summary->mbox_file_size = ntohl (data);
- read (fd, &data, sizeof(data));
- summary->mbox_modtime = ntohl (data);
-
- summary->message_info =
- g_array_new (FALSE, FALSE,
- sizeof (CamelMboxSummaryInformation));
- g_array_set_size (summary->message_info, summary->nb_message);
-
- for (cur_msg = 0; cur_msg < summary->nb_message; cur_msg++) {
- msg_info = (CamelMboxSummaryInformation *)
- (summary->message_info->data) + cur_msg;
-
- /* Read the meta-info. */
- read (fd, &data, sizeof(data));
- msg_info->position = ntohl (data);
- read (fd, &data, sizeof(data));
- msg_info->size = ntohl (data);
- read (fd, &data, sizeof(data));
- msg_info->x_evolution_offset = ntohl (data);
- read (fd, &data, sizeof(data));
- msg_info->uid = ntohl (data);
- msg_info->headers.uid = g_strdup_printf ("%d", msg_info->uid);
- read (fd, &msg_info->status, 1);
-
- /* Read the subject. */
- read (fd, &field_length, sizeof (field_length));
- field_length = ntohl (field_length);
- if (field_length > 0) {
- msg_info->headers.subject =
- g_new0 (gchar, field_length + 1);
- read (fd, msg_info->headers.subject, field_length);
- } else
- msg_info->headers.subject = NULL;
-
- /* Read the sender. */
- read (fd, &field_length, sizeof (field_length));
- field_length = ntohl (field_length);
- if (field_length > 0) {
- msg_info->headers.sender =
- g_new0 (gchar, field_length + 1);
- read (fd, msg_info->headers.sender, field_length);
- } else
- msg_info->headers.sender = NULL;
-
- /* Read the "to" field. */
- read (fd, &field_length, sizeof (field_length));
- field_length = ntohl (field_length);
- if (field_length > 0) {
- msg_info->headers.to =
- g_new0 (gchar, field_length + 1);
- read (fd, msg_info->headers.to, field_length);
- } else
- msg_info->headers.to = NULL;
-
- /* Read the sent date field. */
- read (fd, &field_length, sizeof (field_length));
- field_length = ntohl (field_length);
- if (field_length > 0) {
- msg_info->headers.sent_date =
- g_new0 (gchar, field_length + 1);
- read (fd, msg_info->headers.sent_date, field_length);
- } else
- msg_info->headers.sent_date = NULL;
-
- /* Read the received date field. */
- read (fd, &field_length, sizeof (field_length));
- field_length = ntohl (field_length);
- if (field_length > 0) {
- msg_info->headers.received_date =
- g_new0 (gchar, field_length + 1);
- read (fd, msg_info->headers.received_date,
- field_length);
- } else
- msg_info->headers.received_date = NULL;
- }
-
- close (fd);
- return summary;
-}
-
-
-/**
- * camel_mbox_summary_append_entries:
- * @summary:
- * @entries:
- *
- * append an entry to a summary
- **/
-void
-camel_mbox_summary_append_entries (CamelMboxSummary *summary, GArray *entries)
-{
-
- summary->message_info = g_array_append_vals (summary->message_info,
- entries->data,
- entries->len);
+ mfi = camel_mime_filter_index_new_ibex(s->index);
+
+ while ( (state = camel_mime_parser_step(mp, &data, &datalen)) != HSCAN_EOF ) {
+ switch(state) {
+ case HSCAN_FROM: /* starting a new message content */
+ /* save the current position */
+ d(printf("from = %d\n", (int)camel_mime_parser_tell(mp)));
+ toplevel = FALSE;
+ from = camel_mime_parser_tell(mp);
+ break;
+
+ case HSCAN_FROM_END:
+ d(printf("from-end = %d\n", (int)camel_mime_parser_tell(mp)));
+ d(printf("message from %d to %d\n", from_end, (int)camel_mime_parser_tell(mp)));
+ from_end = camel_mime_parser_tell(mp);
+ break;
+
+ case HSCAN_MESSAGE:
+ case HSCAN_MULTIPART:
+ case HSCAN_HEADER: /* starting a new header */
+ newuid=~0;
+ if (!toplevel) {
+ char name[32];
+ unsigned int olduid, oldflags;
+ int headerlen;
+ int docopy = FALSE;
+
+ /* check for X-Evolution header ... if its there, nothing to do (skip content) */
+ xev = camel_mime_parser_header(mp, "x-evolution", &xevoffset);
+ if (xev) {
+ d(printf("An x-evolution header exists at: %d = %s\n", xevoffset + write_offset, xev));
+ xevoffset = xevoffset + write_offset;
+ if (header_evolution_decode(xev, &olduid, &oldflags) != ~0) {
+ d(printf(" uid = %d = %x\n", olduid, olduid));
+ newuid = olduid;
+#if 0
+ while (camel_mime_parser_step(mp, &data, &datalen) != HSCAN_FROM_END)
+ ;
+ break;
+#endif
+ } else {
+ printf("Invalid xev header? I need to write out a new one ...\n");
+ }
+ }
+
+ toplevel = TRUE;
+
+ /* assign a new uid for this message */
+ if (newuid == ~0) {
+ newuid = s->nextuid++;
+ docopy = TRUE;
+ } else {
+ /* make sure we account for this uid when assigning uid's */
+ /* this really needs a pre-scan pass ... *sigh* */
+ camel_mbox_summary_set_uid(s, newuid);
+ }
+
+ /* setup index name for this uid */
+ sprintf(name, "%x", newuid);
+ camel_mime_filter_index_set_name(mfi, name);
+ /* remove all references to this name from the index */
+ if (s->index)
+ ibex_unindex(s->index, name);
+
+ d(printf("Message content starts at %d\n", camel_mime_parser_tell(mp)));
+
+ if (docopy) {
+ /* now, copy over bits of mbox from last write, and insert the X-Evolution header (at the top of headers) */
+ /* if we already have a valid x-evolution header, use that, dont need to copy */
+ camel_mbox_summary_copy_block(fd, fdout, last_write, from-last_write);
+ last_write = from;
+
+ headerlen = header_write(fdout, camel_mime_parser_headers_raw(mp), newuid, 0);
+ sprintf(name, "X-Evolution: %08x-%04x\n\n", newuid, 0);
+ safe_write(fdout, name, strlen(name));
+ d(printf("new X-Evolution at %d\n", headerlen + from + write_offset));
+ xevoffset = headerlen + from + write_offset;
+ old_offset = write_offset;
+
+ write_offset += (headerlen - (camel_mime_parser_tell(mp)-from)) + strlen(name);
+ last_write = camel_mime_parser_tell(mp);
+ }
+ } else {
+ old_offset = write_offset;
+ }
+
+ /* we only care about the rest for actual content parts */
+ /* TODO: Cleanup, this is a huge mess */
+ if (state != HSCAN_HEADER) {
+ if (message == NULL) {
+ message = message_struct_new(mp, parent, camel_mime_parser_tell_start_headers(mp)+old_offset, camel_mime_parser_tell(mp)+write_offset, xevoffset);
+ parent = (CamelMboxMessageContentInfo *)message->info.content;
+ if (newuid != ~0) {
+ message->info.uid = g_strdup_printf("%u", newuid);
+ } else {
+ g_warning("This shouldn't happen?");
+ }
+ } else {
+ parent = body_part_new(mp, parent, camel_mime_parser_tell_start_headers(mp)+old_offset, camel_mime_parser_tell(mp)+write_offset);
+ }
+ break;
+ }
+
+ if (message == NULL) {
+ message = message_struct_new(mp, parent, camel_mime_parser_tell_start_headers(mp)+old_offset, camel_mime_parser_tell(mp)+write_offset, xevoffset);
+ body = (CamelMboxMessageContentInfo *)message->info.content;
+ if (newuid != ~0) {
+ message->info.uid = g_strdup_printf("%u", newuid);
+ } else {
+ g_warning("This shouldn't happen?");
+ }
+ } else {
+ body = body_part_new(mp, parent, camel_mime_parser_tell_start_headers(mp)+old_offset, camel_mime_parser_tell(mp)+write_offset);
+ }
+
+ /* check headers for types that we can index */
+ ct = camel_mime_parser_content_type(mp);
+ if (header_content_type_is(ct, "text", "*")) {
+ char *encoding;
+ const char *charset;
+
+ /* TODO: The filters should all be cached, so they aren't recreated between
+ messages/message parts */
+ encoding = header_content_encoding_decode(camel_mime_parser_header(mp, "content-transfer-encoding", NULL));
+ if (encoding) {
+ if (!strcasecmp(encoding, "base64")) {
+ d(printf("Adding decoding filter for base64\n"));
+ if (mf64 == NULL)
+ mf64 = camel_mime_filter_basic_new_type(CAMEL_MIME_FILTER_BASIC_BASE64_DEC);
+ enc_id = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)mf64);
+ } else if (!strcasecmp(encoding, "quoted-printable")) {
+ d(printf("Adding decoding filter for quoted-printable\n"));
+ if (mfqp == NULL)
+ mfqp = camel_mime_filter_basic_new_type(CAMEL_MIME_FILTER_BASIC_QP_DEC);
+ enc_id = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)mfqp);
+ }
+ g_free(encoding);
+ }
+
+ charset = header_content_type_param(ct, "charset");
+ if (charset!=NULL
+ && !(strcasecmp(charset, "us-ascii")==0
+ || strcasecmp(charset, "utf-8")==0)) {
+ d(printf("Adding conversion filter from %s to utf-8\n", charset));
+ if (mfc == NULL)
+ mfc = camel_mime_filter_charset_new_convert(charset, "utf-8");
+ if (mfc) {
+ chr_id = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)mfc);
+ } else {
+ g_warning("Cannot convert '%s' to 'utf-8', message display may be corrupt", charset);
+ }
+ }
+
+ doindex = TRUE;
+
+ /* and this filter actually does the indexing */
+ idx_id = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)mfi);
+ } else {
+ doindex = FALSE;
+ }
+ break;
+
+ /* fixme, this needs thought *sigh* */
+ case HSCAN_MESSAGE_END:
+ case HSCAN_MULTIPART_END:
+ if (parent) {
+ parent->endpos = camel_mime_parser_tell(mp)+write_offset;
+ if (parent->info.parent == NULL) {
+ camel_mbox_summary_add(s, message);
+ message = NULL;
+ parent = NULL;
+ } else {
+ parent = (CamelMboxMessageContentInfo *)parent->info.parent;
+ }
+ }
+ break;
+
+ case HSCAN_BODY:
+ if (doindex) {
+ d(printf("Got content to index:\n%.*s", datalen, data));
+ }
+ break;
+
+ case HSCAN_BODY_END:
+ if (body) {
+ body->endpos = camel_mime_parser_tell(mp)+write_offset;
+ if (body->info.parent == NULL) {
+ camel_mbox_summary_add(s, message);
+ message = NULL;
+ }
+ }
+
+ d(printf("end of content, removing decoders\n"));
+ if (enc_id != -1) {
+ camel_mime_parser_filter_remove(mp, enc_id);
+ enc_id = -1;
+ }
+ if (chr_id != -1) {
+ camel_mime_parser_filter_remove(mp, chr_id);
+ chr_id = -1;
+ }
+ if (idx_id != -1) {
+ camel_mime_parser_filter_remove(mp, idx_id);
+ idx_id = -1;
+ }
+ break;
+ }
+ }
+
+ /* did we actually write anything out? Then rename and be done with it. */
+ if (last_write>0) {
+ eof = camel_mime_parser_tell(mp);
+ camel_mbox_summary_copy_block(fd, fdout, last_write, eof-last_write);
+
+ if (close(fdout) == -1) {
+ perror("Could not close output file");
+ unlink(tmpname);
+ } else {
+ printf("renaming %s to %s\n", tmpname, s->folder_path);
+ if (rename(tmpname, s->folder_path) == -1) {
+ perror("Error renaming file");
+ unlink(tmpname);
+ }
+ }
+ } else {
+ /* no, then dont bother touching the inbox */
+ printf("No written changes to mbox, removing tmp file\n");
+ close(fdout);
+ unlink(tmpname);
+ }
+
+ close(fd);
+
+ if (mf64) gtk_object_unref((GtkObject *)mf64);
+ if (mfqp) gtk_object_unref((GtkObject *)mfqp);
+ if (mfc) gtk_object_unref((GtkObject *)mfc);
+ if (mfi) gtk_object_unref((GtkObject *)mfi);
+
+ /* force an index sync? */
+ if (s->index) {
+ ibex_write(s->index);
+ }
+
+ gtk_object_unref((GtkObject *)mp);
+
+ /* and finally ... update the summary sync info */
+ {
+ struct stat st;
+
+ if (stat(s->folder_path, &st) == 0) {
+ s->time = st.st_mtime;
+ s->size = st.st_size;
+ }
+ }
+
+ g_free(tmpname);
+
+ return 0;
+}
+
+CamelMboxSummary *camel_mbox_summary_new(const char *summary, const char *folder, ibex *index)
+{
+ CamelMboxSummary *s;
+
+ s = g_malloc0(sizeof(*s));
+
+ s->dirty = TRUE;
+ s->folder_path = g_strdup(folder);
+ s->summary_path = g_strdup(summary);
+ /* FIXME: refcount index? */
+ s->index = index;
+
+ s->messages = g_ptr_array_new();
+ s->message_uid = g_hash_table_new(g_str_hash, g_str_equal);
+
+ /* always force an update */
+ s->time = 0;
+ s->size = 0;
+
+ s->nextuid = 1;
+
+ /* TODO: force an initial load right now? */
+
+ return s;
+}
+
+void camel_mbox_summary_unref(CamelMboxSummary *s)
+{
+ g_warning("Unimplemented function, mbox_summary_unref");
+}
+
+/* check that the summary is uptodate, TRUE means it is uptodate */
+int camel_mbox_summary_check(CamelMboxSummary *s)
+{
+ struct stat st;
+
+ /* no folder at all? */
+ if (stat(s->folder_path, &st) != 0)
+ return FALSE;
+
+ return (st.st_size == s->size) && (st.st_mtime == s->time);
+}
+
+static void camel_mbox_summary_add(CamelMboxSummary *s, CamelMboxMessageInfo *info)
+{
+ if (info->info.uid == NULL) {
+ info->info.uid = g_strdup_printf("%u", s->nextuid++);
+ }
+ if (g_hash_table_lookup(s->message_uid, info->info.uid)) {
+ g_error("Trying to insert message with clashing uid's");
+ }
+ d(printf("adding %s\n", info->info.uid));
+ g_ptr_array_add(s->messages, info);
+ g_hash_table_insert(s->message_uid, info->info.uid, info);
+ s->dirty = TRUE;
+}
+
+static int summary_header_read(FILE *fp, guint32 *version, time_t *time, size_t *size, guint32 *nextuid)
+{
+ fseek(fp, 0, SEEK_SET);
+ *version = decode_fixed_int(fp);
+ *time = decode_fixed_int(fp);
+ *size = decode_fixed_int(fp);
+ *nextuid = decode_fixed_int(fp);
+ return ferror(fp);
+}
+
+static void
+summary_clear(CamelMboxSummary *s)
+{
+ int i;
+
+ for (i=0;i<s->messages->len;i++) {
+ message_struct_free(g_ptr_array_index(s->messages, i));
+ }
+ g_ptr_array_free(s->messages, TRUE);
+ g_hash_table_destroy(s->message_uid);
+
+ s->messages = g_ptr_array_new();
+ s->message_uid = g_hash_table_new(g_str_hash, g_str_equal);
+}
+
+int camel_mbox_summary_load(CamelMboxSummary *s)
+{
+ struct stat st;
+ FILE *fp;
+ int i, total;
+ CamelMboxMessageInfo *info;
+
+ summary_clear(s);
+
+ if ((fp = fopen(s->summary_path, "r")) == NULL) {
+ g_warning("Loading non-existant summary, generating summary for folder: %s: %s", s->summary_path, strerror(errno));
+ index_folder(s, 0);
+ camel_mbox_summary_save(s);
+ } else {
+ guint32 version, nextuid;
+ time_t time;
+ size_t size;
+
+ if (stat(s->folder_path, &st) != 0) {
+ g_warning("Uh, no folder anyway, aborting");
+ fclose(fp);
+ return -1;
+ }
+
+ if (summary_header_read(fp, &version, &time, &size, &nextuid) != 0
+ || version != CAMEL_MBOX_SUMMARY_VERSION) {
+ g_warning("Summary missing or version mismatch, reloading summary");
+ fclose(fp);
+ index_folder(s, 0);
+ camel_mbox_summary_save(s);
+ return 0;
+ }
+
+ s->nextuid = MAX(s->nextuid, nextuid);
+ s->time = time;
+ s->size = size;
+ total = decode_fixed_int(fp);
+
+ if (time != st.st_mtime || size != st.st_size) {
+ /* if its grown, then just index the new stuff, and load the rest from the summary */
+ if (size < st.st_size) {
+ g_warning("Indexing/summarizing from start position: %d", size);
+
+ d(printf("loading %d items from summary file\n", total));
+ for (i=0;i<total;i++) {
+ info = message_struct_load(fp);
+ if (info) {
+ camel_mbox_summary_add(s, info);
+ } else {
+ break;
+ }
+ }
+ fclose(fp);
+ s->dirty = FALSE;
+ index_folder(s, size); /* if it adds any, it'll dirtify it */
+ camel_mbox_summary_save(s);
+ } else {
+ g_warning("Folder changed/smaller, reindexing everything");
+ index_folder(s, 0);
+ camel_mbox_summary_save(s);
+ fclose(fp);
+ }
+ return 0;
+ }
+
+ printf("loading %d items from summary file\n", total);
+ for (i=0;i<total;i++) {
+ info = message_struct_load(fp);
+ if (info) {
+ camel_mbox_summary_add(s, info);
+ } else {
+ break;
+ }
+ }
+ fclose(fp);
+ s->dirty = FALSE;
+ }
+ return 0;
+}
+
+static int summary_header_write(FILE *fp, CamelMboxSummary *s)
+{
+ fseek(fp, 0, SEEK_SET);
+ encode_fixed_int(fp, CAMEL_MBOX_SUMMARY_VERSION);
+ encode_fixed_int(fp, s->time);
+ /* if we're dirty, then dont *really* save it ... */
+ if (s->dirty)
+ encode_fixed_int(fp, 0);
+ else
+ encode_fixed_int(fp, s->size);
+ encode_fixed_int(fp, s->nextuid);
+ fflush(fp);
+ return ferror(fp);
+}
+
+static int summary_header_save(CamelMboxSummary *s)
+{
+ int fd;
+ FILE *fp;
+
+ fd = open(s->summary_path, O_WRONLY|O_CREAT, 0600);
+ if (fd == -1)
+ return -1;
+ fp = fdopen(fd, "w");
+ if (fp == NULL)
+ return -1;
+
+ summary_header_write(fp, s);
+ return fclose(fp);
+}
+
+int camel_mbox_summary_save(CamelMboxSummary *s)
+{
+ int i, fd;
+ FILE *fp;
+
+ printf("saving summary? %s\n", s->summary_path);
+
+ /* FIXME: error checking */
+ if (s->dirty) {
+ printf("yes\n");
+ fd = open(s->summary_path, O_WRONLY|O_CREAT|O_TRUNC, 0600);
+ if (fd == -1)
+ return -1;
+ fp = fdopen(fd, "w");
+ if (fp == NULL)
+ return -1;
+
+ s->dirty = FALSE;
+
+ summary_header_write(fp, s);
+ encode_fixed_int(fp, s->messages->len);
+
+ printf("message count = %d\n", s->messages->len);
+
+ for (i=0;i<s->messages->len;i++) {
+ message_struct_save(fp, g_ptr_array_index(s->messages, i));
+ }
+ fclose(fp);
+ } else {
+ printf("no\n");
+ }
+ return 0;
+}
+
+CamelMboxMessageInfo *camel_mbox_summary_uid(CamelMboxSummary *s, const char *uid)
+{
+ return g_hash_table_lookup(s->message_uid, uid);
+}
+
+CamelMboxMessageInfo *camel_mbox_summary_index(CamelMboxSummary *s, int index)
+{
+ return g_ptr_array_index(s->messages, index);
+}
+
+int camel_mbox_summary_message_count(CamelMboxSummary *s)
+{
+ return s->messages->len;
+}
+
+guint32 camel_mbox_summary_next_uid(CamelMboxSummary *s)
+{
+ guint32 uid = s->nextuid++;
+
+ summary_header_save(s);
+ return uid;
+}
+
+guint32 camel_mbox_summary_set_uid(CamelMboxSummary *s, guint32 uid)
+{
+ if (s->nextuid < uid) {
+ s->nextuid = uid;
+ summary_header_save(s);
+ }
+ return s->nextuid;
+}
+
+#if 0
+int main(int argc, char **argv)
+{
+ if (argc<2) {
+ printf("usage: %s mbox\n", argv[0]);
+ return 1;
+ }
+
+ gtk_init(&argc, &argv);
+
+ index_folder(argv[1]);
+
+ return 0;
}
+#endif