2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2015 Colin Leroy <colin@colino.net> and
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, see <http://www.gnu.org/licenses/>.
22 #include "claws-features.h"
27 #include <glib/gi18n.h>
31 #include <sys/types.h>
35 #include <curl/curl.h>
36 #include <curl/curlver.h>
40 #include "file-utils.h"
43 #include "procheader.h"
45 #include "folderview.h"
46 #include "folder_item_prefs.h"
47 #include "vcalendar.h"
48 #include "vcal_folder.h"
49 #include "vcal_prefs.h"
50 #include "vcal_manager.h"
51 #include "vcal_meeting_gtk.h"
52 #include "vcal_interface.h"
53 #include "prefs_account.h"
54 #include "prefs_common.h"
57 #include "inputdialog.h"
60 #include "alertpanel.h"
62 #include "mainwindow.h"
63 #include "statusbar.h"
65 #include "passwordstore.h"
67 #include "messageview.h"
72 #define VCAL_FOLDERITEM(item) ((VCalFolderItem *) item)
78 typedef struct _thread_data {
85 typedef struct _IcalFeedData {
87 gchar *pseudoevent_id;
90 typedef struct _VCalFolder VCalFolder;
91 typedef struct _VCalFolderItem VCalFolderItem;
93 static Folder *vcal_folder_new(const gchar * name,
94 const gchar * folder);
95 static void vcal_folder_destroy(Folder * folder);
96 static void vcal_item_destroy(Folder *folder, FolderItem *_item);
97 static gchar *vcal_item_get_path(Folder *folder, FolderItem *item);
99 static gint vcal_scan_tree(Folder * folder);
100 static FolderItem *vcal_item_new(Folder * folder);
101 static gint vcal_get_num_list(Folder * folder, FolderItem * item,
102 MsgNumberList ** list,
103 gboolean * old_uids_valid);
104 static MsgInfo *vcal_get_msginfo(Folder * folder, FolderItem * item,
106 static gchar *vcal_fetch_msg(Folder * folder, FolderItem * item,
108 static gint vcal_add_msg(Folder * folder, FolderItem * _dest,
109 const gchar * file, MsgFlags * flags);
110 static gint vcal_remove_msg(Folder * folder, FolderItem * _item,
112 static FolderItem *vcal_create_folder(Folder * folder,
115 static gint vcal_create_tree(Folder *folder);
116 static gint vcal_remove_folder(Folder *folder, FolderItem *item);
117 static gboolean vcal_scan_required(Folder *folder, FolderItem *item);
118 static void vcal_set_mtime(Folder *folder, FolderItem *item);
119 static void vcal_change_flags(Folder *folder, FolderItem *_item, MsgInfo *msginfo, MsgPermFlags newflags);
121 static void new_meeting_cb(GtkAction *action, gpointer data);
122 static void export_cal_cb(GtkAction *action, gpointer data);
123 static void subscribe_cal_cb(GtkAction *action, gpointer data);
124 static void check_subs_cb(GtkAction *action, gpointer data);
125 static void unsubscribe_cal_cb(GtkAction *action, gpointer data);
126 static void rename_cb(GtkAction *action, gpointer data);
127 static void set_view_cb(GtkAction *action, GtkRadioAction *current, gpointer data);
129 static void add_menuitems(GtkUIManager *ui_manager, FolderItem *item);
130 static void set_sensitivity(GtkUIManager *ui_manager, FolderItem *item);
132 static void update_subscription(const gchar *uri, gboolean verbose);
133 static void vcal_folder_set_batch (Folder *folder,
136 static void convert_to_utc(icalcomponent *calendar);
138 gboolean vcal_subscribe_uri(Folder *folder, const gchar *uri);
140 FolderClass vcal_class;
142 static GSList *created_files = NULL;
143 static GHashTable *hash_uids = NULL;
150 struct _VCalFolderItem
166 static char *vcal_popup_labels[] =
168 N_("_New meeting..."),
169 N_("_Export calendar..."),
170 N_("_Subscribe to Webcal..."),
171 N_("_Unsubscribe..."),
173 N_("U_pdate subscriptions"),
180 static GtkActionEntry vcal_popup_entries[] =
182 {"FolderViewPopup/NewMeeting", NULL, NULL, NULL, NULL, G_CALLBACK(new_meeting_cb) },
183 {"FolderViewPopup/ExportCal", NULL, NULL, NULL, NULL, G_CALLBACK(export_cal_cb) },
185 {"FolderViewPopup/SubscribeCal", NULL, NULL, NULL, NULL, G_CALLBACK(subscribe_cal_cb) },
186 {"FolderViewPopup/UnsubscribeCal", NULL, NULL, NULL, NULL, G_CALLBACK(unsubscribe_cal_cb) },
188 {"FolderViewPopup/RenameFolder", NULL, NULL, NULL, NULL, G_CALLBACK(rename_cb) },
190 {"FolderViewPopup/CheckSubs", NULL, NULL, NULL, NULL, G_CALLBACK(check_subs_cb) },
194 static GtkRadioActionEntry vcal_popup_radio_entries[] = { /* set_view_cb */
195 {"FolderViewPopup/ListView", NULL, NULL, NULL, NULL, 0 },
196 {"FolderViewPopup/WeekView", NULL, NULL, NULL, NULL, 1 },
197 {"FolderViewPopup/MonthView", NULL, NULL, NULL, NULL, 2 },
200 static IcalFeedData *icalfeeddata_new(icalcomponent *evt, gchar *str)
202 IcalFeedData *data = g_new0(IcalFeedData, 1);
204 data->pseudoevent_id = g_strdup(str);
209 static void icalfeeddata_free(IcalFeedData *data)
211 g_free(data->pseudoevent_id);
213 icalcomponent_free(data->event);
217 static void slist_free_icalfeeddata(GSList *list)
220 IcalFeedData *data = (IcalFeedData *)list->data;
221 icalfeeddata_free(data);
226 static void vcal_fill_popup_menu_labels(void)
228 vcal_popup_entries[0].label = _(vcal_popup_labels[0]);
229 vcal_popup_entries[1].label = _(vcal_popup_labels[1]);
230 vcal_popup_entries[2].label = _(vcal_popup_labels[2]);
231 vcal_popup_entries[3].label = _(vcal_popup_labels[3]);
232 vcal_popup_entries[4].label = _(vcal_popup_labels[4]);
233 vcal_popup_entries[5].label = _(vcal_popup_labels[5]);
234 vcal_popup_radio_entries[0].label = _(vcal_popup_labels[6]);
235 vcal_popup_radio_entries[1].label = _(vcal_popup_labels[7]);
236 vcal_popup_radio_entries[2].label = _(vcal_popup_labels[8]);
239 static FolderViewPopup vcal_popup =
244 G_N_ELEMENTS(vcal_popup_entries),
246 vcal_popup_radio_entries,
247 G_N_ELEMENTS(vcal_popup_radio_entries), 1, set_view_cb,
252 static void vcal_item_set_xml(Folder *folder, FolderItem *item, XMLTag *tag)
255 folder_item_set_xml(folder, item, tag);
256 gboolean found_cal_view_setting = FALSE;
258 for (cur = tag->attr; cur != NULL; cur = g_list_next(cur)) {
259 XMLAttr *attr = (XMLAttr *) cur->data;
261 if (!attr || !attr->name || !attr->value) continue;
262 if (!strcmp(attr->name, "uri")) {
263 if (((VCalFolderItem *)item)->uri != NULL)
264 g_free(((VCalFolderItem *)item)->uri);
265 ((VCalFolderItem *)item)->uri = g_strdup(attr->value);
267 if (!strcmp(attr->name, "use_cal_view")) {
268 found_cal_view_setting = TRUE;
269 ((VCalFolderItem *)item)->use_cal_view = atoi(attr->value);
272 if (((VCalFolderItem *)item)->uri == NULL) {
273 /* give a path to inbox */
275 item->path = g_strdup(".meetings");
277 if (!found_cal_view_setting)
278 ((VCalFolderItem *)item)->use_cal_view = 1; /*week view */
282 static XMLTag *vcal_item_get_xml(Folder *folder, FolderItem *item)
286 tag = folder_item_get_xml(folder, item);
288 if (((VCalFolderItem *)item)->uri)
289 xml_tag_add_attr(tag, xml_attr_new("uri", ((VCalFolderItem *)item)->uri));
291 xml_tag_add_attr(tag, xml_attr_new_int("use_cal_view", ((VCalFolderItem *)item)->use_cal_view));
296 static gint vcal_rename_folder(Folder *folder, FolderItem *item,
302 item->name = g_strdup(name);
306 static void vcal_get_sort_type(Folder *folder, FolderSortKey *sort_key,
307 FolderSortType *sort_type)
310 *sort_key = SORT_BY_DATE;
313 static void vcal_item_opened(FolderItem *item)
316 time_t t = time(NULL);
318 localtime_r(&t, &tmdate);
322 tmdate = *localtime(&t);
324 if (!((VCalFolderItem *)(item))->dw
325 && ((VCalFolderItem *)(item))->use_cal_view == 1)
326 ((VCalFolderItem *)(item))->dw = create_day_win(item, tmdate);
327 else if (!((VCalFolderItem *)(item))->mw
328 && ((VCalFolderItem *)(item))->use_cal_view == 2)
329 ((VCalFolderItem *)(item))->mw = create_month_win(item, tmdate);
330 else if (((VCalFolderItem *)(item))->use_cal_view != 0)
331 vcal_folder_refresh_cal(item);
334 void vcal_folder_refresh_cal(FolderItem *item)
336 Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
337 if (item->folder != folder)
339 if (((VCalFolderItem *)(item))->dw)
340 refresh_day_win(((VCalFolderItem *)(item))->dw);
341 if (((VCalFolderItem *)(item))->mw)
342 refresh_month_win(((VCalFolderItem *)(item))->mw);
345 static void vcal_item_closed(FolderItem *item)
347 if (((VCalFolderItem *)(item))->dw) {
348 dw_close_window(((VCalFolderItem *)(item))->dw);
349 ((VCalFolderItem *)(item))->dw = NULL;
351 if (((VCalFolderItem *)(item))->mw) {
352 mw_close_window(((VCalFolderItem *)(item))->mw);
353 ((VCalFolderItem *)(item))->mw = NULL;
357 FolderClass *vcal_folder_get_class()
359 if (vcal_class.idstr == NULL) {
360 debug_print("register class\n");
361 vcal_class.type = F_UNKNOWN;
362 vcal_class.idstr = PLUGIN_NAME;
363 vcal_class.uistr = PLUGIN_NAME;
365 /* Folder functions */
366 vcal_class.new_folder = vcal_folder_new;
367 vcal_class.destroy_folder = vcal_folder_destroy;
368 vcal_class.set_xml = folder_set_xml;
369 vcal_class.get_xml = folder_get_xml;
370 vcal_class.item_set_xml = vcal_item_set_xml;
371 vcal_class.item_get_xml = vcal_item_get_xml;
372 vcal_class.scan_tree = vcal_scan_tree;
373 vcal_class.create_tree = vcal_create_tree;
374 vcal_class.get_sort_type = vcal_get_sort_type;
376 /* FolderItem functions */
377 vcal_class.item_new = vcal_item_new;
378 vcal_class.item_destroy = vcal_item_destroy;
379 vcal_class.item_get_path = vcal_item_get_path;
380 vcal_class.create_folder = vcal_create_folder;
381 vcal_class.remove_folder = vcal_remove_folder;
382 vcal_class.rename_folder = vcal_rename_folder;
383 vcal_class.scan_required = vcal_scan_required;
384 vcal_class.set_mtime = vcal_set_mtime;
385 vcal_class.get_num_list = vcal_get_num_list;
386 vcal_class.set_batch = vcal_folder_set_batch;
388 /* Message functions */
389 vcal_class.get_msginfo = vcal_get_msginfo;
390 vcal_class.fetch_msg = vcal_fetch_msg;
391 vcal_class.add_msg = vcal_add_msg;
392 vcal_class.copy_msg = NULL;
393 vcal_class.remove_msg = vcal_remove_msg;
394 vcal_class.change_flags = vcal_change_flags;
395 vcal_class.subscribe = vcal_subscribe_uri;
397 /* FolderView functions */
398 vcal_class.item_opened = vcal_item_opened;
399 vcal_class.item_closed = vcal_item_closed;
400 debug_print("registered class for real\n");
406 static void vcal_folder_set_batch (Folder *folder,
410 VCalFolderItem *item = (VCalFolderItem *)_item;
412 g_return_if_fail(item != NULL);
414 if (item->batching == batch)
418 item->batching = TRUE;
419 debug_print("vcal switching to batch mode\n");
421 debug_print("vcal switching away from batch mode\n");
423 item->batching = FALSE;
425 vcal_folder_export(folder);
430 static Folder *vcal_folder_new(const gchar * name,
435 debug_print("vcal_folder_new\n");
436 folder = g_new0(VCalFolder, 1);
437 FOLDER(folder)->klass = &vcal_class;
438 folder_init(FOLDER(folder), name);
440 return FOLDER(folder);
443 static void vcal_folder_destroy(Folder *_folder)
447 static FolderItem *vcal_item_new(Folder *folder)
449 VCalFolderItem *item;
450 item = g_new0(VCalFolderItem, 1);
451 item->use_cal_view = 1;
452 return (FolderItem *) item;
456 static void vcal_item_destroy(Folder *folder, FolderItem *_item)
458 VCalFolderItem *item = (VCalFolderItem *)_item;
459 g_return_if_fail(item != NULL);
463 static gchar *vcal_item_get_path(Folder *folder, FolderItem *item)
465 VCalFolderItem *fitem = (VCalFolderItem *)item;
466 if (fitem->uri == NULL)
467 return g_strdup(vcal_manager_get_event_path());
469 gchar *path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
470 "vcalendar", G_DIR_SEPARATOR_S,
476 static gint vcal_scan_tree(Folder *folder)
478 g_return_val_if_fail(folder != NULL, -1);
480 folder->outbox = NULL;
481 folder->draft = NULL;
482 folder->queue = NULL;
483 folder->trash = NULL;
485 debug_print("scanning tree\n");
486 vcal_create_tree(folder);
491 gboolean manual_update = TRUE;
493 static gint feed_fetch(FolderItem *fitem, MsgNumberList ** list, gboolean *old_uids_valid)
495 VCalFolderItem *item = (VCalFolderItem *)fitem;
496 icalcomponent *evt = NULL;
497 icalcomponent_kind type = ICAL_VEVENT_COMPONENT;
499 gint past_msg = -1, today_msg = -1, tomorrow_msg = -1,
500 thisweek_msg = -1, later_msg = -1;
502 debug_print("fetching\n");
505 debug_print("no uri!\n");
509 update_subscription(item->uri, TRUE);
511 *old_uids_valid = FALSE;
515 evt = icalcomponent_get_first_component(
516 item->cal, ICAL_VEVENT_COMPONENT);
518 evt = icalcomponent_get_first_component(
519 item->cal, ICAL_VTODO_COMPONENT);
521 type = ICAL_VTODO_COMPONENT;
524 debug_print("no cal!\n");
527 debug_print("no event\n");
530 g_slist_free(item->numlist);
531 item->numlist = NULL;
535 slist_free_icalfeeddata(item->evtlist);
536 g_slist_free(item->evtlist);
537 item->evtlist = NULL;
542 icalproperty *rprop = icalcomponent_get_first_property(evt, ICAL_RRULE_PROPERTY);
543 struct icalrecurrencetype recur;
544 struct icaltimetype next;
545 icalrecur_iterator* ritr = NULL;
549 icalproperty *rprop2;
550 recur = icalproperty_get_rrule(rprop);
551 rprop2 = icalproperty_new_rrule(recur);
552 prop = icalcomponent_get_first_property(evt, ICAL_DTSTART_PROPERTY);
554 ritr = icalrecur_iterator_new(recur, icalproperty_get_dtstart(prop));
555 next = icalrecur_iterator_next(ritr); /* skip first one */
561 prop = icalcomponent_get_first_property(evt, ICAL_UID_PROPERTY);
563 gchar *orig_uid = NULL;
564 gchar *uid = g_strdup(icalproperty_get_uid(prop));
565 IcalFeedData *data = icalfeeddata_new(
566 icalcomponent_new_clone(evt), NULL);
568 orig_uid = g_strdup(uid);
571 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
572 item->evtlist = g_slist_prepend(item->evtlist, data);
574 debug_print("add %d : %s\n", num, uid);
577 prop = icalcomponent_get_first_property(evt, ICAL_DTSTART_PROPERTY);
579 struct icaltimetype itt = icalproperty_get_dtstart(prop);
580 days = event_to_today(NULL, icaltime_as_timet(itt));
581 if (days == EVENT_PAST && past_msg == -1) {
582 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
583 data = icalfeeddata_new(NULL, EVENT_PAST_ID);
585 } else if (days == EVENT_TODAY && today_msg == -1) {
586 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
587 data = icalfeeddata_new(NULL, EVENT_TODAY_ID);
589 } else if (days == EVENT_TOMORROW && tomorrow_msg == -1) {
590 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
591 data = icalfeeddata_new(NULL, EVENT_TOMORROW_ID);
592 tomorrow_msg = num++;
593 } else if (days == EVENT_THISWEEK && thisweek_msg == -1) {
594 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
595 data = icalfeeddata_new(NULL, EVENT_THISWEEK_ID);
596 thisweek_msg = num++;
597 } else if (days == EVENT_LATER && later_msg == -1) {
598 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
599 data = icalfeeddata_new(NULL, EVENT_LATER_ID);
603 if (past_msg == -1) {
604 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
605 data = icalfeeddata_new(NULL, EVENT_PAST_ID);
610 item->evtlist = g_slist_prepend(item->evtlist, data);
614 struct icaldurationtype ical_dur;
615 struct icaltimetype dtstart = icaltime_null_time();
616 struct icaltimetype dtend = icaltime_null_time();
617 evt = icalcomponent_new_clone(evt);
618 prop = icalcomponent_get_first_property(evt, ICAL_RRULE_PROPERTY);
620 icalcomponent_remove_property(evt, prop);
621 icalproperty_free(prop);
623 prop = icalcomponent_get_first_property(evt, ICAL_DTSTART_PROPERTY);
625 dtstart = icalproperty_get_dtstart(prop);
627 debug_print("event has no DTSTART!\n");
628 prop = icalcomponent_get_first_property(evt, ICAL_DTEND_PROPERTY);
630 dtend = icalproperty_get_dtend(prop);
632 debug_print("event has no DTEND!\n");
633 ical_dur = icaltime_subtract(dtend, dtstart);
634 next = icalrecur_iterator_next(ritr);
635 if (!icaltime_is_null_time(next) &&
636 !icaltime_is_null_time(dtstart) && i < 100) {
637 prop = icalcomponent_get_first_property(evt, ICAL_DTSTART_PROPERTY);
638 icalproperty_set_dtstart(prop, next);
640 prop = icalcomponent_get_first_property(evt, ICAL_DTEND_PROPERTY);
642 icalproperty_set_dtend(prop, icaltime_add(next, ical_dur));
644 prop = icalcomponent_get_first_property(evt, ICAL_UID_PROPERTY);
645 uid = g_strdup_printf("%s-%d", orig_uid, i);
646 icalproperty_set_uid(prop, uid);
647 /* dont free uid, used after (add_new) */
648 data = icalfeeddata_new(evt, NULL);
652 icalcomponent_free(evt);
658 debug_print("no uid!\n");
661 icalproperty_free(rprop);
664 icalrecur_iterator_free(ritr);
667 evt = icalcomponent_get_next_component(
670 if (today_msg == -1) {
671 IcalFeedData *data = icalfeeddata_new(NULL, EVENT_TODAY_ID);
672 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
674 item->evtlist = g_slist_prepend(item->evtlist, data);
676 item->numlist = g_slist_reverse(item->numlist);
677 item->evtlist = g_slist_reverse(item->evtlist);
679 *list = item->numlist ? g_slist_copy(item->numlist) : NULL;
680 debug_print("return %d\n", num);
684 #define VCAL_FOLDER_ADD_EVENT(event) \
687 *list = g_slist_prepend(*list, GINT_TO_POINTER(n_msg)); \
688 debug_print("add %d %s\n", n_msg, event->uid); \
690 days = event_to_today(event, 0); \
692 if (days == EVENT_PAST && past_msg == -1) { \
693 *list = g_slist_prepend(*list, GINT_TO_POINTER(n_msg)); \
694 past_msg = n_msg++; \
695 g_hash_table_insert(hash_uids, GINT_TO_POINTER(past_msg), g_strdup(EVENT_PAST_ID)); \
696 } else if (days == EVENT_TODAY && today_msg == -1) { \
697 *list = g_slist_prepend(*list, GINT_TO_POINTER(n_msg)); \
698 today_msg = n_msg++; \
699 g_hash_table_insert(hash_uids, GINT_TO_POINTER(today_msg), g_strdup(EVENT_TODAY_ID)); \
700 } else if (days == EVENT_TOMORROW && tomorrow_msg == -1) { \
701 *list = g_slist_prepend(*list, GINT_TO_POINTER(n_msg)); \
702 tomorrow_msg = n_msg++; \
703 g_hash_table_insert(hash_uids, GINT_TO_POINTER(tomorrow_msg), g_strdup(EVENT_TOMORROW_ID)); \
704 } else if (days == EVENT_THISWEEK && thisweek_msg == -1) { \
705 *list = g_slist_prepend(*list, GINT_TO_POINTER(n_msg)); \
706 thisweek_msg = n_msg++; \
707 g_hash_table_insert(hash_uids, GINT_TO_POINTER(thisweek_msg), g_strdup(EVENT_THISWEEK_ID)); \
708 } else if (days == EVENT_LATER && later_msg == -1) { \
709 *list = g_slist_prepend(*list, GINT_TO_POINTER(n_msg)); \
710 later_msg = n_msg++; \
711 g_hash_table_insert(hash_uids, GINT_TO_POINTER(later_msg), g_strdup(EVENT_LATER_ID)); \
715 GSList *vcal_get_events_list(FolderItem *item)
719 GSList *events = NULL;
720 GError *error = NULL;
722 if (item != item->folder->inbox) {
723 GSList *subs = vcal_folder_get_webcal_events_for_folder(item);
725 for (cur = subs; cur; cur = cur->next) {
726 /* Don't free that, it's done when subscriptions are
728 icalcomponent *ical = (icalcomponent *)cur->data;
729 VCalEvent *event = vcal_get_event_from_ical(
730 icalcomponent_as_ical_string(ical), NULL);
731 events = g_slist_prepend(events, event);
737 dp = g_dir_open(vcal_manager_get_event_path(), 0, &error);
740 debug_print("couldn't open dir '%s': %s (%d)\n",
741 vcal_manager_get_event_path(), error->message, error->code);
746 while ((d = g_dir_read_name(dp)) != NULL) {
747 VCalEvent *event = NULL;
748 if (d[0] == '.' || strstr(d, ".bak")
749 || !strcmp(d, "internal.ics")
750 || !strcmp(d, "internal.ifb")
751 || !strcmp(d, "multisync"))
754 event = vcal_manager_load_event(d);
757 if (event->rec_occurrence) {
758 vcal_manager_free_event(event);
763 if (event && event->method != ICAL_METHOD_CANCEL) {
764 PrefsAccount *account = vcal_manager_get_account_from_event(event);
765 enum icalparameter_partstat status =
766 account ? vcal_manager_get_reply_for_attendee(event, account->address): ICAL_PARTSTAT_NEEDSACTION;
767 if (status == ICAL_PARTSTAT_ACCEPTED
768 || status == ICAL_PARTSTAT_TENTATIVE) {
769 events = g_slist_prepend(events, event);
771 vcal_manager_free_event(event);
774 if ((status == ICAL_PARTSTAT_ACCEPTED
775 || status == ICAL_PARTSTAT_TENTATIVE)
776 && event->recur && *(event->recur)) {
777 struct icalrecurrencetype recur;
778 struct icaltimetype dtstart;
779 struct icaltimetype next;
780 icalrecur_iterator* ritr;
781 time_t duration = (time_t) NULL;
782 struct icaldurationtype ical_dur;
785 debug_print("dumping recurring events from main event %s\n", d);
786 recur = icalrecurrencetype_from_string(event->recur);
787 dtstart = icaltime_from_string(event->dtstart);
789 duration = icaltime_as_timet(icaltime_from_string(event->dtend))
790 - icaltime_as_timet(icaltime_from_string(event->dtstart));
792 ical_dur = icaldurationtype_from_int(duration);
794 ritr = icalrecur_iterator_new(recur, dtstart);
796 next = icalrecur_iterator_next(ritr); /* skip first one */
797 if (!icaltime_is_null_time(next))
798 next = icalrecur_iterator_next(ritr);
799 debug_print("next time is %snull\n", icaltime_is_null_time(next)?"":"not ");
800 while (!icaltime_is_null_time(next) && i < 100) {
801 const gchar *new_start = NULL, *new_end = NULL;
802 VCalEvent *nevent = NULL;
803 gchar *uid = g_strdup_printf("%s-%d", event->uid, i);
804 new_start = icaltime_as_ical_string(next);
805 new_end = icaltime_as_ical_string(
806 icaltime_add(next, ical_dur));
807 debug_print("adding with start/end %s:%s\n", new_start, new_end);
808 nevent = vcal_manager_new_event(uid, event->organizer, event->orgname,
809 event->location, event->summary, event->description,
810 new_start, new_end, NULL,
811 event->tzid, event->url, event->method,
812 event->sequence, event->type);
814 vcal_manager_copy_attendees(event, nevent);
815 nevent->rec_occurrence = TRUE;
816 vcal_manager_save_event(nevent, FALSE);
817 account = vcal_manager_get_account_from_event(event);
819 account ? vcal_manager_get_reply_for_attendee(event, account->address): ICAL_PARTSTAT_NEEDSACTION;
820 if (status == ICAL_PARTSTAT_ACCEPTED
821 || status == ICAL_PARTSTAT_TENTATIVE) {
822 events = g_slist_prepend(events, nevent);
824 vcal_manager_free_event(nevent);
826 next = icalrecur_iterator_next(ritr);
827 debug_print("next time is %snull\n", icaltime_is_null_time(next)?"":"not ");
830 icalrecur_iterator_free(ritr);
833 vcal_manager_free_event(event);
837 return g_slist_reverse(events);
840 static gint vcal_get_num_list(Folder *folder, FolderItem *item,
841 MsgNumberList ** list, gboolean *old_uids_valid)
844 gint past_msg = -1, today_msg = -1, tomorrow_msg = -1,
845 thisweek_msg = -1, later_msg = -1;
846 GSList *events = NULL, *cur;
848 g_return_val_if_fail (*list == NULL, 0); /* we expect a NULL list */
850 debug_print(" num for %s\n", ((VCalFolderItem *)item)->uri ? ((VCalFolderItem *)item)->uri:"(null)");
852 *old_uids_valid = FALSE;
854 if (((VCalFolderItem *)item)->uri)
855 return feed_fetch(item, list, old_uids_valid);
857 events = vcal_get_events_list(item);
859 debug_print("get_num_list\n");
861 if (hash_uids != NULL)
862 g_hash_table_destroy(hash_uids);
864 hash_uids = g_hash_table_new_full(g_direct_hash, g_direct_equal,
867 for (cur = events; cur; cur = cur->next) {
868 VCalEvent *event = (VCalEvent *)cur->data;
872 g_hash_table_insert(hash_uids, GINT_TO_POINTER(n_msg), g_strdup(event->uid));
874 if (event->rec_occurrence) {
875 vcal_manager_free_event(event);
879 if (event->method != ICAL_METHOD_CANCEL) {
881 VCAL_FOLDER_ADD_EVENT(event);
884 vcal_manager_free_event(event);
889 if (today_msg == -1) {
890 *list = g_slist_prepend(*list, GINT_TO_POINTER(n_msg));
892 g_hash_table_insert(hash_uids, GINT_TO_POINTER(today_msg), g_strdup(EVENT_TODAY_ID));
895 g_slist_free(events);
896 vcal_folder_export(folder);
898 vcal_set_mtime(folder, item);
900 *list = g_slist_reverse(*list);
902 return g_slist_length(*list);
905 static MsgInfo *vcal_parse_msg(const gchar *file, FolderItem *item, int num)
907 MsgInfo *msginfo = NULL;
910 debug_print("parse_msg\n");
912 flags.perm_flags = 0;
914 msginfo = procheader_parse_file(file, flags, TRUE, TRUE);
916 msginfo->msgnum = num;
917 msginfo->folder = item;
921 static MsgInfo *vcal_get_msginfo(Folder * folder,
922 FolderItem * item, gint num)
924 MsgInfo *msginfo = NULL;
927 debug_print("get_msginfo\n");
929 g_return_val_if_fail(item != NULL, NULL);
930 g_return_val_if_fail(num > 0, NULL);
932 file = vcal_fetch_msg(folder, item, num);
938 msginfo = vcal_parse_msg(file, item, num);
941 msginfo->flags.perm_flags = 0;
942 msginfo->flags.tmp_flags = 0;
944 vcal_change_flags(NULL, NULL, msginfo, 0);
946 debug_print(" adding %d\n", num);
951 debug_print(" got msginfo %p\n", msginfo);
956 static gchar *feed_fetch_item(FolderItem * fitem, gint num)
958 gchar *filename = NULL;
959 VCalFolderItem *item = (VCalFolderItem *)fitem;
962 IcalFeedData *data = NULL;
964 if (!item->numlist) {
965 folder_item_scan_full(fitem, FALSE);
967 if (!item->numlist) {
968 debug_print("numlist null\n");
972 ncur = item->numlist;
973 ecur = item->evtlist;
976 if (!ncur || !ecur) {
977 debug_print("list short end (%d to %d) %d,%d\n", i, num, ncur!=NULL, ecur!=NULL);
985 data = (IcalFeedData *)ecur->data;
992 filename = vcal_manager_icalevent_dump(data->event, fitem->name, NULL);
993 else if (data->pseudoevent_id) {
994 filename = vcal_manager_dateevent_dump(data->pseudoevent_id, fitem);
995 created_files = g_slist_prepend(created_files, g_strdup(filename));
997 debug_print("no event\n");
1001 debug_print("feed item dump to %s\n", filename);
1005 static gchar *vcal_fetch_msg(Folder * folder, FolderItem * item,
1008 gchar *filename = NULL;
1009 const gchar *uid = NULL;
1011 debug_print(" fetch for %s %d\n", (((VCalFolderItem *)item)->uri ? ((VCalFolderItem *)item)->uri:"(null)"), num);
1012 if (((VCalFolderItem *)item)->uri)
1013 return feed_fetch_item(item, num);
1017 folder_item_scan_full(item, FALSE);
1018 uid = g_hash_table_lookup(hash_uids, GINT_TO_POINTER(num));
1021 (!strcmp(uid, EVENT_PAST_ID) ||
1022 !strcmp(uid, EVENT_TODAY_ID) ||
1023 !strcmp(uid, EVENT_TOMORROW_ID) ||
1024 !strcmp(uid, EVENT_THISWEEK_ID) ||
1025 !strcmp(uid, EVENT_LATER_ID))) {
1026 filename = vcal_manager_dateevent_dump(uid, item);
1028 VCalEvent *event = NULL;
1029 event = vcal_manager_load_event(uid);
1031 filename = vcal_manager_event_dump(event, FALSE, TRUE, NULL, FALSE);
1034 created_files = g_slist_prepend(created_files, g_strdup(filename));
1037 vcal_manager_free_event(event);
1043 static gint vcal_add_msg(Folder *folder, FolderItem *_dest, const gchar *file, MsgFlags *flags)
1045 gchar *contents = file_read_to_str(file);
1047 vcal_add_event(contents);
1053 static void vcal_remove_event (Folder *folder, MsgInfo *msginfo);
1055 static gint vcal_remove_msg(Folder *folder, FolderItem *_item, gint num)
1057 MsgInfo *msginfo = folder_item_get_msginfo(_item, num);
1062 if (_item == folder->inbox)
1063 vcal_remove_event(folder, msginfo);
1065 procmsg_msginfo_free(&msginfo);
1069 static FolderItem *vcal_create_folder(Folder * folder,
1070 FolderItem * parent,
1074 FolderItem *newitem = NULL;
1075 debug_print("creating new vcal folder\n");
1077 path = g_strconcat((parent->path != NULL) ? parent->path : "", ".", name, NULL);
1078 newitem = folder_item_new(folder, name, path);
1079 folder_item_append(parent, newitem);
1085 static gint vcal_create_tree(Folder *folder)
1087 FolderItem *rootitem, *inboxitem;
1088 GNode *rootnode, *inboxnode;
1090 if (!folder->node) {
1091 rootitem = folder_item_new(folder, folder->name, NULL);
1092 rootitem->folder = folder;
1093 rootnode = g_node_new(rootitem);
1094 folder->node = rootnode;
1095 rootitem->node = rootnode;
1097 rootitem = FOLDER_ITEM(folder->node->data);
1098 rootnode = folder->node;
1101 /* Add inbox folder */
1102 if (!folder->inbox) {
1103 inboxitem = folder_item_new(folder, _("Meetings"), ".meetings");
1104 inboxitem->folder = folder;
1105 inboxitem->stype = F_INBOX;
1106 inboxnode = g_node_new(inboxitem);
1107 inboxitem->node = inboxnode;
1108 folder->inbox = inboxitem;
1109 g_node_append(rootnode, inboxnode);
1111 g_free(folder->inbox->path);
1112 folder->inbox->path = g_strdup(".meetings");
1115 debug_print("created new vcal tree\n");
1119 static gint vcal_remove_folder(Folder *folder, FolderItem *fitem)
1121 VCalFolderItem *item = (VCalFolderItem *)fitem;
1131 folder_item_remove(fitem);
1136 static gboolean vcal_scan_required(Folder *folder, FolderItem *item)
1139 VCalFolderItem *vitem = (VCalFolderItem *)item;
1141 g_return_val_if_fail(item != NULL, FALSE);
1145 } else if (g_stat(vcal_manager_get_event_path(), &s) < 0) {
1147 } else if ((s.st_mtime > item->mtime) &&
1148 (s.st_mtime - 3600 != item->mtime)) {
1154 static gint vcal_folder_lock_count = 0;
1156 static void vcal_set_mtime(Folder *folder, FolderItem *item)
1159 gchar *path = folder_item_get_path(item);
1161 if (folder->inbox != item)
1164 g_return_if_fail(path != NULL);
1166 if (g_stat(path, &s) < 0) {
1167 FILE_OP_ERROR(path, "stat");
1172 item->mtime = s.st_mtime;
1173 debug_print("VCAL: forced mtime of %s to %lld\n",
1174 item->name?item->name:"(null)", (long long)item->mtime);
1178 void vcal_folder_export(Folder *folder)
1180 FolderItem *item = folder?folder->inbox:NULL;
1181 gboolean need_scan = folder?vcal_scan_required(folder, item):TRUE;
1182 gchar *export_pass = NULL;
1183 gchar *export_freebusy_pass = NULL;
1185 if (vcal_folder_lock_count) /* blocked */
1187 vcal_folder_lock_count++;
1189 export_pass = vcal_passwd_get("export");
1190 export_freebusy_pass = vcal_passwd_get("export_freebusy");
1192 if (vcal_meeting_export_calendar(vcalprefs.export_path,
1193 vcalprefs.export_user,
1196 debug_print("exporting calendar\n");
1197 if (vcalprefs.export_enable &&
1198 vcalprefs.export_command &&
1199 strlen(vcalprefs.export_command))
1200 execute_command_line(
1201 vcalprefs.export_command, TRUE, NULL);
1203 if (export_pass != NULL) {
1204 memset(export_pass, 0, strlen(export_pass));
1206 g_free(export_pass);
1207 if (vcal_meeting_export_freebusy(vcalprefs.export_freebusy_path,
1208 vcalprefs.export_freebusy_user,
1209 export_freebusy_pass)) {
1210 debug_print("exporting freebusy\n");
1211 if (vcalprefs.export_freebusy_enable &&
1212 vcalprefs.export_freebusy_command &&
1213 strlen(vcalprefs.export_freebusy_command))
1214 execute_command_line(
1215 vcalprefs.export_freebusy_command, TRUE, NULL);
1217 if (export_freebusy_pass != NULL) {
1218 memset(export_freebusy_pass, 0, strlen(export_freebusy_pass));
1220 g_free(export_freebusy_pass);
1221 vcal_folder_lock_count--;
1222 if (!need_scan && folder) {
1223 vcal_set_mtime(folder, folder->inbox);
1227 static void vcal_remove_event (Folder *folder, MsgInfo *msginfo)
1229 const gchar *uid = msginfo->msgid;
1230 VCalFolderItem *item = (VCalFolderItem *)msginfo->folder;
1233 gchar *file = vcal_manager_get_event_file(uid);
1238 if (!item || !item->batching)
1239 vcal_folder_export(folder);
1245 static void vcal_change_flags(Folder *folder, FolderItem *_item, MsgInfo *msginfo, MsgPermFlags newflags)
1249 if (newflags & MSG_DELETED) {
1250 /* delete the stuff */
1251 msginfo->flags.perm_flags |= MSG_DELETED;
1252 vcal_remove_event(folder, msginfo);
1256 /* accept the rest */
1257 msginfo->flags.perm_flags = newflags;
1260 msginfo->flags.perm_flags &= ~MSG_CLABEL_FLAG_MASK;
1262 date = event_to_today(NULL, msginfo->date_t);
1267 msginfo->flags.perm_flags |= MSG_COLORLABEL_TO_FLAGS(2); /* Red */
1269 case EVENT_TOMORROW:
1271 case EVENT_THISWEEK:
1276 if (msginfo->msgid) {
1277 if (!strcmp(msginfo->msgid, EVENT_TODAY_ID) ||
1278 !strcmp(msginfo->msgid, EVENT_TOMORROW_ID))
1279 msginfo->flags.perm_flags |= MSG_MARKED;
1283 void vcal_folder_gtk_init(void)
1285 vcal_fill_popup_menu_labels();
1287 folderview_register_popup(&vcal_popup);
1290 void vcal_folder_gtk_done(void)
1292 GSList *cur = created_files;
1294 gchar *file = (gchar *)cur->data;
1298 debug_print("removing %s\n", file);
1302 g_slist_free(created_files);
1303 folderview_unregister_popup(&vcal_popup);
1306 static void add_menuitems(GtkUIManager *ui_manager, FolderItem *item)
1308 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "NewMeeting", "FolderViewPopup/NewMeeting", GTK_UI_MANAGER_MENUITEM)
1309 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "ExportCal", "FolderViewPopup/ExportCal", GTK_UI_MANAGER_MENUITEM)
1310 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorVcal1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1311 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SubscribeCal", "FolderViewPopup/SubscribeCal", GTK_UI_MANAGER_MENUITEM)
1312 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "UnsubscribeCal", "FolderViewPopup/UnsubscribeCal", GTK_UI_MANAGER_MENUITEM)
1313 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorVcal2", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1314 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RenameFolder", "FolderViewPopup/RenameFolder", GTK_UI_MANAGER_MENUITEM)
1315 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorVcal3", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1316 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "CheckSubs", "FolderViewPopup/CheckSubs", GTK_UI_MANAGER_MENUITEM)
1317 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorVcal4", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1318 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "ListView", "FolderViewPopup/ListView", GTK_UI_MANAGER_MENUITEM)
1319 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "WeekView", "FolderViewPopup/WeekView", GTK_UI_MANAGER_MENUITEM)
1320 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MonthView", "FolderViewPopup/MonthView", GTK_UI_MANAGER_MENUITEM)
1321 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorVcal5", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1324 static gboolean setting_sensitivity = FALSE;
1325 static void set_sensitivity(GtkUIManager *ui_manager, FolderItem *fitem)
1327 VCalFolderItem *item = (VCalFolderItem *)fitem;
1329 #define SET_SENS(name, sens) \
1330 cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
1332 setting_sensitivity = TRUE;
1334 cm_toggle_menu_set_active_full(ui_manager, "Popup/FolderViewPopup/ListView", (item->use_cal_view == 0));
1335 cm_toggle_menu_set_active_full(ui_manager, "Popup/FolderViewPopup/WeekView", (item->use_cal_view == 1));
1336 cm_toggle_menu_set_active_full(ui_manager, "Popup/FolderViewPopup/MonthView", (item->use_cal_view == 2));
1337 SET_SENS("FolderViewPopup/NewMeeting", item->uri == NULL);
1338 SET_SENS("FolderViewPopup/ExportCal", TRUE);
1339 SET_SENS("FolderViewPopup/SubscribeCal", item->uri == NULL);
1340 SET_SENS("FolderViewPopup/UnsubscribeCal", item->uri != NULL);
1341 SET_SENS("FolderViewPopup/RenameFolder", folder_item_parent(fitem) != NULL);
1342 SET_SENS("FolderViewPopup/CheckSubs", TRUE);
1343 SET_SENS("FolderViewPopup/ListView", folder_item_parent(fitem) != NULL);
1344 SET_SENS("FolderViewPopup/WeekView", folder_item_parent(fitem) != NULL);
1345 SET_SENS("FolderViewPopup/MonthView", folder_item_parent(fitem) != NULL);
1346 setting_sensitivity = FALSE;
1350 static void new_meeting_cb(GtkAction *action, gpointer data)
1352 debug_print("new_meeting_cb\n");
1353 vcal_meeting_create(NULL);
1356 GSList * vcal_folder_get_waiting_events(void)
1358 Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
1359 return vcal_get_events_list(folder->inbox);
1362 typedef struct _get_webcal_data {
1367 static gboolean get_webcal_events_func(GNode *node, gpointer user_data)
1369 FolderItem *item = node->data;
1370 GetWebcalData *data = user_data;
1371 gboolean dummy = FALSE;
1372 GSList *list = NULL, *cur = NULL;
1374 if (data->item && data->item != item)
1377 feed_fetch(item, &list, &dummy);
1381 for (cur = ((VCalFolderItem *)item)->evtlist; cur; cur = cur->next) {
1382 IcalFeedData *fdata = (IcalFeedData *)cur->data;
1384 data->list = g_slist_prepend(data->list, fdata->event);
1389 GSList * vcal_folder_get_webcal_events(void)
1391 GetWebcalData *data = g_new0(GetWebcalData, 1);
1392 Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
1393 GSList *list = NULL;
1395 g_node_traverse(folder->node, G_PRE_ORDER,
1396 G_TRAVERSE_ALL, -1, get_webcal_events_func, data);
1401 return g_slist_reverse(list);
1404 static gboolean vcal_free_data_func(GNode *node, gpointer user_data)
1406 VCalFolderItem *item = node->data;
1409 icalcomponent_free(item->cal);
1412 if (item->numlist) {
1413 g_slist_free(item->numlist);
1414 item->numlist = NULL;
1417 if (item->evtlist) {
1418 slist_free_icalfeeddata(item->evtlist);
1419 g_slist_free(item->evtlist);
1420 item->evtlist = NULL;
1426 void vcal_folder_free_data(void)
1428 Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
1430 g_node_traverse(folder->node, G_PRE_ORDER,
1431 G_TRAVERSE_ALL, -1, vcal_free_data_func, NULL);
1434 GSList * vcal_folder_get_webcal_events_for_folder(FolderItem *item)
1436 GetWebcalData *data = g_new0(GetWebcalData, 1);
1437 Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
1438 GSList *list = NULL;
1440 g_node_traverse(folder->node, G_PRE_ORDER,
1441 G_TRAVERSE_ALL, -1, get_webcal_events_func, data);
1446 return g_slist_reverse(list);
1449 gchar* get_item_event_list_for_date(FolderItem *item, EventTime date)
1451 GSList *strs = NULL;
1453 gchar *result = NULL;
1454 gchar *datestr = NULL;
1456 if (((VCalFolderItem *)item)->uri) {
1457 for (cur = ((VCalFolderItem *)item)->evtlist; cur; cur = cur->next) {
1458 IcalFeedData *fdata = (IcalFeedData *)cur->data;
1460 struct icaltimetype itt;
1461 gchar *summary = NULL;
1465 prop = icalcomponent_get_first_property((icalcomponent *)fdata->event, ICAL_DTSTART_PROPERTY);
1469 itt = icalproperty_get_dtstart(prop);
1470 days = event_to_today(NULL, icaltime_as_timet(itt));
1473 prop = icalcomponent_get_first_property((icalcomponent *)fdata->event, ICAL_SUMMARY_PROPERTY);
1475 if (!g_utf8_validate(icalproperty_get_summary(prop), -1, NULL))
1476 summary = conv_codeset_strdup(icalproperty_get_summary(prop),
1477 conv_get_locale_charset_str(), CS_UTF_8);
1479 summary = g_strdup(icalproperty_get_summary(prop));
1481 summary = g_strdup("-");
1483 strs = g_slist_prepend(strs, summary);
1486 GSList *evtlist = vcal_folder_get_waiting_events();
1487 for (cur = evtlist; cur; cur = cur->next) {
1488 VCalEvent *event = (VCalEvent *)cur->data;
1490 days = event_to_today(event, 0);
1491 gchar *summary = NULL;
1493 summary = g_strdup(event->summary);
1494 strs = g_slist_prepend(strs, summary);
1496 vcal_manager_free_event(event);
1502 datestr=_("in the past");
1507 case EVENT_TOMORROW:
1508 datestr=_("tomorrow");
1510 case EVENT_THISWEEK:
1511 datestr=_("this week");
1518 result = g_strdup_printf(_("\nThese are the events planned %s:\n"),
1519 datestr?datestr:"never");
1521 strs = g_slist_reverse(strs);
1522 for (cur = strs; cur; cur = cur->next) {
1523 int e_len = strlen(result);
1524 int n_len = strlen((gchar *)cur->data);
1526 result = g_realloc(result, e_len+n_len+4);
1527 *(result+e_len) = '\n';
1528 strcpy(result+e_len+1, "- ");
1529 strcpy(result+e_len+3, (gchar *)cur->data);
1531 result = g_realloc(result, e_len+n_len+3);
1532 strcpy(result+e_len, "- ");
1533 strcpy(result+e_len+2, (gchar *)cur->data);
1536 slist_free_strings_full(strs);
1540 static void export_cal_cb(GtkAction *action, gpointer data)
1542 vcal_meeting_export_calendar(NULL, NULL, NULL, FALSE);
1549 static size_t curl_recv(void *buf, size_t size, size_t nmemb, void *stream)
1551 struct CBuf *buffer = (struct CBuf *)stream;
1553 gchar tmpbuf[size*nmemb + 1];
1555 memcpy(tmpbuf, buf, size*nmemb);
1556 tmpbuf[size*nmemb] = '\0';
1559 tmp = g_strconcat(buffer->str, tmpbuf, NULL);
1560 g_free(buffer->str);
1563 buffer->str = g_strdup(tmpbuf);
1569 void *url_read_thread(void *data)
1571 thread_data *td = (thread_data *)data;
1573 CURL *curl_ctx = NULL;
1575 struct CBuf buffer = { NULL };
1576 gchar *t_url = (gchar *)td->url;
1578 while (*t_url == ' ')
1580 if (strchr(t_url, ' '))
1581 *(strchr(t_url, ' ')) = '\0';
1584 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
1585 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
1588 curl_ctx = curl_easy_init();
1590 curl_easy_setopt(curl_ctx, CURLOPT_URL, t_url);
1591 curl_easy_setopt(curl_ctx, CURLOPT_WRITEFUNCTION, curl_recv);
1592 curl_easy_setopt(curl_ctx, CURLOPT_WRITEDATA, &buffer);
1593 curl_easy_setopt(curl_ctx, CURLOPT_TIMEOUT, prefs_common_get_prefs()->io_timeout_secs);
1594 curl_easy_setopt(curl_ctx, CURLOPT_NOSIGNAL, 1);
1595 #if LIBCURL_VERSION_NUM >= 0x070a00
1596 if(vcalprefs.ssl_verify_peer == FALSE) {
1597 curl_easy_setopt(curl_ctx, CURLOPT_SSL_VERIFYPEER, 0);
1598 curl_easy_setopt(curl_ctx, CURLOPT_SSL_VERIFYHOST, 0);
1601 curl_easy_setopt(curl_ctx, CURLOPT_USERAGENT,
1602 "Claws Mail vCalendar plugin "
1603 "(" PLUGINS_URI ")");
1604 curl_easy_setopt(curl_ctx, CURLOPT_FOLLOWLOCATION, 1);
1605 res = curl_easy_perform(curl_ctx);
1608 debug_print("res %d %s\n", res, curl_easy_strerror(res));
1609 td->error = g_strdup(curl_easy_strerror(res));
1611 if(res == CURLE_OPERATION_TIMEOUTED)
1612 log_error(LOG_PROTOCOL, _("Timeout (%d seconds) connecting to %s\n"),
1613 prefs_common_get_prefs()->io_timeout_secs, t_url);
1616 curl_easy_getinfo(curl_ctx, CURLINFO_RESPONSE_CODE, &response_code);
1617 if( response_code >= 400 && response_code < 500 ) {
1618 debug_print("VCalendar: got %ld\n", response_code);
1619 switch(response_code) {
1621 td->error = g_strdup(_("401 (Authorisation required)"));
1624 td->error = g_strdup(_("403 (Unauthorised)"));
1627 td->error = g_strdup(_("404 (Not found)"));
1630 td->error = g_strdup_printf(_("Error %ld"), response_code);
1634 curl_easy_cleanup(curl_ctx);
1636 td->result = g_strdup(buffer.str);
1640 td->done = TRUE; /* let the caller thread join() */
1641 return GINT_TO_POINTER(0);
1644 gchar *vcal_curl_read(const char *url, const gchar *label, gboolean verbose,
1645 void (*callback)(const gchar *url, gchar *data, gboolean verbose, gchar *error))
1653 gchar *error = NULL;
1655 td = g_new0(thread_data, 1);
1662 STATUSBAR_PUSH(mainwindow_get_mainwindow(), label);
1665 if (pthread_create(&pt, NULL, url_read_thread, td) != 0) {
1666 url_read_thread(td);
1672 pthread_join(pt, &res);
1674 url_read_thread(td);
1677 result = td->result;
1681 STATUSBAR_POP(mainwindow_get_mainwindow());
1684 callback(url, result, verbose, error);
1693 gboolean vcal_curl_put(gchar *url, FILE *fp, gint filesize, const gchar *user, const gchar *pass)
1695 gboolean res = TRUE;
1696 CURL *curl_ctx = curl_easy_init();
1697 long response_code = 0;
1699 gchar *userpwd = NULL;
1701 struct curl_slist * headers = curl_slist_append(NULL,
1702 "Content-Type: text/calendar; charset=\"utf-8\"" );
1704 while (*t_url == ' ')
1706 if (strchr(t_url, ' '))
1707 *(strchr(t_url, ' ')) = '\0';
1709 if (user && pass && *user && *pass) {
1710 userpwd = g_strdup_printf("%s:%s",user,pass);
1711 curl_easy_setopt(curl_ctx, CURLOPT_USERPWD, userpwd);
1713 curl_easy_setopt(curl_ctx, CURLOPT_URL, t_url);
1714 curl_easy_setopt(curl_ctx, CURLOPT_UPLOAD, 1);
1715 curl_easy_setopt(curl_ctx, CURLOPT_READFUNCTION, NULL);
1716 curl_easy_setopt(curl_ctx, CURLOPT_READDATA, fp);
1717 curl_easy_setopt(curl_ctx, CURLOPT_HTTPHEADER, headers);
1718 #if LIBCURL_VERSION_NUM >= 0x070a00
1719 if(vcalprefs.ssl_verify_peer == FALSE) {
1720 curl_easy_setopt(curl_ctx, CURLOPT_SSL_VERIFYPEER, 0);
1721 curl_easy_setopt(curl_ctx, CURLOPT_SSL_VERIFYHOST, 0);
1724 curl_easy_setopt(curl_ctx, CURLOPT_USERAGENT,
1725 "Claws Mail vCalendar plugin "
1726 "(" PLUGINS_URI ")");
1727 curl_easy_setopt(curl_ctx, CURLOPT_INFILESIZE, filesize);
1728 res = curl_easy_perform(curl_ctx);
1732 debug_print("res %d %s\n", res, curl_easy_strerror(res));
1737 curl_easy_getinfo(curl_ctx, CURLINFO_RESPONSE_CODE, &response_code);
1738 if (response_code < 200 || response_code >= 300) {
1739 g_warning("Can't export calendar, got code %ld", response_code);
1742 curl_easy_cleanup(curl_ctx);
1743 curl_slist_free_all(headers);
1747 static gboolean folder_item_find_func(GNode *node, gpointer data)
1749 FolderItem *item = node->data;
1751 const gchar *uri = d[0];
1753 if (!uri || !((VCalFolderItem *)item)->uri
1754 || strcmp(uri, ((VCalFolderItem *)item)->uri))
1762 static FolderItem *get_folder_item_for_uri(const gchar *uri)
1764 Folder *root = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
1770 d[0] = (gpointer)uri;
1772 g_node_traverse(root->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1773 folder_item_find_func, d);
1777 static gchar *feed_get_title(const gchar *str)
1779 gchar *title = NULL;
1780 if (strstr(str, "X-WR-CALNAME:")) {
1781 title = g_strdup(strstr(str, "X-WR-CALNAME:")+strlen("X-WR-CALNAME:"));
1782 if (strstr(title, "\n"))
1783 *(strstr(title, "\n")) = '\0';
1784 if (strstr(title, "\r"))
1785 *(strstr(title, "\r")) = '\0';
1786 } else if (strstr(str, "X-WR-CALDESC:")) {
1787 title = g_strdup(strstr(str, "X-WR-CALDESC:")+strlen("X-WR-CALDESC:"));
1788 if (strstr(title, "\n"))
1789 *(strstr(title, "\n")) = '\0';
1790 if (strstr(title, "\r"))
1791 *(strstr(title, "\r")) = '\0';
1797 static void update_subscription_finish(const gchar *uri, gchar *feed, gboolean verbose, gchar *error)
1799 Folder *root = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
1800 FolderItem *item = NULL;
1801 icalcomponent *cal = NULL;
1804 g_warning("can't get root folder");
1812 gchar *err_msg = _("Could not retrieve the Webcal URL:\n%s:\n\n%s");
1814 if (verbose && manual_update) {
1815 gchar *tmp = g_strdup(uri);
1816 if (strlen(uri) > 61) {
1824 alertpanel_error(err_msg, tmp, error ? error:_("Unknown error"));
1827 gchar *msg = g_strdup_printf("%s\n", err_msg);
1828 log_error(LOG_PROTOCOL, msg, uri, error ? error:_("Unknown error"));
1831 main_window_cursor_normal(mainwindow_get_mainwindow());
1839 while (*tmp && isspace((unsigned char)*tmp))
1842 if (strncmp(tmp, "BEGIN:VCALENDAR", strlen("BEGIN:VCALENDAR"))) {
1843 gchar *err_msg = _("This URL does not look like a Webcal URL:\n%s\n%s");
1845 if (verbose && manual_update) {
1846 alertpanel_error(err_msg, uri, error ? error:_("Unknown error"));
1848 gchar *msg = g_strdup_printf("%s\n", err_msg);
1849 log_error(LOG_PROTOCOL, msg, uri, error ? error:_("Unknown error"));
1853 main_window_cursor_normal(mainwindow_get_mainwindow());
1861 item = get_folder_item_for_uri(uri);
1863 gchar *title = feed_get_title(feed);
1864 if (title == NULL) {
1865 if (strstr(uri, "://"))
1866 title = g_path_get_basename(strstr(uri,"://")+3);
1868 title = g_strdup(uri);
1869 subst_for_filename(title);
1871 item = folder_create_folder(root->node->data, title);
1873 if (verbose && manual_update) {
1874 alertpanel_error(_("Could not create directory %s"),
1877 log_error(LOG_PROTOCOL, _("Could not create directory %s"),
1882 main_window_cursor_normal(mainwindow_get_mainwindow());
1885 debug_print("item done %s\n", title);
1886 ((VCalFolderItem *)item)->uri = g_strdup(uri);
1887 ((VCalFolderItem *)item)->feed = feed;
1890 if (((VCalFolderItem *)item)->feed)
1891 g_free(((VCalFolderItem *)item)->feed);
1893 ((VCalFolderItem *)item)->feed = feed;
1894 /* if title differs, update it */
1896 cal = icalparser_parse_string(feed);
1898 convert_to_utc(cal);
1900 if (((VCalFolderItem *)item)->cal)
1901 icalcomponent_free(((VCalFolderItem *)item)->cal);
1903 ((VCalFolderItem *)item)->cal = cal;
1905 main_window_cursor_normal(mainwindow_get_mainwindow());
1906 ((VCalFolderItem *)item)->last_fetch = time(NULL);
1909 static void update_subscription(const gchar *uri, gboolean verbose)
1911 FolderItem *item = get_folder_item_for_uri(uri);
1914 if (prefs_common_get_prefs()->work_offline) {
1916 !inc_offline_should_override(TRUE,
1917 _("Claws Mail needs network access in order "
1918 "to update the Webcal feed.")))
1922 if (time(NULL) - ((VCalFolderItem *)(item))->last_fetch < 60 &&
1923 ((VCalFolderItem *)(item))->cal)
1926 main_window_cursor_wait(mainwindow_get_mainwindow());
1928 label = g_strdup_printf(_("Fetching calendar for %s..."),
1929 item && item->name ? item->name : _("new subscription"));
1930 vcal_curl_read(uri, label, verbose, update_subscription_finish);
1934 static void check_subs_cb(GtkAction *action, gpointer data)
1936 Folder *root = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
1938 if (prefs_common_get_prefs()->work_offline &&
1939 !inc_offline_should_override(TRUE,
1940 _("Claws Mail needs network access in order "
1941 "to update the subscription.")))
1944 folderview_check_new(root);
1947 static void subscribe_cal_cb(GtkAction *action, gpointer data)
1952 tmp = input_dialog(_("Subscribe to Webcal"), _("Enter the Webcal URL:"), NULL);
1956 if (!strncmp(tmp, "http", 4)) {
1958 } else if (!strncmp(tmp, "file://", 7)) {
1960 } else if (!strncmp(tmp, "webcal", 6)) {
1961 uri = g_strconcat("http", tmp+6, NULL);
1964 alertpanel_error(_("Could not parse the URL."));
1968 debug_print("uri %s\n", uri);
1970 update_subscription(uri, TRUE);
1971 folder_write_list();
1975 static void unsubscribe_cal_cb(GtkAction *action, gpointer data)
1977 FolderView *folderview = (FolderView *)data;
1978 FolderItem *item, *opened;
1983 if (!folderview->selected) return;
1985 item = folderview_get_selected_item(folderview);
1986 g_return_if_fail(item != NULL);
1987 g_return_if_fail(item->path != NULL);
1988 g_return_if_fail(item->folder != NULL);
1989 opened = folderview_get_opened_item(folderview);
1991 message = g_strdup_printf
1992 (_("Do you really want to unsubscribe?"));
1993 avalue = alertpanel_full(_("Delete subscription"), message,
1994 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_FIRST,
1995 FALSE, NULL, ALERT_WARNING);
1997 if (avalue != G_ALERTALTERNATE) return;
1999 old_id = folder_item_get_identifier(item);
2001 vcal_item_closed(item);
2003 if (item == opened ||
2004 folder_is_child_of(item, opened)) {
2005 summary_clear_all(folderview->summaryview);
2006 folderview_close_opened(folderview, TRUE);
2009 if (item->folder->klass->remove_folder(item->folder, item) < 0) {
2010 folder_item_scan(item);
2011 alertpanel_error(_("Can't remove the folder '%s'."), item->name);
2016 folder_write_list();
2018 prefs_filtering_delete_path(old_id);
2022 gboolean vcal_subscribe_uri(Folder *folder, const gchar *uri)
2025 if (folder->klass != vcal_folder_get_class())
2031 if (!strncmp(uri, "webcal", 6)) {
2032 tmp = g_strconcat("http", uri+6, NULL);
2036 debug_print("uri %s\n", tmp);
2038 update_subscription(tmp, FALSE);
2039 folder_write_list();
2043 static void rename_cb(GtkAction *action, gpointer data)
2045 FolderView *folderview = (FolderView *)data;
2051 item = folderview_get_selected_item(folderview);
2052 g_return_if_fail(item != NULL);
2053 g_return_if_fail(item->path != NULL);
2054 g_return_if_fail(item->folder != NULL);
2056 name = trim_string(item->name, 32);
2057 message = g_strdup_printf(_("Input new name for '%s':"), name);
2058 new_folder = input_dialog(_("Rename folder"), message, name);
2061 if (!new_folder) return;
2062 AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
2064 if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
2065 alertpanel_error(_("'%c' can't be included in folder name."),
2070 if (folder_find_child_item_by_name(folder_item_parent(item), new_folder)) {
2071 name = trim_string(new_folder, 32);
2072 alertpanel_error(_("The folder '%s' already exists."), name);
2077 if (folder_item_rename(item, new_folder) < 0) {
2078 alertpanel_error(_("The folder could not be renamed.\n"
2079 "The new folder name is not allowed."));
2083 folder_item_prefs_save_config_recursive(item);
2084 folder_write_list();
2087 static void set_view_cb(GtkAction *gaction, GtkRadioAction *current, gpointer data)
2089 FolderView *folderview = (FolderView *)data;
2090 gint action = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (current));
2091 FolderItem *item = NULL, *oitem = NULL;
2093 if (!folderview->selected) return;
2094 if (setting_sensitivity) return;
2096 oitem = folderview_get_opened_item(folderview);
2097 item = folderview_get_selected_item(folderview);
2102 if (((VCalFolderItem *)(item))->use_cal_view == action)
2104 debug_print("set view %d\n", action);
2105 if (oitem && item == oitem && oitem->folder->klass == vcal_folder_get_class())
2106 oitem->folder->klass->item_closed(oitem);
2107 ((VCalFolderItem *)(item))->use_cal_view = action;
2108 if (((VCalFolderItem *)(item))->use_cal_view) {
2109 if (oitem && item == oitem && oitem->folder->klass == vcal_folder_get_class())
2110 oitem->folder->klass->item_opened(oitem);
2114 gchar *vcal_get_event_as_ical_str(VCalEvent *event)
2117 icalcomponent *calendar = icalcomponent_vanew(
2118 ICAL_VCALENDAR_COMPONENT,
2119 icalproperty_new_version("2.0"),
2120 icalproperty_new_prodid(
2121 "-//Claws Mail//NONSGML Claws Mail Calendar//EN"),
2122 icalproperty_new_calscale("GREGORIAN"),
2124 vcal_manager_event_dump(event, FALSE, FALSE, calendar, FALSE);
2125 ical = g_strdup(icalcomponent_as_ical_string(calendar));
2126 icalcomponent_free(calendar);
2131 static gchar *get_name_from_property(icalproperty *p)
2135 if (p && icalproperty_get_parameter_as_string(p, "CN") != NULL)
2136 tmp = g_strdup(icalproperty_get_parameter_as_string(p, "CN"));
2141 static gchar *get_email_from_property(icalproperty *p)
2144 gchar *email = NULL;
2147 tmp = g_strdup(icalproperty_get_organizer(p));
2152 if (!strncasecmp(tmp, "MAILTO:", strlen("MAILTO:")))
2153 email = g_strdup(tmp+strlen("MAILTO:"));
2155 email = g_strdup(tmp);
2161 static void convert_to_utc(icalcomponent *calendar)
2163 icalcomponent *event;
2164 icaltimezone *tz, *tzutc = icaltimezone_get_utc_timezone();
2166 icalparameter *tzid;
2168 cm_return_if_fail(calendar != NULL);
2171 event = icalcomponent_get_first_component(calendar,
2172 ICAL_VEVENT_COMPONENT);
2174 event = icalcomponent_get_next_component(calendar,
2175 ICAL_VEVENT_COMPONENT)) {
2178 if ((prop = icalcomponent_get_first_property(event, ICAL_DTSTART_PROPERTY)) != NULL
2179 && (tzid = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER)) != NULL) {
2180 /* Event has its DTSTART with a timezone specification, let's convert
2181 * to UTC and remove the TZID parameter. */
2183 tz = icalcomponent_get_timezone(calendar, icalparameter_get_iana_value(tzid));
2185 debug_print("Converting DTSTART to UTC.\n");
2186 icaltimetype t = icalproperty_get_dtstart(prop);
2187 icaltimezone_convert_time(&t, tz, tzutc);
2188 icalproperty_set_dtstart(prop, t);
2189 icalproperty_remove_parameter_by_ref(prop, tzid);
2194 if ((prop = icalcomponent_get_first_property(event, ICAL_DTEND_PROPERTY)) != NULL
2195 && (tzid = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER)) != NULL) {
2196 /* Event has its DTEND with a timezone specification, let's convert
2197 * to UTC and remove the TZID parameter. */
2199 tz = icalcomponent_get_timezone(calendar, icalparameter_get_iana_value(tzid));
2201 debug_print("Converting DTEND to UTC.\n");
2202 icaltimetype t = icalproperty_get_dtend(prop);
2203 icaltimezone_convert_time(&t, tz, tzutc);
2204 icalproperty_set_dtend(prop, t);
2205 icalproperty_remove_parameter_by_ref(prop, tzid);
2211 #define GET_PROP(comp,prop,kind) { \
2213 if (!(prop = icalcomponent_get_first_property(comp, kind))) { \
2215 ? icalcomponent_get_first_property(inner, kind) \
2220 #define GET_PROP_LIST(comp,list,kind) { \
2222 if (!(prop = icalcomponent_get_first_property(comp, kind))) { \
2224 ? icalcomponent_get_first_property(inner, kind) \
2227 list = g_slist_prepend(list, prop); \
2228 } while ((prop = icalcomponent_get_next_property(inner, kind)));\
2230 list = g_slist_prepend(list, prop); \
2231 } while ((prop = icalcomponent_get_next_property(comp, kind))); \
2234 #define TO_UTF8(string) { \
2235 if (string && !g_utf8_validate(string, -1, NULL)) { \
2236 gchar *tmp = conv_codeset_strdup(string, \
2237 charset ? charset:conv_get_locale_charset_str(),\
2244 VCalEvent *vcal_get_event_from_ical(const gchar *ical, const gchar *charset)
2246 VCalEvent *event = NULL;
2247 gchar *int_ical = g_strdup(ical);
2248 icalcomponent *comp = icalcomponent_new_from_string(int_ical);
2249 icalcomponent *inner = NULL;
2250 icalproperty *prop = NULL;
2251 GSList *list = NULL, *cur = NULL;
2253 gchar *location = NULL;
2254 gchar *summary = NULL;
2255 gchar *dtstart = NULL;
2256 gchar *dtend = NULL;
2257 gchar *org_email = NULL, *org_name = NULL;
2258 gchar *description = NULL;
2261 gchar *recur = NULL;
2263 enum icalproperty_method method = ICAL_METHOD_REQUEST;
2264 enum icalcomponent_kind type = ICAL_VEVENT_COMPONENT;
2265 GSList *attendees = NULL;
2272 if ((inner = icalcomponent_get_inner(comp)) != NULL)
2273 type = icalcomponent_isa(inner);
2275 GET_PROP(comp, prop, ICAL_UID_PROPERTY);
2277 uid = g_strdup(icalproperty_get_uid(prop));
2279 icalproperty_free(prop);
2281 GET_PROP(comp, prop, ICAL_LOCATION_PROPERTY);
2283 location = g_strdup(icalproperty_get_location(prop));
2285 icalproperty_free(prop);
2287 GET_PROP(comp, prop, ICAL_SUMMARY_PROPERTY);
2289 summary = g_strdup(icalproperty_get_summary(prop));
2291 icalproperty_free(prop);
2294 convert_to_utc(comp);
2296 GET_PROP(comp, prop, ICAL_DTSTART_PROPERTY);
2298 dtstart = g_strdup(icaltime_as_ical_string(icalproperty_get_dtstart(prop)));
2300 icalproperty_free(prop);
2302 GET_PROP(comp, prop, ICAL_DTEND_PROPERTY);
2304 dtend = g_strdup(icaltime_as_ical_string(icalproperty_get_dtend(prop)));
2306 icalproperty_free(prop);
2308 GET_PROP(comp, prop, ICAL_DURATION_PROPERTY);
2310 struct icaldurationtype duration = icalproperty_get_duration(prop);
2311 struct icaltimetype itt;
2312 icalproperty_free(prop);
2313 GET_PROP(comp, prop, ICAL_DTSTART_PROPERTY);
2315 itt = icalproperty_get_dtstart(prop);
2316 icalproperty_free(prop);
2317 dtend = g_strdup(icaltime_as_ical_string(icaltime_add(itt,duration)));
2322 GET_PROP(comp, prop, ICAL_SEQUENCE_PROPERTY);
2324 sequence = icalproperty_get_sequence(prop);
2325 icalproperty_free(prop);
2327 GET_PROP(comp, prop, ICAL_METHOD_PROPERTY);
2329 method = icalproperty_get_method(prop);
2330 icalproperty_free(prop);
2332 GET_PROP(comp, prop, ICAL_ORGANIZER_PROPERTY);
2334 org_email = get_email_from_property(prop);
2336 org_name = get_name_from_property(prop);
2338 icalproperty_free(prop);
2340 GET_PROP(comp, prop, ICAL_DESCRIPTION_PROPERTY);
2342 description = g_strdup(icalproperty_get_description(prop));
2343 TO_UTF8(description);
2344 icalproperty_free(prop);
2346 GET_PROP(comp, prop, ICAL_URL_PROPERTY);
2348 url = g_strdup(icalproperty_get_url(prop));
2350 icalproperty_free(prop);
2352 GET_PROP(comp, prop, ICAL_TZID_PROPERTY);
2354 tzid = g_strdup(icalproperty_get_tzid(prop));
2356 icalproperty_free(prop);
2358 GET_PROP(comp, prop, ICAL_RRULE_PROPERTY);
2360 struct icalrecurrencetype rrule = icalproperty_get_rrule(prop);
2361 recur = g_strdup(icalrecurrencetype_as_string(&rrule));
2363 icalproperty_free(prop);
2365 GET_PROP_LIST(comp, list, ICAL_ATTENDEE_PROPERTY);
2366 for (cur = list; cur; cur = cur->next) {
2367 enum icalparameter_partstat partstat = 0;
2368 enum icalparameter_cutype cutype = 0;
2369 icalparameter *param = NULL;
2370 gchar *email = NULL;
2372 Answer *answer = NULL;
2374 prop = (icalproperty *)(cur->data);
2376 email = get_email_from_property(prop);
2378 name = get_name_from_property(prop);
2381 param = icalproperty_get_first_parameter(prop, ICAL_PARTSTAT_PARAMETER);
2383 partstat = icalparameter_get_partstat(param);
2385 param = icalproperty_get_first_parameter(prop, ICAL_CUTYPE_PARAMETER);
2387 cutype= icalparameter_get_cutype(param);
2390 partstat = ICAL_PARTSTAT_NEEDSACTION;
2392 cutype = ICAL_CUTYPE_INDIVIDUAL;
2393 answer = answer_new(email, name, partstat, cutype);
2394 attendees = g_slist_prepend(attendees, answer);
2397 icalproperty_free(prop);
2401 event = vcal_manager_new_event (uid, org_email, org_name,
2402 location, summary, description,
2403 dtstart, dtend, recur,
2405 method, sequence, type);
2406 event->answers = attendees;
2414 g_free(description);
2419 icalcomponent_free(comp);
2423 gboolean vcal_event_exists(const gchar *id)
2425 MsgInfo *info = NULL;
2426 Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
2430 info = folder_item_get_msginfo_by_msgid(folder->inbox, id);
2432 procmsg_msginfo_free(&info);
2438 void vcal_foreach_event(gboolean (*cb_func)(const gchar *vevent))
2440 GSList *list = vcal_folder_get_waiting_events();
2444 debug_print("calling cb_func...\n");
2445 for (cur = list; cur; cur = cur->next) {
2446 VCalEvent *event = (VCalEvent *)cur->data;
2447 gchar *tmp = vcal_get_event_as_ical_str(event);
2449 debug_print(" ...for event %s\n", event->uid);
2452 vcal_manager_free_event(event);
2457 /* please call vcalendar_refresh_folder_contents() after one or more
2458 * calls to this function */
2459 gboolean vcal_delete_event(const gchar *id)
2461 MsgInfo *info = NULL;
2462 Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
2466 info = folder_item_get_msginfo_by_msgid(folder->inbox, id);
2468 debug_print("removing event %s\n", id);
2469 vcal_remove_event(folder, info);
2470 procmsg_msginfo_free(&info);
2471 folder_item_scan(folder->inbox);
2474 debug_print("not removing unexisting event %s\n", id);
2478 /* please call vcalendar_refresh_folder_contents() after one or more
2479 * calls to this function */
2480 gchar* vcal_add_event(const gchar *vevent)
2482 VCalEvent *event = vcal_get_event_from_ical(vevent, NULL);
2483 gchar *retVal = NULL;
2484 Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
2489 if (vcal_event_exists(event->uid)) {
2490 debug_print("event %s already exists\n", event->uid);
2491 vcal_manager_free_event(event);
2494 debug_print("adding event %s\n", event->uid);
2495 if (!account_find_from_address(event->organizer, FALSE) &&
2496 !vcal_manager_get_account_from_event(event)) {
2497 PrefsAccount *account = account_get_default();
2498 vcal_manager_update_answer(event, account->address,
2500 ICAL_PARTSTAT_ACCEPTED,
2501 ICAL_CUTYPE_INDIVIDUAL);
2502 debug_print("can't find our accounts in event, adding default\n");
2504 vcal_manager_save_event(event, TRUE);
2505 folder_item_scan(folder->inbox);
2506 retVal = vcal_get_event_as_ical_str(event);
2507 vcal_manager_free_event(event);
2513 /* please call vcalendar_refresh_folder_contents() after one or more
2514 * calls to this function */
2515 gchar* vcal_update_event(const gchar *vevent)
2517 VCalEvent *event = vcal_get_event_from_ical(vevent, NULL);
2520 r = vcal_delete_event(event->uid);
2521 vcal_manager_free_event(event);
2523 return vcal_add_event(vevent);