1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
6 * Michael Zucchi <notzed@ximian.com>
7 * Dan Winship <danw@ximian.com>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of version 2 of the GNU Lesser General Public
11 * License as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this program; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
35 #include <camel/camel-db.h>
36 #include <camel/camel-store.h>
37 #include <camel/camel-string-utils.h>
39 #include "camel-imapx-summary.h"
41 #define CAMEL_IMAPX_SUMMARY_VERSION (4)
43 static gboolean info_set_user_flag (CamelMessageInfo *info, const gchar *id, gboolean state);
45 static gboolean summary_header_from_db (CamelFolderSummary *s, CamelFIRecord *mir);
46 static CamelFIRecord * summary_header_to_db (CamelFolderSummary *s, GError **error);
47 static CamelMIRecord * message_info_to_db (CamelFolderSummary *s, CamelMessageInfo *info);
48 static CamelMessageInfo * message_info_from_db (CamelFolderSummary *s, CamelMIRecord *mir);
49 static gboolean content_info_to_db (CamelFolderSummary *s, CamelMessageContentInfo *info, CamelMIRecord *mir);
50 static CamelMessageContentInfo * content_info_from_db (CamelFolderSummary *s, CamelMIRecord *mir);
52 G_DEFINE_TYPE (CamelIMAPXSummary, camel_imapx_summary, CAMEL_TYPE_FOLDER_SUMMARY)
54 static CamelMessageInfo *
55 imapx_message_info_clone (CamelFolderSummary *s,
56 const CamelMessageInfo *mi)
58 CamelIMAPXMessageInfo *to;
59 CamelFolderSummaryClass *folder_summary_class;
60 const CamelIMAPXMessageInfo *from = (const CamelIMAPXMessageInfo *) mi;
62 folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (
63 camel_imapx_summary_parent_class);
65 to = (CamelIMAPXMessageInfo *)
66 folder_summary_class->message_info_clone (s, mi);
67 to->server_flags = from->server_flags;
69 /* FIXME: parent clone should do this */
70 to->info.content = camel_folder_summary_content_info_new (s);
72 return (CamelMessageInfo *) to;
76 camel_imapx_summary_class_init (CamelIMAPXSummaryClass *class)
78 CamelFolderSummaryClass *folder_summary_class;
80 folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (class);
81 folder_summary_class->message_info_size = sizeof (CamelIMAPXMessageInfo);
82 folder_summary_class->content_info_size = sizeof (CamelIMAPXMessageContentInfo);
83 folder_summary_class->message_info_clone = imapx_message_info_clone;
84 folder_summary_class->summary_header_to_db = summary_header_to_db;
85 folder_summary_class->summary_header_from_db = summary_header_from_db;
86 folder_summary_class->message_info_to_db = message_info_to_db;
87 folder_summary_class->message_info_from_db = message_info_from_db;
88 folder_summary_class->content_info_to_db = content_info_to_db;
89 folder_summary_class->content_info_from_db = content_info_from_db;
90 folder_summary_class->info_set_user_flag = info_set_user_flag;
94 camel_imapx_summary_init (CamelIMAPXSummary *obj)
99 sort_uid_cmp (gpointer enc,
105 static gchar *sa1 = NULL, *sa2 = NULL;
106 static gint l1 = 0, l2 = 0;
110 sa1 = g_realloc (sa1, len1 + 1);
114 sa2 = g_realloc (sa2, len2 + 1);
117 strncpy (sa1, data1, len1); sa1[len1] = 0;
118 strncpy (sa2, data2, len2); sa2[len2] = 0;
120 a1 = strtoul (sa1, NULL, 10);
121 a2 = strtoul (sa2, NULL, 10);
123 return (a1 < a1) ? -1 : (a1 > a2) ? 1 : 0;
127 * camel_imapx_summary_new:
128 * @folder: Parent folder.
129 * @filename: the file to store the summary in.
131 * This will create a new CamelIMAPXSummary object and read in the
132 * summary data from disk, if it exists.
134 * Returns: A new CamelIMAPXSummary object.
137 camel_imapx_summary_new (CamelFolder *folder)
139 CamelStore *parent_store;
140 CamelFolderSummary *summary;
141 GError *local_error = NULL;
143 parent_store = camel_folder_get_parent_store (folder);
145 summary = g_object_new (CAMEL_TYPE_IMAPX_SUMMARY, "folder", folder, NULL);
147 /* Don't do DB sort. Its pretty slow to load */
149 camel_db_set_collate (parent_store->cdb_r, "uid", "imapx_uid_sort", (CamelDBCollate)sort_uid_cmp);
150 summary->sort_by = "uid";
151 summary->collate = "imapx_uid_sort";
154 camel_folder_summary_set_build_content (summary, TRUE);
156 if (!camel_folder_summary_load_from_db (summary, &local_error)) {
157 /* FIXME: Isn't this dangerous ? We clear the summary
158 if it cannot be loaded, for some random reason.
159 We need to pass the error and find out why it is not loaded etc. ? */
160 camel_folder_summary_clear (summary, NULL);
161 g_message ("Unable to load summary: %s\n", local_error->message);
162 g_clear_error (&local_error);
169 summary_header_from_db (CamelFolderSummary *s,
172 CamelIMAPXSummary *ims = CAMEL_IMAPX_SUMMARY (s);
173 CamelFolderSummaryClass *folder_summary_class;
176 folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (
177 camel_imapx_summary_parent_class);
179 if (!folder_summary_class->summary_header_from_db (s, mir))
184 ims->version = bdata_extract_digit (&part);
185 ims->validity = bdata_extract_digit (&part);
187 if (ims->version >= 4) {
188 ims->uidnext = bdata_extract_digit (&part);
189 ims->modseq = bdata_extract_digit (&part);
192 if (ims->version > CAMEL_IMAPX_SUMMARY_VERSION) {
193 g_warning("Unknown summary version\n");
201 static CamelFIRecord *
202 summary_header_to_db (CamelFolderSummary *s,
205 CamelIMAPXSummary *ims = CAMEL_IMAPX_SUMMARY (s);
206 CamelFolderSummaryClass *folder_summary_class;
207 struct _CamelFIRecord *fir;
209 folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (
210 camel_imapx_summary_parent_class);
212 fir = folder_summary_class->summary_header_to_db (s, error);
215 fir->bdata = g_strdup_printf ("%d %" G_GUINT64_FORMAT " %u %" G_GUINT64_FORMAT, CAMEL_IMAPX_SUMMARY_VERSION,
216 (guint64) ims->validity, ims->uidnext,
217 (guint64) ims->modseq);
221 static CamelMessageInfo *
222 message_info_from_db (CamelFolderSummary *s,
225 CamelMessageInfo *info;
226 CamelIMAPXMessageInfo *iinfo;
227 CamelFolderSummaryClass *folder_summary_class;
229 folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (
230 camel_imapx_summary_parent_class);
232 info = folder_summary_class->message_info_from_db (s, mir);
234 gchar *part = mir->bdata;
236 iinfo = (CamelIMAPXMessageInfo *) info;
237 iinfo->server_flags = bdata_extract_digit (&part);
243 static CamelMIRecord *
244 message_info_to_db (CamelFolderSummary *s,
245 CamelMessageInfo *info)
247 CamelIMAPXMessageInfo *iinfo = (CamelIMAPXMessageInfo *) info;
248 CamelFolderSummaryClass *folder_summary_class;
249 struct _CamelMIRecord *mir;
251 folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (
252 camel_imapx_summary_parent_class);
254 mir = folder_summary_class->message_info_to_db (s, info);
256 mir->bdata = g_strdup_printf ("%u", iinfo->server_flags);
262 info_set_user_flag (CamelMessageInfo *info,
266 CamelFolderSummaryClass *folder_summary_class;
269 folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (
270 camel_imapx_summary_parent_class);
272 res = folder_summary_class->info_set_user_flag (info, id, state);
274 /* there was a change, so do not forget to store it to server */
276 ((CamelIMAPXMessageInfo *) info)->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
281 static CamelMessageContentInfo *
282 content_info_from_db (CamelFolderSummary *s,
285 CamelFolderSummaryClass *folder_summary_class;
286 gchar *part = mir->cinfo;
289 folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (
290 camel_imapx_summary_parent_class);
296 type = bdata_extract_digit (&part);
301 return folder_summary_class->content_info_from_db (s, mir);
303 return camel_folder_summary_content_info_new (s);
307 content_info_to_db (CamelFolderSummary *s,
308 CamelMessageContentInfo *info,
311 CamelFolderSummaryClass *folder_summary_class;
314 folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (
315 camel_imapx_summary_parent_class);
319 mir->cinfo = oldr ? g_strdup_printf("%s 1", oldr) : g_strdup ("1");
321 return folder_summary_class->content_info_to_db (s, info, mir);
324 mir->cinfo = oldr ? g_strdup_printf("%s 0", oldr) : g_strdup ("0");
331 camel_imapx_summary_add_offline (CamelFolderSummary *summary,
333 CamelMimeMessage *message,
334 const CamelMessageInfo *info)
336 CamelIMAPXMessageInfo *mi;
337 const CamelFlag *flag;
340 /* Create summary entry */
341 mi = (CamelIMAPXMessageInfo *) camel_folder_summary_info_new_from_message (summary, message, NULL);
343 /* Copy flags 'n' tags */
344 mi->info.flags = camel_message_info_flags (info);
346 flag = camel_message_info_user_flags (info);
348 camel_message_info_set_user_flag ((CamelMessageInfo *) mi, flag->name, TRUE);
351 tag = camel_message_info_user_tags (info);
353 camel_message_info_set_user_tag ((CamelMessageInfo *) mi, tag->name, tag->value);
357 mi->info.size = camel_message_info_size (info);
358 mi->info.uid = camel_pstring_strdup (uid);
360 camel_folder_summary_add (summary, (CamelMessageInfo *) mi);
364 camel_imapx_summary_add_offline_uncached (CamelFolderSummary *summary,
366 const CamelMessageInfo *info)
368 CamelIMAPXMessageInfo *mi;
370 mi = camel_message_info_clone (info);
371 mi->info.uid = camel_pstring_strdup (uid);
373 camel_folder_summary_add (summary, (CamelMessageInfo *) mi);