1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*-
3 * Copyright (C) 2001 Ximian Inc. (www.ximian.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-file-utils.h"
38 #include "camel-mime-message.h"
39 #include "camel-operation.h"
41 #include "camel-spool-summary.h"
44 #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
46 #define CAMEL_SPOOL_SUMMARY_VERSION (0x400)
48 static int spool_summary_load(CamelLocalSummary *cls, int forceindex, CamelException *ex);
49 static int spool_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex);
51 static int spool_summary_sync_full(CamelMboxSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex);
53 static void camel_spool_summary_class_init (CamelSpoolSummaryClass *klass);
54 static void camel_spool_summary_init (CamelSpoolSummary *obj);
55 static void camel_spool_summary_finalise (CamelObject *obj);
57 static CamelFolderSummaryClass *camel_spool_summary_parent;
60 camel_spool_summary_get_type(void)
62 static CamelType type = CAMEL_INVALID_TYPE;
64 if (type == CAMEL_INVALID_TYPE) {
65 type = camel_type_register(camel_mbox_summary_get_type(), "CamelSpoolSummary",
66 sizeof (CamelSpoolSummary),
67 sizeof (CamelSpoolSummaryClass),
68 (CamelObjectClassInitFunc) camel_spool_summary_class_init,
70 (CamelObjectInitFunc) camel_spool_summary_init,
71 (CamelObjectFinalizeFunc) camel_spool_summary_finalise);
78 camel_spool_summary_class_init(CamelSpoolSummaryClass *klass)
80 CamelLocalSummaryClass *lklass = (CamelLocalSummaryClass *)klass;
81 CamelMboxSummaryClass *mklass = (CamelMboxSummaryClass *)klass;
83 camel_spool_summary_parent = CAMEL_FOLDER_SUMMARY_CLASS(camel_mbox_summary_get_type());
85 lklass->load = spool_summary_load;
86 lklass->check = spool_summary_check;
88 mklass->sync_full = spool_summary_sync_full;
92 camel_spool_summary_init(CamelSpoolSummary *obj)
94 struct _CamelFolderSummary *s = (CamelFolderSummary *)obj;
96 /* message info size is from mbox parent */
98 /* and a unique file version */
99 s->version += CAMEL_SPOOL_SUMMARY_VERSION;
103 camel_spool_summary_finalise(CamelObject *obj)
105 /*CamelSpoolSummary *mbs = CAMEL_SPOOL_SUMMARY(obj);*/
109 camel_spool_summary_new(struct _CamelFolder *folder, const char *mbox_name)
111 CamelSpoolSummary *new = (CamelSpoolSummary *)camel_object_new(camel_spool_summary_get_type());
113 ((CamelFolderSummary *)new)->folder = folder;
115 camel_local_summary_construct((CamelLocalSummary *)new, NULL, mbox_name, NULL);
120 spool_summary_load(CamelLocalSummary *cls, int forceindex, CamelException *ex)
122 g_warning("spool summary - not loading anything\n");
126 /* perform a full sync */
128 spool_summary_sync_full(CamelMboxSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex)
130 int fd = -1, fdout = -1;
131 char tmpname[64] = { '\0' };
133 off_t spoollen, outlen;
136 guint32 flags = (expunge?1:0);
138 d(printf("performing full summary/sync\n"));
140 camel_operation_start(NULL, _("Storing folder"));
142 fd = open(((CamelLocalSummary *)cls)->folder_path, O_RDWR);
144 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
145 _("Could not open file: %s: %s"),
146 ((CamelLocalSummary *)cls)->folder_path,
148 camel_operation_end(NULL);
152 sprintf (tmpname, "/tmp/spool.camel.XXXXXX");
153 fdout = g_mkstemp (tmpname);
155 d(printf("Writing tmp file to %s\n", tmpname));
157 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
158 _("Cannot open temporary mailbox: %s"),
163 if (camel_mbox_summary_sync_mbox((CamelMboxSummary *)cls, flags, changeinfo, fd, fdout, ex) == -1)
167 /* sync out content */
168 if (fsync(fdout) == -1) {
169 g_warning("Cannot sync temporary folder: %s", strerror (errno));
170 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
171 _("Could not sync temporary folder %s: %s"),
172 ((CamelLocalSummary *)cls)->folder_path,
177 /* see if we can write this much to the spool file */
178 if (fstat(fd, &st) == -1) {
179 g_warning("Cannot sync temporary folder: %s", strerror (errno));
180 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
181 _("Could not sync temporary folder %s: %s"),
182 ((CamelLocalSummary *)cls)->folder_path,
186 spoollen = st.st_size;
188 if (fstat(fdout, &st) == -1) {
189 g_warning("Cannot sync temporary folder: %s", strerror (errno));
190 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
191 _("Could not sync temporary folder %s: %s"),
192 ((CamelLocalSummary *)cls)->folder_path,
198 /* I think this is the right way to do this - checking that the file will fit the new data */
200 && (lseek(fd, outlen-1, SEEK_SET) == -1
201 || write(fd, "", 1) != 1
203 || lseek(fd, 0, SEEK_SET) == -1
204 || lseek(fdout, 0, SEEK_SET) == -1)) {
205 g_warning("Cannot sync spool folder: %s", strerror (errno));
206 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
207 _("Could not sync spool folder %s: %s"),
208 ((CamelLocalSummary *)cls)->folder_path,
210 /* incase we ran out of room, remove any trailing space first */
211 ftruncate(fd, spoollen);
216 /* now copy content back */
217 buffer = g_malloc(8192);
221 size = read(fdout, buffer, 8192);
222 } while (size == -1 && errno == EINTR);
227 sizeout = write(fd, p, size);
232 } while ((sizeout == -1 && errno == EINTR) && size > 0);
237 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
238 _("Could not sync spool folder %s: %s\n"
239 "Folder may be corrupt, copy saved in `%s'"),
240 ((CamelLocalSummary *)cls)->folder_path,
241 g_strerror (errno), tmpname);
242 /* so we dont delete it */
251 d(printf("Closing folders\n"));
253 if (ftruncate(fd, outlen) == -1) {
254 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
255 _("Could not sync spool folder %s: %s\n"
256 "Folder may be corrupt, copy saved in `%s'"),
257 ((CamelLocalSummary *)cls)->folder_path,
258 g_strerror (errno), tmpname);
263 if (close(fd) == -1) {
264 g_warning("Cannot close source folder: %s", strerror (errno));
265 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
266 _("Could not sync spool folder %s: %s\n"
267 "Folder may be corrupt, copy saved in `%s'"),
268 ((CamelLocalSummary *)cls)->folder_path,
269 g_strerror (errno), tmpname);
277 if (tmpname[0] != '\0')
280 camel_operation_end(NULL);
290 if (tmpname[0] != '\0')
293 camel_operation_end(NULL);
299 spool_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex)
303 CamelFolderSummary *s = (CamelFolderSummary *)cls;
305 if (((CamelLocalSummaryClass *)camel_spool_summary_parent)->check(cls, changeinfo, ex) == -1)
308 /* check to see if we need to copy/update the file; missing xev headers prompt this */
310 count = camel_folder_summary_count(s);
311 for (i=0;!work && i<count; i++) {
312 CamelMboxMessageInfo *info = (CamelMboxMessageInfo *)camel_folder_summary_index(s, i);
314 work = (info->info.info.flags & (CAMEL_MESSAGE_FOLDER_NOXEV)) != 0;
315 camel_message_info_free((CamelMessageInfo *)info);
318 /* if we do, then write out the headers using sync_full, etc */
320 d(printf("Have to add new headers, re-syncing from the start to accomplish this\n"));
321 if (((CamelMboxSummaryClass *)((CamelObject *)cls)->klass)->sync_full((CamelMboxSummary *)cls, FALSE, changeinfo, ex) == -1)
324 if (stat(cls->folder_path, &st) == -1) {
325 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
326 _("Unknown error: %s"),
331 ((CamelMboxSummary *)cls)->folder_size = st.st_size;
332 ((CamelFolderSummary *)cls)->time = st.st_mtime;