1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- */
2 /*
3 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4 *
5 * This library is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Michael Zucchi <notzed@ximian.com>
18 */
19
20 #include "evolution-data-server-config.h"
21
22 #include <dirent.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30
31 #include <glib/gi18n-lib.h>
32
33 #include "camel-mh-folder.h"
34 #include "camel-mh-store.h"
35 #include "camel-mh-summary.h"
36
37 #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
38
G_DEFINE_TYPE(CamelMhFolder,camel_mh_folder,CAMEL_TYPE_LOCAL_FOLDER)39 G_DEFINE_TYPE (CamelMhFolder, camel_mh_folder, CAMEL_TYPE_LOCAL_FOLDER)
40
41 static gchar *
42 mh_folder_get_filename (CamelFolder *folder,
43 const gchar *uid,
44 GError **error)
45 {
46 CamelLocalFolder *lf = (CamelLocalFolder *) folder;
47
48 return g_strdup_printf ("%s/%s", lf->folder_path, uid);
49 }
50
51 static gboolean
mh_folder_append_message_sync(CamelFolder * folder,CamelMimeMessage * message,CamelMessageInfo * info,gchar ** appended_uid,GCancellable * cancellable,GError ** error)52 mh_folder_append_message_sync (CamelFolder *folder,
53 CamelMimeMessage *message,
54 CamelMessageInfo *info,
55 gchar **appended_uid,
56 GCancellable *cancellable,
57 GError **error)
58 {
59 CamelLocalFolder *lf = (CamelLocalFolder *) folder;
60 CamelStream *output_stream;
61 CamelMessageInfo *mi;
62 gchar *name;
63 gboolean has_attachment;
64
65 /* FIXME: probably needs additional locking (although mh doesn't appear do do it) */
66
67 d (printf ("Appending message\n"));
68
69 camel_local_folder_lock_changes (lf);
70
71 /* If we can't lock, don't do anything */
72 if (!lf || camel_local_folder_lock (lf, CAMEL_LOCK_WRITE, error) == -1) {
73 camel_local_folder_unlock_changes (lf);
74 return FALSE;
75 }
76
77 /* add it to the summary/assign the uid, etc */
78 mi = camel_local_summary_add ((CamelLocalSummary *) camel_folder_get_folder_summary (folder), message, info, lf->changes, error);
79 camel_local_folder_unlock_changes (lf);
80 if (mi == NULL)
81 goto check_changed;
82
83 has_attachment = camel_mime_message_has_attachment (message);
84 if (((camel_message_info_get_flags (mi) & CAMEL_MESSAGE_ATTACHMENTS) && !has_attachment) ||
85 ((camel_message_info_get_flags (mi) & CAMEL_MESSAGE_ATTACHMENTS) == 0 && has_attachment)) {
86 camel_message_info_set_flags (mi, CAMEL_MESSAGE_ATTACHMENTS, has_attachment ? CAMEL_MESSAGE_ATTACHMENTS : 0);
87 }
88
89 d (printf ("Appending message: uid is %s\n", camel_message_info_get_uid (mi)));
90
91 /* write it out, use the uid we got from the summary */
92 name = g_strdup_printf ("%s/%s", lf->folder_path, camel_message_info_get_uid (mi));
93 output_stream = camel_stream_fs_new_with_name (
94 name, O_WRONLY | O_CREAT, 0600, error);
95 if (output_stream == NULL)
96 goto fail_write;
97
98 if (camel_data_wrapper_write_to_stream_sync (
99 (CamelDataWrapper *) message, output_stream, cancellable, error) == -1
100 || camel_stream_close (output_stream, cancellable, error) == -1)
101 goto fail_write;
102
103 /* close this? */
104 g_object_unref (output_stream);
105
106 g_free (name);
107
108 if (appended_uid)
109 *appended_uid = g_strdup(camel_message_info_get_uid(mi));
110
111 goto check_changed;
112
113 fail_write:
114
115 /* remove the summary info so we are not out-of-sync with the mh folder */
116 camel_folder_summary_remove (camel_folder_get_folder_summary (folder), mi);
117
118 g_prefix_error (
119 error, _("Cannot append message to mh folder: %s: "), name);
120
121 if (output_stream) {
122 g_object_unref (output_stream);
123 unlink (name);
124 }
125
126 g_free (name);
127
128 check_changed:
129 camel_local_folder_unlock (lf);
130
131 camel_local_folder_claim_changes (lf);
132
133 g_clear_object (&mi);
134
135 return TRUE;
136 }
137
138 static CamelMimeMessage *
mh_folder_get_message_sync(CamelFolder * folder,const gchar * uid,GCancellable * cancellable,GError ** error)139 mh_folder_get_message_sync (CamelFolder *folder,
140 const gchar *uid,
141 GCancellable *cancellable,
142 GError **error)
143 {
144 CamelLocalFolder *lf = (CamelLocalFolder *) folder;
145 CamelStream *message_stream = NULL;
146 CamelMimeMessage *message = NULL;
147 CamelMessageInfo *info;
148 gchar *name = NULL;
149
150 d (printf ("getting message: %s\n", uid));
151
152 if (!lf || camel_local_folder_lock (lf, CAMEL_LOCK_WRITE, error) == -1)
153 return NULL;
154
155 /* get the message summary info */
156 if ((info = camel_folder_summary_get (camel_folder_get_folder_summary (folder), uid)) == NULL) {
157 set_cannot_get_message_ex (
158 error, CAMEL_FOLDER_ERROR_INVALID_UID,
159 uid, lf->folder_path, _("No such message"));
160 goto fail;
161 }
162
163 /* we only need it to check the message exists */
164 g_clear_object (&info);
165
166 name = g_strdup_printf ("%s/%s", lf->folder_path, uid);
167 message_stream = camel_stream_fs_new_with_name (
168 name, O_RDONLY, 0, error);
169 if (message_stream == NULL) {
170 g_prefix_error (
171 error, _("Cannot get message %s from folder %s: "),
172 name, lf->folder_path);
173 goto fail;
174 }
175
176 message = camel_mime_message_new ();
177 if (!camel_data_wrapper_construct_from_stream_sync (
178 (CamelDataWrapper *) message,
179 message_stream, cancellable, error)) {
180 g_prefix_error (
181 error, _("Cannot get message %s from folder %s: "),
182 name, lf->folder_path);
183 g_object_unref (message);
184 message = NULL;
185
186 }
187 g_object_unref (message_stream);
188
189 fail:
190 g_free (name);
191
192 camel_local_folder_unlock (lf);
193
194 camel_local_folder_claim_changes (lf);
195
196 return message;
197 }
198
199 static CamelLocalSummary *
mh_folder_create_summary(CamelLocalFolder * lf,const gchar * folder,CamelIndex * index)200 mh_folder_create_summary (CamelLocalFolder *lf,
201 const gchar *folder,
202 CamelIndex *index)
203 {
204 return (CamelLocalSummary *) camel_mh_summary_new (
205 CAMEL_FOLDER (lf), folder, index);
206 }
207
208 static void
camel_mh_folder_class_init(CamelMhFolderClass * class)209 camel_mh_folder_class_init (CamelMhFolderClass *class)
210 {
211 CamelFolderClass *folder_class;
212 CamelLocalFolderClass *local_folder_class;
213
214 folder_class = CAMEL_FOLDER_CLASS (class);
215 folder_class->get_filename = mh_folder_get_filename;
216 folder_class->append_message_sync = mh_folder_append_message_sync;
217 folder_class->get_message_sync = mh_folder_get_message_sync;
218
219 local_folder_class = CAMEL_LOCAL_FOLDER_CLASS (class);
220 local_folder_class->create_summary = mh_folder_create_summary;
221 }
222
223 static void
camel_mh_folder_init(CamelMhFolder * mh_folder)224 camel_mh_folder_init (CamelMhFolder *mh_folder)
225 {
226 }
227
228 CamelFolder *
camel_mh_folder_new(CamelStore * parent_store,const gchar * full_name,guint32 flags,GCancellable * cancellable,GError ** error)229 camel_mh_folder_new (CamelStore *parent_store,
230 const gchar *full_name,
231 guint32 flags,
232 GCancellable *cancellable,
233 GError **error)
234 {
235 CamelFolder *folder;
236 gchar *basename;
237
238 d (printf ("Creating mh folder: %s\n", full_name));
239
240 basename = g_path_get_basename (full_name);
241
242 folder = g_object_new (
243 CAMEL_TYPE_MH_FOLDER,
244 "display-name", basename, "full-name", full_name,
245 "parent-store", parent_store, NULL);
246 folder = (CamelFolder *) camel_local_folder_construct (
247 CAMEL_LOCAL_FOLDER (folder), flags, cancellable, error);
248
249 g_free (basename);
250
251 return folder;
252 }
253
254