1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*-
3 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5 * Authors: Michael Zucchi <notzed@ximian.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
33 #include <sys/types.h>
35 #include <glib/gi18n-lib.h>
37 #include "camel-spool-summary.h"
38 #include "camel-local-private.h"
41 #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
43 #define CAMEL_SPOOL_SUMMARY_VERSION (0x400)
45 static gint spool_summary_load(CamelLocalSummary *cls, gint forceindex, CamelException *ex);
46 static gint spool_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex);
48 static gint spool_summary_sync_full(CamelMboxSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex);
49 static gint spool_summary_need_index(void);
51 static void camel_spool_summary_class_init (CamelSpoolSummaryClass *klass);
52 static void camel_spool_summary_init (CamelSpoolSummary *obj);
53 static void camel_spool_summary_finalize (CamelObject *obj);
55 static CamelFolderSummaryClass *camel_spool_summary_parent;
58 camel_spool_summary_get_type(void)
60 static CamelType type = CAMEL_INVALID_TYPE;
62 if (type == CAMEL_INVALID_TYPE) {
63 type = camel_type_register(camel_mbox_summary_get_type(), "CamelSpoolSummary",
64 sizeof (CamelSpoolSummary),
65 sizeof (CamelSpoolSummaryClass),
66 (CamelObjectClassInitFunc) camel_spool_summary_class_init,
68 (CamelObjectInitFunc) camel_spool_summary_init,
69 (CamelObjectFinalizeFunc) camel_spool_summary_finalize);
76 camel_spool_summary_class_init(CamelSpoolSummaryClass *klass)
78 CamelLocalSummaryClass *lklass = (CamelLocalSummaryClass *)klass;
79 CamelMboxSummaryClass *mklass = (CamelMboxSummaryClass *)klass;
81 camel_spool_summary_parent = CAMEL_FOLDER_SUMMARY_CLASS(camel_mbox_summary_get_type());
83 lklass->load = spool_summary_load;
84 lklass->check = spool_summary_check;
85 lklass->need_index = spool_summary_need_index;
87 mklass->sync_full = spool_summary_sync_full;
91 camel_spool_summary_init(CamelSpoolSummary *obj)
93 struct _CamelFolderSummary *s = (CamelFolderSummary *)obj;
95 /* message info size is from mbox parent */
97 /* and a unique file version */
98 s->version += CAMEL_SPOOL_SUMMARY_VERSION;
102 camel_spool_summary_finalize(CamelObject *obj)
104 /*CamelSpoolSummary *mbs = CAMEL_SPOOL_SUMMARY(obj);*/
108 camel_spool_summary_new(struct _CamelFolder *folder, const gchar *mbox_name)
110 CamelSpoolSummary *new = (CamelSpoolSummary *)camel_object_new(camel_spool_summary_get_type());
112 ((CamelFolderSummary *)new)->folder = folder;
114 camel_db_set_collate (folder->parent_store->cdb_r, "bdata", "spool_frompos_sort", (CamelDBCollate)camel_local_frompos_sort);
115 ((CamelFolderSummary *)new)->sort_by = "bdata";
116 ((CamelFolderSummary *)new)->collate = "spool_frompos_sort";
118 camel_local_summary_construct((CamelLocalSummary *)new, NULL, mbox_name, NULL);
119 camel_folder_summary_load_from_db ((CamelFolderSummary *)new, NULL);
124 spool_summary_load(CamelLocalSummary *cls, gint forceindex, CamelException *ex)
126 g_warning("spool summary - not loading anything\n");
130 /* perform a full sync */
132 spool_summary_sync_full(CamelMboxSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex)
134 gint fd = -1, fdout = -1;
135 gchar tmpname[64] = { '\0' };
137 off_t spoollen, outlen;
140 guint32 flags = (expunge?1:0);
142 d(printf("performing full summary/sync\n"));
144 camel_operation_start(NULL, _("Storing folder"));
146 fd = open(((CamelLocalSummary *)cls)->folder_path, O_RDWR|O_LARGEFILE);
148 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
149 _("Could not open file: %s: %s"),
150 ((CamelLocalSummary *)cls)->folder_path,
152 camel_operation_end(NULL);
156 sprintf (tmpname, "/tmp/spool.camel.XXXXXX");
157 fdout = g_mkstemp (tmpname);
159 d(printf("Writing tmp file to %s\n", tmpname));
161 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
162 _("Cannot open temporary mailbox: %s"),
167 if (camel_mbox_summary_sync_mbox((CamelMboxSummary *)cls, flags, changeinfo, fd, fdout, ex) == -1)
170 /* sync out content */
171 if (fsync(fdout) == -1) {
172 g_warning("Cannot sync temporary folder: %s", g_strerror (errno));
173 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
174 _("Could not sync temporary folder %s: %s"),
175 ((CamelLocalSummary *)cls)->folder_path,
180 /* see if we can write this much to the spool file */
181 if (fstat(fd, &st) == -1) {
182 g_warning("Cannot sync temporary folder: %s", g_strerror (errno));
183 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
184 _("Could not sync temporary folder %s: %s"),
185 ((CamelLocalSummary *)cls)->folder_path,
189 spoollen = st.st_size;
191 if (fstat(fdout, &st) == -1) {
192 g_warning("Cannot sync temporary folder: %s", g_strerror (errno));
193 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
194 _("Could not sync temporary folder %s: %s"),
195 ((CamelLocalSummary *)cls)->folder_path,
201 /* I think this is the right way to do this - checking that the file will fit the new data */
203 && (lseek(fd, outlen-1, SEEK_SET) == -1
204 || write(fd, "", 1) != 1
206 || lseek(fd, 0, SEEK_SET) == -1
207 || lseek(fdout, 0, SEEK_SET) == -1)) {
208 g_warning("Cannot sync spool folder: %s", g_strerror (errno));
209 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
210 _("Could not sync spool folder %s: %s"),
211 ((CamelLocalSummary *)cls)->folder_path,
213 /* incase we ran out of room, remove any trailing space first */
214 ftruncate(fd, spoollen);
218 /* now copy content back */
219 buffer = g_malloc(8192);
223 size = read(fdout, buffer, 8192);
224 } while (size == -1 && errno == EINTR);
229 sizeout = write(fd, p, size);
234 } while ((sizeout == -1 && errno == EINTR) && size > 0);
239 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
240 _("Could not sync spool folder %s: %s\n"
241 "Folder may be corrupt, copy saved in '%s'"),
242 ((CamelLocalSummary *)cls)->folder_path,
243 g_strerror (errno), tmpname);
244 /* so we dont delete it */
253 d(printf("Closing folders\n"));
255 if (ftruncate(fd, outlen) == -1) {
256 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
257 _("Could not sync spool folder %s: %s\n"
258 "Folder may be corrupt, copy saved in '%s'"),
259 ((CamelLocalSummary *)cls)->folder_path,
260 g_strerror (errno), tmpname);
265 if (close(fd) == -1) {
266 g_warning("Cannot close source folder: %s", g_strerror (errno));
267 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
268 _("Could not sync spool folder %s: %s\n"
269 "Folder may be corrupt, copy saved in '%s'"),
270 ((CamelLocalSummary *)cls)->folder_path,
271 g_strerror (errno), tmpname);
279 if (tmpname[0] != '\0')
282 camel_operation_end(NULL);
292 if (tmpname[0] != '\0')
295 camel_operation_end(NULL);
301 spool_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex)
305 CamelFolderSummary *s = (CamelFolderSummary *)cls;
307 if (((CamelLocalSummaryClass *)camel_spool_summary_parent)->check(cls, changeinfo, ex) == -1)
310 /* check to see if we need to copy/update the file; missing xev headers prompt this */
312 count = camel_folder_summary_count(s);
313 for (i=0;!work && i<count; i++) {
314 CamelMboxMessageInfo *info = (CamelMboxMessageInfo *)camel_folder_summary_index(s, i);
316 work = (info->info.info.flags & (CAMEL_MESSAGE_FOLDER_NOXEV)) != 0;
317 camel_message_info_free((CamelMessageInfo *)info);
320 /* if we do, then write out the headers using sync_full, etc */
322 d(printf("Have to add new headers, re-syncing from the start to accomplish this\n"));
323 if (((CamelMboxSummaryClass *)((CamelObject *)cls)->klass)->sync_full((CamelMboxSummary *)cls, FALSE, changeinfo, ex) == -1)
326 if (stat(cls->folder_path, &st) == -1) {
327 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
328 _("Unknown error: %s"),
333 ((CamelMboxSummary *)cls)->folder_size = st.st_size;
334 ((CamelFolderSummary *)cls)->time = st.st_mtime;
341 spool_summary_need_index(void) {