Fix FSF address (Tobias Mueller, #470445)
[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 2004 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
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <ctype.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36
37 #include <glib.h>
38 #include <glib/gi18n-lib.h>
39 #include <glib/gstdio.h>
40
41 #include "camel-data-cache.h"
42 #include "camel-file-utils.h"
43 #include "camel-folder-summary.h"
44 #include "camel-folder.h"
45 #include "camel-offline-journal.h"
46 #include "camel-private.h"
47
48 #define d(x) x
49
50 static void camel_offline_journal_class_init (CamelOfflineJournalClass *klass);
51 static void camel_offline_journal_init (CamelOfflineJournal *journal, CamelOfflineJournalClass *klass);
52 static void camel_offline_journal_finalize (CamelObject *object);
53
54
55 static CamelObjectClass *parent_class = NULL;
56
57
58 CamelType
59 camel_offline_journal_get_type (void)
60 {
61         static CamelType type = 0;
62         
63         if (!type) {
64                 type = camel_type_register (camel_object_get_type (),
65                                             "CamelOfflineJournal",
66                                             sizeof (CamelOfflineJournal),
67                                             sizeof (CamelOfflineJournalClass),
68                                             (CamelObjectClassInitFunc) camel_offline_journal_class_init,
69                                             NULL,
70                                             (CamelObjectInitFunc) camel_offline_journal_init,
71                                             (CamelObjectFinalizeFunc) camel_offline_journal_finalize);
72         }
73         
74         return type;
75 }
76
77 static void
78 camel_offline_journal_class_init (CamelOfflineJournalClass *klass)
79 {
80         parent_class = camel_type_get_global_classfuncs (CAMEL_OBJECT_TYPE);
81 }
82
83 static void
84 camel_offline_journal_init (CamelOfflineJournal *journal, CamelOfflineJournalClass *klass)
85 {
86         journal->folder = NULL;
87         journal->filename = NULL;
88         e_dlist_init (&journal->queue);
89 }
90
91 static void
92 camel_offline_journal_finalize (CamelObject *object)
93 {
94         CamelOfflineJournal *journal = (CamelOfflineJournal *) object;
95         EDListNode *entry;
96         
97         g_free (journal->filename);
98         
99         while ((entry = e_dlist_remhead (&journal->queue)))
100                 CAMEL_OFFLINE_JOURNAL_GET_CLASS (journal)->entry_free (journal, entry);
101 }
102
103 /**
104  * camel_offline_journal_construct:
105  * @journal: a #CamelOfflineJournal object
106  * @folder: a #CamelFolder object
107  * @filename: a filename to save/load the journal
108  *
109  * Constructs a journal object.
110  **/
111 void
112 camel_offline_journal_construct (CamelOfflineJournal *journal, CamelFolder *folder, const char *filename)
113 {
114         EDListNode *entry;
115         FILE *fp;
116         
117         journal->filename = g_strdup (filename);
118         journal->folder = folder;
119         
120         if ((fp = g_fopen (filename, "rb"))) {
121                 while ((entry = CAMEL_OFFLINE_JOURNAL_GET_CLASS (journal)->entry_load (journal, fp)))
122                         e_dlist_addtail (&journal->queue, entry);
123                 
124                 fclose (fp);
125         }
126 }
127
128
129 /**
130  * camel_offline_journal_set_filename:
131  * @journal: a #CamelOfflineJournal object
132  * @filename: a filename to load/save the journal to
133  *
134  * Set the filename where the journal should load/save from.
135  **/
136 void
137 camel_offline_journal_set_filename (CamelOfflineJournal *journal, const char *filename)
138 {
139         g_return_if_fail (CAMEL_IS_OFFLINE_JOURNAL (journal));
140         
141         g_free (journal->filename);
142         journal->filename = g_strdup (filename);
143 }
144
145
146 /**
147  * camel_offline_journal_write:
148  * @journal: a #CamelOfflineJournal object
149  * @ex: a #CamelException
150  *
151  * Save the journal to disk.
152  *
153  * Returns %0 on success or %-1 on fail
154  **/
155 int
156 camel_offline_journal_write (CamelOfflineJournal *journal, CamelException *ex)
157 {
158         EDListNode *entry;
159         FILE *fp;
160         int fd;
161         
162         if ((fd = g_open (journal->filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0666)) == -1) {
163                 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
164                                       _("Cannot write offline journal for folder `%s': %s"),
165                                       journal->folder->full_name, g_strerror (errno));
166                 return -1;
167         }
168         
169         fp = fdopen (fd, "w");
170         entry = journal->queue.head;
171         while (entry->next) {
172                 if (CAMEL_OFFLINE_JOURNAL_GET_CLASS (journal)->entry_write (journal, entry, fp) == -1)
173                         goto exception;
174                 entry = entry->next;
175         }
176         
177         if (fsync (fd) == -1)
178                 goto exception;
179         
180         fclose (fp);
181         
182         return 0;
183         
184  exception:
185         
186         camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
187                               _("Cannot write offline journal for folder `%s': %s"),
188                               journal->folder->full_name, g_strerror (errno));
189         
190         fclose (fp);
191         
192         return -1;
193 }
194
195
196 /**
197  * camel_offline_journal_replay:
198  * @journal: a #CamelOfflineJournal object
199  * @ex: a #CamelException
200  *
201  * Replay all entries in the journal.
202  *
203  * Returns %0 on success (no entry failed to replay) or %-1 on fail
204  **/
205 int
206 camel_offline_journal_replay (CamelOfflineJournal *journal, CamelException *ex)
207 {
208         EDListNode *entry, *next;
209         CamelException lex;
210         int failed = 0;
211         
212         camel_exception_init (&lex);
213         
214         entry = journal->queue.head;
215         while (entry->next) {
216                 next = entry->next;
217                 if (CAMEL_OFFLINE_JOURNAL_GET_CLASS (journal)->entry_play (journal, entry, &lex) == -1) {
218                         if (failed == 0)
219                                 camel_exception_xfer (ex, &lex);
220                         camel_exception_clear (&lex);
221                         failed++;
222                 } else {
223                         e_dlist_remove (entry);
224                 }
225                 entry = next;
226         }
227         
228         if (failed > 0)
229                 return -1;
230         
231         return 0;
232 }