1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*-
3 * Authors: Michael Zucchi <notzed@ximian.com>
5 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.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
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
33 #include <sys/types.h>
35 #include <glib/gi18n-lib.h>
36 #include <glib/gstdio.h>
38 #include "camel-maildir-folder.h"
39 #include "camel-maildir-store.h"
40 #include "camel-maildir-summary.h"
42 #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
44 G_DEFINE_TYPE (CamelMaildirFolder, camel_maildir_folder, CAMEL_TYPE_LOCAL_FOLDER)
47 maildir_folder_cmp_uids (CamelFolder *folder,
51 CamelMessageInfo *a, *b;
54 g_return_val_if_fail (folder != NULL, 0);
55 g_return_val_if_fail (folder->summary != NULL, 0);
57 a = camel_folder_summary_get (folder->summary, uid1);
58 b = camel_folder_summary_get (folder->summary, uid2);
60 g_return_val_if_fail (a != NULL, 0);
61 g_return_val_if_fail (b != NULL, 0);
63 tma = camel_message_info_date_received (a);
64 tmb = camel_message_info_date_received (b);
66 camel_message_info_free (a);
67 camel_message_info_free (b);
69 return tma < tmb ? -1 : tma == tmb ? 0 : 1;
73 maildir_folder_sort_uids (CamelFolder *folder,
76 g_return_if_fail (camel_maildir_folder_parent_class != NULL);
77 g_return_if_fail (folder != NULL);
79 if (uids && uids->len > 1)
80 camel_folder_summary_prepare_fetch_all (folder->summary, NULL);
82 /* Chain up to parent's sort_uids() method. */
83 CAMEL_FOLDER_CLASS (camel_maildir_folder_parent_class)->sort_uids (folder, uids);
87 maildir_folder_get_filename (CamelFolder *folder,
91 CamelLocalFolder *lf = (CamelLocalFolder *) folder;
92 CamelMaildirMessageInfo *mdi;
93 CamelMessageInfo *info;
96 /* get the message summary info */
97 if ((info = camel_folder_summary_get (folder->summary, uid)) == NULL) {
98 set_cannot_get_message_ex (
99 error, CAMEL_FOLDER_ERROR_INVALID_UID,
100 uid, lf->folder_path, _("No such message"));
104 mdi = (CamelMaildirMessageInfo *) info;
106 /* If filename is NULL, it means folder_summary_check is not yet executed.
107 * Try to find the file in the folder and use it, otherwise construct its
108 * name based on actual flags.
110 if (!camel_maildir_info_filename (mdi)) {
111 const gchar *uid = camel_message_info_uid (info);
117 dirname = g_strdup_printf ("%s/cur", lf->folder_path);
118 dir = g_dir_open (dirname, 0, NULL);
122 const gchar *filename;
123 gint uid_len = strlen (uid);
125 while (filename = g_dir_read_name (dir), filename) {
126 if (g_str_has_prefix (filename, uid) && (filename[uid_len] == '\0' || filename[uid_len] == ':')) {
127 camel_maildir_info_set_filename (mdi, g_strdup (filename));
136 if (!camel_maildir_info_filename (mdi)) {
137 camel_maildir_info_set_filename (mdi, camel_maildir_summary_info_to_name (mdi));
141 res = g_strdup_printf ("%s/cur/%s", lf->folder_path, camel_maildir_info_filename (mdi));
143 camel_message_info_free (info);
149 maildir_folder_append_message_sync (CamelFolder *folder,
150 CamelMimeMessage *message,
151 CamelMessageInfo *info,
152 gchar **appended_uid,
153 GCancellable *cancellable,
156 CamelLocalFolder *lf = (CamelLocalFolder *) folder;
157 CamelStream *output_stream;
158 CamelMessageInfo *mi;
159 CamelMaildirMessageInfo *mdi;
160 gchar *name, *dest = NULL;
161 gboolean success = TRUE, has_attachment;
163 d(printf("Appending message\n"));
165 /* If we can't lock, don't do anything */
166 if (!lf || camel_local_folder_lock (lf, CAMEL_LOCK_WRITE, error) == -1)
169 /* add it to the summary/assign the uid, etc */
170 mi = camel_local_summary_add (
171 CAMEL_LOCAL_SUMMARY (folder->summary),
172 message, info, lf->changes, error);
176 has_attachment = camel_mime_message_has_attachment (message);
177 if (((camel_message_info_flags (mi) & CAMEL_MESSAGE_ATTACHMENTS) && !has_attachment) ||
178 ((camel_message_info_flags (mi) & CAMEL_MESSAGE_ATTACHMENTS) == 0 && has_attachment)) {
179 camel_message_info_set_flags (mi, CAMEL_MESSAGE_ATTACHMENTS, has_attachment ? CAMEL_MESSAGE_ATTACHMENTS : 0);
182 mdi = (CamelMaildirMessageInfo *) mi;
184 d(printf("Appending message: uid is %s filename is %s\n", camel_message_info_uid(mi), mdi->filename));
186 /* write it out to tmp, use the uid we got from the summary */
187 name = g_strdup_printf ("%s/tmp/%s", lf->folder_path, camel_message_info_uid(mi));
188 output_stream = camel_stream_fs_new_with_name (
189 name, O_WRONLY | O_CREAT, 0600, error);
190 if (output_stream == NULL)
193 if (camel_data_wrapper_write_to_stream_sync (
194 (CamelDataWrapper *) message, output_stream, cancellable, error) == -1
195 || camel_stream_close (output_stream, cancellable, error) == -1)
198 /* now move from tmp to cur (bypass new, does it matter?) */
199 dest = g_strdup_printf("%s/cur/%s", lf->folder_path, camel_maildir_info_filename (mdi));
200 if (g_rename (name, dest) == -1) {
203 g_io_error_from_errno (errno),
204 "%s", g_strerror (errno));
212 *appended_uid = g_strdup(camel_message_info_uid(mi));
215 g_object_unref (output_stream);
221 /* remove the summary info so we are not out-of-sync with the mh folder */
222 camel_folder_summary_remove (CAMEL_FOLDER_SUMMARY (folder->summary), mi);
225 error, _("Cannot append message to maildir folder: %s: "),
229 g_object_unref (output_stream);
239 camel_local_folder_unlock (lf);
241 if (camel_folder_change_info_changed (lf->changes)) {
242 camel_folder_changed (folder, lf->changes);
243 camel_folder_change_info_clear (lf->changes);
249 static CamelMimeMessage *
250 maildir_folder_get_message_sync (CamelFolder *folder,
252 GCancellable *cancellable,
255 CamelLocalFolder *lf = (CamelLocalFolder *) folder;
256 CamelStream *message_stream = NULL;
257 CamelMimeMessage *message = NULL;
260 d(printf("getting message: %s\n", uid));
262 if (!lf || camel_local_folder_lock (lf, CAMEL_LOCK_WRITE, error) == -1)
265 name = maildir_folder_get_filename (folder, uid, error);
269 message_stream = camel_stream_fs_new_with_name (
270 name, O_RDONLY, 0, error);
271 if (message_stream == NULL) {
273 error, _("Cannot get message %s from folder %s: "),
274 uid, lf->folder_path);
278 message = camel_mime_message_new ();
279 if (!camel_data_wrapper_construct_from_stream_sync (
280 (CamelDataWrapper *) message,
281 message_stream, cancellable, error)) {
283 error, _("Cannot get message %s from folder %s: "),
284 uid, lf->folder_path);
285 g_object_unref (message);
289 g_object_unref (message_stream);
293 camel_local_folder_unlock (lf);
295 if (lf && camel_folder_change_info_changed (lf->changes)) {
296 camel_folder_changed (folder, lf->changes);
297 camel_folder_change_info_clear (lf->changes);
304 maildir_folder_transfer_messages_to_sync (CamelFolder *source,
307 gboolean delete_originals,
308 GPtrArray **transferred_uids,
309 GCancellable *cancellable,
312 gboolean fallback = FALSE;
314 if (delete_originals && CAMEL_IS_MAILDIR_FOLDER (source) && CAMEL_IS_MAILDIR_FOLDER (dest)
315 && camel_folder_get_parent_store (source) == camel_folder_get_parent_store (dest)) {
317 CamelLocalFolder *lf = (CamelLocalFolder *) source;
318 CamelLocalFolder *df = (CamelLocalFolder *) dest;
320 camel_operation_push_message (
321 cancellable, _("Moving messages"));
323 camel_folder_freeze (dest);
324 camel_folder_freeze (source);
326 for (i = 0; i < uids->len; i++) {
327 gchar *uid = (gchar *) uids->pdata[i];
328 gchar *s_filename, *d_filename, *new_filename;
329 CamelMaildirMessageInfo *mdi;
330 CamelMessageInfo *info;
332 if ((info = camel_folder_summary_get (source->summary, uid)) == NULL) {
333 set_cannot_get_message_ex (
334 error, CAMEL_FOLDER_ERROR_INVALID_UID,
335 uid, lf->folder_path, _("No such message"));
339 mdi = (CamelMaildirMessageInfo *) info;
340 new_filename = camel_maildir_summary_info_to_name (mdi);
342 d_filename = g_strdup_printf ("%s/cur/%s", df->folder_path, new_filename);
343 s_filename = g_strdup_printf("%s/cur/%s", lf->folder_path, camel_maildir_info_filename (mdi));
345 if (g_rename (s_filename, d_filename) != 0) {
346 if (errno == EXDEV) {
352 g_io_error_from_errno (errno),
353 _("Cannot transfer message to destination folder: %s"),
355 camel_message_info_free (info);
358 g_free (new_filename);
362 CamelMessageInfo *clone;
363 CamelMaildirMessageInfo *mclone;
365 clone = camel_message_info_clone (info);
366 clone->summary = dest->summary;
368 mclone = (CamelMaildirMessageInfo *) clone;
369 /* preserve also UID, as it matches the file name */
370 mclone->info.info.uid = camel_pstring_strdup (camel_message_info_uid (info));
371 camel_maildir_info_set_filename (clone, g_strdup (new_filename));
372 /* unset deleted flag when transferring from trash folder */
373 if ((source->folder_flags & CAMEL_FOLDER_IS_TRASH) != 0)
374 camel_message_info_set_flags (info, CAMEL_MESSAGE_DELETED, 0);
375 /* unset junk flag when transferring from junk folder */
376 if ((source->folder_flags & CAMEL_FOLDER_IS_JUNK) != 0)
377 camel_message_info_set_flags (info, CAMEL_MESSAGE_JUNK, 0);
378 camel_folder_summary_add (dest->summary, clone);
380 camel_folder_change_info_add_uid (df->changes, camel_message_info_uid (clone));
382 camel_folder_set_message_flags (
383 source, uid, CAMEL_MESSAGE_DELETED |
384 CAMEL_MESSAGE_SEEN, ~0);
385 camel_folder_change_info_remove_uid (lf->changes, camel_message_info_uid (info));
386 camel_folder_summary_remove (source->summary, info);
389 camel_message_info_free (info);
392 g_free (new_filename);
395 if (lf && camel_folder_change_info_changed (lf->changes)) {
396 camel_folder_changed (source, lf->changes);
397 camel_folder_change_info_clear (lf->changes);
400 if (df && camel_folder_change_info_changed (df->changes)) {
401 camel_folder_changed (dest, df->changes);
402 camel_folder_change_info_clear (df->changes);
405 camel_folder_thaw (source);
406 camel_folder_thaw (dest);
408 camel_operation_pop_message (cancellable);
413 CamelFolderClass *folder_class;
415 /* Chain up to parent's transfer_messages_to() method. */
416 folder_class = CAMEL_FOLDER_CLASS (camel_maildir_folder_parent_class);
417 return folder_class->transfer_messages_to_sync (
418 source, uids, dest, delete_originals,
419 transferred_uids, cancellable, error);
425 static CamelLocalSummary *
426 maildir_folder_create_summary (CamelLocalFolder *lf,
430 return (CamelLocalSummary *) camel_maildir_summary_new (
431 CAMEL_FOLDER (lf), folder, index);
435 camel_maildir_folder_class_init (CamelMaildirFolderClass *class)
437 CamelFolderClass *folder_class;
438 CamelLocalFolderClass *local_folder_class;
440 folder_class = CAMEL_FOLDER_CLASS (class);
441 folder_class->cmp_uids = maildir_folder_cmp_uids;
442 folder_class->sort_uids = maildir_folder_sort_uids;
443 folder_class->get_filename = maildir_folder_get_filename;
444 folder_class->append_message_sync = maildir_folder_append_message_sync;
445 folder_class->get_message_sync = maildir_folder_get_message_sync;
446 folder_class->transfer_messages_to_sync = maildir_folder_transfer_messages_to_sync;
448 local_folder_class = CAMEL_LOCAL_FOLDER_CLASS (class);
449 local_folder_class->create_summary = maildir_folder_create_summary;
453 camel_maildir_folder_init (CamelMaildirFolder *maildir_folder)
458 camel_maildir_folder_new (CamelStore *parent_store,
459 const gchar *full_name,
461 GCancellable *cancellable,
465 CamelService *service;
466 CamelSettings *settings;
467 gboolean filter_inbox;
470 d(printf("Creating maildir folder: %s\n", full_name));
472 if (g_strcmp0 (full_name, ".") == 0)
473 basename = g_strdup (_("Inbox"));
475 basename = g_path_get_basename (full_name);
477 folder = g_object_new (
478 CAMEL_TYPE_MAILDIR_FOLDER,
479 "display-name", basename,
480 "full-name", full_name,
481 "parent-store", parent_store,
484 service = CAMEL_SERVICE (parent_store);
486 settings = camel_service_ref_settings (service);
488 filter_inbox = camel_store_settings_get_filter_inbox (
489 CAMEL_STORE_SETTINGS (settings));
491 g_object_unref (settings);
493 if (filter_inbox && strcmp (full_name, ".") == 0)
494 folder->folder_flags |= CAMEL_FOLDER_FILTER_RECENT;
496 folder = (CamelFolder *) camel_local_folder_construct (
497 CAMEL_LOCAL_FOLDER (folder), flags, cancellable, error);
501 /* indexing doesn't work with maildir properly, thus disable it */
502 g_object_set (folder, "index-body", FALSE, NULL);