diff options
Diffstat (limited to 'camel/providers/local/camel-spool-summary.c')
-rw-r--r-- | camel/providers/local/camel-spool-summary.c | 1274 |
1 files changed, 0 insertions, 1274 deletions
diff --git a/camel/providers/local/camel-spool-summary.c b/camel/providers/local/camel-spool-summary.c deleted file mode 100644 index 6a44fdf7cb..0000000000 --- a/camel/providers/local/camel-spool-summary.c +++ /dev/null @@ -1,1274 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- - * - * Copyright (C) 2001 Ximian Inc. (www.ximian.com) - * - * Authors: Michael Zucchi <notzed@ximian.com> - * - * 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. - * - * 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 - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <ctype.h> -#include <sys/stat.h> -#include <sys/uio.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> - -#include "camel-spool-summary.h" -#include "camel-mime-message.h" -#include "camel-file-utils.h" -#include "camel-operation.h" - -#define io(x) -#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ - -#define CAMEL_SPOOL_SUMMARY_VERSION (0x400) - -struct _CamelSpoolSummaryPrivate { -}; - -#define _PRIVATE(o) (((CamelSpoolSummary *)(o))->priv) - -static int summary_header_load (CamelFolderSummary *, FILE *); -static int summary_header_save (CamelFolderSummary *, FILE *); - -static CamelMessageInfo * message_info_new (CamelFolderSummary *, struct _header_raw *); -static CamelMessageInfo * message_info_new_from_parser(CamelFolderSummary *s, CamelMimeParser *mp); -static CamelMessageInfo * message_info_load (CamelFolderSummary *, FILE *); -static int message_info_save (CamelFolderSummary *, FILE *, CamelMessageInfo *); - -static int spool_summary_decode_x_evolution(CamelSpoolSummary *cls, const char *xev, CamelMessageInfo *mi); -static char *spool_summary_encode_x_evolution(CamelSpoolSummary *cls, const CamelMessageInfo *mi); - -static int spool_summary_load(CamelSpoolSummary *cls, int forceindex, CamelException *ex); -static int spool_summary_check(CamelSpoolSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex); -static int spool_summary_sync(CamelSpoolSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex); -static CamelMessageInfo *spool_summary_add(CamelSpoolSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *, CamelException *ex); - -static int spool_summary_sync_full(CamelSpoolSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex); - -static void camel_spool_summary_class_init (CamelSpoolSummaryClass *klass); -static void camel_spool_summary_init (CamelSpoolSummary *obj); -static void camel_spool_summary_finalise (CamelObject *obj); -static CamelFolderSummaryClass *camel_spool_summary_parent; - -CamelType -camel_spool_summary_get_type(void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - type = camel_type_register(camel_folder_summary_get_type(), "CamelSpoolSummary", - sizeof (CamelSpoolSummary), - sizeof (CamelSpoolSummaryClass), - (CamelObjectClassInitFunc) camel_spool_summary_class_init, - NULL, - (CamelObjectInitFunc) camel_spool_summary_init, - (CamelObjectFinalizeFunc) camel_spool_summary_finalise); - } - - return type; -} - -static void -camel_spool_summary_class_init(CamelSpoolSummaryClass *klass) -{ - CamelFolderSummaryClass *sklass = (CamelFolderSummaryClass *) klass; - - camel_spool_summary_parent = CAMEL_FOLDER_SUMMARY_CLASS(camel_type_get_global_classfuncs(camel_folder_summary_get_type())); - - sklass->summary_header_load = summary_header_load; - sklass->summary_header_save = summary_header_save; - - sklass->message_info_new = message_info_new; - sklass->message_info_new_from_parser = message_info_new_from_parser; - sklass->message_info_load = message_info_load; - sklass->message_info_save = message_info_save; - - klass->load = spool_summary_load; - klass->check = spool_summary_check; - klass->sync = spool_summary_sync; - klass->add = spool_summary_add; - - klass->encode_x_evolution = spool_summary_encode_x_evolution; - klass->decode_x_evolution = spool_summary_decode_x_evolution; -} - -static void -camel_spool_summary_init(CamelSpoolSummary *obj) -{ - struct _CamelSpoolSummaryPrivate *p; - struct _CamelFolderSummary *s = (CamelFolderSummary *)obj; - - p = _PRIVATE(obj) = g_malloc0(sizeof(*p)); - - /* subclasses need to set the right instance data sizes */ - s->message_info_size = sizeof(CamelSpoolMessageInfo); - s->content_info_size = sizeof(CamelMessageContentInfo); - - /* and a unique file version */ - s->version += CAMEL_SPOOL_SUMMARY_VERSION; -} - -static void -camel_spool_summary_finalise(CamelObject *obj) -{ - CamelSpoolSummary *mbs = CAMEL_SPOOL_SUMMARY(obj); - - g_free(mbs->folder_path); -} - -CamelSpoolSummary * -camel_spool_summary_new(const char *filename) -{ - CamelSpoolSummary *new = (CamelSpoolSummary *)camel_object_new(camel_spool_summary_get_type()); - - camel_folder_summary_set_build_content(CAMEL_FOLDER_SUMMARY(new), FALSE); - new->folder_path = g_strdup(filename); - - return new; -} - -static int -spool_summary_load(CamelSpoolSummary *cls, int forceindex, CamelException *ex) -{ - g_warning("spool_summary_load() should nto b e called\n"); - - return camel_folder_summary_load((CamelFolderSummary *)cls); -} - -/* load/check the summary */ -int -camel_spool_summary_load(CamelSpoolSummary *cls, int forceindex, CamelException *ex) -{ - struct stat st; - CamelFolderSummary *s = (CamelFolderSummary *)cls; - - g_warning("spool_summary_load() should nto b e called\n"); - - d(printf("Loading summary ...\n")); - - if (forceindex - || stat(s->summary_path, &st) == -1 - || ((CamelSpoolSummaryClass *)(CAMEL_OBJECT_GET_CLASS(cls)))->load(cls, forceindex, ex) == -1) { - camel_folder_summary_clear((CamelFolderSummary *)cls); - } - - return camel_spool_summary_check(cls, NULL, ex); -} - -char * -camel_spool_summary_encode_x_evolution(CamelSpoolSummary *cls, const CamelMessageInfo *info) -{ - return ((CamelSpoolSummaryClass *)(CAMEL_OBJECT_GET_CLASS(cls)))->encode_x_evolution(cls, info); -} - -int -camel_spool_summary_decode_x_evolution(CamelSpoolSummary *cls, const char *xev, CamelMessageInfo *info) -{ - return ((CamelSpoolSummaryClass *)(CAMEL_OBJECT_GET_CLASS(cls)))->decode_x_evolution(cls, xev, info); -} - -int -camel_spool_summary_check(CamelSpoolSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - int ret; - - ret = ((CamelSpoolSummaryClass *)(CAMEL_OBJECT_GET_CLASS(cls)))->check(cls, changeinfo, ex); - - return ret; -} - -int -camel_spool_summary_sync(CamelSpoolSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - return ((CamelSpoolSummaryClass *)(CAMEL_OBJECT_GET_CLASS(cls)))->sync(cls, expunge, changeinfo, ex); -} - -CamelMessageInfo * -camel_spool_summary_add(CamelSpoolSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *ci, CamelException *ex) -{ - return ((CamelSpoolSummaryClass *)(CAMEL_OBJECT_GET_CLASS(cls)))->add(cls, msg, info, ci, ex); -} - -/** - * camel_spool_summary_write_headers: - * @fd: - * @header: - * @xevline: - * - * Write a bunch of headers to the file @fd. IF xevline is non NULL, then - * an X-Evolution header line is created at the end of all of the headers. - * The headers written are termianted with a blank line. - * - * Return value: -1 on error, otherwise the number of bytes written. - **/ -int -camel_spool_summary_write_headers(int fd, struct _header_raw *header, char *xevline) -{ - int outlen = 0, len; - int newfd; - FILE *out; - - /* dum de dum, maybe the whole sync function should just use stdio for output */ - newfd = dup(fd); - if (newfd == -1) - return -1; - - out = fdopen(newfd, "w"); - if (out == NULL) { - close(newfd); - errno = EINVAL; - return -1; - } - - while (header) { - if (strcmp(header->name, "X-Evolution")) { - len = fprintf(out, "%s:%s\n", header->name, header->value); - if (len == -1) { - fclose(out); - return -1; - } - outlen += len; - } - header = header->next; - } - - if (xevline) { - len = fprintf(out, "X-Evolution: %s\n\n", xevline); - if (len == -1) { - fclose(out); - return -1; - } - outlen += len; - } - - if (fclose(out) == -1) - return -1; - - return outlen; -} - -static int -summary_header_load(CamelFolderSummary *s, FILE *in) -{ - CamelSpoolSummary *mbs = CAMEL_SPOOL_SUMMARY(s); - - if (((CamelFolderSummaryClass *)camel_spool_summary_parent)->summary_header_load(s, in) == -1) - return -1; - - return camel_file_util_decode_uint32(in, &mbs->folder_size); -} - -static int -summary_header_save(CamelFolderSummary *s, FILE *out) -{ - CamelSpoolSummary *mbs = CAMEL_SPOOL_SUMMARY(s); - - if (((CamelFolderSummaryClass *)camel_spool_summary_parent)->summary_header_save(s, out) == -1) - return -1; - - return camel_file_util_encode_uint32(out, mbs->folder_size); -} - -static CamelMessageInfo * -message_info_new(CamelFolderSummary *s, struct _header_raw *h) -{ - CamelMessageInfo *mi; - CamelSpoolSummary *cls = (CamelSpoolSummary *)s; - - mi = ((CamelFolderSummaryClass *)camel_spool_summary_parent)->message_info_new(s, h); - if (mi) { - CamelSpoolMessageInfo *mbi = (CamelSpoolMessageInfo *)mi; - const char *xev; - - xev = header_raw_find(&h, "X-Evolution", NULL); - if (xev==NULL || camel_spool_summary_decode_x_evolution(cls, xev, mi) == -1) { - /* to indicate it has no xev header */ - mi->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED | CAMEL_MESSAGE_FOLDER_NOXEV; - camel_message_info_set_uid(mi, camel_folder_summary_next_uid_string(s)); - } - - mbi->frompos = -1; - } - - return mi; -} - -static CamelMessageInfo * -message_info_new_from_parser(CamelFolderSummary *s, CamelMimeParser *mp) -{ - CamelMessageInfo *mi; - - mi = ((CamelFolderSummaryClass *)camel_spool_summary_parent)->message_info_new_from_parser(s, mp); - if (mi) { - CamelSpoolMessageInfo *mbi = (CamelSpoolMessageInfo *)mi; - - mbi->frompos = camel_mime_parser_tell_start_from(mp); - } - - return mi; -} - -static CamelMessageInfo * -message_info_load(CamelFolderSummary *s, FILE *in) -{ - CamelMessageInfo *mi; - - io(printf("loading spool message info\n")); - - mi = ((CamelFolderSummaryClass *)camel_spool_summary_parent)->message_info_load(s, in); - if (mi) { - CamelSpoolMessageInfo *mbi = (CamelSpoolMessageInfo *)mi; - - if (camel_file_util_decode_off_t(in, &mbi->frompos) == -1) - goto error; - } - - return mi; -error: - camel_folder_summary_info_free(s, mi); - return NULL; -} - -static int -message_info_save(CamelFolderSummary *s, FILE *out, CamelMessageInfo *mi) -{ - CamelSpoolMessageInfo *mbi = (CamelSpoolMessageInfo *)mi; - - io(printf("saving spool message info\n")); - - if (((CamelFolderSummaryClass *)camel_spool_summary_parent)->message_info_save(s, out, mi) == -1 - || camel_file_util_encode_off_t(out, mbi->frompos) == -1) - return -1; - - return 0; -} - -static int -summary_rebuild(CamelSpoolSummary *cls, off_t offset, CamelException *ex) -{ - CamelFolderSummary *s = (CamelFolderSummary *)cls; - CamelMimeParser *mp; - int fd; - int ok = 0; - struct stat st; - off_t size = 0; - - /* FIXME: If there is a failure, it shouldn't clear the summary and restart, - it should try and merge the summary info's. This is a bit tricky. */ - - camel_operation_start(NULL, _("Summarising folder")); - - fd = open(cls->folder_path, O_RDONLY); - if (fd == -1) { - printf("%s failed to open: %s", cls->folder_path, strerror(errno)); - camel_exception_setv(ex, 1, _("Could not open folder: %s: summarising from position %ld: %s"), - cls->folder_path, offset, strerror(errno)); - camel_operation_end(NULL); - return -1; - } - - if (fstat(fd, &st) == 0) - size = st.st_size; - - mp = camel_mime_parser_new(); - camel_mime_parser_init_with_fd(mp, fd); - camel_mime_parser_scan_from(mp, TRUE); - camel_mime_parser_seek(mp, offset, SEEK_SET); - - if (offset > 0) { - if (camel_mime_parser_step(mp, NULL, NULL) == HSCAN_FROM) { - if (camel_mime_parser_tell_start_from(mp) != offset) { - g_warning("The next message didn't start where I expected, building summary from start"); - camel_mime_parser_drop_step(mp); - offset = 0; - camel_mime_parser_seek(mp, offset, SEEK_SET); - camel_folder_summary_clear(s); - } else { - camel_mime_parser_unstep(mp); - } - } else { - d(printf("mime parser state ran out? state is %d\n", camel_mime_parser_state(mp))); - camel_object_unref(CAMEL_OBJECT(mp)); - /* end of file - no content? no error either */ - camel_operation_end(NULL); - return 0; - } - } - - while (camel_mime_parser_step(mp, NULL, NULL) == HSCAN_FROM) { - CamelMessageInfo *info; - off_t pc = camel_mime_parser_tell_start_from (mp) + 1; - - camel_operation_progress (NULL, (int) (((float) pc / size) * 100)); - - info = camel_folder_summary_add_from_parser(s, mp); - if (info == NULL) { - camel_exception_setv(ex, 1, _("Fatal mail parser error near position %ld in folder %s"), - camel_mime_parser_tell(mp), cls->folder_path); - ok = -1; - break; - } - - g_assert(camel_mime_parser_step(mp, NULL, NULL) == HSCAN_FROM_END); - } - - camel_object_unref(CAMEL_OBJECT (mp)); - - /* update the file size/mtime in the summary */ - if (ok != -1) { - if (stat(cls->folder_path, &st) == 0) { - camel_folder_summary_touch(s); - cls->folder_size = st.st_size; - s->time = st.st_mtime; - } - } - - camel_operation_end(NULL); - - return ok; -} - -/* like summary_rebuild, but also do changeinfo stuff (if supplied) */ -static int -summary_update(CamelSpoolSummary *cls, off_t offset, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - int ret, i, count; - CamelFolderSummary *s = (CamelFolderSummary *)cls; - - d(printf("Calling summary update, from pos %d\n", (int)offset)); - - if (changeinfo) { - /* we use the diff function of the change_info to build the update list. */ - for (i = 0; i < camel_folder_summary_count(s); i++) { - CamelMessageInfo *mi = camel_folder_summary_index(s, i); - - camel_folder_change_info_add_source(changeinfo, camel_message_info_uid(mi)); - camel_folder_summary_info_free(s, mi); - } - } - - /* do the actual work */ - ret = summary_rebuild(cls, offset, ex); - - if (changeinfo) { - count = camel_folder_summary_count(s); - for (i = 0; i < count; i++) { - CamelMessageInfo *mi = camel_folder_summary_index(s, i); - camel_folder_change_info_add_update(changeinfo, camel_message_info_uid(mi)); - camel_folder_summary_info_free(s, mi); - } - camel_folder_change_info_build_diff(changeinfo); - } - - return ret; -} - -static int -spool_summary_check(CamelSpoolSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - CamelFolderSummary *s = (CamelFolderSummary *)cls; - struct stat st; - int ret = 0; - - d(printf("Checking summary\n")); - - /* check if the summary is up-to-date */ - if (stat(cls->folder_path, &st) == -1) { - camel_folder_summary_clear(s); - camel_exception_setv(ex, 1, _("Cannot summarise folder: %s: %s"), cls->folder_path, strerror(errno)); - return -1; - } - - if (st.st_size == 0) { - /* empty? No need to scan at all */ - d(printf("Empty spool, clearing summary\n")); - camel_folder_summary_clear(s); - ret = 0; - } else if (s->messages->len == 0) { - /* if we are empty, then we rebuilt from scratch */ - d(printf("Empty summary, rebuilding from start\n")); - ret = summary_update(cls, 0, changeinfo, ex); - } else { - /* is the summary uptodate? */ - if (st.st_size != cls->folder_size || st.st_mtime != s->time) { - if (cls->folder_size < st.st_size) { - /* this will automatically rescan from 0 if there is a problem */ - d(printf("folder grew, attempting to rebuild from %d\n", cls->folder_size)); - ret = summary_update(cls, cls->folder_size, changeinfo, ex); - } else { - d(printf("folder shrank! rebuilding from start\n")); - camel_folder_summary_clear(s); - ret = summary_update(cls, 0, changeinfo, ex); - } - } - } - - if (ret != -1) { - int i, work, count; - - /* check to see if we need to copy/update the file; missing xev headers prompt this */ - work = FALSE; - count = camel_folder_summary_count(s); - for (i=0;!work && i<count; i++) { - CamelMessageInfo *info = camel_folder_summary_index(s, i); - g_assert(info); - work = (info->flags & (CAMEL_MESSAGE_FOLDER_NOXEV)) != 0; - camel_folder_summary_info_free(s, info); - } - - /* if we do, then write out the headers using sync_full, etc */ - if (work) { - d(printf("Have to add new headers, re-syncing from the start to accomplish this\n")); - ret = spool_summary_sync_full(cls, FALSE, changeinfo, ex); - - if (stat(cls->folder_path, &st) == -1) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Unknown error: %s"), strerror(errno)); - return -1; - } - } - cls->folder_size = st.st_size; - s->time = st.st_mtime; - } - - return ret; -} - -static char *tz_months[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" -}; - -static char *tz_days[] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" -}; - -/* tries to build a From line, based on message headers */ -char * -camel_spool_summary_build_from(struct _header_raw *header) -{ - GString *out = g_string_new("From "); - char *ret; - const char *tmp; - time_t thetime; - int offset; - struct tm tm; - - tmp = header_raw_find(&header, "Sender", NULL); - if (tmp == NULL) - tmp = header_raw_find(&header, "From", NULL); - if (tmp != NULL) { - struct _header_address *addr = header_address_decode(tmp); - - tmp = NULL; - if (addr) { - if (addr->type == HEADER_ADDRESS_NAME) { - g_string_append(out, addr->v.addr); - tmp = ""; - } - header_address_unref(addr); - } - } - if (tmp == NULL) { - g_string_append(out, "unknown@nodomain.now.au"); - } - - /* try use the received header to get the date */ - tmp = header_raw_find(&header, "Received", NULL); - if (tmp) { - tmp = strrchr(tmp, ';'); - if (tmp) - tmp++; - } - - /* if there isn't one, try the Date field */ - if (tmp == NULL) - tmp = header_raw_find(&header, "Date", NULL); - - thetime = header_decode_date(tmp, &offset); - - thetime += ((offset / 100) * (60 * 60)) + (offset % 100) * 60; - - /* a pseudo, but still bogus attempt at thread safing the function */ - /*memcpy(&tm, gmtime(&thetime), sizeof(tm));*/ - gmtime_r(&thetime, &tm); - - g_string_sprintfa(out, " %s %s %d %02d:%02d:%02d %4d\n", - tz_days[tm.tm_wday], - tz_months[tm.tm_mon], tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year + 1900); - - ret = out->str; - g_string_free(out, FALSE); - return ret; -} - -/* perform a full sync */ -static int -spool_summary_sync_full(CamelSpoolSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - CamelFolderSummary *s = (CamelFolderSummary *)cls; - CamelMimeParser *mp = NULL; - int i, count; - CamelSpoolMessageInfo *info = NULL; - int fd = -1, fdout = -1; - char *tmpname = NULL; - char *buffer, *xevnew = NULL, *p; - int len; - const char *fromline; - int lastdel = FALSE; - off_t spoollen, outlen; - int size, sizeout; - struct stat st; - - d(printf("performing full summary/sync\n")); - - camel_operation_start(NULL, _("Synchronising folder")); - - fd = open(cls->folder_path, O_RDWR); - if (fd == -1) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not open folder to summarise: %s: %s"), - cls->folder_path, strerror(errno)); - camel_operation_end(NULL); - return -1; - } - - mp = camel_mime_parser_new(); - camel_mime_parser_scan_from(mp, TRUE); - camel_mime_parser_scan_pre_from(mp, TRUE); - camel_mime_parser_init_with_fd(mp, fd); - -#ifdef HAVE_MKSTEMP - tmpname = alloca(64); - sprintf(tmpname, "/tmp/spool.camel.XXXXXX"); - fdout = mkstemp(tmpname); -#else -#warning "Your system has no mkstemp(3), spool updating may be insecure" - tmpname = alloca(L_tmpnam); - tmpnam(tmpname); - fdout = open(tmpname, O_RDWR|O_CREAT|O_EXCL, 0600); -#endif - d(printf("Writing tmp file to %s\n", tmpname)); - if (fdout == -1) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot open temporary mailbox: %s"), strerror(errno)); - goto error; - } - - count = camel_folder_summary_count(s); - for (i = 0; i < count; i++) { - int pc = (i + 1) * 100 / count; - - camel_operation_progress(NULL, pc); - - info = (CamelSpoolMessageInfo *)camel_folder_summary_index(s, i); - - g_assert(info); - - d(printf("Looking at message %s\n", camel_message_info_uid(info))); - - /* only need to seek past deleted messages, otherwise we should be at the right spot/state already */ - if (lastdel) { - d(printf("seeking to %d\n", (int)info->frompos)); - camel_mime_parser_seek(mp, info->frompos, SEEK_SET); - } - - if (camel_mime_parser_step(mp, &buffer, &len) != HSCAN_FROM) { - g_warning("Expected a From line here, didn't get it"); - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Summary and folder mismatch, even after a sync")); - goto error; - } - - if (camel_mime_parser_tell_start_from(mp) != info->frompos) { - g_warning("Didn't get the next message where I expected (%d) got %d instead", - (int)info->frompos, (int)camel_mime_parser_tell_start_from(mp)); - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Summary and folder mismatch, even after a sync")); - goto error; - } - - lastdel = FALSE; - if (expunge && info->info.flags & CAMEL_MESSAGE_DELETED) { - const char *uid = camel_message_info_uid(info); - - d(printf("Deleting %s\n", uid)); - -#if 0 - if (cls->index) - ibex_unindex(cls->index, (char *)uid); -#endif - /* remove it from the change list */ - camel_folder_change_info_remove_uid(changeinfo, uid); - camel_folder_summary_remove(s, (CamelMessageInfo *)info); - camel_folder_summary_info_free(s, (CamelMessageInfo *)info); - count--; - i--; - info = NULL; - lastdel = TRUE; - } else { - /* otherwise, the message is staying, copy its From_ line across */ - if (i>0) { - write(fdout, "\n", 1); - } - info->frompos = lseek(fdout, 0, SEEK_CUR); - fromline = camel_mime_parser_from_line(mp); - write(fdout, fromline, strlen(fromline)); - } - - if (info && info->info.flags & (CAMEL_MESSAGE_FOLDER_NOXEV | CAMEL_MESSAGE_FOLDER_FLAGGED)) { - d(printf("Updating header for %s flags = %08x\n", camel_message_info_uid(info), info->info.flags)); - - if (camel_mime_parser_step(mp, &buffer, &len) == HSCAN_FROM_END) { - g_warning("camel_mime_parser_step failed (2)"); - goto error; - } - - xevnew = camel_spool_summary_encode_x_evolution(cls, (CamelMessageInfo *)info); - if (camel_spool_summary_write_headers(fdout, camel_mime_parser_headers_raw(mp), xevnew) == -1) { - d(printf("Error writing to tmp mailbox\n")); - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Error writing to temp mailbox: %s"), - strerror(errno)); - goto error; - } - info->info.flags &= 0xffff; - g_free(xevnew); - xevnew = NULL; - camel_mime_parser_drop_step(mp); - } - - camel_mime_parser_drop_step(mp); - if (info) { - d(printf("looking for message content to copy across from %d\n", (int)camel_mime_parser_tell(mp))); - while (camel_mime_parser_step(mp, &buffer, &len) == HSCAN_PRE_FROM) { - d(printf("copying spool contents to tmp: '%.*s'\n", len, buffer)); - if (write(fdout, buffer, len) != len) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Writing to tmp mailbox failed: %s: %s"), - cls->folder_path, strerror(errno)); - goto error; - } - } - d(printf("we are now at %d, from = %d\n", (int)camel_mime_parser_tell(mp), - (int)camel_mime_parser_tell_start_from(mp))); - camel_mime_parser_unstep(mp); - camel_folder_summary_info_free(s, (CamelMessageInfo *)info); - info = NULL; - } - } - - /* sync out content */ - if (fsync(fdout) == -1) { - g_warning("Cannot sync temporary folder: %s", strerror(errno)); - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not sync temporary folder %s: %s"), - cls->folder_path, strerror(errno)); - goto error; - } - - /* see if we can write this much to the spool file */ - if (fstat(fd, &st) == -1) { - g_warning("Cannot sync temporary folder: %s", strerror(errno)); - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not sync temporary folder %s: %s"), - cls->folder_path, strerror(errno)); - goto error; - } - spoollen = st.st_size; - - if (fstat(fdout, &st) == -1) { - g_warning("Cannot sync temporary folder: %s", strerror(errno)); - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not sync temporary folder %s: %s"), - cls->folder_path, strerror(errno)); - goto error; - } - outlen = st.st_size; - - /* I think this is the right way to do this */ - if (outlen>0 - && (lseek(fd, outlen-1, SEEK_SET) == -1 - || write(fd, "", 1) != 1 - || fsync(fd) == -1 - || lseek(fd, 0, SEEK_SET) == -1 - || lseek(fdout, 0, SEEK_SET) == -1)) { - g_warning("Cannot sync spool folder: %s", strerror(errno)); - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not sync spool folder %s: %s"), - cls->folder_path, strerror(errno)); - /* incase we ran out of room, remove any trailing space first */ - ftruncate(fd, spoollen); - goto error; - } - - - /* now copy content back */ - buffer = g_malloc(8192); - size = 1; - while (size>0) { - do { - size = read(fdout, buffer, 8192); - } while (size == -1 && errno == EINTR); - - if (size > 0) { - p = buffer; - do { - sizeout = write(fd, p, size); - if (sizeout > 0) { - p+= sizeout; - size -= sizeout; - } - } while ((sizeout == -1 && errno == EINTR) && size > 0); - size = sizeout; - } - - if (size == -1) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not sync spool folder %s: %s\n" - "Folder may be corrupt, copy saved in `%s'"), - cls->folder_path, strerror(errno), tmpnam); - /* so we dont delete it */ - close(fdout); - tmpname = NULL; - fdout = -1; - g_free(buffer); - goto error; - } - } - - g_free(buffer); - - d(printf("Closing folders\n")); - - if (ftruncate(fd, outlen) == -1) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not sync spool folder %s: %s\n" - "Folder may be corrupt, copy saved in `%s'"), - cls->folder_path, strerror(errno), tmpnam); - close(fdout); - tmpname = NULL; - fdout = -1; - goto error; - } - - if (close(fd) == -1) { - g_warning("Cannot close source folder: %s", strerror(errno)); - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not sync spool folder %s: %s\n" - "Folder may be corrupt, copy saved in `%s'"), - cls->folder_path, strerror(errno), tmpnam); - close(fdout); - tmpname = NULL; - fdout = -1; - fd = -1; - goto error; - } - - close(fdout); - unlink(tmpname); - - camel_object_unref((CamelObject *)mp); - camel_operation_end(NULL); - - return 0; - error: - if (fd != -1) - close(fd); - - if (fdout != -1) - close(fdout); - - g_free(xevnew); - - if (tmpname) - unlink(tmpname); - if (mp) - camel_object_unref((CamelObject *)mp); - if (info) - camel_folder_summary_info_free(s, (CamelMessageInfo *)info); - - camel_operation_end(NULL); - - return -1; -} - -/* perform a quick sync - only system flags have changed */ -static int -spool_summary_sync_quick(CamelSpoolSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - CamelFolderSummary *s = (CamelFolderSummary *)cls; - CamelMimeParser *mp = NULL; - int i, count; - CamelSpoolMessageInfo *info = NULL; - int fd = -1; - char *xevnew, *xevtmp; - const char *xev; - int len; - off_t lastpos; - - d(printf("Performing quick summary sync\n")); - - camel_operation_start(NULL, _("Synchronising folder")); - - fd = open(cls->folder_path, O_RDWR); - if (fd == -1) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not open folder to summarise: %s: %s"), - cls->folder_path, strerror(errno)); - - camel_operation_end(NULL); - return -1; - } - - mp = camel_mime_parser_new(); - camel_mime_parser_scan_from(mp, TRUE); - camel_mime_parser_scan_pre_from(mp, TRUE); - camel_mime_parser_init_with_fd(mp, fd); - - count = camel_folder_summary_count(s); - for (i = 0; i < count; i++) { - int xevoffset; - int pc = (i+1)*100/count; - - camel_operation_progress(NULL, pc); - - info = (CamelSpoolMessageInfo *)camel_folder_summary_index(s, i); - - g_assert(info); - - d(printf("Checking message %s %08x\n", camel_message_info_uid(info), info->info.flags)); - - if ((info->info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED) == 0) { - camel_folder_summary_info_free(s, (CamelMessageInfo *)info); - info = NULL; - continue; - } - - d(printf("Updating message %s\n", camel_message_info_uid(info))); - - camel_mime_parser_seek(mp, info->frompos, SEEK_SET); - - if (camel_mime_parser_step(mp, 0, 0) != HSCAN_FROM) { - g_warning("Expected a From line here, didn't get it"); - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Summary and folder mismatch, even after a sync")); - goto error; - } - - if (camel_mime_parser_tell_start_from(mp) != info->frompos) { - g_warning("Didn't get the next message where I expected (%d) got %d instead", - (int)info->frompos, (int)camel_mime_parser_tell_start_from(mp)); - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Summary and folder mismatch, even after a sync")); - goto error; - } - - if (camel_mime_parser_step(mp, 0, 0) == HSCAN_FROM_END) { - g_warning("camel_mime_parser_step failed (2)"); - goto error; - } - - xev = camel_mime_parser_header(mp, "X-Evolution", &xevoffset); - if (xev == NULL || camel_spool_summary_decode_x_evolution(cls, xev, NULL) == -1) { - g_warning("We're supposed to have a valid x-ev header, but we dont"); - goto error; - } - xevnew = camel_spool_summary_encode_x_evolution(cls, (CamelMessageInfo *)info); - /* SIGH: encode_param_list is about the only function which folds headers by itself. - This should be fixed somehow differently (either parser doesn't fold headers, - or param_list doesn't, or something */ - xevtmp = header_unfold(xevnew); - /* the raw header contains a leading ' ', so (dis)count that too */ - if (strlen(xev)-1 != strlen(xevtmp)) { - g_free(xevnew); - g_free(xevtmp); - g_warning("Hmm, the xev headers shouldn't have changed size, but they did"); - goto error; - } - g_free(xevtmp); - - /* we write out the xevnew string, assuming its been folded identically to the original too! */ - - lastpos = lseek(fd, 0, SEEK_CUR); - lseek(fd, xevoffset+strlen("X-Evolution: "), SEEK_SET); - do { - len = write(fd, xevnew, strlen(xevnew)); - } while (len == -1 && errno == EINTR); - lseek(fd, lastpos, SEEK_SET); - g_free(xevnew); - - camel_mime_parser_drop_step(mp); - camel_mime_parser_drop_step(mp); - - info->info.flags &= 0xffff; - camel_folder_summary_info_free(s, (CamelMessageInfo *)info); - } - - d(printf("Closing folders\n")); - - if (close(fd) == -1) { - g_warning("Cannot close source folder: %s", strerror(errno)); - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not close source folder %s: %s"), - cls->folder_path, strerror(errno)); - fd = -1; - goto error; - } - - camel_object_unref((CamelObject *)mp); - - camel_operation_end(NULL); - - return 0; - error: - if (fd != -1) - close(fd); - if (mp) - camel_object_unref((CamelObject *)mp); - if (info) - camel_folder_summary_info_free(s, (CamelMessageInfo *)info); - - camel_operation_end(NULL); - - return -1; -} - -static int -spool_summary_sync(CamelSpoolSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex) -{ - struct stat st; - CamelFolderSummary *s = (CamelFolderSummary *)cls; - int i, count; - int quick = TRUE, work=FALSE; - int ret; - - /* first, sync ourselves up, just to make sure */ - summary_update(cls, cls->folder_size, changeinfo, ex); - if (camel_exception_is_set(ex)) - return -1; - - count = camel_folder_summary_count(s); - if (count == 0) - return 0; - - /* check what work we have to do, if any */ - for (i=0;quick && i<count; i++) { - CamelMessageInfo *info = camel_folder_summary_index(s, i); - g_assert(info); - if ((expunge && (info->flags & CAMEL_MESSAGE_DELETED)) || - (info->flags & (CAMEL_MESSAGE_FOLDER_NOXEV|CAMEL_MESSAGE_FOLDER_XEVCHANGE))) - quick = FALSE; - else - work |= (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0; - camel_folder_summary_info_free(s, info); - } - - /* yuck i hate this logic, but its to simplify the 'all ok, update summary' and failover cases */ - ret = -1; - if (quick) { - if (work) { - ret = spool_summary_sync_quick(cls, expunge, changeinfo, ex); - if (ret == -1) { - g_warning("failed a quick-sync, trying a full sync"); - camel_exception_clear(ex); - } - } else { - ret = 0; - } - } - - if (ret == -1) - ret = spool_summary_sync_full(cls, expunge, changeinfo, ex); - if (ret == -1) - return -1; - - if (stat(cls->folder_path, &st) == -1) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Unknown error: %s"), strerror(errno)); - return -1; - } - - camel_folder_summary_touch(s); - s->time = st.st_mtime; - cls->folder_size = st.st_size; - /*camel_folder_summary_save(s);*/ - - return 0; -} - - -static CamelMessageInfo * -spool_summary_add(CamelSpoolSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *ci, CamelException *ex) -{ - CamelMessageInfo *mi; - char *xev; - - d(printf("Adding message to summary\n")); - - mi = camel_folder_summary_add_from_message((CamelFolderSummary *)cls, msg); - if (mi) { - d(printf("Added, uid = %s\n", camel_message_info_uid(mi))); - if (info) { - CamelTag *tag = info->user_tags; - CamelFlag *flag = info->user_flags; - - while (flag) { - camel_flag_set(&mi->user_flags, flag->name, TRUE); - flag = flag->next; - } - - while (tag) { - camel_tag_set(&mi->user_tags, tag->name, tag->value); - tag = tag->next; - } - - mi->flags = mi->flags | (info->flags & 0xffff); - } - mi->flags &= ~(CAMEL_MESSAGE_FOLDER_NOXEV|CAMEL_MESSAGE_FOLDER_FLAGGED); - xev = camel_spool_summary_encode_x_evolution(cls, mi); - camel_medium_set_header((CamelMedium *)msg, "X-Evolution", xev); - g_free(xev); - camel_folder_change_info_add_uid(ci, camel_message_info_uid(mi)); - } else { - d(printf("Failed!\n")); - camel_exception_set(ex, 1, _("Unable to add message to summary: unknown reason")); - } - return mi; -} - -static char * -spool_summary_encode_x_evolution(CamelSpoolSummary *cls, const CamelMessageInfo *mi) -{ - GString *out = g_string_new(""); - struct _header_param *params = NULL; - GString *val = g_string_new(""); - CamelFlag *flag = mi->user_flags; - CamelTag *tag = mi->user_tags; - char *ret; - const char *p, *uidstr; - guint32 uid; - - /* FIXME: work out what to do with uid's that aren't stored here? */ - /* FIXME: perhaps make that a mbox folder only issue?? */ - p = uidstr = camel_message_info_uid(mi); - while (*p && isdigit(*p)) - p++; - if (*p == 0 && sscanf(uidstr, "%u", &uid) == 1) { - g_string_sprintf(out, "%08x-%04x", uid, mi->flags & 0xffff); - } else { - g_string_sprintf(out, "%s-%04x", uidstr, mi->flags & 0xffff); - } - - if (flag || tag) { - val = g_string_new(""); - - if (flag) { - while (flag) { - g_string_append(val, flag->name); - if (flag->next) - g_string_append_c(val, ','); - flag = flag->next; - } - header_set_param(¶ms, "flags", val->str); - g_string_truncate(val, 0); - } - if (tag) { - while (tag) { - g_string_append(val, tag->name); - g_string_append_c(val, '='); - g_string_append(val, tag->value); - if (tag->next) - g_string_append_c(val, ','); - tag = tag->next; - } - header_set_param(¶ms, "tags", val->str); - } - g_string_free(val, TRUE); - header_param_list_format_append(out, params); - header_param_list_free(params); - } - ret = out->str; - g_string_free(out, FALSE); - return ret; -} - -static int -spool_summary_decode_x_evolution(CamelSpoolSummary *cls, const char *xev, CamelMessageInfo *mi) -{ - struct _header_param *params, *scan; - guint32 uid, flags; - char *header; - int i; - - /* check for uid/flags */ - header = header_token_decode(xev); - if (header && strlen(header) == strlen("00000000-0000") - && sscanf(header, "%08x-%04x", &uid, &flags) == 2) { - char uidstr[20]; - if (mi) { - sprintf(uidstr, "%u", uid); - camel_message_info_set_uid(mi, g_strdup(uidstr)); - mi->flags = flags; - } - } else { - g_free(header); - return -1; - } - g_free(header); - - if (mi == NULL) - return 0; - - /* check for additional data */ - header = strchr(xev, ';'); - if (header) { - params = header_param_list_decode(header+1); - scan = params; - while (scan) { - if (!strcasecmp(scan->name, "flags")) { - char **flagv = g_strsplit(scan->value, ",", 1000); - - for (i=0;flagv[i];i++) { - camel_flag_set(&mi->user_flags, flagv[i], TRUE); - } - g_strfreev(flagv); - } else if (!strcasecmp(scan->name, "tags")) { - char **tagv = g_strsplit(scan->value, ",", 10000); - char *val; - - for (i=0;tagv[i];i++) { - val = strchr(tagv[i], '='); - if (val) { - *val++ = 0; - camel_tag_set(&mi->user_tags, tagv[i], val); - val[-1]='='; - } - } - g_strfreev(tagv); - } - scan = scan->next; - } - header_param_list_free(params); - } - return 0; -} - |