09b36e0a63958da66d243cc59a674183e819b18f
[platform/upstream/evolution-data-server.git] / camel / camel-offline-journal.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  Authors: Jeffrey Stedfast <fejj@novell.com>
4  *
5  *  Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU Lesser General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <ctype.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35
36 #include <glib.h>
37 #include <glib/gi18n-lib.h>
38 #include <glib/gstdio.h>
39
40 #include "camel-data-cache.h"
41 #include "camel-file-utils.h"
42 #include "camel-folder-summary.h"
43 #include "camel-folder.h"
44 #include "camel-offline-journal.h"
45 #include "camel-private.h"
46
47 #define d(x)
48
49 static void camel_offline_journal_class_init (CamelOfflineJournalClass *klass);
50 static void camel_offline_journal_init (CamelOfflineJournal *journal, CamelOfflineJournalClass *klass);
51 static void camel_offline_journal_finalize (CamelObject *object);
52
53 static CamelObjectClass *parent_class = NULL;
54
55 CamelType
56 camel_offline_journal_get_type (void)
57 {
58         static CamelType type = NULL;
59
60         if (!type) {
61                 type = camel_type_register (camel_object_get_type (),
62                                             "CamelOfflineJournal",
63                                             sizeof (CamelOfflineJournal),
64                                             sizeof (CamelOfflineJournalClass),
65                                             (CamelObjectClassInitFunc) camel_offline_journal_class_init,
66                                             NULL,
67                                             (CamelObjectInitFunc) camel_offline_journal_init,
68                                             (CamelObjectFinalizeFunc) camel_offline_journal_finalize);
69         }
70
71         return type;
72 }
73
74 static void
75 camel_offline_journal_class_init (CamelOfflineJournalClass *klass)
76 {
77         parent_class = camel_type_get_global_classfuncs (CAMEL_OBJECT_TYPE);
78 }
79
80 static void
81 camel_offline_journal_init (CamelOfflineJournal *journal, CamelOfflineJournalClass *klass)
82 {
83         journal->folder = NULL;
84         journal->filename = NULL;
85         camel_dlist_init (&journal->queue);
86 }
87
88 static void
89 camel_offline_journal_finalize (CamelObject *object)
90 {
91         CamelOfflineJournal *journal = (CamelOfflineJournal *) object;
92         CamelDListNode *entry;
93
94         g_free (journal->filename);
95
96         while ((entry = camel_dlist_remhead (&journal->queue)))
97                 CAMEL_OFFLINE_JOURNAL_GET_CLASS (journal)->entry_free (journal, entry);
98 }
99
100 /**
101  * camel_offline_journal_construct:
102  * @journal: a #CamelOfflineJournal object
103  * @folder: a #CamelFolder object
104  * @filename: a filename to save/load the journal
105  *
106  * Constructs a journal object.
107  **/
108 void
109 camel_offline_journal_construct (CamelOfflineJournal *journal, CamelFolder *folder, const gchar *filename)
110 {
111         CamelDListNode *entry;
112         FILE *fp;
113
114         journal->filename = g_strdup (filename);
115         journal->folder = folder;
116
117         if ((fp = g_fopen (filename, "rb"))) {
118                 while ((entry = CAMEL_OFFLINE_JOURNAL_GET_CLASS (journal)->entry_load (journal, fp)))
119                         camel_dlist_addtail (&journal->queue, entry);
120
121                 fclose (fp);
122         }
123 }
124
125 /**
126  * camel_offline_journal_set_filename:
127  * @journal: a #CamelOfflineJournal object
128  * @filename: a filename to load/save the journal to
129  *
130  * Set the filename where the journal should load/save from.
131  **/
132 void
133 camel_offline_journal_set_filename (CamelOfflineJournal *journal, const gchar *filename)
134 {
135         g_return_if_fail (CAMEL_IS_OFFLINE_JOURNAL (journal));
136
137         g_free (journal->filename);
138         journal->filename = g_strdup (filename);
139 }
140
141 /**
142  * camel_offline_journal_write:
143  * @journal: a #CamelOfflineJournal object
144  * @ex: a #CamelException
145  *
146  * Save the journal to disk.
147  *
148  * Returns: %0 on success or %-1 on fail
149  **/
150 gint
151 camel_offline_journal_write (CamelOfflineJournal *journal, CamelException *ex)
152 {
153         CamelDListNode *entry;
154         FILE *fp;
155         gint fd;
156
157         if ((fd = g_open (journal->filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0666)) == -1) {
158                 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
159                                       _("Cannot write offline journal for folder '%s': %s"),
160                                       journal->folder->full_name, g_strerror (errno));
161                 return -1;
162         }
163
164         fp = fdopen (fd, "w");
165         entry = journal->queue.head;
166         while (entry->next) {
167                 if (CAMEL_OFFLINE_JOURNAL_GET_CLASS (journal)->entry_write (journal, entry, fp) == -1)
168                         goto exception;
169                 entry = entry->next;
170         }
171
172         if (fsync (fd) == -1)
173                 goto exception;
174
175         fclose (fp);
176
177         return 0;
178
179  exception:
180
181         camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
182                               _("Cannot write offline journal for folder '%s': %s"),
183                               journal->folder->full_name, g_strerror (errno));
184
185         fclose (fp);
186
187         return -1;
188 }
189
190 /**
191  * camel_offline_journal_replay:
192  * @journal: a #CamelOfflineJournal object
193  * @ex: a #CamelException
194  *
195  * Replay all entries in the journal.
196  *
197  * Returns: %0 on success (no entry failed to replay) or %-1 on fail
198  **/
199 gint
200 camel_offline_journal_replay (CamelOfflineJournal *journal, CamelException *ex)
201 {
202         CamelDListNode *entry, *next;
203         CamelException lex;
204         gint failed = 0;
205
206         camel_exception_init (&lex);
207
208         entry = journal->queue.head;
209         while (entry->next) {
210                 next = entry->next;
211                 if (CAMEL_OFFLINE_JOURNAL_GET_CLASS (journal)->entry_play (journal, entry, &lex) == -1) {
212                         if (failed == 0)
213                                 camel_exception_xfer (ex, &lex);
214                         camel_exception_clear (&lex);
215                         failed++;
216                 } else {
217                         camel_dlist_remove (entry);
218                 }
219                 entry = next;
220         }
221
222         if (failed > 0)
223                 return -1;
224
225         return 0;
226 }