Improve some sieve-related translations
[claws.git] / src / plugins / vcalendar / vcal_manager.c
blob6c17c42cba89bd2d93a0c141492f32fa19daf310
1 /*
2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2017 Colin Leroy <colin@colino.net> and
4 * the Claws Mail team
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
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 General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #include "claws-features.h"
24 #endif
26 #include <stddef.h>
27 #include <glib.h>
28 #include <glib/gi18n.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #ifdef USE_PTHREAD
33 #include <pthread.h>
34 #endif
35 #include <libical/ical.h>
36 #include "vcalendar.h"
37 #include "vcal_folder.h"
38 #include "vcal_manager.h"
39 #include "vcal_meeting_gtk.h"
40 #include "vcal_prefs.h"
41 #include "xml.h"
42 #include "xmlprops.h"
43 #include "prefs.h"
44 #include "prefs_common.h"
45 #include "prefs_account.h"
46 #include "alertpanel.h"
47 #include "account.h"
48 #include "codeconv.h"
49 #include <time.h>
50 #include "folder.h"
51 #include "quoted-printable.h"
52 #include "file-utils.h"
53 #include "utils.h"
54 #include "defs.h"
56 #ifdef G_OS_WIN32
57 #define getuid() 0
58 #endif
60 Answer *answer_new(const gchar *attendee,
61 const gchar *name,
62 icalparameter_partstat ans,
63 icalparameter_cutype cutype)
65 Answer *answer = g_new0(Answer, 1);
66 answer->attendee = g_strdup(attendee);
67 answer->name = g_strdup(name);
68 if (!answer->name)
69 answer->name = g_strdup("");
70 if (!answer->attendee)
71 answer->attendee = g_strdup("");
72 answer->answer = ans;
73 answer->cutype = cutype;
74 return answer;
77 static void answer_free(Answer *answer)
79 g_free(answer->attendee);
80 g_free(answer->name);
81 g_free(answer);
84 static GSList *answer_find(VCalEvent *event, Answer *answer)
86 GSList *cur = event->answers;
87 while (cur && cur->data) {
88 Answer *b = (Answer *)cur->data;
89 if (!strcasecmp(b->attendee, answer->attendee))
90 return cur;
91 cur = cur->next;
93 return NULL;
96 void vcal_manager_copy_attendees(VCalEvent *src, VCalEvent *dest)
98 GSList *cur = src->answers;
99 while (cur && cur->data) {
100 Answer *a = (Answer *)cur->data;
101 Answer *b = answer_new(a->attendee, a->name, a->answer, a->cutype);
102 dest->answers = g_slist_prepend(dest->answers, b);
103 cur = cur->next;
105 dest->answers = g_slist_reverse(dest->answers);
108 gchar *vcal_manager_answer_get_text(icalparameter_partstat ans)
110 static gchar *replies[5]={
111 N_("accepted"),
112 N_("tentatively accepted"),
113 N_("declined"),
114 N_("did not answer"),
115 N_("unknown")
118 switch (ans) {
119 case ICAL_PARTSTAT_ACCEPTED:
120 return _(replies[0]);
121 break;
122 case ICAL_PARTSTAT_DECLINED:
123 return _(replies[2]);
124 break;
125 case ICAL_PARTSTAT_TENTATIVE:
126 return _(replies[1]);
127 break;
128 case ICAL_PARTSTAT_NEEDSACTION:
129 return _(replies[3]);
130 case ICAL_PARTSTAT_DELEGATED:
131 case ICAL_PARTSTAT_COMPLETED:
132 case ICAL_PARTSTAT_X:
133 case ICAL_PARTSTAT_INPROCESS:
134 case ICAL_PARTSTAT_NONE:
135 case ICAL_PARTSTAT_FAILED:
136 return _(replies[4]);
137 break;
139 return NULL;
142 gchar *vcal_manager_cutype_get_text(icalparameter_cutype type)
144 static gchar *replies[5]={
145 N_("individual"),
146 N_("group"),
147 N_("resource"),
148 N_("room"),
149 N_("unknown")
152 switch (type) {
153 case ICAL_CUTYPE_INDIVIDUAL:
154 return _(replies[0]);
155 break;
156 case ICAL_CUTYPE_GROUP:
157 return _(replies[1]);
158 break;
159 case ICAL_CUTYPE_RESOURCE:
160 return _(replies[2]);
161 break;
162 case ICAL_CUTYPE_ROOM:
163 return _(replies[3]);
164 default:
165 return _(replies[4]);
166 break;
168 return NULL;
171 static GSList *answer_remove(VCalEvent *event, Answer *answer)
173 GSList *cur = answer_find(event, answer);
174 if (cur) {
175 Answer *b = (Answer *)cur->data;
176 event->answers = g_slist_remove(event->answers, b);
177 answer_free(b);
179 return event->answers;
182 static GSList *answer_add(VCalEvent *event, Answer *answer)
184 event->answers = g_slist_append(event->answers, answer);
185 return event->answers;
188 GSList *vcal_manager_get_answers_emails(VCalEvent *event)
190 GSList *new = NULL;
191 GSList *cur = event->answers;
192 while (cur && cur->data) {
193 Answer *b = (Answer *)cur->data;
194 new = g_slist_prepend(new, b->attendee);
195 cur = cur->next;
197 new = g_slist_reverse(new);
198 return new;
201 icalparameter_partstat vcal_manager_get_reply_for_attendee(VCalEvent *event, const gchar *att)
203 Answer *a = answer_new(att, NULL, 0, 0);
204 GSList *ans = answer_find(event, a);
205 icalparameter_partstat res = 0;
206 if (ans) {
207 Answer *b = (Answer *)ans->data;
208 res = b->answer;
210 answer_free(a);
211 return res;
214 gchar *vcal_manager_get_cutype_text_for_attendee(VCalEvent *event, const gchar *att)
216 icalparameter_cutype status = vcal_manager_get_cutype_for_attendee(event, att);
217 gchar *res = NULL;
218 if (status != 0)
219 res = g_strdup(vcal_manager_cutype_get_text(status));
221 return res;
224 icalparameter_cutype vcal_manager_get_cutype_for_attendee(VCalEvent *event, const gchar *att)
226 Answer *a = answer_new(att, NULL, 0, 0);
227 GSList *ans = answer_find(event, a);
228 icalparameter_cutype res = 0;
229 if (ans) {
230 Answer *b = (Answer *)ans->data;
231 res = b->cutype;
233 answer_free(a);
234 return res;
237 gchar *vcal_manager_get_reply_text_for_attendee(VCalEvent *event, const gchar *att)
239 icalparameter_partstat status = vcal_manager_get_reply_for_attendee(event, att);
240 gchar *res = NULL;
241 if (status != 0)
242 res = g_strdup(vcal_manager_answer_get_text(status));
244 return res;
247 gchar *vcal_manager_get_attendee_name(VCalEvent *event, const gchar *att)
249 Answer *a = answer_new(att, NULL, 0, 0);
250 GSList *ans = answer_find(event, a);
251 gchar *res = NULL;
252 if (ans) {
253 Answer *b = (Answer *)ans->data;
254 if (b->name)
255 res = g_strdup(b->name);
257 answer_free(a);
258 return res;
261 void vcal_manager_event_print(VCalEvent *event)
263 GSList *list = event->answers;
264 printf( "event->uid\t\t%s\n"
265 "event->organizer\t\t%s\n"
266 "event->start\t\t%s\n"
267 "event->end\t\t%s\n"
268 "event->location\t\t%s\n"
269 "event->summary\t\t%s\n"
270 "event->description\t%s\n"
271 "event->url\t%s\n"
272 "event->dtstart\t\t%s\n"
273 "event->dtend\t\t%s\n"
274 "event->recur\t\t%s\n"
275 "event->tzid\t\t%s\n"
276 "event->method\t\t%d\n"
277 "event->sequence\t\t%d\n",
278 event->uid,
279 event->organizer,
280 event->start,
281 event->end,
282 event->location,
283 event->summary,
284 event->description,
285 event->url,
286 event->dtstart,
287 event->dtend,
288 event->recur,
289 event->tzid,
290 event->method,
291 event->sequence);
292 while (list && list->data) {
293 Answer *a = (Answer *)list->data;
294 printf(" ans: %s %s, %s\n", a->name, a->attendee, vcal_manager_answer_get_text(a->answer));
295 list = list->next;
300 static gchar *write_headers(PrefsAccount *account,
301 VCalEvent *event,
302 gboolean short_headers,
303 gboolean is_reply,
304 gboolean is_pseudo_event);
306 gchar *vcal_manager_event_dump(VCalEvent *event, gboolean is_reply, gboolean is_pseudo_event,
307 icalcomponent *use_calendar, gboolean modif)
309 gchar *organizer = g_strdup_printf("MAILTO:%s", event->organizer);
310 PrefsAccount *account = vcal_manager_get_account_from_event(event);
311 gchar *attendee = NULL;
312 gchar *body, *headers;
313 gchar *tmpfile = NULL;
314 icalcomponent *calendar, *ievent, *timezone, *tzc;
315 icalproperty *attprop;
316 icalproperty *orgprop;
317 icalparameter_partstat status = ICAL_PARTSTAT_NEEDSACTION;
318 gchar *sanitized_uid = g_strdup(event->uid);
320 subst_for_filename(sanitized_uid);
322 tmpfile = g_strdup_printf("%s%cevt-%d-%s", get_tmp_dir(),
323 G_DIR_SEPARATOR, getuid(), sanitized_uid);
324 g_free(sanitized_uid);
326 if (!account) {
327 g_free(organizer);
328 g_free(tmpfile);
329 debug_print("no account found\n");
330 return NULL;
333 attendee = g_strdup_printf("MAILTO:%s", account->address);
335 if (vcal_manager_get_reply_for_attendee(event, account->address) != 0)
336 status = vcal_manager_get_reply_for_attendee(event, account->address);
338 tzset();
340 if (use_calendar != NULL) {
341 calendar = use_calendar;
342 g_free(tmpfile);
343 tmpfile = NULL;
344 } else
345 calendar =
346 icalcomponent_vanew(
347 ICAL_VCALENDAR_COMPONENT,
348 icalproperty_new_version("2.0"),
349 icalproperty_new_prodid(
350 "-//Claws Mail//NONSGML Claws Mail Calendar//EN"),
351 icalproperty_new_calscale("GREGORIAN"),
352 icalproperty_new_method(is_reply ? ICAL_METHOD_REPLY:event->method),
353 (void*)0
356 if (!calendar) {
357 g_warning("can't generate calendar");
358 g_free(organizer);
359 g_free(tmpfile);
360 g_free(attendee);
361 return NULL;
364 orgprop = icalproperty_new_organizer(organizer);
366 timezone = icalcomponent_new(ICAL_VTIMEZONE_COMPONENT);
368 icalcomponent_add_property(timezone,
369 icalproperty_new_tzid("UTC")); /* free */
371 tzc = icalcomponent_new(ICAL_XSTANDARD_COMPONENT);
372 icalcomponent_add_property(tzc,
373 icalproperty_new_dtstart(
374 icaltime_from_string("19700101T000000")));
375 icalcomponent_add_property(tzc,
376 icalproperty_new_tzoffsetfrom(0.0));
377 icalcomponent_add_property(tzc,
378 icalproperty_new_tzoffsetto(0.0));
379 icalcomponent_add_property(tzc,
380 icalproperty_new_tzname("Greenwich meridian time"));
382 icalcomponent_add_component(timezone, tzc);
384 ievent =
385 icalcomponent_vanew(
386 ICAL_VEVENT_COMPONENT, (void*)0);
388 if (!ievent) {
389 g_warning("can't generate event");
390 g_free(organizer);
391 g_free(tmpfile);
392 g_free(attendee);
393 return NULL;
396 icalcomponent_add_property(ievent,
397 icalproperty_new_uid(event->uid));
398 icalcomponent_add_property(ievent,
399 icalproperty_vanew_dtstamp(icaltime_from_timet_with_zone(time(NULL), TRUE, NULL), (void*)0));
400 icalcomponent_add_property(ievent,
401 icalproperty_vanew_dtstart((icaltime_from_string(event->dtstart)), (void*)0));
402 icalcomponent_add_property(ievent,
403 icalproperty_vanew_dtend((icaltime_from_string(event->dtend)), (void*)0));
404 if (event->recur && *(event->recur)) {
405 icalcomponent_add_property(ievent,
406 icalproperty_vanew_rrule((icalrecurrencetype_from_string(event->recur)), (void*)0));
408 icalcomponent_add_property(ievent,
409 icalproperty_new_description(event->description));
410 icalcomponent_add_property(ievent,
411 icalproperty_new_summary(event->summary));
412 icalcomponent_add_property(ievent,
413 icalproperty_new_sequence(modif && !is_reply ? event->sequence + 1 : event->sequence));
414 icalcomponent_add_property(ievent,
415 icalproperty_new_class(ICAL_CLASS_PUBLIC));
416 icalcomponent_add_property(ievent,
417 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 icalcomponent_add_property(ievent,
427 icalproperty_vanew_created(icaltime_from_timet_with_zone(time(NULL), TRUE, NULL), (void*)0));
428 icalcomponent_add_property(ievent,
429 icalproperty_vanew_lastmodified(icaltime_from_timet_with_zone(time(NULL), TRUE, NULL), (void*)0));
430 icalcomponent_add_property(ievent,
431 orgprop);
433 if (!icalcomponent_get_first_component(calendar, ICAL_VTIMEZONE_COMPONENT))
434 icalcomponent_add_component(calendar, timezone);
435 else
436 icalcomponent_free(timezone);
438 icalcomponent_add_component(calendar, ievent);
440 if (event->url && *(event->url)) {
441 attprop = icalproperty_new_url(event->url);
442 icalcomponent_add_property(ievent, attprop);
445 if (is_reply) {
446 /* dump only this attendee */
447 attprop =
448 icalproperty_vanew_attendee(
449 attendee,
450 icalparameter_new_role(
451 ICAL_ROLE_REQPARTICIPANT),
452 icalparameter_new_rsvp(ICAL_RSVP_TRUE),
453 icalparameter_new_partstat(status),
454 (void*)0
456 icalcomponent_add_property(ievent, attprop);
457 } else {
458 /* dump all attendees */
459 GSList *cur = event->answers;
460 while (cur && cur->data) {
461 Answer *a = (Answer *)cur->data;
463 if (a->cutype == 0)
464 a->cutype = ICAL_CUTYPE_INDIVIDUAL;
465 if (a->answer == 0)
466 a->answer = ICAL_PARTSTAT_NEEDSACTION;
468 attprop =
469 icalproperty_vanew_attendee(
470 a->attendee,
471 icalparameter_new_role(
472 ICAL_ROLE_REQPARTICIPANT),
473 icalparameter_new_rsvp(ICAL_RSVP_TRUE),
474 icalparameter_new_cutype(a->cutype),
475 icalparameter_new_partstat(a->answer),
476 (void*)0
479 icalcomponent_add_property(ievent, attprop);
480 cur = cur->next;
484 if (use_calendar) {
485 g_free(organizer);
486 g_free(tmpfile);
487 g_free(attendee);
488 return NULL;
491 headers = write_headers(account, event, is_pseudo_event, is_reply, is_pseudo_event);
493 if (!headers) {
494 g_warning("can't get headers");
495 g_free(organizer);
496 g_free(tmpfile);
497 g_free(attendee);
498 return NULL;
501 body = g_strdup_printf("%s"
502 "\n"
503 "%s", headers, icalcomponent_as_ical_string(calendar));
505 if (str_write_to_file(body, tmpfile, FALSE) < 0) {
506 g_free(tmpfile);
507 tmpfile = NULL;
510 chmod(tmpfile, S_IRUSR|S_IWUSR);
512 g_free(body);
513 g_free(headers);
514 icalcomponent_free(calendar);
515 g_free(attendee);
516 g_free(organizer);
518 tzset();
520 return tmpfile;
523 static void get_rfc822_date_from_time_t(gchar *buf, gint len, time_t t)
525 #ifndef G_OS_WIN32
526 struct tm *lt;
527 gchar day[4], mon[4];
528 gint dd, hh, mm, ss, yyyy;
529 gchar buft1[512];
530 struct tm buft2;
532 lt = localtime_r(&t, &buft2);
533 if (sscanf(asctime_r(lt, buft1), "%3s %3s %d %d:%d:%d %d\n",
534 day, mon, &dd, &hh, &mm, &ss, &yyyy) != 7)
535 g_warning("failed reading date/time");
536 g_snprintf(buf, len, "%s, %d %s %d %02d:%02d:%02d %s",
537 day, dd, mon, yyyy, hh, mm, ss, tzoffset(&t));
538 #else
539 GDateTime *dt = g_date_time_new_from_unix_local(t);
540 gchar *buf2 = g_date_time_format(dt, "%a, %e %b %Y %H:%M:%S %z");
541 g_date_time_unref(dt);
542 strncpy(buf, buf2, len);
543 g_free(buf2);
544 #endif
547 static gchar *write_headers_date(const gchar *uid)
549 gchar subject[512];
550 gchar *t_subject;
551 gchar date[RFC822_DATE_BUFFSIZE];
552 time_t t;
553 struct tm lt;
555 memset(subject, 0, sizeof(subject));
556 memset(date, 0, sizeof(date));
558 if (!strcmp(uid, EVENT_PAST_ID)) {
559 t = 1;
560 t_subject = _("Past");
561 } else if (!strcmp(uid, EVENT_TODAY_ID)) {
562 t = time(NULL);
563 t_subject = _("Today");
564 } else if (!strcmp(uid, EVENT_TOMORROW_ID)) {
565 t = time(NULL) + 86400;
566 t_subject = _("Tomorrow");
567 } else if (!strcmp(uid, EVENT_THISWEEK_ID)) {
568 t = time(NULL) + (86400*2);
569 t_subject = _("This week");
570 } else if (!strcmp(uid, EVENT_LATER_ID)) {
571 t = time(NULL) + (86400*7);
572 t_subject = _("Later");
573 } else {
574 g_warning("unknown spec date");
575 return NULL;
578 #ifndef G_OS_WIN32
579 struct tm buft;
580 lt = *localtime_r(&t, &buft);
581 #else
582 if (t < 0)
583 t = 1;
584 lt = *localtime(&t);
585 #endif
586 lt.tm_hour = lt.tm_min = lt.tm_sec = 0;
587 t = mktime(&lt);
588 get_rfc822_date_from_time_t(date, sizeof(date), t);
589 conv_encode_header(subject, 511, t_subject, strlen("Subject: "), FALSE);
591 return g_strdup_printf("From: -\n"
592 "To: -\n"
593 "Subject: %s\n"
594 "Date: %s\n"
595 "MIME-Version: 1.0\n"
596 "Content-Type: text/plain; charset=\"UTF-8\";\n"
597 "Content-Transfer-Encoding: quoted-printable\n"
598 "Message-ID: <%s>\n",
599 subject,
600 date,
601 uid);
604 gchar *vcal_manager_dateevent_dump(const gchar *uid, FolderItem *item)
606 gchar *sanitized_uid = NULL;
607 gchar *headers = NULL;
608 gchar *lines, *body, *tmpfile;
609 EventTime date;
610 sanitized_uid = g_strdup(uid);
611 subst_for_filename(sanitized_uid);
613 tmpfile = g_strdup_printf("%s%cevt-%d-%s", get_tmp_dir(),
614 G_DIR_SEPARATOR, getuid(), sanitized_uid);
615 g_free(sanitized_uid);
617 headers = write_headers_date(uid);
619 if (!headers) {
620 g_warning("can't get headers");
621 g_free(tmpfile);
622 return NULL;
625 if (!strcmp(uid, EVENT_PAST_ID))
626 date = EVENT_PAST;
627 else if (!strcmp(uid, EVENT_TODAY_ID))
628 date = EVENT_TODAY;
629 else if (!strcmp(uid, EVENT_TOMORROW_ID))
630 date = EVENT_TOMORROW;
631 else if (!strcmp(uid, EVENT_THISWEEK_ID))
632 date = EVENT_THISWEEK;
633 else if (!strcmp(uid, EVENT_LATER_ID))
634 date = EVENT_LATER;
635 else
636 date = EVENT_PAST;
638 lines = get_item_event_list_for_date(item, date);
639 body = g_strdup_printf("%s"
640 "\n"
641 "%s", headers, lines);
642 g_free(lines);
643 if (str_write_to_file(body, tmpfile, FALSE) < 0) {
644 g_free(tmpfile);
645 tmpfile = NULL;
646 } else
647 chmod(tmpfile, S_IRUSR|S_IWUSR);
649 g_free(body);
650 g_free(headers);
652 return tmpfile;
655 static gchar *write_headers_ical(PrefsAccount *account,
656 icalcomponent *ievent,
657 gchar *orga);
659 gchar *vcal_manager_icalevent_dump(icalcomponent *event, gchar *orga, icalcomponent *use_calendar)
661 PrefsAccount *account = account_get_cur_account();
662 gchar *body, *headers, *qpbody;
663 gchar **lines = NULL;
664 gchar *tmpfile = NULL;
665 icalcomponent *calendar;
666 icalproperty *prop;
667 icalcomponent *ievent = NULL;
668 int i = 0;
670 ievent = icalcomponent_new_clone(event);
672 prop = icalcomponent_get_first_property(ievent, ICAL_UID_PROPERTY);
673 if (prop) {
674 gchar *sanitized_uid = g_strdup(icalproperty_get_uid(prop));
676 subst_for_filename(sanitized_uid);
678 tmpfile = g_strdup_printf("%s%cevt-%d-%s", get_tmp_dir(),
679 G_DIR_SEPARATOR, getuid(), sanitized_uid);
680 g_free(sanitized_uid);
681 icalproperty_free(prop);
682 } else {
683 tmpfile = g_strdup_printf("%s%cevt-%d-%p", get_tmp_dir(),
684 G_DIR_SEPARATOR, getuid(), ievent);
687 if (!account) {
688 g_free(tmpfile);
689 icalcomponent_free(ievent);
690 return NULL;
693 tzset();
695 if (use_calendar != NULL) {
696 calendar = use_calendar;
697 g_free(tmpfile);
698 tmpfile = NULL;
699 } else
700 calendar =
701 icalcomponent_vanew(
702 ICAL_VCALENDAR_COMPONENT,
703 icalproperty_new_version("2.0"),
704 icalproperty_new_prodid(
705 "-//Claws Mail//NONSGML Claws Mail Calendar//EN"),
706 icalproperty_new_calscale("GREGORIAN"),
707 icalproperty_new_method(ICAL_METHOD_PUBLISH),
708 (void*)0
711 if (!calendar) {
712 g_warning("can't generate calendar");
713 g_free(tmpfile);
714 icalcomponent_free(ievent);
715 return NULL;
718 icalcomponent_add_component(calendar, ievent);
720 if (use_calendar)
721 return NULL;
723 headers = write_headers_ical(account, ievent, orga);
725 if (!headers) {
726 g_warning("can't get headers");
727 g_free(tmpfile);
728 icalcomponent_free(calendar);
729 return NULL;
732 lines = g_strsplit(icalcomponent_as_ical_string(calendar), "\n", 0);
733 qpbody = g_strdup("");
735 /* encode to quoted-printable */
736 while (lines[i]) {
737 gint e_len = strlen(qpbody), n_len = 0;
738 gchar *outline = conv_codeset_strdup(lines[i], CS_UTF_8, conv_get_outgoing_charset_str());
739 gchar *qpoutline = g_malloc(strlen(outline)*8 + 1);
741 qp_encode_line(qpoutline, (guchar *)outline);
742 n_len = strlen(qpoutline);
744 qpbody = g_realloc(qpbody, e_len + n_len + 1);
745 strcpy(qpbody+e_len, qpoutline);
746 *(qpbody+n_len+e_len) = '\0';
748 g_free(outline);
749 g_free(qpoutline);
750 i++;
753 body = g_strdup_printf("%s"
754 "\n"
755 "%s", headers, qpbody);
757 if (str_write_to_file(body, tmpfile, FALSE) < 0) {
758 g_free(tmpfile);
759 tmpfile = NULL;
760 } else
761 chmod(tmpfile, S_IRUSR|S_IWUSR);
763 g_strfreev(lines);
764 g_free(body);
765 g_free(qpbody);
766 g_free(headers);
767 icalcomponent_free(calendar);
769 return tmpfile;
772 VCalEvent * vcal_manager_new_event (const gchar *uid,
773 const gchar *organizer,
774 const gchar *orgname,
775 const gchar *location,
776 const gchar *summary,
777 const gchar *description,
778 const gchar *dtstart,
779 const gchar *dtend,
780 const gchar *recur,
781 const gchar *tzid,
782 const gchar *url,
783 icalproperty_method method,
784 gint sequence,
785 icalcomponent_kind type)
787 VCalEvent *event = g_new0(VCalEvent, 1);
789 event->uid = g_strdup(uid?uid:"");
790 event->organizer = g_strdup(organizer?organizer:"");
791 event->orgname = g_strdup(orgname?orgname:"");
793 if (dtend && *(dtend)) {
794 time_t tmp = icaltime_as_timet((icaltime_from_string(dtend)));
795 GDateTime *dt = g_date_time_new_from_unix_local(tmp);
796 event->end = g_date_time_format(dt, "%a, %e %b %Y %H:%M:%S %Z");
797 g_date_time_unref(dt);
800 if (dtstart && *(dtstart)) {
801 time_t tmp = icaltime_as_timet((icaltime_from_string(dtstart)));
802 GDateTime *dt = g_date_time_new_from_unix_local(tmp);
803 event->start = g_date_time_format(dt, "%a, %e %b %Y %H:%M:%S %Z");
804 g_date_time_unref(dt);
806 event->dtstart = g_strdup(dtstart?dtstart:"");
807 event->dtend = g_strdup(dtend?dtend:"");
808 event->recur = g_strdup(recur?recur:"");
809 event->location = g_strdup(location?location:"");
810 event->summary = g_strdup(summary?summary:"");
811 event->description = g_strdup(description?description:"");
812 event->url = g_strdup(url?url:"");
813 event->tzid = g_strdup(tzid?tzid:"");
814 event->method = method;
815 event->sequence = sequence;
816 event->type = type;
817 event->rec_occurrence = FALSE;
818 while (strchr(event->summary, '\n'))
819 *(strchr(event->summary, '\n')) = ' ';
821 return event;
824 void vcal_manager_free_event (VCalEvent *event)
826 GSList *cur;
827 if (!event)
828 return;
830 g_free(event->uid);
831 g_free(event->organizer);
832 g_free(event->orgname);
833 g_free(event->start);
834 g_free(event->end);
835 g_free(event->location);
836 g_free(event->summary);
837 g_free(event->dtstart);
838 g_free(event->dtend);
839 g_free(event->recur);
840 g_free(event->tzid);
841 g_free(event->description);
842 g_free(event->url);
843 for (cur = event->answers; cur; cur = cur->next) {
844 answer_free((Answer *)cur->data);
846 g_slist_free(event->answers);
847 g_free(event);
850 gchar *vcal_manager_get_event_path(void)
852 static gchar *event_path = NULL;
853 if (!event_path)
854 event_path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
855 "vcalendar", NULL);
857 return event_path;
860 gchar *vcal_manager_get_event_file(const gchar *uid)
862 gchar *tmp = g_strdup(uid);
863 gchar *res = NULL;
865 subst_for_filename(tmp);
866 res = g_strconcat(vcal_manager_get_event_path(), G_DIR_SEPARATOR_S,
867 tmp, NULL);
868 g_free(tmp);
869 return res;
872 PrefsAccount *vcal_manager_get_account_from_event(VCalEvent *event)
874 GSList *list = vcal_manager_get_answers_emails(event);
875 GSList *cur = list;
877 /* find an attendee corresponding to one of our accounts */
878 while (cur && cur->data) {
879 gchar *email = (gchar *)cur->data;
880 if (account_find_from_address(email, FALSE)) {
881 g_slist_free(list);
882 return account_find_from_address(email, FALSE);
884 cur = cur->next;
886 g_slist_free(list);
887 return NULL;
890 void vcal_manager_save_event (VCalEvent *event, gboolean export_after)
892 XMLTag *tag = NULL;
893 XMLNode *xmlnode = NULL;
894 GNode *rootnode = NULL;
895 PrefFile *pfile;
896 gchar *path = NULL;
897 GSList *answers = event->answers;
898 gchar *tmp = NULL;
899 gint tmp_method = event->method;
901 tag = xml_tag_new("event");
902 xml_tag_add_attr(tag, xml_attr_new("organizer", event->organizer));
903 xml_tag_add_attr(tag, xml_attr_new("orgname", event->orgname));
904 xml_tag_add_attr(tag, xml_attr_new("location", event->location));
905 xml_tag_add_attr(tag, xml_attr_new("summary", event->summary));
906 xml_tag_add_attr(tag, xml_attr_new("description", event->description));
907 xml_tag_add_attr(tag, xml_attr_new("url", event->url));
908 xml_tag_add_attr(tag, xml_attr_new("dtstart", event->dtstart));
909 xml_tag_add_attr(tag, xml_attr_new("dtend", event->dtend));
910 xml_tag_add_attr(tag, xml_attr_new("recur", event->recur));
911 xml_tag_add_attr(tag, xml_attr_new("tzid", event->tzid));
913 /* updating answers saves events, don't save them with reply type */
914 if (tmp_method == ICAL_METHOD_REPLY)
915 tmp_method = ICAL_METHOD_REQUEST;
917 tmp = g_strdup_printf("%d", tmp_method);
918 xml_tag_add_attr(tag, xml_attr_new("method", tmp));
919 g_free(tmp);
921 tmp = g_strdup_printf("%d", event->sequence);
922 xml_tag_add_attr(tag, xml_attr_new("sequence", tmp));
923 g_free(tmp);
925 tmp = g_strdup_printf("%d", event->type);
926 xml_tag_add_attr(tag, xml_attr_new("type", tmp));
927 g_free(tmp);
929 tmp = g_strdup_printf("%"CM_TIME_FORMAT, event->postponed);
930 xml_tag_add_attr(tag, xml_attr_new("postponed", tmp));
931 g_free(tmp);
933 tmp = g_strdup_printf("%d", event->rec_occurrence);
934 xml_tag_add_attr(tag, xml_attr_new("rec_occurrence", tmp));
935 g_free(tmp);
937 xmlnode = xml_node_new(tag, NULL);
938 rootnode = g_node_new(xmlnode);
940 while (answers && answers->data) {
941 XMLNode *ansxmlnode = NULL;
942 GNode *ansnode = NULL;
943 XMLTag *anstag = xml_tag_new("answer");
944 Answer *a = (Answer *)answers->data;
945 xml_tag_add_attr(anstag, xml_attr_new("attendee", a->attendee));
946 xml_tag_add_attr(anstag, xml_attr_new("name", a->name?a->name:""));
947 tmp = g_strdup_printf("%d", a->answer);
948 xml_tag_add_attr(anstag, xml_attr_new("answer", tmp));
949 g_free(tmp);
950 tmp = g_strdup_printf("%d", a->cutype);
951 xml_tag_add_attr(anstag, xml_attr_new("cutype", tmp));
952 g_free(tmp);
953 ansxmlnode = xml_node_new(anstag, NULL);
954 ansnode = g_node_new(ansxmlnode);
955 g_node_append(rootnode, ansnode);
956 answers = answers->next;
959 path = vcal_manager_get_event_file(event->uid);
961 if ((pfile = prefs_write_open(path)) == NULL) {
962 gchar *dir_path = vcal_manager_get_event_path();
963 if (!is_dir_exist(dir_path) && make_dir(vcal_manager_get_event_path()) != 0) {
964 g_free(dir_path);
965 g_free(path);
966 return;
968 g_free(dir_path);
969 if ((pfile = prefs_write_open(path)) == NULL) {
970 g_free(path);
971 return;
975 g_free(path);
976 xml_file_put_xml_decl(pfile->fp);
977 xml_write_tree(rootnode, pfile->fp);
978 xml_free_tree(rootnode);
980 if (prefs_file_close(pfile) < 0) {
981 g_warning("failed to write event");
982 return;
985 if (export_after)
986 vcal_folder_export(NULL);
989 static VCalEvent *event_get_from_xml (const gchar *uid, GNode *node)
991 XMLNode *xmlnode;
992 GList *list;
993 gchar *org = NULL, *location = NULL, *summary = NULL, *orgname = NULL;
994 gchar *dtstart = NULL, *dtend = NULL, *tzid = NULL;
995 gchar *description = NULL, *url = NULL, *recur = NULL;
996 VCalEvent *event = NULL;
997 icalproperty_method method = ICAL_METHOD_REQUEST;
998 icalcomponent_kind type = ICAL_VEVENT_COMPONENT;
999 gint sequence = 0, rec_occurrence = 0;
1000 time_t postponed = (time_t)0;
1002 g_return_val_if_fail(node->data != NULL, NULL);
1004 xmlnode = node->data;
1005 if (g_strcmp0(xmlnode->tag->tag, "event") != 0) {
1006 g_warning("tag name != \"event\"");
1007 return NULL;
1010 list = xmlnode->tag->attr;
1011 for (; list != NULL; list = list->next) {
1012 XMLAttr *attr = list->data;
1014 if (!attr || !attr->name || !attr->value) continue;
1015 if (!strcmp(attr->name, "organizer"))
1016 org = g_strdup(attr->value);
1017 if (!strcmp(attr->name, "orgname"))
1018 orgname = g_strdup(attr->value);
1019 if (!strcmp(attr->name, "location"))
1020 location = g_strdup(attr->value);
1021 if (!strcmp(attr->name, "summary"))
1022 summary = g_strdup(attr->value);
1023 if (!strcmp(attr->name, "description"))
1024 description = g_strdup(attr->value);
1025 if (!strcmp(attr->name, "url"))
1026 url = g_strdup(attr->value);
1027 if (!strcmp(attr->name, "dtstart"))
1028 dtstart = g_strdup(attr->value);
1029 if (!strcmp(attr->name, "dtend"))
1030 dtend = g_strdup(attr->value);
1031 if (!strcmp(attr->name, "recur"))
1032 recur = g_strdup(attr->value);
1033 if (!strcmp(attr->name, "tzid"))
1034 tzid = g_strdup(attr->value);
1035 if (!strcmp(attr->name, "type"))
1036 type = atoi(attr->value);
1037 if (!strcmp(attr->name, "method"))
1038 method = atoi(attr->value);
1039 if (!strcmp(attr->name, "sequence"))
1040 sequence = atoi(attr->value);
1041 if (!strcmp(attr->name, "postponed"))
1042 postponed = atoi(attr->value);
1043 if (!strcmp(attr->name, "rec_occurrence"))
1044 rec_occurrence = atoi(attr->value);
1047 event = vcal_manager_new_event(uid, org, orgname, location, summary, description,
1048 dtstart, dtend, recur, tzid, url, method,
1049 sequence, type);
1051 event->postponed = postponed;
1052 event->rec_occurrence = rec_occurrence;
1054 g_free(org);
1055 g_free(orgname);
1056 g_free(location);
1057 g_free(summary);
1058 g_free(description);
1059 g_free(url);
1060 g_free(dtstart);
1061 g_free(dtend);
1062 g_free(recur);
1063 g_free(tzid);
1065 node = node->children;
1066 while (node != NULL) {
1067 gchar *attendee = NULL;
1068 gchar *name = NULL;
1069 icalparameter_partstat answer = ICAL_PARTSTAT_NEEDSACTION;
1070 icalparameter_cutype cutype = ICAL_CUTYPE_INDIVIDUAL;
1072 xmlnode = node->data;
1073 if (g_strcmp0(xmlnode->tag->tag, "answer") != 0) {
1074 g_warning("tag name != \"answer\"");
1075 return event;
1077 list = xmlnode->tag->attr;
1078 for (; list != NULL; list = list->next) {
1079 XMLAttr *attr = list->data;
1081 if (!attr || !attr->name || !attr->value) continue;
1082 if (!strcmp(attr->name, "attendee"))
1083 attendee = g_strdup(attr->value);
1084 if (!strcmp(attr->name, "name"))
1085 name = g_strdup(attr->value);
1086 if (!strcmp(attr->name, "answer"))
1087 answer = atoi(attr->value);
1088 if (!strcmp(attr->name, "cutype"))
1089 cutype = atoi(attr->value);
1092 event->answers = g_slist_prepend(event->answers, answer_new(attendee, name, answer, cutype));
1093 g_free(attendee);
1094 g_free(name);
1095 node = node->next;
1097 event->answers = g_slist_reverse(event->answers);
1099 return event;
1102 VCalEvent *vcal_manager_load_event (const gchar *uid)
1104 GNode *node;
1105 gchar *path = NULL;
1106 VCalEvent *event = NULL;
1108 path = vcal_manager_get_event_file(uid);
1110 if (!is_file_exist(path)) {
1111 g_free(path);
1112 return NULL;
1115 node = xml_parse_file(path);
1117 g_free(path);
1119 if (!node) {
1120 g_warning("no node");
1121 return NULL;
1124 event = event_get_from_xml(uid, node);
1125 /* vcal_manager_event_print(event); */
1126 xml_free_tree(node);
1128 if (!event)
1129 return NULL;
1131 while (strchr(event->summary, '\n'))
1132 *(strchr(event->summary, '\n')) = ' ';
1134 return event;
1138 void vcal_manager_update_answer (VCalEvent *event,
1139 const gchar *attendee,
1140 const gchar *name,
1141 icalparameter_partstat ans,
1142 icalparameter_cutype cutype)
1144 Answer *answer = NULL;
1145 GSList *existing = NULL;
1146 Answer *existing_a = NULL;
1148 if (!ans)
1149 return;
1151 answer = answer_new(attendee, name, ans, cutype);
1152 existing = answer_find(event, answer);
1154 if (existing) {
1155 existing_a = (Answer *)existing->data;
1157 if (!answer->name && existing_a->name)
1158 answer->name = g_strdup(existing_a->name);
1159 if (!answer->cutype && existing_a->cutype)
1160 answer->cutype = existing_a->cutype;
1162 answer_remove(event, answer);
1165 answer_add(event, answer);
1167 vcal_manager_save_event(event, FALSE);
1170 static gchar *write_headers(PrefsAccount *account,
1171 VCalEvent *event,
1172 gboolean short_headers,
1173 gboolean is_reply,
1174 gboolean is_pseudo_display)
1176 gchar *subject = NULL;
1177 gchar date[RFC822_DATE_BUFFSIZE];
1178 gchar *save_folder = NULL;
1179 gchar *result = NULL;
1180 gchar *queue_headers = NULL;
1181 gchar *method_str = NULL;
1182 gchar *attendees = NULL;
1183 icalparameter_partstat status;
1184 gchar *prefix = NULL;
1185 gchar enc_subject[512], enc_from[512], *from = NULL;
1186 gchar *msgid;
1187 gchar *calmsgid = NULL;
1189 cm_return_val_if_fail(account != NULL, NULL);
1191 memset(date, 0, sizeof(date));
1193 if (is_pseudo_display) {
1194 struct icaltimetype itt = (icaltime_from_string(event->dtstart));
1195 time_t t = icaltime_as_timet(itt);
1196 get_rfc822_date_from_time_t(date, sizeof(date), t);
1197 } else {
1198 get_rfc822_date(date, sizeof(date));
1201 if (account_get_special_folder(account, F_OUTBOX)) {
1202 save_folder = folder_item_get_identifier(account_get_special_folder
1203 (account, F_OUTBOX));
1206 if (!is_reply) {
1207 GSList *cur = event->answers;
1208 while (cur && cur->data) {
1209 gchar *tmp = NULL;
1210 Answer *a = (Answer *)cur->data;
1212 if (strcasecmp(a->attendee, event->organizer)) {
1213 if (attendees) {
1214 tmp = g_strdup_printf("%s>,\n <%s", attendees, a->attendee);
1215 g_free(attendees);
1216 attendees = tmp;
1217 } else {
1218 attendees = g_strdup_printf("%s", a->attendee);
1221 cur = cur->next;
1225 if (!short_headers) {
1226 queue_headers = g_strdup_printf("S:%s\n"
1227 "SSV:%s\n"
1228 "R:<%s>\n"
1229 "MAID:%d\n"
1230 "%s%s%s"
1231 "X-Claws-End-Special-Headers: 1\n",
1232 account->address,
1233 account->smtp_server,
1234 is_reply ? event->organizer:attendees,
1235 account->account_id,
1236 save_folder?"SCF:":"",
1237 save_folder?save_folder:"",
1238 save_folder?"\n":"");
1239 } else {
1240 queue_headers = g_strdup("");
1243 prefix = "";
1244 if (is_reply) {
1245 method_str = "REPLY";
1246 status = vcal_manager_get_reply_for_attendee(event, account->address);
1247 if (status == ICAL_PARTSTAT_ACCEPTED)
1248 prefix = _("Accepted: ");
1249 else if (status == ICAL_PARTSTAT_DECLINED)
1250 prefix = _("Declined: ");
1251 else if (status == ICAL_PARTSTAT_TENTATIVE)
1252 prefix = _("Tentatively Accepted: ");
1253 else
1254 prefix = "Re: ";
1255 } else if (event->method == ICAL_METHOD_PUBLISH) {
1256 method_str = "PUBLISH";
1257 } else if (event->method == ICAL_METHOD_CANCEL) {
1258 method_str = "CANCEL";
1259 } else {
1260 method_str = "REQUEST";
1263 subject = g_strdup_printf("%s%s", prefix, event->summary);
1265 conv_encode_header_full(enc_subject, sizeof(enc_subject), subject, strlen("Subject: "),
1266 FALSE, conv_get_outgoing_charset_str());
1267 from = is_reply?account->name:(event->orgname?event->orgname:"");
1268 conv_encode_header_full(enc_from, sizeof(enc_from), from, strlen("From: "),
1269 TRUE, conv_get_outgoing_charset_str());
1271 if (is_pseudo_display && event->uid) {
1272 calmsgid = g_strdup_printf("Message-ID: <%s>\n",event->uid);
1273 } else {
1274 calmsgid = g_strdup("");
1277 msgid = prefs_account_generate_msgid(account);
1279 result = g_strdup_printf("%s"
1280 "From: %s <%s>\n"
1281 "To: <%s>\n"
1282 "Subject: %s\n"
1283 "Date: %s\n"
1284 "MIME-Version: 1.0\n"
1285 "Content-Type: text/calendar; method=%s; charset=\"%s\"\n"
1286 "Content-Transfer-Encoding: 8bit\n"
1287 "%s"
1288 "%s: <%s>\n",
1289 queue_headers,
1290 enc_from,
1291 is_reply ? account->address:event->organizer,
1292 is_reply ? event->organizer:(attendees?attendees:event->organizer),
1293 enc_subject,
1294 date,
1295 method_str,
1296 CS_UTF_8,
1297 calmsgid,
1298 is_pseudo_display?
1299 "In-Reply-To":"Message-ID",
1300 is_pseudo_display?
1301 event_to_today_str(event, 0):msgid);
1302 g_free(calmsgid);
1303 g_free(subject);
1304 g_free(save_folder);
1305 g_free(queue_headers);
1306 g_free(attendees);
1307 g_free(msgid);
1308 return result;
1313 static gchar *write_headers_ical(PrefsAccount *account,
1314 icalcomponent *ievent,
1315 gchar *orga)
1317 gchar subject[512];
1318 gchar date[RFC822_DATE_BUFFSIZE];
1319 gchar *result = NULL;
1320 gchar *method_str = NULL;
1321 gchar *summary = NULL;
1322 gchar *organizer = NULL;
1323 gchar *orgname = NULL;
1324 icalproperty *prop = NULL;
1325 gchar *calmsgid = NULL;
1327 time_t t = (time_t)0;
1329 memset(subject, 0, sizeof(subject));
1330 memset(date, 0, sizeof(date));
1332 prop = icalcomponent_get_first_property(ievent, ICAL_SUMMARY_PROPERTY);
1333 if (prop) {
1334 summary = g_strdup(icalproperty_get_summary(prop));
1335 icalproperty_free(prop);
1336 } else {
1337 summary = g_strdup("");
1340 while (strchr(summary, '\n'))
1341 *(strchr(summary, '\n')) = ' ';
1343 prop = icalcomponent_get_first_property(ievent, ICAL_ORGANIZER_PROPERTY);
1344 if (prop) {
1345 organizer = g_strdup(icalproperty_get_organizer(prop));
1346 if (icalproperty_get_parameter_as_string(prop, "CN") != NULL)
1347 orgname = g_strdup(icalproperty_get_parameter_as_string(prop, "CN"));
1349 icalproperty_free(prop);
1350 } else {
1351 organizer = orga? g_strdup(orga):g_strdup("");
1354 prop = icalcomponent_get_first_property(ievent, ICAL_DTSTART_PROPERTY);
1355 if (prop) {
1356 t = icaltime_as_timet(icalproperty_get_dtstart(prop));
1357 get_rfc822_date_from_time_t(date, sizeof(date), t);
1358 } else {
1359 get_rfc822_date(date, sizeof(date));
1362 conv_encode_header(subject, 511, summary, strlen("Subject: "), FALSE);
1364 method_str = "PUBLISH";
1366 prop = icalcomponent_get_first_property(ievent, ICAL_UID_PROPERTY);
1367 if (prop) {
1368 calmsgid = g_strdup_printf("Message-ID: <%s>\n",icalproperty_get_uid(prop));
1369 icalproperty_free(prop);
1370 } else {
1371 calmsgid = g_strdup("");
1375 result = g_strdup_printf("From: %s <%s>\n"
1376 "To: <%s>\n"
1377 "Subject: %s%s\n"
1378 "Date: %s\n"
1379 "MIME-Version: 1.0\n"
1380 "Content-Type: text/calendar; method=%s; charset=\"%s\"; vcalsave=\"no\"\n"
1381 "Content-Transfer-Encoding: quoted-printable\n"
1382 "%s"
1383 "In-Reply-To: <%s>\n",
1384 orgname?orgname:"",
1385 !strncmp(organizer, "MAILTO:", 7) ? organizer+7 : organizer,
1386 account->address,
1388 subject,
1389 date,
1390 method_str,
1391 conv_get_outgoing_charset_str(),
1392 calmsgid,
1393 event_to_today_str(NULL, t));
1395 g_free(calmsgid);
1396 g_free(orgname);
1397 g_free(organizer);
1398 g_free(summary);
1400 return result;
1405 static gboolean vcal_manager_send (PrefsAccount *account,
1406 VCalEvent *event,
1407 gboolean is_reply)
1409 gchar *tmpfile = NULL;
1410 gint msgnum;
1411 FolderItem *folderitem;
1412 gchar *msgpath = NULL;
1413 Folder *folder = NULL;
1415 tmpfile = vcal_manager_event_dump(event, is_reply, FALSE, NULL, TRUE);
1417 if (!tmpfile)
1418 return FALSE;
1420 folderitem = account_get_special_folder(account, F_QUEUE);
1421 if (!folderitem) {
1422 g_warning("can't find queue folder for %s", account->address);
1423 g_unlink(tmpfile);
1424 g_free(tmpfile);
1425 return FALSE;
1427 folder_item_scan(folderitem);
1429 if ((msgnum = folder_item_add_msg(folderitem, tmpfile, NULL, TRUE)) < 0) {
1430 g_warning("can't queue the message");
1431 g_unlink(tmpfile);
1432 g_free(tmpfile);
1433 return FALSE;
1436 msgpath = folder_item_fetch_msg(folderitem, msgnum);
1438 if (!prefs_common_get_prefs()->work_offline) {
1439 gchar *err = NULL;
1440 gboolean queued_removed = FALSE;
1441 gint val = procmsg_send_message_queue_with_lock(msgpath, &err, folderitem, msgnum, &queued_removed);
1442 if (val == 0) {
1443 if (!queued_removed)
1444 folder_item_remove_msg(folderitem, msgnum);
1445 folder_item_scan(folderitem);
1446 } else if (err) {
1447 alertpanel_error_log("%s", err);
1448 g_free(err);
1451 g_unlink(tmpfile);
1452 g_free(tmpfile);
1453 g_free(msgpath);
1455 folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
1456 if (folder) {
1457 folder_item_scan(folder->inbox);
1458 vcalviewer_reload(folder->inbox);
1459 } else
1460 g_warning("couldn't find vCalendar folder class");
1461 return TRUE;
1464 gboolean vcal_manager_reply (PrefsAccount *account,
1465 VCalEvent *event)
1467 return vcal_manager_send(account, event, TRUE);
1470 gboolean vcal_manager_request (PrefsAccount *account,
1471 VCalEvent *event)
1473 return vcal_manager_send(account, event, FALSE);
1476 EventTime event_to_today(VCalEvent *event, time_t t)
1478 struct tm evtstart, today;
1479 time_t evtstart_t, today_t;
1480 struct icaltimetype itt;
1482 tzset();
1484 today_t = time(NULL);
1485 if (event) {
1486 itt = icaltime_from_string(event->dtstart);
1487 evtstart_t = icaltime_as_timet(itt);
1488 } else {
1489 evtstart_t = t;
1492 #ifndef G_OS_WIN32
1493 struct tm buft;
1494 today = *localtime_r(&today_t, &buft);
1495 localtime_r(&evtstart_t, &evtstart);
1496 #else
1497 if (today_t < 0)
1498 today_t = 1;
1499 if (evtstart_t < 0)
1500 evtstart_t = 1;
1501 today = *localtime(&today_t);
1502 evtstart = *localtime(&evtstart_t);
1503 #endif
1505 if (today.tm_year == evtstart.tm_year) {
1506 int days = evtstart.tm_yday - today.tm_yday;
1507 if (days < 0) {
1508 return EVENT_PAST;
1509 } else if (days == 0) {
1510 return EVENT_TODAY;
1511 } else if (days == 1) {
1512 return EVENT_TOMORROW;
1513 } else if (days > 1 && days < 7) {
1514 return EVENT_THISWEEK;
1515 } else {
1516 return EVENT_LATER;
1518 } else if (today.tm_year > evtstart.tm_year) {
1519 return EVENT_PAST;
1520 } else if (today.tm_year == evtstart.tm_year - 1) {
1521 int days = ((365 - today.tm_yday) + evtstart.tm_yday);
1522 if (days == 0) {
1523 return EVENT_TODAY;
1524 } else if (days == 1) {
1525 return EVENT_TOMORROW;
1526 } else if (days > 1 && days < 7) {
1527 return EVENT_THISWEEK;
1528 } else {
1529 return EVENT_LATER;
1531 } else
1532 return EVENT_LATER;
1535 const gchar *event_to_today_str(VCalEvent *event, time_t t)
1537 EventTime days = event_to_today(event, t);
1538 switch(days) {
1539 case EVENT_PAST:
1540 return EVENT_PAST_ID;
1541 case EVENT_TODAY:
1542 return EVENT_TODAY_ID;
1543 case EVENT_TOMORROW:
1544 return EVENT_TOMORROW_ID;
1545 case EVENT_THISWEEK:
1546 return EVENT_THISWEEK_ID;
1547 case EVENT_LATER:
1548 return EVENT_LATER_ID;
1550 return NULL;