1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Authors: Jeffrey Stedfast <fejj@novell.com>
5 * Copyright 2004 Novell, Inc. (www.novell.com)
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.
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.
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.
35 #include <sys/types.h>
38 #include <glib/gi18n-lib.h>
40 #include "camel-data-cache.h"
41 #include "camel-file-utils.h"
42 #include "camel-folder-summary.h"
43 #include "camel-folder.h"
45 #include "camel-groupwise-folder.h"
46 #include "camel-groupwise-journal.h"
47 #include "camel-groupwise-store.h"
52 static void camel_groupwise_journal_class_init (CamelGroupwiseJournalClass *klass);
53 static void camel_groupwise_journal_init (CamelGroupwiseJournal *journal, CamelGroupwiseJournalClass *klass);
54 static void camel_groupwise_journal_finalize (CamelObject *object);
56 static void groupwise_entry_free (CamelOfflineJournal *journal, EDListNode *entry);
57 static EDListNode *groupwise_entry_load (CamelOfflineJournal *journal, FILE *in);
58 static int groupwise_entry_write (CamelOfflineJournal *journal, EDListNode *entry, FILE *out);
59 static int groupwise_entry_play (CamelOfflineJournal *journal, EDListNode *entry, CamelException *ex);
62 static CamelOfflineJournalClass *parent_class = NULL;
66 camel_groupwise_journal_get_type (void)
68 static CamelType type = 0;
71 type = camel_type_register (camel_offline_journal_get_type (),
72 "CamelGroupwiseJournal",
73 sizeof (CamelGroupwiseJournal),
74 sizeof (CamelGroupwiseJournalClass),
75 (CamelObjectClassInitFunc) camel_groupwise_journal_class_init,
77 (CamelObjectInitFunc) camel_groupwise_journal_init,
78 (CamelObjectFinalizeFunc) camel_groupwise_journal_finalize);
85 camel_groupwise_journal_class_init (CamelGroupwiseJournalClass *klass)
87 CamelOfflineJournalClass *journal_class = (CamelOfflineJournalClass *) klass;
89 parent_class = (CamelOfflineJournalClass *) camel_type_get_global_classfuncs (CAMEL_TYPE_OFFLINE_JOURNAL);
91 journal_class->entry_free = groupwise_entry_free;
92 journal_class->entry_load = groupwise_entry_load;
93 journal_class->entry_write = groupwise_entry_write;
94 journal_class->entry_play = groupwise_entry_play;
98 camel_groupwise_journal_init (CamelGroupwiseJournal *journal, CamelGroupwiseJournalClass *klass)
104 camel_groupwise_journal_finalize (CamelObject *object)
110 groupwise_entry_free (CamelOfflineJournal *journal, EDListNode *entry)
112 CamelGroupwiseJournalEntry *groupwise_entry = (CamelGroupwiseJournalEntry *) entry;
114 g_free (groupwise_entry->uid);
115 g_free (groupwise_entry->original_uid);
116 g_free (groupwise_entry->source_container);
117 g_free (groupwise_entry);
121 groupwise_entry_load (CamelOfflineJournal *journal, FILE *in)
123 CamelGroupwiseJournalEntry *entry;
125 entry = g_malloc0 (sizeof (CamelGroupwiseJournalEntry));
127 if (camel_file_util_decode_uint32 (in, &entry->type) == -1)
130 switch (entry->type) {
131 case CAMEL_GROUPWISE_JOURNAL_ENTRY_APPEND:
132 if (camel_file_util_decode_string (in, &entry->uid) == -1)
135 case CAMEL_GROUPWISE_JOURNAL_ENTRY_TRANSFER:
136 if (camel_file_util_decode_string (in, &entry->uid) == -1)
138 if (camel_file_util_decode_string (in, &entry->original_uid) == -1)
140 if (camel_file_util_decode_string (in, &entry->source_container) == -1)
147 return (EDListNode *) entry;
151 if (entry->type == CAMEL_GROUPWISE_JOURNAL_ENTRY_TRANSFER)
152 g_free (entry->source_container);
161 groupwise_entry_write (CamelOfflineJournal *journal, EDListNode *entry, FILE *out)
163 CamelGroupwiseJournalEntry *groupwise_entry = (CamelGroupwiseJournalEntry *) entry;
165 if (camel_file_util_encode_uint32 (out, groupwise_entry->type) == -1)
168 switch (groupwise_entry->type) {
169 case CAMEL_GROUPWISE_JOURNAL_ENTRY_APPEND:
170 if (camel_file_util_encode_string (out, groupwise_entry->uid))
173 case CAMEL_GROUPWISE_JOURNAL_ENTRY_TRANSFER:
174 if (camel_file_util_encode_string (out, groupwise_entry->uid))
176 if (camel_file_util_encode_string (out, groupwise_entry->original_uid))
178 if (camel_file_util_encode_string (out, groupwise_entry->source_container))
182 g_assert_not_reached ();
189 gw_message_info_dup_to (CamelMessageInfoBase *dest, CamelMessageInfoBase *src)
191 camel_flag_list_copy (&dest->user_flags, &src->user_flags);
192 camel_tag_list_copy (&dest->user_tags, &src->user_tags);
193 dest->date_received = src->date_received;
194 dest->date_sent = src->date_sent;
195 dest->flags = src->flags;
196 dest->size = src->size;
200 groupwise_entry_play_append (CamelOfflineJournal *journal, CamelGroupwiseJournalEntry *entry, CamelException *ex)
202 CamelGroupwiseFolder *gw_folder = (CamelGroupwiseFolder *) journal->folder;
203 CamelFolder *folder = journal->folder;
204 CamelMimeMessage *message;
205 CamelMessageInfo *info;
209 /* if the message isn't in the cache, the user went behind our backs so "not our problem" */
210 if (!gw_folder->cache || !(stream = camel_data_cache_get (gw_folder->cache, "cache", entry->uid, ex)))
213 message = camel_mime_message_new ();
214 if (camel_data_wrapper_construct_from_stream ((CamelDataWrapper *) message, stream) == -1) {
215 camel_object_unref (message);
216 camel_object_unref (stream);
220 camel_object_unref (stream);
222 if (!(info = camel_folder_summary_uid (folder->summary, entry->uid))) {
223 /* Note: this should never happen, but rather than crash lets make a new info */
224 info = camel_message_info_new (NULL);
227 camel_exception_init (&lex);
228 camel_folder_append_message (folder, message, info, NULL, &lex);
229 camel_message_info_free (info);
230 camel_object_unref (message);
232 if (camel_exception_is_set (&lex)) {
233 camel_exception_xfer (ex, &lex);
239 camel_folder_summary_remove_uid (folder->summary, entry->uid);
240 camel_data_cache_remove (gw_folder->cache, "cache", entry->uid, NULL);
246 groupwise_entry_play_transfer (CamelOfflineJournal *journal, CamelGroupwiseJournalEntry *entry, CamelException *ex)
248 CamelGroupwiseFolder *gw_folder = (CamelGroupwiseFolder *) journal->folder;
249 CamelFolder *folder = journal->folder;
250 CamelGroupwiseMessageInfo *real;
251 CamelMessageInfoBase *info;
252 GPtrArray *xuids, *uids;
257 if (!(info = (CamelMessageInfoBase *) camel_folder_summary_uid (folder->summary, entry->uid))) {
258 /* Note: this should never happen, but rather than crash lets make a new info */
259 info = camel_message_info_new (NULL);
262 name = camel_groupwise_store_folder_lookup ((CamelGroupwiseStore *) folder->parent_store, entry->source_container);
263 if (name && (src = camel_store_get_folder (folder->parent_store, name, 0, ex))) {
264 uids = g_ptr_array_sized_new (1);
265 g_ptr_array_add (uids, entry->original_uid);
267 camel_exception_init (&lex);
268 camel_folder_transfer_messages_to (src, uids, folder, &xuids, FALSE, &lex);
269 if (!camel_exception_is_set (&lex)) {
270 real = (CamelGroupwiseMessageInfo *) camel_folder_summary_uid (folder->summary, xuids->pdata[0]);
272 /* transfer all the system flags, user flags/tags, etc */
273 gw_message_info_dup_to ((CamelMessageInfoBase *) real, (CamelMessageInfoBase *) info);
274 camel_message_info_free (real);
276 camel_exception_xfer (ex, &lex);
280 g_ptr_array_free (xuids, TRUE);
281 g_ptr_array_free (uids, TRUE);
282 camel_object_unref (src);
284 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot get folder container %s"),
285 entry->source_container);
289 /* message was successfully transferred, remove the fake item from the cache/summary */
290 camel_folder_summary_remove_uid (folder->summary, entry->uid);
291 camel_data_cache_remove (gw_folder->cache, "cache", entry->uid, NULL);
292 camel_message_info_free (info);
298 camel_message_info_free (info);
304 groupwise_entry_play (CamelOfflineJournal *journal, EDListNode *entry, CamelException *ex)
306 CamelGroupwiseJournalEntry *groupwise_entry = (CamelGroupwiseJournalEntry *) entry;
308 switch (groupwise_entry->type) {
309 case CAMEL_GROUPWISE_JOURNAL_ENTRY_APPEND:
310 return groupwise_entry_play_append (journal, groupwise_entry, ex);
311 case CAMEL_GROUPWISE_JOURNAL_ENTRY_TRANSFER:
312 return groupwise_entry_play_transfer (journal, groupwise_entry, ex);
314 g_assert_not_reached ();
321 CamelOfflineJournal *
322 camel_groupwise_journal_new (CamelGroupwiseFolder *folder, const char *filename)
324 CamelOfflineJournal *journal;
326 g_return_val_if_fail (CAMEL_IS_GROUPWISE_FOLDER (folder), NULL);
328 journal = (CamelOfflineJournal *) camel_object_new (camel_groupwise_journal_get_type ());
329 camel_offline_journal_construct (journal, (CamelFolder *) folder, filename);
335 update_cache (CamelGroupwiseJournal *groupwise_journal, CamelMimeMessage *message,
336 const CamelMessageInfo *mi, char **updated_uid, CamelException *ex)
338 CamelOfflineJournal *journal = (CamelOfflineJournal *) groupwise_journal;
339 CamelGroupwiseFolder *groupwise_folder = (CamelGroupwiseFolder *) journal->folder;
340 CamelFolder *folder = (CamelFolder *) journal->folder;
341 CamelMessageInfo *info;
346 if (groupwise_folder->cache == NULL) {
347 camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
348 _("Cannot append message in offline mode: cache unavailable"));
352 nextuid = camel_folder_summary_next_uid (folder->summary);
353 uid = g_strdup_printf ("-%u", nextuid);
355 if (!(cache = camel_data_cache_add (groupwise_folder->cache, "cache", uid, ex))) {
356 folder->summary->nextuid--;
361 if (camel_data_wrapper_write_to_stream ((CamelDataWrapper *) message, cache) == -1
362 || camel_stream_flush (cache) == -1) {
363 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
364 _("Cannot append message in offline mode: %s"),
366 camel_data_cache_remove (groupwise_folder->cache, "cache", uid, NULL);
367 folder->summary->nextuid--;
368 camel_object_unref (cache);
373 camel_object_unref (cache);
375 info = camel_folder_summary_info_new_from_message (folder->summary, message);
377 info->uid = g_strdup (uid);
379 gw_message_info_dup_to ((CamelMessageInfoBase *) info, (CamelMessageInfoBase *) mi);
381 camel_folder_summary_add (folder->summary, info);
384 *updated_uid = g_strdup (uid);
392 camel_groupwise_journal_append (CamelGroupwiseJournal *groupwise_journal, CamelMimeMessage *message,
393 const CamelMessageInfo *mi, char **appended_uid, CamelException *ex)
395 CamelOfflineJournal *journal = (CamelOfflineJournal *) groupwise_journal;
396 CamelGroupwiseJournalEntry *entry;
399 if (!update_cache (groupwise_journal, message, mi, &uid, ex))
402 entry = g_new (CamelGroupwiseJournalEntry, 1);
403 entry->type = CAMEL_GROUPWISE_JOURNAL_ENTRY_APPEND;
406 e_dlist_addtail (&journal->queue, (EDListNode *) entry);
409 *appended_uid = g_strdup (uid);
413 camel_groupwise_journal_transfer (CamelGroupwiseJournal *groupwise_journal, CamelGroupwiseFolder *source_folder,
414 CamelMimeMessage *message, const CamelMessageInfo *mi,
415 const char *original_uid, char **transferred_uid,
418 CamelOfflineJournal *journal = (CamelOfflineJournal *) groupwise_journal;
419 CamelGroupwiseStore *gw_store= CAMEL_GROUPWISE_STORE(journal->folder->parent_store) ;
420 CamelGroupwiseJournalEntry *entry;
423 if (!update_cache (groupwise_journal, message, mi, &uid, ex))
426 entry = g_new (CamelGroupwiseJournalEntry, 1);
427 entry->type = CAMEL_GROUPWISE_JOURNAL_ENTRY_APPEND;
429 entry->original_uid = g_strdup (original_uid);
430 entry->source_container = g_strdup (camel_groupwise_store_container_id_lookup (gw_store, ((CamelFolder *)source_folder)->name));
432 e_dlist_addtail (&journal->queue, (EDListNode *) entry);
435 *transferred_uid = g_strdup (uid);