support image/x-eps format via pdf_viewer
[claws.git] / src / plugins / vcalendar / vcal_manager.c
blob4e008a332f64af05ccf3bb2e9614dad9e346d0a7
1 /*
2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2023 the Claws Mail team and Colin Leroy <colin@colino.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #include "claws-features.h"
23 #endif
25 #include <stddef.h>
26 #include <glib.h>
27 #include <glib/gi18n.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #ifdef USE_PTHREAD
32 #include <pthread.h>
33 #endif
34 #include <libical/ical.h>
35 #include "vcalendar.h"
36 #include "vcal_folder.h"
37 #include "vcal_manager.h"
38 #include "vcal_meeting_gtk.h"
39 #include "vcal_prefs.h"
40 #include "xml.h"
41 #include "xmlprops.h"
42 #include "prefs.h"
43 #include "prefs_common.h"
44 #include "prefs_account.h"
45 #include "alertpanel.h"
46 #include "account.h"
47 #include "codeconv.h"
48 #include <time.h>
49 #include "folder.h"
50 #include "quoted-printable.h"
51 #include "file-utils.h"
52 #include "utils.h"
53 #include "defs.h"
55 #ifdef G_OS_WIN32
56 #define getuid() 0
57 #endif
59 Answer *answer_new(const gchar *attendee,
60 const gchar *name,
61 icalparameter_partstat ans,
62 icalparameter_cutype cutype)
64 Answer *answer = g_new0(Answer, 1);
65 answer->attendee = g_strdup(attendee);
66 answer->name = g_strdup(name);
67 if (!answer->name)
68 answer->name = g_strdup("");
69 if (!answer->attendee)
70 answer->attendee = g_strdup("");
71 answer->answer = ans;
72 answer->cutype = cutype;
73 return answer;
76 static void answer_free(Answer *answer)
78 g_free(answer->attendee);
79 g_free(answer->name);
80 g_free(answer);
83 static GSList *answer_find(VCalEvent *event, Answer *answer)
85 GSList *cur = event->answers;
86 while (cur && cur->data) {
87 Answer *b = (Answer *)cur->data;
88 if (!strcasecmp(b->attendee, answer->attendee))
89 return cur;
90 cur = cur->next;
92 return NULL;
95 void vcal_manager_copy_attendees(VCalEvent *src, VCalEvent *dest)
97 GSList *cur = src->answers;
98 while (cur && cur->data) {
99 Answer *a = (Answer *)cur->data;
100 Answer *b = answer_new(a->attendee, a->name, a->answer, a->cutype);
101 dest->answers = g_slist_prepend(dest->answers, b);
102 cur = cur->next;
104 dest->answers = g_slist_reverse(dest->answers);
107 gchar *vcal_manager_answer_get_text(icalparameter_partstat ans)
109 static gchar *replies[5]={
110 N_("accepted"),
111 N_("tentatively accepted"),
112 N_("declined"),
113 N_("did not answer"),
114 N_("unknown")
117 switch (ans) {
118 case ICAL_PARTSTAT_ACCEPTED:
119 return _(replies[0]);
120 break;
121 case ICAL_PARTSTAT_DECLINED:
122 return _(replies[2]);
123 break;
124 case ICAL_PARTSTAT_TENTATIVE:
125 return _(replies[1]);
126 break;
127 case ICAL_PARTSTAT_NEEDSACTION:
128 return _(replies[3]);
129 case ICAL_PARTSTAT_DELEGATED:
130 case ICAL_PARTSTAT_COMPLETED:
131 case ICAL_PARTSTAT_X:
132 case ICAL_PARTSTAT_INPROCESS:
133 case ICAL_PARTSTAT_NONE:
134 case ICAL_PARTSTAT_FAILED:
135 return _(replies[4]);
136 break;
138 return NULL;
141 gchar *vcal_manager_cutype_get_text(icalparameter_cutype type)
143 static gchar *replies[5]={
144 N_("individual"),
145 N_("group"),
146 N_("resource"),
147 N_("room"),
148 N_("unknown")
151 switch (type) {
152 case ICAL_CUTYPE_INDIVIDUAL:
153 return _(replies[0]);
154 break;
155 case ICAL_CUTYPE_GROUP:
156 return _(replies[1]);
157 break;
158 case ICAL_CUTYPE_RESOURCE:
159 return _(replies[2]);
160 break;
161 case ICAL_CUTYPE_ROOM:
162 return _(replies[3]);
163 default:
164 return _(replies[4]);
165 break;
167 return NULL;
170 static GSList *answer_remove(VCalEvent *event, Answer *answer)
172 GSList *cur = answer_find(event, answer);
173 if (cur) {
174 Answer *b = (Answer *)cur->data;
175 event->answers = g_slist_remove(event->answers, b);
176 answer_free(b);
178 return event->answers;
181 static GSList *answer_add(VCalEvent *event, Answer *answer)
183 event->answers = g_slist_append(event->answers, answer);
184 return event->answers;
187 GSList *vcal_manager_get_answers_emails(VCalEvent *event)
189 GSList *new = NULL;
190 GSList *cur = event->answers;
191 while (cur && cur->data) {
192 Answer *b = (Answer *)cur->data;
193 new = g_slist_prepend(new, b->attendee);
194 cur = cur->next;
196 new = g_slist_reverse(new);
197 return new;
200 icalparameter_partstat vcal_manager_get_reply_for_attendee(VCalEvent *event, const gchar *att)
202 Answer *a = answer_new(att, NULL, 0, 0);
203 GSList *ans = answer_find(event, a);
204 icalparameter_partstat res = 0;
205 if (ans) {
206 Answer *b = (Answer *)ans->data;
207 res = b->answer;
209 answer_free(a);
210 return res;
213 gchar *vcal_manager_get_cutype_text_for_attendee(VCalEvent *event, const gchar *att)
215 icalparameter_cutype status = vcal_manager_get_cutype_for_attendee(event, att);
216 gchar *res = NULL;
217 if (status != 0)
218 res = g_strdup(vcal_manager_cutype_get_text(status));
220 return res;
223 icalparameter_cutype vcal_manager_get_cutype_for_attendee(VCalEvent *event, const gchar *att)
225 Answer *a = answer_new(att, NULL, 0, 0);
226 GSList *ans = answer_find(event, a);
227 icalparameter_cutype res = 0;
228 if (ans) {
229 Answer *b = (Answer *)ans->data;
230 res = b->cutype;
232 answer_free(a);
233 return res;
236 gchar *vcal_manager_get_reply_text_for_attendee(VCalEvent *event, const gchar *att)
238 icalparameter_partstat status = vcal_manager_get_reply_for_attendee(event, att);
239 gchar *res = NULL;
240 if (status != 0)
241 res = g_strdup(vcal_manager_answer_get_text(status));
243 return res;
246 gchar *vcal_manager_get_attendee_name(VCalEvent *event, const gchar *att)
248 Answer *a = answer_new(att, NULL, 0, 0);
249 GSList *ans = answer_find(event, a);
250 gchar *res = NULL;
251 if (ans) {
252 Answer *b = (Answer *)ans->data;
253 if (b->name)
254 res = g_strdup(b->name);
256 answer_free(a);
257 return res;
260 void vcal_manager_event_print(VCalEvent *event)
262 GSList *list = event->answers;
263 printf( "event->uid\t\t%s\n"
264 "event->organizer\t\t%s\n"
265 "event->start\t\t%s\n"
266 "event->end\t\t%s\n"
267 "event->location\t\t%s\n"
268 "event->summary\t\t%s\n"
269 "event->description\t%s\n"
270 "event->url\t%s\n"
271 "event->dtstart\t\t%s\n"
272 "event->dtend\t\t%s\n"
273 "event->recur\t\t%s\n"
274 "event->tzid\t\t%s\n"
275 "event->method\t\t%d\n"
276 "event->sequence\t\t%d\n",
277 event->uid,
278 event->organizer,
279 event->start,
280 event->end,
281 event->location,
282 event->summary,
283 event->description,
284 event->url,
285 event->dtstart,
286 event->dtend,
287 event->recur,
288 event->tzid,
289 event->method,
290 event->sequence);
291 while (list && list->data) {
292 Answer *a = (Answer *)list->data;
293 printf(" ans: %s %s, %s\n", a->name, a->attendee, vcal_manager_answer_get_text(a->answer));
294 list = list->next;
299 static gchar *write_headers(PrefsAccount *account,
300 VCalEvent *event,
301 gboolean short_headers,
302 gboolean is_reply,
303 gboolean is_pseudo_event);
305 gchar *vcal_manager_event_dump(VCalEvent *event, gboolean is_reply, gboolean is_pseudo_event,
306 icalcomponent *use_calendar, gboolean modif)
308 gchar *organizer = g_strdup_printf("MAILTO:%s", event->organizer);
309 PrefsAccount *account = vcal_manager_get_account_from_event(event);
310 gchar *attendee = NULL;
311 gchar *body, *headers;
312 gchar *tmpfile = NULL;
313 icalcomponent *calendar, *ievent, *timezone, *tzc;
314 icalproperty *attprop;
315 icalproperty *orgprop;
316 icalparameter_partstat status = ICAL_PARTSTAT_NEEDSACTION;
317 gchar *sanitized_uid = g_strdup(event->uid);
319 subst_for_filename(sanitized_uid);
321 tmpfile = g_strdup_printf("%s%cevt-%d-%s", get_tmp_dir(),
322 G_DIR_SEPARATOR, getuid(), sanitized_uid);
323 g_free(sanitized_uid);
325 if (!account) {
326 g_free(organizer);
327 g_free(tmpfile);
328 debug_print("no account found\n");
329 return NULL;
332 attendee = g_strdup_printf("MAILTO:%s", account->address);
334 if (vcal_manager_get_reply_for_attendee(event, account->address) != 0)
335 status = vcal_manager_get_reply_for_attendee(event, account->address);
337 tzset();
339 if (use_calendar != NULL) {
340 calendar = use_calendar;
341 g_free(tmpfile);
342 tmpfile = NULL;
343 } else
344 calendar =
345 icalcomponent_vanew(
346 ICAL_VCALENDAR_COMPONENT,
347 icalproperty_new_version("2.0"),
348 icalproperty_new_prodid(
349 "-//Claws Mail//NONSGML Claws Mail Calendar//EN"),
350 icalproperty_new_calscale("GREGORIAN"),
351 icalproperty_new_method(is_reply ? ICAL_METHOD_REPLY:event->method),
352 (void*)0
355 if (!calendar) {
356 g_warning("can't generate calendar");
357 g_free(organizer);
358 g_free(tmpfile);
359 g_free(attendee);
360 return NULL;
363 orgprop = icalproperty_new_organizer(organizer);
365 timezone = icalcomponent_new(ICAL_VTIMEZONE_COMPONENT);
367 icalcomponent_add_property(timezone,
368 icalproperty_new_tzid("UTC")); /* free */
370 tzc = icalcomponent_new(ICAL_XSTANDARD_COMPONENT);
371 icalcomponent_add_property(tzc,
372 icalproperty_new_dtstart(
373 icaltime_from_string("19700101T000000")));
374 icalcomponent_add_property(tzc,
375 icalproperty_new_tzoffsetfrom(0.0));
376 icalcomponent_add_property(tzc,
377 icalproperty_new_tzoffsetto(0.0));
378 icalcomponent_add_property(tzc,
379 icalproperty_new_tzname("Greenwich meridian time"));
381 icalcomponent_add_component(timezone, tzc);
383 ievent =
384 icalcomponent_vanew(
385 ICAL_VEVENT_COMPONENT, (void*)0);
387 if (!ievent) {
388 g_warning("can't generate event");
389 g_free(organizer);
390 g_free(tmpfile);
391 g_free(attendee);
392 return NULL;
395 icalcomponent_add_property(ievent,
396 icalproperty_new_uid(event->uid));
397 icalcomponent_add_property(ievent,
398 icalproperty_vanew_dtstamp(icaltime_from_timet_with_zone(time(NULL), TRUE, NULL), (void*)0));
399 icalcomponent_add_property(ievent,
400 icalproperty_vanew_dtstart((icaltime_from_string(event->dtstart)), (void*)0));
401 icalcomponent_add_property(ievent,
402 icalproperty_vanew_dtend((icaltime_from_string(event->dtend)), (void*)0));
403 if (event->recur && *(event->recur)) {
404 icalcomponent_add_property(ievent,
405 icalproperty_vanew_rrule((icalrecurrencetype_from_string(event->recur)), (void*)0));
407 icalcomponent_add_property(ievent,
408 icalproperty_new_description(event->description));
409 icalcomponent_add_property(ievent,
410 icalproperty_new_summary(event->summary));
411 icalcomponent_add_property(ievent,
412 icalproperty_new_sequence(modif && !is_reply ? event->sequence + 1 : event->sequence));
413 icalcomponent_add_property(ievent,
414 icalproperty_new_class(ICAL_CLASS_PUBLIC));
415 icalcomponent_add_property(ievent,
416 icalproperty_new_transp(ICAL_TRANSP_OPAQUE));
418 if (event->location && *event->location)
419 icalcomponent_add_property(ievent,
420 icalproperty_new_location(event->location));
421 else
422 icalcomponent_add_property(ievent,
423 icalproperty_new_location(""));
424 icalcomponent_add_property(ievent,
425 icalproperty_new_status(ICAL_STATUS_CONFIRMED));
426 if (event->created != NULL && event->created[0] != '\0') {
427 icalcomponent_add_property(ievent,
428 icalproperty_vanew_created(icaltime_from_string(event->created), (void*)0));
429 } else {
430 icalcomponent_add_property(ievent,
431 icalproperty_vanew_created(icaltime_from_timet_with_zone(time(NULL), FALSE, NULL), (void*)0));
433 if (event->last_modified != NULL && event->last_modified[0] != '\0' && !modif) {
434 icalcomponent_add_property(ievent,
435 icalproperty_vanew_lastmodified(icaltime_from_string(event->last_modified), (void*)0));
436 } else {
437 icalcomponent_add_property(ievent,
438 icalproperty_vanew_lastmodified(icaltime_from_timet_with_zone(time(NULL), FALSE, NULL), (void*)0));
440 icalcomponent_add_property(ievent,
441 orgprop);
443 if (!icalcomponent_get_first_component(calendar, ICAL_VTIMEZONE_COMPONENT))
444 icalcomponent_add_component(calendar, timezone);
445 else
446 icalcomponent_free(timezone);
448 icalcomponent_add_component(calendar, ievent);
450 if (event->url && *(event->url)) {
451 attprop = icalproperty_new_url(event->url);
452 icalcomponent_add_property(ievent, attprop);
455 if (is_reply) {
456 /* dump only this attendee */
457 attprop =
458 icalproperty_vanew_attendee(
459 attendee,
460 icalparameter_new_role(
461 ICAL_ROLE_REQPARTICIPANT),
462 icalparameter_new_rsvp(ICAL_RSVP_TRUE),
463 icalparameter_new_partstat(status),
464 (void*)0
466 icalcomponent_add_property(ievent, attprop);
467 } else {
468 /* dump all attendees */
469 GSList *cur = event->answers;
470 while (cur && cur->data) {
471 Answer *a = (Answer *)cur->data;
473 if (a->cutype == 0)
474 a->cutype = ICAL_CUTYPE_INDIVIDUAL;
475 if (a->answer == 0)
476 a->answer = ICAL_PARTSTAT_NEEDSACTION;
478 attprop =
479 icalproperty_vanew_attendee(
480 a->attendee,
481 icalparameter_new_role(
482 ICAL_ROLE_REQPARTICIPANT),
483 icalparameter_new_rsvp(ICAL_RSVP_TRUE),
484 icalparameter_new_cutype(a->cutype),
485 icalparameter_new_partstat(a->answer),
486 (void*)0
489 icalcomponent_add_property(ievent, attprop);
490 cur = cur->next;
494 if (use_calendar) {
495 g_free(organizer);
496 g_free(tmpfile);
497 g_free(attendee);
498 return NULL;
501 headers = write_headers(account, event, is_pseudo_event, is_reply, is_pseudo_event);
503 if (!headers) {
504 g_warning("can't get headers");
505 g_free(organizer);
506 g_free(tmpfile);
507 g_free(attendee);
508 return NULL;
511 body = g_strdup_printf("%s"
512 "\n"
513 "%s", headers, icalcomponent_as_ical_string(calendar));
515 if (str_write_to_file(body, tmpfile, FALSE) < 0) {
516 g_free(tmpfile);
517 tmpfile = NULL;
520 chmod(tmpfile, S_IRUSR|S_IWUSR);
522 g_free(body);
523 g_free(headers);
524 icalcomponent_free(calendar);
525 g_free(attendee);
526 g_free(organizer);
528 tzset();
530 return tmpfile;
533 static void get_rfc822_date_from_time_t(gchar *buf, gint len, time_t t)
535 #ifndef G_OS_WIN32
536 struct tm *lt;
537 gchar day[4], mon[4];
538 gint dd, hh, mm, ss, yyyy;
539 gchar buft1[512];
540 struct tm buft2;
542 lt = localtime_r(&t, &buft2);
543 if (sscanf(asctime_r(lt, buft1), "%3s %3s %d %d:%d:%d %d\n",
544 day, mon, &dd, &hh, &mm, &ss, &yyyy) != 7)
545 g_warning("failed reading date/time");
546 g_snprintf(buf, len, "%s, %d %s %d %02d:%02d:%02d %s",
547 day, dd, mon, yyyy, hh, mm, ss, tzoffset(&t));
548 #else
549 GDateTime *dt = g_date_time_new_from_unix_local(t);
550 if (dt == NULL) {
551 g_warning("failed getting date/time");
552 g_snprintf(buf, len, "(NULL)");
553 return;
556 gchar *ret = g_date_time_format(dt, "%a, %e %b %Y %T %z");
557 g_date_time_unref(dt);
559 if (ret == NULL) {
560 g_warning("failed formatting date/time");
561 g_snprintf(buf, len, "(NULL)");
562 return;
565 g_snprintf(buf, len, ret);
566 g_free(ret);
567 #endif
570 static gchar *write_headers_date(const gchar *uid)
572 gchar subject[512];
573 gchar *t_subject;
574 gchar date[RFC822_DATE_BUFFSIZE];
575 time_t t;
576 struct tm lt;
578 memset(subject, 0, sizeof(subject));
579 memset(date, 0, sizeof(date));
581 if (!strcmp(uid, EVENT_PAST_ID)) {
582 t = 1;
583 t_subject = _("Past");
584 } else if (!strcmp(uid, EVENT_TODAY_ID)) {
585 t = time(NULL);
586 t_subject = _("Today");
587 } else if (!strcmp(uid, EVENT_TOMORROW_ID)) {
588 t = time(NULL) + 86400;
589 t_subject = _("Tomorrow");
590 } else if (!strcmp(uid, EVENT_THISWEEK_ID)) {
591 t = time(NULL) + (86400*2);
592 t_subject = _("This week");
593 } else if (!strcmp(uid, EVENT_LATER_ID)) {
594 t = time(NULL) + (86400*7);
595 t_subject = _("Later");
596 } else {
597 g_warning("unknown spec date");
598 return NULL;
601 #ifndef G_OS_WIN32
602 struct tm buft;
603 lt = *localtime_r(&t, &buft);
604 #else
605 if (t < 0)
606 t = 1;
607 lt = *localtime(&t);
608 #endif
609 lt.tm_hour = lt.tm_min = lt.tm_sec = 0;
610 t = mktime(&lt);
611 get_rfc822_date_from_time_t(date, sizeof(date), t);
612 conv_encode_header(subject, 511, t_subject, strlen("Subject: "), FALSE);
614 return g_strdup_printf("From: -\n"
615 "To: -\n"
616 "Subject: %s\n"
617 "Date: %s\n"
618 "MIME-Version: 1.0\n"
619 "Content-Type: text/plain; charset=\"UTF-8\";\n"
620 "Content-Transfer-Encoding: quoted-printable\n"
621 "Message-ID: <%s>\n",
622 subject,
623 date,
624 uid);
627 gchar *vcal_manager_dateevent_dump(const gchar *uid, FolderItem *item)
629 gchar *sanitized_uid = NULL;
630 gchar *headers = NULL;
631 gchar *lines, *body, *tmpfile;
632 EventTime date;
633 sanitized_uid = g_strdup(uid);
634 subst_for_filename(sanitized_uid);
636 tmpfile = g_strdup_printf("%s%cevt-%d-%s", get_tmp_dir(),
637 G_DIR_SEPARATOR, getuid(), sanitized_uid);
638 g_free(sanitized_uid);
640 headers = write_headers_date(uid);
642 if (!headers) {
643 g_warning("can't get headers");
644 g_free(tmpfile);
645 return NULL;
648 if (!strcmp(uid, EVENT_PAST_ID))
649 date = EVENT_PAST;
650 else if (!strcmp(uid, EVENT_TODAY_ID))
651 date = EVENT_TODAY;
652 else if (!strcmp(uid, EVENT_TOMORROW_ID))
653 date = EVENT_TOMORROW;
654 else if (!strcmp(uid, EVENT_THISWEEK_ID))
655 date = EVENT_THISWEEK;
656 else if (!strcmp(uid, EVENT_LATER_ID))
657 date = EVENT_LATER;
658 else
659 date = EVENT_PAST;
661 lines = get_item_event_list_for_date(item, date);
662 body = g_strdup_printf("%s"
663 "\n"
664 "%s", headers, lines);
665 g_free(lines);
666 if (str_write_to_file(body, tmpfile, FALSE) < 0) {
667 g_free(tmpfile);
668 tmpfile = NULL;
669 } else
670 chmod(tmpfile, S_IRUSR|S_IWUSR);
672 g_free(body);
673 g_free(headers);
675 return tmpfile;
678 static gchar *write_headers_ical(PrefsAccount *account,
679 icalcomponent *ievent,
680 gchar *orga);
682 gchar *vcal_manager_icalevent_dump(icalcomponent *event, gchar *orga, icalcomponent *use_calendar)
684 PrefsAccount *account = account_get_cur_account();
685 gchar *body, *headers, *qpbody;
686 gchar **lines = NULL;
687 gchar *tmpfile = NULL;
688 icalcomponent *calendar;
689 icalproperty *prop;
690 icalcomponent *ievent = NULL;
691 int i = 0;
693 ievent = icalcomponent_new_clone(event);
695 prop = icalcomponent_get_first_property(ievent, ICAL_UID_PROPERTY);
696 if (prop) {
697 gchar *sanitized_uid = g_strdup(icalproperty_get_uid(prop));
699 subst_for_filename(sanitized_uid);
701 tmpfile = g_strdup_printf("%s%cevt-%d-%s", get_tmp_dir(),
702 G_DIR_SEPARATOR, getuid(), sanitized_uid);
703 g_free(sanitized_uid);
704 icalproperty_free(prop);
705 } else {
706 tmpfile = g_strdup_printf("%s%cevt-%d-%p", get_tmp_dir(),
707 G_DIR_SEPARATOR, getuid(), ievent);
710 if (!account) {
711 g_free(tmpfile);
712 icalcomponent_free(ievent);
713 return NULL;
716 tzset();
718 if (use_calendar != NULL) {
719 calendar = use_calendar;
720 g_free(tmpfile);
721 tmpfile = NULL;
722 } else
723 calendar =
724 icalcomponent_vanew(
725 ICAL_VCALENDAR_COMPONENT,
726 icalproperty_new_version("2.0"),
727 icalproperty_new_prodid(
728 "-//Claws Mail//NONSGML Claws Mail Calendar//EN"),
729 icalproperty_new_calscale("GREGORIAN"),
730 icalproperty_new_method(ICAL_METHOD_PUBLISH),
731 (void*)0
734 if (!calendar) {
735 g_warning("can't generate calendar");
736 g_free(tmpfile);
737 icalcomponent_free(ievent);
738 return NULL;
741 icalcomponent_add_component(calendar, ievent);
743 if (use_calendar)
744 return NULL;
746 headers = write_headers_ical(account, ievent, orga);
748 if (!headers) {
749 g_warning("can't get headers");
750 g_free(tmpfile);
751 icalcomponent_free(calendar);
752 return NULL;
755 lines = g_strsplit(icalcomponent_as_ical_string(calendar), "\n", 0);
756 qpbody = g_strdup("");
758 /* encode to quoted-printable */
759 while (lines[i]) {
760 gint e_len = strlen(qpbody), n_len = 0;
761 gchar *outline = conv_codeset_strdup(lines[i], CS_UTF_8, conv_get_outgoing_charset_str());
762 gchar *qpoutline = g_malloc(strlen(outline)*8 + 1);
764 qp_encode_line(qpoutline, (guchar *)outline);
765 n_len = strlen(qpoutline);
767 qpbody = g_realloc(qpbody, e_len + n_len + 1);
768 strcpy(qpbody+e_len, qpoutline);
769 *(qpbody+n_len+e_len) = '\0';
771 g_free(outline);
772 g_free(qpoutline);
773 i++;
776 body = g_strdup_printf("%s"
777 "\n"
778 "%s", headers, qpbody);
780 if (str_write_to_file(body, tmpfile, FALSE) < 0) {
781 g_free(tmpfile);
782 tmpfile = NULL;
783 } else
784 chmod(tmpfile, S_IRUSR|S_IWUSR);
786 g_strfreev(lines);
787 g_free(body);
788 g_free(qpbody);
789 g_free(headers);
790 icalcomponent_free(calendar);
792 return tmpfile;
795 VCalEvent * vcal_manager_new_event (const gchar *uid,
796 const gchar *organizer,
797 const gchar *orgname,
798 const gchar *location,
799 const gchar *summary,
800 const gchar *description,
801 const gchar *dtstart,
802 const gchar *dtend,
803 const gchar *recur,
804 const gchar *tzid,
805 const gchar *url,
806 icalproperty_method method,
807 gint sequence,
808 const gchar *created,
809 const gchar *last_modified,
810 icalcomponent_kind type)
812 VCalEvent *event = g_new0(VCalEvent, 1);
814 event->uid = g_strdup(uid?uid:"");
815 event->organizer = g_strdup(organizer?organizer:"");
816 event->orgname = g_strdup(orgname?orgname:"");
818 if (dtend && *(dtend)) {
819 time_t tmp = icaltime_as_timet((icaltime_from_string(dtend)));
820 GDateTime *dt = g_date_time_new_from_unix_local(tmp);
821 event->end = g_date_time_format(dt, "%a, %e %b %Y %H:%M:%S %Z");
822 g_date_time_unref(dt);
825 if (dtstart && *(dtstart)) {
826 time_t tmp = icaltime_as_timet((icaltime_from_string(dtstart)));
827 GDateTime *dt = g_date_time_new_from_unix_local(tmp);
828 event->start = g_date_time_format(dt, "%a, %e %b %Y %H:%M:%S %Z");
829 g_date_time_unref(dt);
831 event->dtstart = g_strdup(dtstart?dtstart:"");
832 event->dtend = g_strdup(dtend?dtend:"");
833 event->recur = g_strdup(recur?recur:"");
834 event->location = g_strdup(location?location:"");
835 event->summary = g_strdup(summary?summary:"");
836 event->description = g_strdup(description?description:"");
837 event->url = g_strdup(url?url:"");
838 event->tzid = g_strdup(tzid?tzid:"");
839 event->method = method;
840 event->sequence = sequence;
841 event->created = g_strdup(created?created:"");
842 event->last_modified = g_strdup(last_modified?last_modified:"");
843 event->type = type;
844 event->rec_occurrence = FALSE;
845 while (strchr(event->summary, '\n'))
846 *(strchr(event->summary, '\n')) = ' ';
848 return event;
851 void vcal_manager_free_event (VCalEvent *event)
853 GSList *cur;
854 if (!event)
855 return;
857 g_free(event->uid);
858 g_free(event->organizer);
859 g_free(event->orgname);
860 g_free(event->start);
861 g_free(event->end);
862 g_free(event->location);
863 g_free(event->summary);
864 g_free(event->dtstart);
865 g_free(event->dtend);
866 g_free(event->recur);
867 g_free(event->tzid);
868 g_free(event->description);
869 g_free(event->url);
870 for (cur = event->answers; cur; cur = cur->next) {
871 answer_free((Answer *)cur->data);
873 g_slist_free(event->answers);
874 g_free(event);
877 gchar *vcal_manager_get_event_path(void)
879 static gchar *event_path = NULL;
880 if (!event_path)
881 event_path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
882 "vcalendar", NULL);
884 return event_path;
887 gchar *vcal_manager_get_event_file(const gchar *uid)
889 gchar *tmp = g_strdup(uid);
890 gchar *res = NULL;
892 subst_for_filename(tmp);
893 res = g_strconcat(vcal_manager_get_event_path(), G_DIR_SEPARATOR_S,
894 tmp, NULL);
895 g_free(tmp);
896 return res;
899 PrefsAccount *vcal_manager_get_account_from_event(VCalEvent *event)
901 GSList *list = vcal_manager_get_answers_emails(event);
902 GSList *cur = list;
904 /* find an attendee corresponding to one of our accounts */
905 while (cur && cur->data) {
906 gchar *email = (gchar *)cur->data;
907 if (account_find_from_address(email, FALSE)) {
908 g_slist_free(list);
909 return account_find_from_address(email, FALSE);
911 cur = cur->next;
913 g_slist_free(list);
914 return NULL;
917 void vcal_manager_save_event (VCalEvent *event, gboolean export_after)
919 XMLTag *tag = NULL;
920 XMLNode *xmlnode = NULL;
921 GNode *rootnode = NULL;
922 PrefFile *pfile;
923 gchar *path = NULL;
924 GSList *answers = event->answers;
925 gchar *tmp = NULL;
926 gint tmp_method = event->method;
928 tag = xml_tag_new("event");
929 xml_tag_add_attr(tag, xml_attr_new("organizer", event->organizer));
930 xml_tag_add_attr(tag, xml_attr_new("orgname", event->orgname));
931 xml_tag_add_attr(tag, xml_attr_new("location", event->location));
932 xml_tag_add_attr(tag, xml_attr_new("summary", event->summary));
933 xml_tag_add_attr(tag, xml_attr_new("description", event->description));
934 xml_tag_add_attr(tag, xml_attr_new("url", event->url));
935 xml_tag_add_attr(tag, xml_attr_new("dtstart", event->dtstart));
936 xml_tag_add_attr(tag, xml_attr_new("dtend", event->dtend));
937 xml_tag_add_attr(tag, xml_attr_new("recur", event->recur));
938 xml_tag_add_attr(tag, xml_attr_new("tzid", event->tzid));
940 /* updating answers saves events, don't save them with reply type */
941 if (tmp_method == ICAL_METHOD_REPLY)
942 tmp_method = ICAL_METHOD_REQUEST;
944 tmp = g_strdup_printf("%d", tmp_method);
945 xml_tag_add_attr(tag, xml_attr_new("method", tmp));
946 g_free(tmp);
948 tmp = g_strdup_printf("%d", event->sequence);
949 xml_tag_add_attr(tag, xml_attr_new("sequence", tmp));
950 xml_tag_add_attr(tag, xml_attr_new("created", event->created));
951 xml_tag_add_attr(tag, xml_attr_new("last_modified", event->last_modified));
952 g_free(tmp);
954 tmp = g_strdup_printf("%d", event->type);
955 xml_tag_add_attr(tag, xml_attr_new("type", tmp));
956 g_free(tmp);
958 tmp = g_strdup_printf("%"CM_TIME_FORMAT, event->postponed);
959 xml_tag_add_attr(tag, xml_attr_new("postponed", tmp));
960 g_free(tmp);
962 tmp = g_strdup_printf("%d", event->rec_occurrence);
963 xml_tag_add_attr(tag, xml_attr_new("rec_occurrence", tmp));
964 g_free(tmp);
966 xmlnode = xml_node_new(tag, NULL);
967 rootnode = g_node_new(xmlnode);
969 while (answers && answers->data) {
970 XMLNode *ansxmlnode = NULL;
971 GNode *ansnode = NULL;
972 XMLTag *anstag = xml_tag_new("answer");
973 Answer *a = (Answer *)answers->data;
974 xml_tag_add_attr(anstag, xml_attr_new("attendee", a->attendee));
975 xml_tag_add_attr(anstag, xml_attr_new("name", a->name?a->name:""));
976 tmp = g_strdup_printf("%d", a->answer);
977 xml_tag_add_attr(anstag, xml_attr_new("answer", tmp));
978 g_free(tmp);
979 tmp = g_strdup_printf("%d", a->cutype);
980 xml_tag_add_attr(anstag, xml_attr_new("cutype", tmp));
981 g_free(tmp);
982 ansxmlnode = xml_node_new(anstag, NULL);
983 ansnode = g_node_new(ansxmlnode);
984 g_node_append(rootnode, ansnode);
985 answers = answers->next;
988 path = vcal_manager_get_event_file(event->uid);
990 if ((pfile = prefs_write_open(path)) == NULL) {
991 gchar *dir_path = vcal_manager_get_event_path();
992 if (!is_dir_exist(dir_path) && make_dir(vcal_manager_get_event_path()) != 0) {
993 g_free(dir_path);
994 g_free(path);
995 return;
997 g_free(dir_path);
998 if ((pfile = prefs_write_open(path)) == NULL) {
999 g_free(path);
1000 return;
1004 g_free(path);
1005 xml_file_put_xml_decl(pfile->fp);
1006 xml_write_tree(rootnode, pfile->fp);
1007 xml_free_tree(rootnode);
1009 if (prefs_file_close(pfile) < 0) {
1010 g_warning("failed to write event");
1011 return;
1014 if (export_after)
1015 vcal_folder_export(NULL);
1018 static VCalEvent *event_get_from_xml (const gchar *uid, GNode *node)
1020 XMLNode *xmlnode;
1021 GList *list;
1022 gchar *org = NULL, *location = NULL, *summary = NULL, *orgname = NULL;
1023 gchar *dtstart = NULL, *dtend = NULL, *tzid = NULL;
1024 gchar *created = NULL, *last_modified = NULL;
1025 gchar *description = NULL, *url = NULL, *recur = NULL;
1026 VCalEvent *event = NULL;
1027 icalproperty_method method = ICAL_METHOD_REQUEST;
1028 icalcomponent_kind type = ICAL_VEVENT_COMPONENT;
1029 gint sequence = 0, rec_occurrence = 0;
1030 time_t postponed = (time_t)0;
1032 g_return_val_if_fail(node->data != NULL, NULL);
1034 xmlnode = node->data;
1035 if (g_strcmp0(xmlnode->tag->tag, "event") != 0) {
1036 g_warning("tag name != \"event\"");
1037 return NULL;
1040 list = xmlnode->tag->attr;
1041 for (; list != NULL; list = list->next) {
1042 XMLAttr *attr = list->data;
1044 if (!attr || !attr->name || !attr->value) continue;
1045 if (!strcmp(attr->name, "organizer"))
1046 org = g_strdup(attr->value);
1047 if (!strcmp(attr->name, "orgname"))
1048 orgname = g_strdup(attr->value);
1049 if (!strcmp(attr->name, "location"))
1050 location = g_strdup(attr->value);
1051 if (!strcmp(attr->name, "summary"))
1052 summary = g_strdup(attr->value);
1053 if (!strcmp(attr->name, "description"))
1054 description = g_strdup(attr->value);
1055 if (!strcmp(attr->name, "url"))
1056 url = g_strdup(attr->value);
1057 if (!strcmp(attr->name, "dtstart"))
1058 dtstart = g_strdup(attr->value);
1059 if (!strcmp(attr->name, "dtend"))
1060 dtend = g_strdup(attr->value);
1061 if (!strcmp(attr->name, "recur"))
1062 recur = g_strdup(attr->value);
1063 if (!strcmp(attr->name, "tzid"))
1064 tzid = g_strdup(attr->value);
1065 if (!strcmp(attr->name, "type"))
1066 type = atoi(attr->value);
1067 if (!strcmp(attr->name, "method"))
1068 method = atoi(attr->value);
1069 if (!strcmp(attr->name, "sequence"))
1070 sequence = atoi(attr->value);
1071 if (!strcmp(attr->name, "created"))
1072 created = g_strdup(attr->value);
1073 if (!strcmp(attr->name, "last_modified"))
1074 last_modified = g_strdup(attr->value);
1075 if (!strcmp(attr->name, "postponed"))
1076 postponed = atoi(attr->value);
1077 if (!strcmp(attr->name, "rec_occurrence"))
1078 rec_occurrence = atoi(attr->value);
1081 event = vcal_manager_new_event(uid, org, orgname, location, summary, description,
1082 dtstart, dtend, recur, tzid, url, method,
1083 sequence, created, last_modified, type);
1085 event->postponed = postponed;
1086 event->rec_occurrence = rec_occurrence;
1088 g_free(org);
1089 g_free(orgname);
1090 g_free(location);
1091 g_free(summary);
1092 g_free(description);
1093 g_free(url);
1094 g_free(dtstart);
1095 g_free(dtend);
1096 g_free(recur);
1097 g_free(tzid);
1098 g_free(created);
1099 g_free(last_modified);
1101 node = node->children;
1102 while (node != NULL) {
1103 gchar *attendee = NULL;
1104 gchar *name = NULL;
1105 icalparameter_partstat answer = ICAL_PARTSTAT_NEEDSACTION;
1106 icalparameter_cutype cutype = ICAL_CUTYPE_INDIVIDUAL;
1108 xmlnode = node->data;
1109 if (g_strcmp0(xmlnode->tag->tag, "answer") != 0) {
1110 g_warning("tag name != \"answer\"");
1111 return event;
1113 list = xmlnode->tag->attr;
1114 for (; list != NULL; list = list->next) {
1115 XMLAttr *attr = list->data;
1117 if (!attr || !attr->name || !attr->value) continue;
1118 if (!strcmp(attr->name, "attendee"))
1119 attendee = g_strdup(attr->value);
1120 if (!strcmp(attr->name, "name"))
1121 name = g_strdup(attr->value);
1122 if (!strcmp(attr->name, "answer"))
1123 answer = atoi(attr->value);
1124 if (!strcmp(attr->name, "cutype"))
1125 cutype = atoi(attr->value);
1128 event->answers = g_slist_prepend(event->answers, answer_new(attendee, name, answer, cutype));
1129 g_free(attendee);
1130 g_free(name);
1131 node = node->next;
1133 event->answers = g_slist_reverse(event->answers);
1135 return event;
1138 VCalEvent *vcal_manager_load_event (const gchar *uid)
1140 GNode *node;
1141 gchar *path = NULL;
1142 VCalEvent *event = NULL;
1144 path = vcal_manager_get_event_file(uid);
1146 if (!is_file_exist(path)) {
1147 g_free(path);
1148 return NULL;
1151 node = xml_parse_file(path);
1153 g_free(path);
1155 if (!node) {
1156 g_warning("no node");
1157 return NULL;
1160 event = event_get_from_xml(uid, node);
1161 /* vcal_manager_event_print(event); */
1162 xml_free_tree(node);
1164 if (!event)
1165 return NULL;
1167 while (strchr(event->summary, '\n'))
1168 *(strchr(event->summary, '\n')) = ' ';
1170 return event;
1174 void vcal_manager_update_answer (VCalEvent *event,
1175 const gchar *attendee,
1176 const gchar *name,
1177 icalparameter_partstat ans,
1178 icalparameter_cutype cutype)
1180 Answer *answer = NULL;
1181 GSList *existing = NULL;
1182 Answer *existing_a = NULL;
1184 if (!ans)
1185 return;
1187 answer = answer_new(attendee, name, ans, cutype);
1188 existing = answer_find(event, answer);
1190 if (existing) {
1191 existing_a = (Answer *)existing->data;
1193 if (!answer->name && existing_a->name)
1194 answer->name = g_strdup(existing_a->name);
1195 if (!answer->cutype && existing_a->cutype)
1196 answer->cutype = existing_a->cutype;
1198 answer_remove(event, answer);
1201 answer_add(event, answer);
1203 vcal_manager_save_event(event, FALSE);
1206 static gchar *write_headers(PrefsAccount *account,
1207 VCalEvent *event,
1208 gboolean short_headers,
1209 gboolean is_reply,
1210 gboolean is_pseudo_display)
1212 gchar *subject = NULL;
1213 gchar date[RFC822_DATE_BUFFSIZE];
1214 gchar *save_folder = NULL;
1215 gchar *result = NULL;
1216 gchar *queue_headers = NULL;
1217 gchar *method_str = NULL;
1218 gchar *attendees = NULL;
1219 icalparameter_partstat status;
1220 gchar *prefix = NULL;
1221 gchar enc_subject[512], enc_from[512], *from = NULL;
1222 gchar *msgid;
1223 gchar *calmsgid = NULL;
1225 cm_return_val_if_fail(account != NULL, NULL);
1227 memset(date, 0, sizeof(date));
1229 if (is_pseudo_display) {
1230 struct icaltimetype itt = (icaltime_from_string(event->dtstart));
1231 time_t t = icaltime_as_timet(itt);
1232 get_rfc822_date_from_time_t(date, sizeof(date), t);
1233 } else {
1234 get_rfc822_date(date, sizeof(date));
1237 if (account_get_special_folder(account, F_OUTBOX)) {
1238 save_folder = folder_item_get_identifier(account_get_special_folder
1239 (account, F_OUTBOX));
1242 if (!is_reply) {
1243 GSList *cur = event->answers;
1244 while (cur && cur->data) {
1245 gchar *tmp = NULL;
1246 Answer *a = (Answer *)cur->data;
1248 if (strcasecmp(a->attendee, event->organizer)) {
1249 if (attendees) {
1250 tmp = g_strdup_printf("%s>,\n <%s", attendees, a->attendee);
1251 g_free(attendees);
1252 attendees = tmp;
1253 } else {
1254 attendees = g_strdup_printf("%s", a->attendee);
1257 cur = cur->next;
1261 if (!short_headers) {
1262 queue_headers = g_strdup_printf("S:%s\n"
1263 "SSV:%s\n"
1264 "R:<%s>\n"
1265 "MAID:%d\n"
1266 "%s%s%s"
1267 "X-Claws-End-Special-Headers: 1\n",
1268 account->address,
1269 account->smtp_server,
1270 is_reply ? event->organizer:attendees,
1271 account->account_id,
1272 save_folder?"SCF:":"",
1273 save_folder?save_folder:"",
1274 save_folder?"\n":"");
1275 } else {
1276 queue_headers = g_strdup("");
1279 prefix = "";
1280 if (is_reply) {
1281 method_str = "REPLY";
1282 status = vcal_manager_get_reply_for_attendee(event, account->address);
1283 if (status == ICAL_PARTSTAT_ACCEPTED)
1284 prefix = _("Accepted: ");
1285 else if (status == ICAL_PARTSTAT_DECLINED)
1286 prefix = _("Declined: ");
1287 else if (status == ICAL_PARTSTAT_TENTATIVE)
1288 prefix = _("Tentatively Accepted: ");
1289 else
1290 prefix = "Re: ";
1291 } else if (event->method == ICAL_METHOD_PUBLISH) {
1292 method_str = "PUBLISH";
1293 } else if (event->method == ICAL_METHOD_CANCEL) {
1294 method_str = "CANCEL";
1295 } else {
1296 method_str = "REQUEST";
1299 subject = g_strdup_printf("%s%s", prefix, event->summary);
1301 conv_encode_header_full(enc_subject, sizeof(enc_subject), subject, strlen("Subject: "),
1302 FALSE, conv_get_outgoing_charset_str());
1303 from = is_reply?account->name:(event->orgname?event->orgname:"");
1304 conv_encode_header_full(enc_from, sizeof(enc_from), from, strlen("From: "),
1305 TRUE, conv_get_outgoing_charset_str());
1307 if (is_pseudo_display && event->uid) {
1308 calmsgid = g_strdup_printf("Message-ID: <%s>\n",event->uid);
1309 } else {
1310 calmsgid = g_strdup("");
1313 msgid = prefs_account_generate_msgid(account);
1315 result = g_strdup_printf("%s"
1316 "From: %s <%s>\n"
1317 "To: <%s>\n"
1318 "Subject: %s\n"
1319 "Date: %s\n"
1320 "MIME-Version: 1.0\n"
1321 "Content-Type: text/calendar; method=%s; charset=\"%s\"\n"
1322 "Content-Transfer-Encoding: 8bit\n"
1323 "%s"
1324 "%s: <%s>\n",
1325 queue_headers,
1326 enc_from,
1327 is_reply ? account->address:event->organizer,
1328 is_reply ? event->organizer:(attendees?attendees:event->organizer),
1329 enc_subject,
1330 date,
1331 method_str,
1332 CS_UTF_8,
1333 calmsgid,
1334 is_pseudo_display?
1335 "In-Reply-To":"Message-ID",
1336 is_pseudo_display?
1337 event_to_today_str(event, 0):msgid);
1338 g_free(calmsgid);
1339 g_free(subject);
1340 g_free(save_folder);
1341 g_free(queue_headers);
1342 g_free(attendees);
1343 g_free(msgid);
1344 return result;
1349 static gchar *write_headers_ical(PrefsAccount *account,
1350 icalcomponent *ievent,
1351 gchar *orga)
1353 gchar subject[512];
1354 gchar date[RFC822_DATE_BUFFSIZE];
1355 gchar *result = NULL;
1356 gchar *method_str = NULL;
1357 gchar *summary = NULL;
1358 gchar *organizer = NULL;
1359 gchar *orgname = NULL;
1360 icalproperty *prop = NULL;
1361 gchar *calmsgid = NULL;
1363 time_t t = (time_t)0;
1365 memset(subject, 0, sizeof(subject));
1366 memset(date, 0, sizeof(date));
1368 prop = icalcomponent_get_first_property(ievent, ICAL_SUMMARY_PROPERTY);
1369 summary = g_strdup(icalproperty_get_summary(prop));
1370 icalproperty_free(prop);
1371 if (!summary)
1372 summary = g_strdup(_("[no summary]"));
1374 while (strchr(summary, '\n'))
1375 *(strchr(summary, '\n')) = ' ';
1377 prop = icalcomponent_get_first_property(ievent, ICAL_ORGANIZER_PROPERTY);
1378 if (prop) {
1379 organizer = g_strdup(icalproperty_get_organizer(prop));
1380 if (icalproperty_get_parameter_as_string(prop, "CN") != NULL)
1381 orgname = g_strdup(icalproperty_get_parameter_as_string(prop, "CN"));
1383 icalproperty_free(prop);
1384 } else {
1385 organizer = orga? g_strdup(orga):g_strdup("");
1388 prop = icalcomponent_get_first_property(ievent, ICAL_DTSTART_PROPERTY);
1389 if (prop) {
1390 t = icaltime_as_timet(icalproperty_get_dtstart(prop));
1391 get_rfc822_date_from_time_t(date, sizeof(date), t);
1392 } else {
1393 get_rfc822_date(date, sizeof(date));
1396 conv_encode_header(subject, 511, summary, strlen("Subject: "), FALSE);
1398 method_str = "PUBLISH";
1400 prop = icalcomponent_get_first_property(ievent, ICAL_UID_PROPERTY);
1401 if (prop) {
1402 calmsgid = g_strdup_printf("Message-ID: <%s>\n",icalproperty_get_uid(prop));
1403 icalproperty_free(prop);
1404 } else {
1405 calmsgid = g_strdup("");
1409 result = g_strdup_printf("From: %s <%s>\n"
1410 "To: <%s>\n"
1411 "Subject: %s%s\n"
1412 "Date: %s\n"
1413 "MIME-Version: 1.0\n"
1414 "Content-Type: text/calendar; method=%s; charset=\"%s\"; vcalsave=\"no\"\n"
1415 "Content-Transfer-Encoding: quoted-printable\n"
1416 "%s"
1417 "In-Reply-To: <%s>\n",
1418 orgname?orgname:"",
1419 !strncmp(organizer, "MAILTO:", 7) ? organizer+7 : organizer,
1420 account->address,
1422 subject,
1423 date,
1424 method_str,
1425 conv_get_outgoing_charset_str(),
1426 calmsgid,
1427 event_to_today_str(NULL, t));
1429 g_free(calmsgid);
1430 g_free(orgname);
1431 g_free(organizer);
1432 g_free(summary);
1434 return result;
1439 static gboolean vcal_manager_send (PrefsAccount *account,
1440 VCalEvent *event,
1441 gboolean is_reply)
1443 gchar *tmpfile = NULL;
1444 gint msgnum;
1445 FolderItem *folderitem;
1446 gchar *msgpath = NULL;
1447 Folder *folder = NULL;
1449 tmpfile = vcal_manager_event_dump(event, is_reply, FALSE, NULL, TRUE);
1451 if (!tmpfile)
1452 return FALSE;
1454 folderitem = account_get_special_folder(account, F_QUEUE);
1455 if (!folderitem) {
1456 g_warning("can't find queue folder for %s", account->address);
1457 g_unlink(tmpfile);
1458 g_free(tmpfile);
1459 return FALSE;
1461 folder_item_scan(folderitem);
1463 if ((msgnum = folder_item_add_msg(folderitem, tmpfile, NULL, TRUE)) < 0) {
1464 g_warning("can't queue the message");
1465 g_unlink(tmpfile);
1466 g_free(tmpfile);
1467 return FALSE;
1470 msgpath = folder_item_fetch_msg(folderitem, msgnum);
1472 if (!prefs_common_get_prefs()->work_offline) {
1473 gchar *err = NULL;
1474 gboolean queued_removed = FALSE;
1475 gint val = procmsg_send_message_queue_with_lock(msgpath, &err, folderitem, msgnum, &queued_removed);
1476 if (val == 0) {
1477 if (!queued_removed)
1478 folder_item_remove_msg(folderitem, msgnum);
1479 folder_item_scan(folderitem);
1480 } else if (err) {
1481 alertpanel_error_log("%s", err);
1482 g_free(err);
1485 g_unlink(tmpfile);
1486 g_free(tmpfile);
1487 g_free(msgpath);
1489 folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
1490 if (folder) {
1491 folder_item_scan(folder->inbox);
1492 vcalviewer_reload(folder->inbox);
1493 } else
1494 g_warning("couldn't find vCalendar folder class");
1495 return TRUE;
1498 gboolean vcal_manager_reply (PrefsAccount *account,
1499 VCalEvent *event)
1501 return vcal_manager_send(account, event, TRUE);
1504 gboolean vcal_manager_request (PrefsAccount *account,
1505 VCalEvent *event)
1507 return vcal_manager_send(account, event, FALSE);
1510 EventTime event_to_today(VCalEvent *event, time_t t)
1512 struct tm evtstart, today;
1513 time_t evtstart_t, today_t;
1514 struct icaltimetype itt;
1516 tzset();
1518 today_t = time(NULL);
1519 if (event) {
1520 itt = icaltime_from_string(event->dtstart);
1521 evtstart_t = icaltime_as_timet(itt);
1522 } else {
1523 evtstart_t = t;
1526 #ifndef G_OS_WIN32
1527 struct tm buft;
1528 today = *localtime_r(&today_t, &buft);
1529 localtime_r(&evtstart_t, &evtstart);
1530 #else
1531 if (today_t < 0)
1532 today_t = 1;
1533 if (evtstart_t < 0)
1534 evtstart_t = 1;
1535 today = *localtime(&today_t);
1536 evtstart = *localtime(&evtstart_t);
1537 #endif
1539 if (today.tm_year == evtstart.tm_year) {
1540 int days = evtstart.tm_yday - today.tm_yday;
1541 if (days < 0) {
1542 return EVENT_PAST;
1543 } else if (days == 0) {
1544 return EVENT_TODAY;
1545 } else if (days == 1) {
1546 return EVENT_TOMORROW;
1547 } else if (days > 1 && days < 7) {
1548 return EVENT_THISWEEK;
1549 } else {
1550 return EVENT_LATER;
1552 } else if (today.tm_year > evtstart.tm_year) {
1553 return EVENT_PAST;
1554 } else if (today.tm_year == evtstart.tm_year - 1) {
1555 int days = ((365 - today.tm_yday) + evtstart.tm_yday);
1556 if (days == 0) {
1557 return EVENT_TODAY;
1558 } else if (days == 1) {
1559 return EVENT_TOMORROW;
1560 } else if (days > 1 && days < 7) {
1561 return EVENT_THISWEEK;
1562 } else {
1563 return EVENT_LATER;
1565 } else
1566 return EVENT_LATER;
1569 const gchar *event_to_today_str(VCalEvent *event, time_t t)
1571 EventTime days = event_to_today(event, t);
1572 switch(days) {
1573 case EVENT_PAST:
1574 return EVENT_PAST_ID;
1575 case EVENT_TODAY:
1576 return EVENT_TODAY_ID;
1577 case EVENT_TOMORROW:
1578 return EVENT_TOMORROW_ID;
1579 case EVENT_THISWEEK:
1580 return EVENT_THISWEEK_ID;
1581 case EVENT_LATER:
1582 return EVENT_LATER_ID;
1584 return NULL;