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 library is free software you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation.
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this library; if not, see <http://www.gnu.org/licenses/>.
31 #include <sys/types.h>
33 #include <glib/gstdio.h>
34 #include <glib/gi18n-lib.h>
36 #include "camel-spool-summary.h"
37 #include "camel-local-private.h"
38 #include "camel-win32.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,
48 static gint spool_summary_check (CamelLocalSummary *cls,
49 CamelFolderChangeInfo *changeinfo,
50 GCancellable *cancellable,
53 static gint spool_summary_sync_full (CamelMboxSummary *cls,
55 CamelFolderChangeInfo *changeinfo,
56 GCancellable *cancellable,
58 static gint spool_summary_need_index (void);
60 G_DEFINE_TYPE (CamelSpoolSummary, camel_spool_summary, CAMEL_TYPE_MBOX_SUMMARY)
63 camel_spool_summary_class_init (CamelSpoolSummaryClass *class)
65 CamelLocalSummaryClass *local_summary_class;
66 CamelMboxSummaryClass *mbox_summary_class;
68 local_summary_class = CAMEL_LOCAL_SUMMARY_CLASS (class);
69 local_summary_class->load = spool_summary_load;
70 local_summary_class->check = spool_summary_check;
71 local_summary_class->need_index = spool_summary_need_index;
73 mbox_summary_class = CAMEL_MBOX_SUMMARY_CLASS (class);
74 mbox_summary_class->sync_full = spool_summary_sync_full;
78 camel_spool_summary_init (CamelSpoolSummary *spool_summary)
80 CamelFolderSummary *folder_summary;
82 folder_summary = CAMEL_FOLDER_SUMMARY (spool_summary);
84 /* message info size is from mbox parent */
86 /* and a unique file version */
87 folder_summary->version += CAMEL_SPOOL_SUMMARY_VERSION;
91 camel_spool_summary_new (CamelFolder *folder,
92 const gchar *mbox_name)
94 CamelSpoolSummary *new;
96 new = g_object_new (CAMEL_TYPE_SPOOL_SUMMARY, "folder", folder, NULL);
98 CamelStore *parent_store;
100 parent_store = camel_folder_get_parent_store (folder);
101 camel_db_set_collate (parent_store->cdb_r, "bdata", "spool_frompos_sort", (CamelDBCollate) camel_local_frompos_sort);
102 ((CamelFolderSummary *) new)->sort_by = "bdata";
103 ((CamelFolderSummary *) new)->collate = "spool_frompos_sort";
105 camel_local_summary_construct ((CamelLocalSummary *) new, mbox_name, NULL);
106 camel_folder_summary_load_from_db ((CamelFolderSummary *) new, NULL);
111 spool_summary_load (CamelLocalSummary *cls,
115 /* if not loading, then rescan mbox file content */
116 camel_local_summary_check_force (cls);
121 /* perform a full sync */
123 spool_summary_sync_full (CamelMboxSummary *cls,
125 CamelFolderChangeInfo *changeinfo,
126 GCancellable *cancellable,
129 gint fd = -1, fdout = -1;
130 gchar tmpname[64] = { '\0' };
132 goffset spoollen, outlen;
135 guint32 flags = (expunge ? 1 : 0);
137 d (printf ("performing full summary/sync\n"));
139 camel_operation_push_message (cancellable, _("Storing folder"));
141 fd = open (((CamelLocalSummary *) cls)->folder_path, O_RDWR | O_LARGEFILE);
145 g_io_error_from_errno (errno),
146 _("Could not open file: %s: %s"),
147 ((CamelLocalSummary *) cls)->folder_path,
149 camel_operation_pop_message (cancellable);
153 g_snprintf (tmpname, sizeof (tmpname), "/tmp/spool.camel.XXXXXX");
154 fdout = g_mkstemp (tmpname);
156 d (printf ("Writing tmp file to %s\n", tmpname));
160 g_io_error_from_errno (errno),
161 _("Cannot open temporary mailbox: %s"),
166 if (camel_mbox_summary_sync_mbox (
167 (CamelMboxSummary *) cls, flags, changeinfo,
168 fd, fdout, cancellable, error) == -1)
171 /* sync out content */
172 if (fsync (fdout) == -1) {
173 g_warning ("Cannot synchronize temporary folder: %s", g_strerror (errno));
176 g_io_error_from_errno (errno),
177 _("Could not synchronize temporary folder %s: %s"),
178 ((CamelLocalSummary *) cls)->folder_path,
183 /* see if we can write this much to the spool file */
184 if (fstat (fd, &st) == -1) {
185 g_warning ("Cannot synchronize temporary folder: %s", g_strerror (errno));
188 g_io_error_from_errno (errno),
189 _("Could not synchronize temporary folder %s: %s"),
190 ((CamelLocalSummary *) cls)->folder_path,
194 spoollen = st.st_size;
196 if (fstat (fdout, &st) == -1) {
197 g_warning ("Cannot synchronize temporary folder: %s", g_strerror (errno));
200 g_io_error_from_errno (errno),
201 _("Could not synchronize temporary folder %s: %s"),
202 ((CamelLocalSummary *) cls)->folder_path,
208 /* I think this is the right way to do this - checking that the file will fit the new data */
210 && (lseek (fd, outlen - 1, SEEK_SET) == -1
211 || write (fd, "", 1) != 1
213 || lseek (fd, 0, SEEK_SET) == -1
214 || lseek (fdout, 0, SEEK_SET) == -1)) {
215 g_warning ("Cannot synchronize spool folder: %s", g_strerror (errno));
218 g_io_error_from_errno (errno),
219 _("Could not synchronize spool folder %s: %s"),
220 ((CamelLocalSummary *) cls)->folder_path,
222 /* incase we ran out of room, remove any trailing space first */
223 if (ftruncate (fd, spoollen) == -1) {
224 g_debug ("%s: Failed to call ftruncate: %s", G_STRFUNC, g_strerror (errno));
229 /* now copy content back */
230 buffer = g_malloc (8192);
234 size = read (fdout, buffer, 8192);
235 } while (size == -1 && errno == EINTR);
240 sizeout = write (fd, p, size);
245 } while ((sizeout == -1 && errno == EINTR) && size > 0);
252 g_io_error_from_errno (errno),
253 _("Could not synchronize spool folder %s: %s\n"
254 "Folder may be corrupt, copy saved in '%s'"),
255 ((CamelLocalSummary *) cls)->folder_path,
256 g_strerror (errno), tmpname);
257 /* so we dont delete it */
266 d (printf ("Closing folders\n"));
268 if (ftruncate (fd, outlen) == -1) {
271 g_io_error_from_errno (errno),
272 _("Could not synchronize spool folder %s: %s\n"
273 "Folder may be corrupt, copy saved in '%s'"),
274 ((CamelLocalSummary *) cls)->folder_path,
275 g_strerror (errno), tmpname);
280 if (close (fd) == -1) {
281 g_warning ("Cannot close source folder: %s", g_strerror (errno));
284 g_io_error_from_errno (errno),
285 _("Could not synchronize spool folder %s: %s\n"
286 "Folder may be corrupt, copy saved in '%s'"),
287 ((CamelLocalSummary *) cls)->folder_path,
288 g_strerror (errno), tmpname);
296 if (tmpname[0] != '\0')
299 camel_operation_pop_message (cancellable);
309 if (tmpname[0] != '\0')
312 camel_operation_pop_message (cancellable);
318 spool_summary_check (CamelLocalSummary *cls,
319 CamelFolderChangeInfo *changeinfo,
320 GCancellable *cancellable,
326 CamelFolderSummary *s = (CamelFolderSummary *) cls;
327 GPtrArray *known_uids;
329 if (CAMEL_LOCAL_SUMMARY_CLASS (camel_spool_summary_parent_class)->check (cls, changeinfo, cancellable, error) == -1)
332 /* check to see if we need to copy/update the file; missing xev headers prompt this */
334 camel_folder_summary_prepare_fetch_all (s, error);
335 known_uids = camel_folder_summary_get_array (s);
336 for (i = 0; !work && known_uids && i < known_uids->len; i++) {
337 CamelMboxMessageInfo *info = (CamelMboxMessageInfo *) camel_folder_summary_get (s, g_ptr_array_index (known_uids, i));
339 work = (info->info.info.flags & (CAMEL_MESSAGE_FOLDER_NOXEV)) != 0;
340 camel_message_info_unref (info);
342 camel_folder_summary_free_array (known_uids);
344 /* if we do, then write out the headers using sync_full, etc */
346 d (printf ("Have to add new headers, re-syncing from the start to accomplish this\n"));
347 if (CAMEL_MBOX_SUMMARY_GET_CLASS (cls)->sync_full (
348 CAMEL_MBOX_SUMMARY (cls), FALSE,
349 changeinfo, cancellable, error) == -1)
352 if (g_stat (cls->folder_path, &st) == -1) {
355 g_io_error_from_errno (errno),
356 _("Unknown error: %s"),
361 ((CamelMboxSummary *) cls)->folder_size = st.st_size;
362 ((CamelFolderSummary *) cls)->time = st.st_mtime;
369 spool_summary_need_index (void)