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 <ctype.h>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28
29 #include <glib/gi18n-lib.h>
30 #include <glib/gstdio.h>
31
32 #include "camel-local-summary.h"
33
34 #define w(x)
35 #define io(x)
36 #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
37
38 #define CAMEL_LOCAL_SUMMARY_VERSION (1)
39
40 static CamelFIRecord *
41 summary_header_save (CamelFolderSummary *,
42 GError **error);
43 static gboolean summary_header_load (CamelFolderSummary *,
44 CamelFIRecord *);
45
46 static CamelMessageInfo *
47 message_info_new_from_headers (CamelFolderSummary *,
48 const CamelNameValueArray *);
49
50 static gint local_summary_decode_x_evolution
51 (CamelLocalSummary *cls,
52 const gchar *xev,
53 CamelMessageInfo *mi);
54 static gchar * local_summary_encode_x_evolution
55 (CamelLocalSummary *cls,
56 const CamelMessageInfo *mi);
57
58 static gint local_summary_load (CamelLocalSummary *cls,
59 gint forceindex,
60 GError **error);
61 static gint local_summary_check (CamelLocalSummary *cls,
62 CamelFolderChangeInfo *changeinfo,
63 GCancellable *cancellable,
64 GError **error);
65 static gint local_summary_sync (CamelLocalSummary *cls,
66 gboolean expunge,
67 CamelFolderChangeInfo *changeinfo,
68 GCancellable *cancellable,
69 GError **error);
70 static CamelMessageInfo *
71 local_summary_add (CamelLocalSummary *cls,
72 CamelMimeMessage *msg,
73 const CamelMessageInfo *info,
74 CamelFolderChangeInfo *,
75 GError **error);
76 static gint local_summary_need_index (void);
77
G_DEFINE_TYPE(CamelLocalSummary,camel_local_summary,CAMEL_TYPE_FOLDER_SUMMARY)78 G_DEFINE_TYPE (CamelLocalSummary, camel_local_summary, CAMEL_TYPE_FOLDER_SUMMARY)
79
80 static void
81 local_summary_dispose (GObject *object)
82 {
83 CamelLocalSummary *local_summary;
84
85 local_summary = CAMEL_LOCAL_SUMMARY (object);
86 g_clear_object (&local_summary->index);
87
88 /* Chain up to parent's dispose() method. */
89 G_OBJECT_CLASS (camel_local_summary_parent_class)->dispose (object);
90 }
91
92 static void
local_summary_finalize(GObject * object)93 local_summary_finalize (GObject *object)
94 {
95 CamelLocalSummary *local_summary;
96
97 local_summary = CAMEL_LOCAL_SUMMARY (object);
98
99 g_free (local_summary->folder_path);
100
101 /* Chain up to parent's finalize() method. */
102 G_OBJECT_CLASS (camel_local_summary_parent_class)->finalize (object);
103 }
104
105 static void
camel_local_summary_class_init(CamelLocalSummaryClass * class)106 camel_local_summary_class_init (CamelLocalSummaryClass *class)
107 {
108 GObjectClass *object_class;
109 CamelFolderSummaryClass *folder_summary_class;
110
111 object_class = G_OBJECT_CLASS (class);
112 object_class->dispose = local_summary_dispose;
113 object_class->finalize = local_summary_finalize;
114
115 folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (class);
116 folder_summary_class->summary_header_load = summary_header_load;
117 folder_summary_class->summary_header_save = summary_header_save;
118 folder_summary_class->message_info_new_from_headers = message_info_new_from_headers;
119
120 class->load = local_summary_load;
121 class->check = local_summary_check;
122 class->sync = local_summary_sync;
123 class->add = local_summary_add;
124 class->encode_x_evolution = local_summary_encode_x_evolution;
125 class->decode_x_evolution = local_summary_decode_x_evolution;
126 class->need_index = local_summary_need_index;
127 }
128
129 static void
camel_local_summary_init(CamelLocalSummary * local_summary)130 camel_local_summary_init (CamelLocalSummary *local_summary)
131 {
132 CamelFolderSummary *folder_summary;
133
134 folder_summary = CAMEL_FOLDER_SUMMARY (local_summary);
135
136 /* and a unique file version */
137 camel_folder_summary_set_version (folder_summary, camel_folder_summary_get_version (folder_summary) + CAMEL_LOCAL_SUMMARY_VERSION);
138 }
139
140 void
camel_local_summary_construct(CamelLocalSummary * new,const gchar * local_name,CamelIndex * index)141 camel_local_summary_construct (CamelLocalSummary *new,
142 const gchar *local_name,
143 CamelIndex *index)
144 {
145 new->folder_path = g_strdup (local_name);
146 new->index = index;
147 if (index)
148 g_object_ref (index);
149 }
150
151 static gboolean
local_summary_load(CamelLocalSummary * cls,gint forceindex,GError ** error)152 local_summary_load (CamelLocalSummary *cls,
153 gint forceindex,
154 GError **error)
155 {
156 d (g_print ("\nlocal_summary_load called \n"));
157 return camel_folder_summary_load ((CamelFolderSummary *) cls, error);
158 }
159
160 /* load/check the summary */
161 gboolean
camel_local_summary_load(CamelLocalSummary * cls,gint forceindex,GError ** error)162 camel_local_summary_load (CamelLocalSummary *cls,
163 gint forceindex,
164 GError **error)
165 {
166 CamelLocalSummaryClass *class;
167
168 d (printf ("Loading summary ...\n"));
169
170 class = CAMEL_LOCAL_SUMMARY_GET_CLASS (cls);
171
172 if ((forceindex && class->need_index ())
173 || !class->load (cls, forceindex, error)) {
174 w (g_warning ("Could not load summary: flags may be reset"));
175 camel_folder_summary_clear ((CamelFolderSummary *) cls, NULL);
176 return FALSE;
177 }
178
179 return TRUE;
180 }
181
camel_local_summary_check_force(CamelLocalSummary * cls)182 void camel_local_summary_check_force (CamelLocalSummary *cls)
183 {
184 cls->check_force = 1;
185 }
186
187 gchar *
camel_local_summary_encode_x_evolution(CamelLocalSummary * cls,const CamelMessageInfo * info)188 camel_local_summary_encode_x_evolution (CamelLocalSummary *cls,
189 const CamelMessageInfo *info)
190 {
191 return CAMEL_LOCAL_SUMMARY_GET_CLASS (cls)->encode_x_evolution (cls, info);
192 }
193
194 gint
camel_local_summary_decode_x_evolution(CamelLocalSummary * cls,const gchar * xev,CamelMessageInfo * info)195 camel_local_summary_decode_x_evolution (CamelLocalSummary *cls,
196 const gchar *xev,
197 CamelMessageInfo *info)
198 {
199 return CAMEL_LOCAL_SUMMARY_GET_CLASS (cls)->decode_x_evolution (cls, xev, info);
200 }
201
202 /*#define DOSTATS*/
203 #ifdef DOSTATS
204 struct _stat_info {
205 gint mitotal;
206 gint micount;
207 gint citotal;
208 gint cicount;
209 gint msgid;
210 gint msgcount;
211 };
212
213 static void
do_stat_ci(CamelLocalSummary * cls,struct _stat_info * info,CamelMessageContentInfo * ci)214 do_stat_ci (CamelLocalSummary *cls,
215 struct _stat_info *info,
216 CamelMessageContentInfo *ci)
217 {
218 info->cicount++;
219 info->citotal += ((CamelFolderSummary *) cls)->content_info_size /*+ 4 memchunks are 1/4 byte overhead per mi */;
220 if (ci->id)
221 info->citotal += strlen (ci->id) + 4;
222 if (ci->description)
223 info->citotal += strlen (ci->description) + 4;
224 if (ci->encoding)
225 info->citotal += strlen (ci->encoding) + 4;
226 if (ci->type) {
227 CamelContentType *ct = ci->type;
228 struct _camel_header_param *param;
229
230 info->citotal += sizeof (*ct) + 4;
231 if (ct->type)
232 info->citotal += strlen (ct->type) + 4;
233 if (ct->subtype)
234 info->citotal += strlen (ct->subtype) + 4;
235 param = ct->params;
236 while (param) {
237 info->citotal += sizeof (*param) + 4;
238 if (param->name)
239 info->citotal += strlen (param->name) + 4;
240 if (param->value)
241 info->citotal += strlen (param->value) + 4;
242 param = param->next;
243 }
244 }
245 ci = ci->childs;
246 while (ci) {
247 do_stat_ci (cls, info, ci);
248 ci = ci->next;
249 }
250 }
251
252 static void
do_stat_mi(CamelLocalSummary * cls,struct _stat_info * info,CamelMessageInfo * mi)253 do_stat_mi (CamelLocalSummary *cls,
254 struct _stat_info *info,
255 CamelMessageInfo *mi)
256 {
257 info->micount++;
258 info->mitotal += ((CamelFolderSummary *) cls)->content_info_size /*+ 4 */;
259
260 if (mi->subject)
261 info->mitotal += strlen (mi->subject) + 4;
262 if (mi->to)
263 info->mitotal += strlen (mi->to) + 4;
264 if (mi->from)
265 info->mitotal += strlen (mi->from) + 4;
266 if (mi->cc)
267 info->mitotal += strlen (mi->cc) + 4;
268 if (mi->uid)
269 info->mitotal += strlen (mi->uid) + 4;
270
271 if (mi->references) {
272 info->mitotal += (mi->references->size - 1) * sizeof (CamelSummaryMessageID) + sizeof (CamelSummaryReferences) + 4;
273 info->msgid += (mi->references->size) * sizeof (CamelSummaryMessageID);
274 info->msgcount += mi->references->size;
275 }
276
277 /* dont have any user flags yet */
278
279 if (mi->content) {
280 do_stat_ci (cls, info, mi->content);
281 }
282 }
283
284 #endif
285
286 gint
camel_local_summary_check(CamelLocalSummary * cls,CamelFolderChangeInfo * changeinfo,GCancellable * cancellable,GError ** error)287 camel_local_summary_check (CamelLocalSummary *cls,
288 CamelFolderChangeInfo *changeinfo,
289 GCancellable *cancellable,
290 GError **error)
291 {
292 CamelLocalSummaryClass *local_summary_class;
293 gint ret;
294
295 local_summary_class = CAMEL_LOCAL_SUMMARY_GET_CLASS (cls);
296 ret = local_summary_class->check (cls, changeinfo, cancellable, error);
297
298 #ifdef DOSTATS
299 if (ret != -1) {
300 gint i;
301 CamelFolderSummary *s = (CamelFolderSummary *) cls;
302 GPtrArray *known_uids;
303 struct _stat_info stats = { 0 };
304
305 known_uids = camel_folder_summary_get_array (s);
306 for (i = 0; i < camel_folder_summary_count (s); i++) {
307 CamelMessageInfo *info = camel_folder_summary_get (s, g_ptr_array_index (known_uids, i));
308 do_stat_mi (cls, &stats, info);
309 g_clear_object (&info);
310 }
311 camel_folder_summary_free_array (known_uids);
312
313 printf ("\nMemory used by summary:\n\n");
314 printf (
315 "Total of %d messages\n",
316 camel_folder_summary_count (s));
317 printf (
318 "Total: %d bytes (ave %f)\n",
319 stats.citotal + stats.mitotal,
320 (gdouble) (stats.citotal + stats.mitotal) /
321 (gdouble) camel_folder_summary_count (s));
322 printf (
323 "Message Info: %d (ave %f)\n",
324 stats.mitotal,
325 (gdouble) stats.mitotal / (gdouble) stats.micount);
326 printf (
327 "Content Info; %d (ave %f) count %d\n",
328 stats.citotal,
329 (gdouble) stats.citotal / (gdouble) stats.cicount,
330 stats.cicount);
331 printf (
332 "message id's: %d (ave %f) count %d\n",
333 stats.msgid,
334 (gdouble) stats.msgid / (gdouble) stats.msgcount,
335 stats.msgcount);
336 }
337 #endif
338 return ret;
339 }
340
341 gint
camel_local_summary_sync(CamelLocalSummary * cls,gboolean expunge,CamelFolderChangeInfo * changeinfo,GCancellable * cancellable,GError ** error)342 camel_local_summary_sync (CamelLocalSummary *cls,
343 gboolean expunge,
344 CamelFolderChangeInfo *changeinfo,
345 GCancellable *cancellable,
346 GError **error)
347 {
348 CamelLocalSummaryClass *local_summary_class;
349
350 local_summary_class = CAMEL_LOCAL_SUMMARY_GET_CLASS (cls);
351
352 return local_summary_class->sync (cls, expunge, changeinfo, cancellable, error);
353 }
354
355 CamelMessageInfo *
camel_local_summary_add(CamelLocalSummary * cls,CamelMimeMessage * msg,const CamelMessageInfo * info,CamelFolderChangeInfo * ci,GError ** error)356 camel_local_summary_add (CamelLocalSummary *cls,
357 CamelMimeMessage *msg,
358 const CamelMessageInfo *info,
359 CamelFolderChangeInfo *ci,
360 GError **error)
361 {
362 CamelLocalSummaryClass *local_summary_class;
363
364 local_summary_class = CAMEL_LOCAL_SUMMARY_GET_CLASS (cls);
365
366 return local_summary_class->add (cls, msg, info, ci, error);
367 }
368
369 /**
370 * camel_local_summary_write_headers:
371 * @fd: a file descriptor to write to
372 * @headers: a #CamelNameValueArray with headers to write
373 * @xevline: (nullable): an optional value of X-Evolution header to add
374 * @status: (nullable): an optional value of Status header to add
375 * @xstatus: (nullable): an optional value of X-Status header to add
376 *
377 * Write a bunch of headers to the file @fd. If xevline is non NULL, then
378 * an X-Evolution header line is created at the end of all of the headers.
379 * If @status is non NULL, then a Status header line is also written.
380 * The headers written are termianted with a blank line.
381 *
382 * Returns: -1 on error, otherwise the number of bytes written.
383 **/
384 gint
camel_local_summary_write_headers(gint fd,CamelNameValueArray * headers,const gchar * xevline,const gchar * status,const gchar * xstatus)385 camel_local_summary_write_headers (gint fd,
386 CamelNameValueArray *headers,
387 const gchar *xevline,
388 const gchar *status,
389 const gchar *xstatus)
390 {
391 gint outlen = 0, len;
392 gint newfd;
393 guint ii;
394 const gchar *header_name = NULL, *header_value = NULL;
395 FILE *out;
396
397 /* dum de dum, maybe the whole sync function should just use stdio for output */
398 newfd = dup (fd);
399 if (newfd == -1)
400 return -1;
401
402 out = fdopen (newfd, "w");
403 if (out == NULL) {
404 close (newfd);
405 errno = EINVAL;
406 return -1;
407 }
408
409 for (ii = 0; camel_name_value_array_get (headers, ii, &header_name, &header_value); ii++) {
410 if (strcmp (header_name, "X-Evolution") != 0
411 && (status == NULL || strcmp (header_name, "Status") != 0)
412 && (xstatus == NULL || strcmp (header_name, "X-Status") != 0)) {
413 len = fprintf (out, "%s:%s\n", header_name, header_value);
414 if (len == -1) {
415 fclose (out);
416 return -1;
417 }
418 outlen += len;
419 }
420 }
421
422 if (status) {
423 len = fprintf (out, "Status: %s\n", status);
424 if (len == -1) {
425 fclose (out);
426 return -1;
427 }
428 outlen += len;
429 }
430
431 if (xstatus) {
432 len = fprintf (out, "X-Status: %s\n", xstatus);
433 if (len == -1) {
434 fclose (out);
435 return -1;
436 }
437 outlen += len;
438 }
439
440 if (xevline) {
441 len = fprintf (out, "X-Evolution: %s\n", xevline);
442 if (len == -1) {
443 fclose (out);
444 return -1;
445 }
446 outlen += len;
447 }
448
449 len = fprintf (out, "\n");
450 if (len == -1) {
451 fclose (out);
452 return -1;
453 }
454 outlen += len;
455
456 if (fclose (out) == -1)
457 return -1;
458
459 return outlen;
460 }
461
462 static gint
local_summary_check(CamelLocalSummary * cls,CamelFolderChangeInfo * changeinfo,GCancellable * cancellable,GError ** error)463 local_summary_check (CamelLocalSummary *cls,
464 CamelFolderChangeInfo *changeinfo,
465 GCancellable *cancellable,
466 GError **error)
467 {
468 /* FIXME: sync index here ? */
469 return 0;
470 }
471
472 static gint
local_summary_sync(CamelLocalSummary * cls,gboolean expunge,CamelFolderChangeInfo * changeinfo,GCancellable * cancellable,GError ** error)473 local_summary_sync (CamelLocalSummary *cls,
474 gboolean expunge,
475 CamelFolderChangeInfo *changeinfo,
476 GCancellable *cancellable,
477 GError **error)
478 {
479 CamelFolderSummary *folder_summary;
480 GError *local_error = NULL;
481
482 folder_summary = CAMEL_FOLDER_SUMMARY (cls);
483
484 if (!camel_folder_summary_save (folder_summary, &local_error)) {
485 CamelFolder *folder = camel_folder_summary_get_folder (folder_summary);
486 g_warning ("Could not save summary for local providers folder '%s': %s",
487 folder ? camel_folder_get_full_name (folder) : "???",
488 local_error ? local_error->message : "Unknown error");
489 if (local_error)
490 g_propagate_error (error, local_error);
491 return -1;
492 }
493
494 if (cls->index && camel_index_sync (cls->index) == -1) {
495 g_warning ("Could not sync index for %s: %s", cls->folder_path, g_strerror (errno));
496 return -1;
497 }
498
499 return 0;
500 }
501
502 static gint
local_summary_need_index(void)503 local_summary_need_index (void)
504 {
505 return 1;
506 }
507
508 static CamelMessageInfo *
local_summary_add(CamelLocalSummary * cls,CamelMimeMessage * msg,const CamelMessageInfo * info,CamelFolderChangeInfo * ci,GError ** error)509 local_summary_add (CamelLocalSummary *cls,
510 CamelMimeMessage *msg,
511 const CamelMessageInfo *info,
512 CamelFolderChangeInfo *ci,
513 GError **error)
514 {
515 CamelFolderSummary *summary;
516 CamelMessageInfo *mi;
517 gchar *xev;
518
519 d (printf ("Adding message to summary\n"));
520
521 summary = CAMEL_FOLDER_SUMMARY (cls);
522
523 mi = camel_folder_summary_info_new_from_message (summary, msg);
524 camel_message_info_set_abort_notifications (mi, TRUE);
525
526 if (info) {
527 camel_message_info_take_user_flags (mi, camel_message_info_dup_user_flags (info));
528 camel_message_info_take_user_tags (mi, camel_message_info_dup_user_tags (info));
529 camel_message_info_set_flags (mi, ~0, camel_message_info_get_flags (info));
530 camel_message_info_set_size (mi, camel_message_info_get_size (info));
531 }
532
533 /* we need to calculate the size ourselves */
534 if (camel_message_info_get_size (mi) == 0) {
535 camel_message_info_set_size (mi, camel_data_wrapper_calculate_size_sync (CAMEL_DATA_WRAPPER (msg), NULL, NULL));
536 }
537
538 camel_message_info_set_flags (mi, CAMEL_MESSAGE_FOLDER_NOXEV, 0);
539 xev = camel_local_summary_encode_x_evolution (cls, mi);
540 camel_medium_set_header ((CamelMedium *) msg, "X-Evolution", xev);
541 g_free (xev);
542
543 camel_message_info_set_abort_notifications (mi, FALSE);
544 camel_folder_summary_add (summary, mi, FALSE);
545 camel_folder_change_info_add_uid (ci, camel_message_info_get_uid (mi));
546
547 return mi;
548 }
549
550 static gchar *
local_summary_encode_x_evolution(CamelLocalSummary * cls,const CamelMessageInfo * mi)551 local_summary_encode_x_evolution (CamelLocalSummary *cls,
552 const CamelMessageInfo *mi)
553 {
554 GString *out = g_string_new ("");
555 struct _camel_header_param *params = NULL;
556 guint32 flags;
557 const CamelNamedFlags *user_flags;
558 const CamelNameValueArray *user_tags;
559 gchar *ret;
560 const gchar *p, *uidstr;
561 guint32 uid;
562
563 camel_message_info_property_lock (mi);
564
565 /* FIXME: work out what to do with uid's that aren't stored here? */
566 /* FIXME: perhaps make that a mbox folder only issue?? */
567 p = uidstr = camel_message_info_get_uid (mi);
568 flags = camel_message_info_get_flags (mi);
569 while (*p && isdigit (*p))
570 p++;
571 if (*p == 0 && sscanf (uidstr, "%u", &uid) == 1) {
572 g_string_printf (out, "%08x-%04x", uid, flags & 0xffff);
573 } else {
574 g_string_printf (out, "%s-%04x", uidstr, flags & 0xffff);
575 }
576
577 user_flags = camel_message_info_get_user_flags (mi);
578 user_tags = camel_message_info_get_user_tags (mi);
579
580 if (user_flags || user_tags) {
581 GString *val = g_string_new ("");
582 const gchar *name, *value;
583 guint ii, len;
584
585 len = camel_named_flags_get_length (user_flags);
586 if (len) {
587 for (ii = 0; ii < len; ii++) {
588 name = camel_named_flags_get (user_flags, ii);
589 if (!name)
590 continue;
591
592 if (val->len)
593 g_string_append_c (val, ',');
594 g_string_append (val, name);
595 }
596 camel_header_set_param (¶ms, "flags", val->str);
597 g_string_truncate (val, 0);
598 }
599
600 len = camel_name_value_array_get_length (user_tags);
601 if (len) {
602 for (ii = 0; ii < len; ii++) {
603 if (!camel_name_value_array_get (user_tags, ii, &name, &value))
604 continue;
605
606 if (val->len)
607 g_string_append_c (val, ',');
608
609 g_string_append (val, name);
610 g_string_append_c (val, '=');
611 g_string_append (val, value);
612 }
613 camel_header_set_param (¶ms, "tags", val->str);
614 }
615 g_string_free (val, TRUE);
616
617 camel_header_param_list_format_append (out, params);
618 camel_header_param_list_free (params);
619 }
620 ret = out->str;
621 g_string_free (out, FALSE);
622
623 camel_message_info_property_unlock (mi);
624
625 return ret;
626 }
627
628 static gint
local_summary_decode_x_evolution(CamelLocalSummary * cls,const gchar * xev,CamelMessageInfo * mi)629 local_summary_decode_x_evolution (CamelLocalSummary *cls,
630 const gchar *xev,
631 CamelMessageInfo *mi)
632 {
633 struct _camel_header_param *params, *scan;
634 guint32 uid, flags;
635 gchar *header;
636 gint i;
637 gchar uidstr[20];
638
639 uidstr[0] = 0;
640
641 /* check for uid/flags */
642 header = camel_header_token_decode (xev);
643 if (header && strlen (header) == strlen ("00000000-0000")
644 && sscanf (header, "%08x-%04x", &uid, &flags) == 2) {
645 if (mi)
646 g_snprintf (uidstr, sizeof (uidstr), "%u", uid);
647 } else {
648 g_free (header);
649 return -1;
650 }
651 g_free (header);
652
653 if (mi == NULL)
654 return 0;
655
656 /* check for additional data */
657 header = strchr (xev, ';');
658 if (header) {
659 params = camel_header_param_list_decode (header + 1);
660 scan = params;
661 while (scan) {
662 if (!g_ascii_strcasecmp (scan->name, "flags")) {
663 gchar **flagv = g_strsplit (scan->value, ",", 1000);
664
665 for (i = 0; flagv[i]; i++)
666 camel_message_info_set_user_flag (mi, flagv[i], TRUE);
667 g_strfreev (flagv);
668 } else if (!g_ascii_strcasecmp (scan->name, "tags")) {
669 gchar **tagv = g_strsplit (scan->value, ",", 10000);
670 gchar *val;
671
672 for (i = 0; tagv[i]; i++) {
673 val = strchr (tagv[i], '=');
674 if (val) {
675 *val++ = 0;
676 camel_message_info_set_user_tag (mi, tagv[i], val);
677 val[-1]='=';
678 }
679 }
680 g_strfreev (tagv);
681 }
682 scan = scan->next;
683 }
684 camel_header_param_list_free (params);
685 }
686
687 camel_message_info_set_uid (mi, uidstr);
688 camel_message_info_set_flags (mi, ~0, flags);
689
690 return 0;
691 }
692
693 static gboolean
summary_header_load(CamelFolderSummary * s,CamelFIRecord * fir)694 summary_header_load (CamelFolderSummary *s,
695 CamelFIRecord *fir)
696 {
697 CamelLocalSummary *cls = (CamelLocalSummary *) s;
698 gchar *part, *tmp;
699
700 /* We dont actually add our own headers, but version that we don't anyway */
701
702 if (!CAMEL_FOLDER_SUMMARY_CLASS (camel_local_summary_parent_class)->summary_header_load (s, fir))
703 return FALSE;
704
705 part = fir->bdata;
706 if (part) {
707 cls->version = camel_util_bdata_get_number (&part, 0);
708 }
709
710 /* keep only the rest of the bdata there (strip our version digit) */
711 tmp = g_strdup (part);
712 g_free (fir->bdata);
713 fir->bdata = tmp;
714
715 return TRUE;
716 }
717
718 static struct _CamelFIRecord *
summary_header_save(CamelFolderSummary * s,GError ** error)719 summary_header_save (CamelFolderSummary *s,
720 GError **error)
721 {
722 CamelFolderSummaryClass *folder_summary_class;
723 struct _CamelFIRecord *fir;
724
725 /* Chain up to parent's summary_header_save() method. */
726 folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (camel_local_summary_parent_class);
727 fir = folder_summary_class->summary_header_save (s, NULL);
728 if (fir)
729 fir->bdata = g_strdup_printf ("%d", CAMEL_LOCAL_SUMMARY_VERSION);
730
731 return fir;
732 }
733
734 static CamelMessageInfo *
message_info_new_from_headers(CamelFolderSummary * summary,const CamelNameValueArray * headers)735 message_info_new_from_headers (CamelFolderSummary *summary,
736 const CamelNameValueArray *headers)
737 {
738 CamelMessageInfo *mi;
739 CamelLocalSummary *cls = (CamelLocalSummary *) summary;
740
741 mi = CAMEL_FOLDER_SUMMARY_CLASS (camel_local_summary_parent_class)->message_info_new_from_headers (summary, headers);
742 if (mi) {
743 const gchar *xev;
744 gint doindex = FALSE;
745
746 xev = camel_name_value_array_get_named (headers, CAMEL_COMPARE_CASE_INSENSITIVE, "X-Evolution");
747 if (xev == NULL || camel_local_summary_decode_x_evolution (cls, xev, mi) == -1) {
748 gchar *uid;
749
750 uid = camel_folder_summary_next_uid_string (summary);
751
752 /* to indicate it has no xev header */
753 camel_message_info_set_flags (mi, CAMEL_MESSAGE_FOLDER_FLAGGED | CAMEL_MESSAGE_FOLDER_NOXEV, CAMEL_MESSAGE_FOLDER_FLAGGED | CAMEL_MESSAGE_FOLDER_NOXEV);
754 camel_message_info_set_uid (mi, uid);
755
756 g_free (uid);
757
758 /* shortcut, no need to look it up in the index library */
759 doindex = TRUE;
760 }
761
762 if (cls->index
763 && (doindex
764 || cls->index_force
765 || !camel_index_has_name (cls->index, camel_message_info_get_uid (mi)))) {
766 d (printf ("Am indexing message %s\n", camel_message_info_get_uid (mi)));
767 camel_folder_summary_set_index (summary, cls->index);
768 } else {
769 d (printf ("Not indexing message %s\n", camel_message_info_get_uid (mi)));
770 camel_folder_summary_set_index (summary, NULL);
771 }
772 }
773
774 return mi;
775 }
776