2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 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, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #include "claws-features.h"
28 #include <glib/gi18n.h>
32 #include <sys/types.h>
36 #include <curl/curl.h>
37 #include <curl/curlver.h>
42 #include "procheader.h"
44 #include "folderview.h"
45 #include "vcalendar.h"
46 #include "vcal_folder.h"
47 #include "vcal_prefs.h"
48 #include "vcal_manager.h"
49 #include "vcal_meeting_gtk.h"
50 #include "vcal_interface.h"
51 #include "prefs_account.h"
52 #include "prefs_common.h"
55 #include "inputdialog.h"
58 #include "alertpanel.h"
60 #include "mainwindow.h"
61 #include "statusbar.h"
64 #include "messageview.h"
69 #define VCAL_FOLDERITEM(item) ((VCalFolderItem *) item)
75 typedef struct _thread_data {
82 typedef struct _IcalFeedData {
84 gchar *pseudoevent_id;
87 typedef struct _VCalFolder VCalFolder;
88 typedef struct _VCalFolderItem VCalFolderItem;
90 static Folder *vcal_folder_new(const gchar * name,
91 const gchar * folder);
92 static void vcal_folder_destroy(Folder * folder);
93 static void vcal_item_destroy(Folder *folder, FolderItem *_item);
94 static gchar *vcal_item_get_path(Folder *folder, FolderItem *item);
96 static gint vcal_scan_tree(Folder * folder);
97 static FolderItem *vcal_item_new(Folder * folder);
98 static gint vcal_get_num_list(Folder * folder, FolderItem * item,
99 MsgNumberList ** list,
100 gboolean * old_uids_valid);
101 static MsgInfo *vcal_get_msginfo(Folder * folder, FolderItem * item,
103 static gchar *vcal_fetch_msg(Folder * folder, FolderItem * item,
105 static gint vcal_add_msg(Folder * folder, FolderItem * _dest,
106 const gchar * file, MsgFlags * flags);
107 static gint vcal_remove_msg(Folder * folder, FolderItem * _item,
109 static FolderItem *vcal_create_folder(Folder * folder,
112 static gint vcal_create_tree(Folder *folder);
113 static gint vcal_remove_folder(Folder *folder, FolderItem *item);
114 static gboolean vcal_scan_required(Folder *folder, FolderItem *item);
115 static void vcal_set_mtime(Folder *folder, FolderItem *item);
116 static void vcal_change_flags(Folder *folder, FolderItem *_item, MsgInfo *msginfo, MsgPermFlags newflags);
118 static void new_meeting_cb(GtkAction *action, gpointer data);
119 static void export_cal_cb(GtkAction *action, gpointer data);
120 static void subscribe_cal_cb(GtkAction *action, gpointer data);
121 static void check_subs_cb(GtkAction *action, gpointer data);
122 static void unsubscribe_cal_cb(GtkAction *action, gpointer data);
123 static void rename_cb(GtkAction *action, gpointer data);
124 static void set_view_cb(GtkAction *action, GtkRadioAction *current, gpointer data);
126 static void add_menuitems(GtkUIManager *ui_manager, FolderItem *item);
127 static void set_sensitivity(GtkUIManager *ui_manager, FolderItem *item);
129 static void update_subscription(const gchar *uri, gboolean verbose);
130 static void vcal_folder_set_batch (Folder *folder,
134 gboolean vcal_subscribe_uri(Folder *folder, const gchar *uri);
136 FolderClass vcal_class;
138 static GSList *created_files = NULL;
139 static GHashTable *hash_uids = NULL;
146 struct _VCalFolderItem
162 static char *vcal_popup_labels[] =
164 N_("_New meeting..."),
165 N_("_Export calendar..."),
166 N_("_Subscribe to webCal..."),
167 N_("_Unsubscribe..."),
169 N_("U_pdate subscriptions"),
176 static GtkActionEntry vcal_popup_entries[] =
178 {"FolderViewPopup/NewMeeting", NULL, NULL, NULL, NULL, G_CALLBACK(new_meeting_cb) },
179 {"FolderViewPopup/ExportCal", NULL, NULL, NULL, NULL, G_CALLBACK(export_cal_cb) },
181 {"FolderViewPopup/SubscribeCal", NULL, NULL, NULL, NULL, G_CALLBACK(subscribe_cal_cb) },
182 {"FolderViewPopup/UnsubscribeCal", NULL, NULL, NULL, NULL, G_CALLBACK(unsubscribe_cal_cb) },
184 {"FolderViewPopup/RenameFolder", NULL, NULL, NULL, NULL, G_CALLBACK(rename_cb) },
186 {"FolderViewPopup/CheckSubs", NULL, NULL, NULL, NULL, G_CALLBACK(check_subs_cb) },
190 static GtkRadioActionEntry vcal_popup_radio_entries[] = { /* set_view_cb */
191 {"FolderViewPopup/ListView", NULL, NULL, NULL, NULL, 0 },
192 {"FolderViewPopup/WeekView", NULL, NULL, NULL, NULL, 1 },
193 {"FolderViewPopup/MonthView", NULL, NULL, NULL, NULL, 2 },
196 static IcalFeedData *icalfeeddata_new(icalcomponent *evt, gchar *str)
198 IcalFeedData *data = g_new0(IcalFeedData, 1);
200 data->pseudoevent_id = g_strdup(str);
205 static void icalfeeddata_free(IcalFeedData *data)
207 g_free(data->pseudoevent_id);
209 icalcomponent_free(data->event);
213 static void slist_free_icalfeeddata(GSList *list)
216 IcalFeedData *data = (IcalFeedData *)list->data;
217 icalfeeddata_free(data);
222 static void vcal_fill_popup_menu_labels(void)
224 vcal_popup_entries[0].label = _(vcal_popup_labels[0]);
225 vcal_popup_entries[1].label = _(vcal_popup_labels[1]);
226 vcal_popup_entries[2].label = _(vcal_popup_labels[2]);
227 vcal_popup_entries[3].label = _(vcal_popup_labels[3]);
228 vcal_popup_entries[4].label = _(vcal_popup_labels[4]);
229 vcal_popup_entries[5].label = _(vcal_popup_labels[5]);
230 vcal_popup_radio_entries[0].label = _(vcal_popup_labels[6]);
231 vcal_popup_radio_entries[1].label = _(vcal_popup_labels[7]);
232 vcal_popup_radio_entries[2].label = _(vcal_popup_labels[8]);
235 static FolderViewPopup vcal_popup =
240 G_N_ELEMENTS(vcal_popup_entries),
242 vcal_popup_radio_entries,
243 G_N_ELEMENTS(vcal_popup_radio_entries), 1, set_view_cb,
248 static void vcal_item_set_xml(Folder *folder, FolderItem *item, XMLTag *tag)
251 folder_item_set_xml(folder, item, tag);
252 gboolean found_cal_view_setting = FALSE;
254 for (cur = tag->attr; cur != NULL; cur = g_list_next(cur)) {
255 XMLAttr *attr = (XMLAttr *) cur->data;
257 if (!attr || !attr->name || !attr->value) continue;
258 if (!strcmp(attr->name, "uri")) {
259 if (((VCalFolderItem *)item)->uri != NULL)
260 g_free(((VCalFolderItem *)item)->uri);
261 ((VCalFolderItem *)item)->uri = g_strdup(attr->value);
263 if (!strcmp(attr->name, "use_cal_view")) {
264 found_cal_view_setting = TRUE;
265 ((VCalFolderItem *)item)->use_cal_view = atoi(attr->value);
268 if (((VCalFolderItem *)item)->uri == NULL) {
269 /* give a path to inbox */
271 item->path = g_strdup(".meetings");
273 if (!found_cal_view_setting)
274 ((VCalFolderItem *)item)->use_cal_view = 1; /*week view */
278 static XMLTag *vcal_item_get_xml(Folder *folder, FolderItem *item)
282 tag = folder_item_get_xml(folder, item);
284 if (((VCalFolderItem *)item)->uri)
285 xml_tag_add_attr(tag, xml_attr_new("uri", ((VCalFolderItem *)item)->uri));
287 xml_tag_add_attr(tag, xml_attr_new_int("use_cal_view", ((VCalFolderItem *)item)->use_cal_view));
292 static gint vcal_rename_folder(Folder *folder, FolderItem *item,
298 item->name = g_strdup(name);
302 static void vcal_get_sort_type(Folder *folder, FolderSortKey *sort_key,
303 FolderSortType *sort_type)
306 *sort_key = SORT_BY_DATE;
309 static void vcal_item_opened(FolderItem *item)
312 time_t t = time(NULL);
314 localtime_r(&t, &tmdate);
318 tmdate = *localtime(&t);
320 if (!((VCalFolderItem *)(item))->dw
321 && ((VCalFolderItem *)(item))->use_cal_view == 1)
322 ((VCalFolderItem *)(item))->dw = create_day_win(item, tmdate);
323 else if (!((VCalFolderItem *)(item))->mw
324 && ((VCalFolderItem *)(item))->use_cal_view == 2)
325 ((VCalFolderItem *)(item))->mw = create_month_win(item, tmdate);
326 else if (((VCalFolderItem *)(item))->use_cal_view != 0)
327 vcal_folder_refresh_cal(item);
330 void vcal_folder_refresh_cal(FolderItem *item)
332 Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
333 if (item->folder != folder)
335 if (((VCalFolderItem *)(item))->dw)
336 refresh_day_win(((VCalFolderItem *)(item))->dw);
337 if (((VCalFolderItem *)(item))->mw)
338 refresh_month_win(((VCalFolderItem *)(item))->mw);
341 static void vcal_item_closed(FolderItem *item)
343 if (((VCalFolderItem *)(item))->dw) {
344 dw_close_window(((VCalFolderItem *)(item))->dw);
345 ((VCalFolderItem *)(item))->dw = NULL;
347 if (((VCalFolderItem *)(item))->mw) {
348 mw_close_window(((VCalFolderItem *)(item))->mw);
349 ((VCalFolderItem *)(item))->mw = NULL;
353 FolderClass *vcal_folder_get_class()
355 if (vcal_class.idstr == NULL) {
356 debug_print("register class\n");
357 vcal_class.type = F_UNKNOWN;
358 vcal_class.idstr = "vCalendar";
359 vcal_class.uistr = "vCalendar";
361 /* Folder functions */
362 vcal_class.new_folder = vcal_folder_new;
363 vcal_class.destroy_folder = vcal_folder_destroy;
364 vcal_class.set_xml = folder_set_xml;
365 vcal_class.get_xml = folder_get_xml;
366 vcal_class.item_set_xml = vcal_item_set_xml;
367 vcal_class.item_get_xml = vcal_item_get_xml;
368 vcal_class.scan_tree = vcal_scan_tree;
369 vcal_class.create_tree = vcal_create_tree;
370 vcal_class.get_sort_type = vcal_get_sort_type;
372 /* FolderItem functions */
373 vcal_class.item_new = vcal_item_new;
374 vcal_class.item_destroy = vcal_item_destroy;
375 vcal_class.item_get_path = vcal_item_get_path;
376 vcal_class.create_folder = vcal_create_folder;
377 vcal_class.remove_folder = vcal_remove_folder;
378 vcal_class.rename_folder = vcal_rename_folder;
379 vcal_class.scan_required = vcal_scan_required;
380 vcal_class.set_mtime = vcal_set_mtime;
381 vcal_class.get_num_list = vcal_get_num_list;
382 vcal_class.set_batch = vcal_folder_set_batch;
384 /* Message functions */
385 vcal_class.get_msginfo = vcal_get_msginfo;
386 vcal_class.fetch_msg = vcal_fetch_msg;
387 vcal_class.add_msg = vcal_add_msg;
388 vcal_class.copy_msg = NULL;
389 vcal_class.remove_msg = vcal_remove_msg;
390 vcal_class.change_flags = vcal_change_flags;
391 vcal_class.subscribe = vcal_subscribe_uri;
393 /* FolderView functions */
394 vcal_class.item_opened = vcal_item_opened;
395 vcal_class.item_closed = vcal_item_closed;
396 debug_print("registered class for real\n");
402 static void vcal_folder_set_batch (Folder *folder,
406 VCalFolderItem *item = (VCalFolderItem *)_item;
408 g_return_if_fail(item != NULL);
410 if (item->batching == batch)
414 item->batching = TRUE;
415 debug_print("vcal switching to batch mode\n");
417 debug_print("vcal switching away from batch mode\n");
419 item->batching = FALSE;
421 vcal_folder_export(folder);
426 static Folder *vcal_folder_new(const gchar * name,
431 debug_print("vcal_folder_new\n");
432 folder = g_new0(VCalFolder, 1);
433 FOLDER(folder)->klass = &vcal_class;
434 folder_init(FOLDER(folder), name);
436 return FOLDER(folder);
439 static void vcal_folder_destroy(Folder *_folder)
443 static FolderItem *vcal_item_new(Folder *folder)
445 VCalFolderItem *item;
446 item = g_new0(VCalFolderItem, 1);
447 item->use_cal_view = 1;
448 return (FolderItem *) item;
452 static void vcal_item_destroy(Folder *folder, FolderItem *_item)
454 VCalFolderItem *item = (VCalFolderItem *)_item;
455 g_return_if_fail(item != NULL);
459 static gchar *vcal_item_get_path(Folder *folder, FolderItem *item)
461 VCalFolderItem *fitem = (VCalFolderItem *)item;
462 if (fitem->uri == NULL)
463 return g_strdup(vcal_manager_get_event_path());
465 gchar *path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
466 "vcalendar", G_DIR_SEPARATOR_S,
472 static gint vcal_scan_tree(Folder *folder)
474 g_return_val_if_fail(folder != NULL, -1);
476 folder->outbox = NULL;
477 folder->draft = NULL;
478 folder->queue = NULL;
479 folder->trash = NULL;
481 debug_print("scanning tree\n");
482 vcal_create_tree(folder);
487 gboolean manual_update = TRUE;
489 static gint feed_fetch(FolderItem *fitem, MsgNumberList ** list, gboolean *old_uids_valid)
491 VCalFolderItem *item = (VCalFolderItem *)fitem;
492 icalcomponent *evt = NULL;
493 icalcomponent_kind type = ICAL_VEVENT_COMPONENT;
495 gint past_msg = -1, today_msg = -1, tomorrow_msg = -1,
496 thisweek_msg = -1, later_msg = -1;
498 debug_print("fetching\n");
501 debug_print("no uri!\n");
505 update_subscription(item->uri, TRUE);
507 *old_uids_valid = FALSE;
511 evt = icalcomponent_get_first_component(
512 item->cal, ICAL_VEVENT_COMPONENT);
514 evt = icalcomponent_get_first_component(
515 item->cal, ICAL_VTODO_COMPONENT);
517 type = ICAL_VTODO_COMPONENT;
520 debug_print("no cal!\n");
523 debug_print("no event\n");
526 g_slist_free(item->numlist);
527 item->numlist = NULL;
531 slist_free_icalfeeddata(item->evtlist);
532 g_slist_free(item->evtlist);
533 item->evtlist = NULL;
538 icalproperty *rprop = icalcomponent_get_first_property(evt, ICAL_RRULE_PROPERTY);
539 struct icalrecurrencetype recur;
540 struct icaltimetype next;
541 icalrecur_iterator* ritr = NULL;
545 icalproperty *rprop2;
546 recur = icalproperty_get_rrule(rprop);
547 rprop2 = icalproperty_new_rrule(recur);
548 prop = icalcomponent_get_first_property(evt, ICAL_DTSTART_PROPERTY);
550 ritr = icalrecur_iterator_new(recur, icalproperty_get_dtstart(prop));
551 next = icalrecur_iterator_next(ritr); /* skip first one */
557 prop = icalcomponent_get_first_property(evt, ICAL_UID_PROPERTY);
559 gchar *orig_uid = NULL;
560 gchar *uid = g_strdup(icalproperty_get_uid(prop));
561 IcalFeedData *data = icalfeeddata_new(
562 icalcomponent_new_clone(evt), NULL);
564 orig_uid = g_strdup(uid);
567 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
568 item->evtlist = g_slist_prepend(item->evtlist, data);
570 debug_print("add %d : %s\n", num, uid);
573 prop = icalcomponent_get_first_property(evt, ICAL_DTSTART_PROPERTY);
575 struct icaltimetype itt = icalproperty_get_dtstart(prop);
576 days = event_to_today(NULL, icaltime_as_timet(itt));
577 if (days == EVENT_PAST && past_msg == -1) {
578 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
579 data = icalfeeddata_new(NULL, EVENT_PAST_ID);
581 } else if (days == EVENT_TODAY && today_msg == -1) {
582 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
583 data = icalfeeddata_new(NULL, EVENT_TODAY_ID);
585 } else if (days == EVENT_TOMORROW && tomorrow_msg == -1) {
586 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
587 data = icalfeeddata_new(NULL, EVENT_TOMORROW_ID);
588 tomorrow_msg = num++;
589 } else if (days == EVENT_THISWEEK && thisweek_msg == -1) {
590 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
591 data = icalfeeddata_new(NULL, EVENT_THISWEEK_ID);
592 thisweek_msg = num++;
593 } else if (days == EVENT_LATER && later_msg == -1) {
594 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
595 data = icalfeeddata_new(NULL, EVENT_LATER_ID);
599 if (past_msg == -1) {
600 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
601 data = icalfeeddata_new(NULL, EVENT_PAST_ID);
606 item->evtlist = g_slist_prepend(item->evtlist, data);
610 struct icaldurationtype ical_dur;
611 struct icaltimetype dtstart, dtend;
612 evt = icalcomponent_new_clone(evt);
613 prop = icalcomponent_get_first_property(evt, ICAL_RRULE_PROPERTY);
615 icalcomponent_remove_property(evt, prop);
616 icalproperty_free(prop);
618 prop = icalcomponent_get_first_property(evt, ICAL_DTSTART_PROPERTY);
620 dtstart = icalproperty_get_dtstart(prop);
621 prop = icalcomponent_get_first_property(evt, ICAL_DTEND_PROPERTY);
623 dtend = icalproperty_get_dtend(prop);
624 ical_dur = icaltime_subtract(dtend, dtstart);
625 next = icalrecur_iterator_next(ritr);
626 if (!icaltime_is_null_time(next) &&
627 !icaltime_is_null_time(dtstart) && i < 100) {
628 prop = icalcomponent_get_first_property(evt, ICAL_DTSTART_PROPERTY);
629 icalproperty_set_dtstart(prop, next);
631 prop = icalcomponent_get_first_property(evt, ICAL_DTEND_PROPERTY);
633 icalproperty_set_dtend(prop, icaltime_add(next, ical_dur));
635 prop = icalcomponent_get_first_property(evt, ICAL_UID_PROPERTY);
636 uid = g_strdup_printf("%s-%d", orig_uid, i);
637 icalproperty_set_uid(prop, uid);
638 /* dont free uid, used after (add_new) */
639 data = icalfeeddata_new(evt, NULL);
643 icalcomponent_free(evt);
649 debug_print("no uid!\n");
652 icalproperty_free(rprop);
655 icalrecur_iterator_free(ritr);
658 evt = icalcomponent_get_next_component(
661 if (today_msg == -1) {
662 IcalFeedData *data = icalfeeddata_new(NULL, EVENT_TODAY_ID);
663 item->numlist = g_slist_prepend(item->numlist, GINT_TO_POINTER(num));
665 item->evtlist = g_slist_prepend(item->evtlist, data);
667 item->numlist = g_slist_reverse(item->numlist);
668 item->evtlist = g_slist_reverse(item->evtlist);
670 *list = item->numlist ? g_slist_copy(item->numlist) : NULL;
671 debug_print("return %d\n", num);
675 #define VCAL_FOLDER_ADD_EVENT(event) \
678 *list = g_slist_prepend(*list, GINT_TO_POINTER(n_msg)); \
679 debug_print("add %d %s\n", n_msg, event->uid); \
681 days = event_to_today(event, 0); \
683 if (days == EVENT_PAST && past_msg == -1) { \
684 *list = g_slist_prepend(*list, GINT_TO_POINTER(n_msg)); \
685 past_msg = n_msg++; \
686 g_hash_table_insert(hash_uids, GINT_TO_POINTER(past_msg), g_strdup(EVENT_PAST_ID)); \
687 } else if (days == EVENT_TODAY && today_msg == -1) { \
688 *list = g_slist_prepend(*list, GINT_TO_POINTER(n_msg)); \
689 today_msg = n_msg++; \
690 g_hash_table_insert(hash_uids, GINT_TO_POINTER(today_msg), g_strdup(EVENT_TODAY_ID)); \
691 } else if (days == EVENT_TOMORROW && tomorrow_msg == -1) { \
692 *list = g_slist_prepend(*list, GINT_TO_POINTER(n_msg)); \
693 tomorrow_msg = n_msg++; \
694 g_hash_table_insert(hash_uids, GINT_TO_POINTER(tomorrow_msg), g_strdup(EVENT_TOMORROW_ID)); \
695 } else if (days == EVENT_THISWEEK && thisweek_msg == -1) { \
696 *list = g_slist_prepend(*list, GINT_TO_POINTER(n_msg)); \
697 thisweek_msg = n_msg++; \
698 g_hash_table_insert(hash_uids, GINT_TO_POINTER(thisweek_msg), g_strdup(EVENT_THISWEEK_ID)); \
699 } else if (days == EVENT_LATER && later_msg == -1) { \
700 *list = g_slist_prepend(*list, GINT_TO_POINTER(n_msg)); \
701 later_msg = n_msg++; \
702 g_hash_table_insert(hash_uids, GINT_TO_POINTER(later_msg), g_strdup(EVENT_LATER_ID)); \
706 GSList *vcal_get_events_list(FolderItem *item)
710 GSList *events = NULL;
712 if (item != item->folder->inbox) {
713 GSList *subs = vcal_folder_get_webcal_events_for_folder(item);
715 for (cur = subs; cur; cur = cur->next) {
716 /* Don't free that, it's done when subscriptions are
718 icalcomponent *ical = (icalcomponent *)cur->data;
719 VCalEvent *event = vcal_get_event_from_ical(
720 icalcomponent_as_ical_string(ical), NULL);
721 events = g_slist_prepend(events, event);
727 dp = opendir(vcal_manager_get_event_path());
730 FILE_OP_ERROR(vcal_manager_get_event_path(), "opendir");
734 while ((d = readdir(dp)) != NULL) {
735 VCalEvent *event = NULL;
736 if (d->d_name[0] == '.' || strstr(d->d_name, ".bak")
737 || !strcmp(d->d_name, "internal.ics")
738 || !strcmp(d->d_name, "internal.ifb")
739 || !strcmp(d->d_name, "multisync"))
742 event = vcal_manager_load_event(d->d_name);
745 if (event->rec_occurence) {
746 vcal_manager_free_event(event);
747 claws_unlink(d->d_name);
751 if (event && event->method != ICAL_METHOD_CANCEL) {
752 PrefsAccount *account = vcal_manager_get_account_from_event(event);
753 enum icalparameter_partstat status =
754 account ? vcal_manager_get_reply_for_attendee(event, account->address): ICAL_PARTSTAT_NEEDSACTION;
755 if (status == ICAL_PARTSTAT_ACCEPTED
756 || status == ICAL_PARTSTAT_TENTATIVE) {
757 events = g_slist_prepend(events, event);
759 vcal_manager_free_event(event);
762 if ((status == ICAL_PARTSTAT_ACCEPTED
763 || status == ICAL_PARTSTAT_TENTATIVE)
764 && event->recur && *(event->recur)) {
765 struct icalrecurrencetype recur;
766 struct icaltimetype dtstart;
767 struct icaltimetype next;
768 icalrecur_iterator* ritr;
769 time_t duration = (time_t) NULL;
770 struct icaldurationtype ical_dur;
773 debug_print("dumping recurring events from main event %s\n", d->d_name);
774 recur = icalrecurrencetype_from_string(event->recur);
775 dtstart = icaltime_from_string(event->dtstart);
777 duration = icaltime_as_timet(icaltime_from_string(event->dtend))
778 - icaltime_as_timet(icaltime_from_string(event->dtstart));
780 ical_dur = icaldurationtype_from_int(duration);
782 ritr = icalrecur_iterator_new(recur, dtstart);
784 next = icalrecur_iterator_next(ritr); /* skip first one */
785 if (!icaltime_is_null_time(next))
786 next = icalrecur_iterator_next(ritr);
787 debug_print("next time is %snull\n", icaltime_is_null_time(next)?"":"not ");
788 while (!icaltime_is_null_time(next) && i < 100) {
789 gchar *new_start = NULL, *new_end = NULL;
790 VCalEvent *nevent = NULL;
791 gchar *uid = g_strdup_printf("%s-%d", event->uid, i);
792 new_start = icaltime_as_ical_string(next);
793 new_end = icaltime_as_ical_string(
794 icaltime_add(next, ical_dur));
795 debug_print("adding with start/end %s:%s\n", new_start, new_end);
796 nevent = vcal_manager_new_event(uid, event->organizer, event->orgname,
797 event->location, event->summary, event->description,
798 new_start, new_end, NULL,
799 event->tzid, event->url, event->method,
800 event->sequence, event->type);
802 vcal_manager_copy_attendees(event, nevent);
803 nevent->rec_occurence = TRUE;
804 vcal_manager_save_event(nevent, FALSE);
805 account = vcal_manager_get_account_from_event(event);
807 account ? vcal_manager_get_reply_for_attendee(event, account->address): ICAL_PARTSTAT_NEEDSACTION;
808 if (status == ICAL_PARTSTAT_ACCEPTED
809 || status == ICAL_PARTSTAT_TENTATIVE) {
810 events = g_slist_prepend(events, nevent);
812 vcal_manager_free_event(nevent);
814 next = icalrecur_iterator_next(ritr);
815 debug_print("next time is %snull\n", icaltime_is_null_time(next)?"":"not ");
818 icalrecur_iterator_free(ritr);
821 vcal_manager_free_event(event);
825 return g_slist_reverse(events);
828 static gint vcal_get_num_list(Folder *folder, FolderItem *item,
829 MsgNumberList ** list, gboolean *old_uids_valid)
832 gint past_msg = -1, today_msg = -1, tomorrow_msg = -1,
833 thisweek_msg = -1, later_msg = -1;
834 GSList *events = NULL, *cur;
836 g_return_val_if_fail (*list == NULL, 0); /* we expect a NULL list */
838 debug_print(" num for %s\n", ((VCalFolderItem *)item)->uri ? ((VCalFolderItem *)item)->uri:"(null)");
840 *old_uids_valid = FALSE;
842 if (((VCalFolderItem *)item)->uri)
843 return feed_fetch(item, list, old_uids_valid);
845 events = vcal_get_events_list(item);
847 debug_print("get_num_list\n");
849 if (hash_uids != NULL)
850 g_hash_table_destroy(hash_uids);
852 hash_uids = g_hash_table_new_full(g_direct_hash, g_direct_equal,
855 for (cur = events; cur; cur = cur->next) {
856 VCalEvent *event = (VCalEvent *)cur->data;
860 g_hash_table_insert(hash_uids, GINT_TO_POINTER(n_msg), g_strdup(event->uid));
862 if (event->rec_occurence) {
863 vcal_manager_free_event(event);
867 if (event->method != ICAL_METHOD_CANCEL) {
869 VCAL_FOLDER_ADD_EVENT(event);
872 vcal_manager_free_event(event);
877 if (today_msg == -1) {
878 *list = g_slist_prepend(*list, GINT_TO_POINTER(n_msg));
880 g_hash_table_insert(hash_uids, GINT_TO_POINTER(today_msg), g_strdup(EVENT_TODAY_ID));
883 g_slist_free(events);
884 vcal_folder_export(folder);
886 vcal_set_mtime(folder, item);
888 *list = g_slist_reverse(*list);
890 return g_slist_length(*list);
893 static MsgInfo *vcal_parse_msg(const gchar *file, FolderItem *item, int num)
895 MsgInfo *msginfo = NULL;
898 debug_print("parse_msg\n");
900 flags.perm_flags = 0;
902 msginfo = procheader_parse_file(file, flags, TRUE, TRUE);
904 msginfo->msgnum = num;
905 msginfo->folder = item;
909 static MsgInfo *vcal_get_msginfo(Folder * folder,
910 FolderItem * item, gint num)
912 MsgInfo *msginfo = NULL;
915 debug_print("get_msginfo\n");
917 g_return_val_if_fail(item != NULL, NULL);
918 g_return_val_if_fail(num > 0, NULL);
920 file = vcal_fetch_msg(folder, item, num);
926 msginfo = vcal_parse_msg(file, item, num);
929 msginfo->flags.perm_flags = 0;
930 msginfo->flags.tmp_flags = 0;
932 vcal_change_flags(NULL, NULL, msginfo, 0);
934 debug_print(" adding %d\n", num);
939 debug_print(" got msginfo %p\n", msginfo);
944 static gchar *feed_fetch_item(FolderItem * fitem, gint num)
946 gchar *filename = NULL;
947 VCalFolderItem *item = (VCalFolderItem *)fitem;
950 IcalFeedData *data = NULL;
952 if (!item->numlist) {
953 folder_item_scan_full(fitem, FALSE);
955 if (!item->numlist) {
956 debug_print("numlist null\n");
960 ncur = item->numlist;
961 ecur = item->evtlist;
964 if (!ncur || !ecur) {
965 debug_print("list short end (%d to %d) %d,%d\n", i, num, ncur!=NULL, ecur!=NULL);
973 data = (IcalFeedData *)ecur->data;
980 filename = vcal_manager_icalevent_dump(data->event, fitem->name, NULL);
981 else if (data->pseudoevent_id) {
982 filename = vcal_manager_dateevent_dump(data->pseudoevent_id, fitem);
983 created_files = g_slist_prepend(created_files, g_strdup(filename));
985 debug_print("no event\n");
989 debug_print("feed item dump to %s\n", filename);
993 static gchar *vcal_fetch_msg(Folder * folder, FolderItem * item,
996 gchar *filename = NULL;
997 const gchar *uid = NULL;
999 debug_print(" fetch for %s %d\n", (((VCalFolderItem *)item)->uri ? ((VCalFolderItem *)item)->uri:"(null)"), num);
1000 if (((VCalFolderItem *)item)->uri)
1001 return feed_fetch_item(item, num);
1005 folder_item_scan_full(item, FALSE);
1006 uid = g_hash_table_lookup(hash_uids, GINT_TO_POINTER(num));
1009 (!strcmp(uid, EVENT_PAST_ID) ||
1010 !strcmp(uid, EVENT_TODAY_ID) ||
1011 !strcmp(uid, EVENT_TOMORROW_ID) ||
1012 !strcmp(uid, EVENT_THISWEEK_ID) ||
1013 !strcmp(uid, EVENT_LATER_ID))) {
1014 filename = vcal_manager_dateevent_dump(uid, item);
1016 VCalEvent *event = NULL;
1017 event = vcal_manager_load_event(uid);
1019 filename = vcal_manager_event_dump(event, FALSE, TRUE, NULL, FALSE);
1022 created_files = g_slist_prepend(created_files, g_strdup(filename));
1025 vcal_manager_free_event(event);
1031 static gint vcal_add_msg(Folder *folder, FolderItem *_dest, const gchar *file, MsgFlags *flags)
1033 gchar *contents = file_read_to_str(file);
1035 vcal_add_event(contents);
1041 static void vcal_remove_event (Folder *folder, MsgInfo *msginfo);
1043 static gint vcal_remove_msg(Folder *folder, FolderItem *_item, gint num)
1045 MsgInfo *msginfo = folder_item_get_msginfo(_item, num);
1050 if (_item == folder->inbox)
1051 vcal_remove_event(folder, msginfo);
1053 procmsg_msginfo_free(msginfo);
1057 static FolderItem *vcal_create_folder(Folder * folder,
1058 FolderItem * parent,
1062 FolderItem *newitem = NULL;
1063 debug_print("creating new vcal folder\n");
1065 path = g_strconcat((parent->path != NULL) ? parent->path : "", ".", name, NULL);
1066 newitem = folder_item_new(folder, name, path);
1067 folder_item_append(parent, newitem);
1073 static gint vcal_create_tree(Folder *folder)
1075 FolderItem *rootitem, *inboxitem;
1076 GNode *rootnode, *inboxnode;
1078 if (!folder->node) {
1079 rootitem = folder_item_new(folder, folder->name, NULL);
1080 rootitem->folder = folder;
1081 rootnode = g_node_new(rootitem);
1082 folder->node = rootnode;
1083 rootitem->node = rootnode;
1085 rootitem = FOLDER_ITEM(folder->node->data);
1086 rootnode = folder->node;
1089 /* Add inbox folder */
1090 if (!folder->inbox) {
1091 inboxitem = folder_item_new(folder, _("Meetings"), ".meetings");
1092 inboxitem->folder = folder;
1093 inboxitem->stype = F_INBOX;
1094 inboxnode = g_node_new(inboxitem);
1095 inboxitem->node = inboxnode;
1096 folder->inbox = inboxitem;
1097 g_node_append(rootnode, inboxnode);
1099 g_free(folder->inbox->path);
1100 folder->inbox->path = g_strdup(".meetings");
1103 debug_print("created new vcal tree\n");
1107 static gint vcal_remove_folder(Folder *folder, FolderItem *fitem)
1109 VCalFolderItem *item = (VCalFolderItem *)fitem;
1119 folder_item_remove(fitem);
1124 static gboolean vcal_scan_required(Folder *folder, FolderItem *item)
1127 VCalFolderItem *vitem = (VCalFolderItem *)item;
1129 g_return_val_if_fail(item != NULL, FALSE);
1133 } else if (g_stat(vcal_manager_get_event_path(), &s) < 0) {
1135 } else if ((s.st_mtime > item->mtime) &&
1136 (s.st_mtime - 3600 != item->mtime)) {
1142 static gint vcal_folder_lock_count = 0;
1144 static void vcal_set_mtime(Folder *folder, FolderItem *item)
1147 gchar *path = folder_item_get_path(item);
1149 if (folder->inbox != item)
1152 g_return_if_fail(path != NULL);
1154 if (g_stat(path, &s) < 0) {
1155 FILE_OP_ERROR(path, "stat");
1160 item->mtime = s.st_mtime;
1161 debug_print("VCAL: forced mtime of %s to %ld\n", item->name?item->name:"(null)", item->mtime);
1165 void vcal_folder_export(Folder *folder)
1167 FolderItem *item = folder?folder->inbox:NULL;
1168 gboolean need_scan = folder?vcal_scan_required(folder, item):TRUE;
1170 if (vcal_folder_lock_count) /* blocked */
1172 vcal_folder_lock_count++;
1173 if (vcal_meeting_export_calendar(vcalprefs.export_path,
1174 vcalprefs.export_user,
1175 vcalprefs.export_pass,
1177 debug_print("exporting calendar\n");
1178 if (vcalprefs.export_enable &&
1179 vcalprefs.export_command &&
1180 strlen(vcalprefs.export_command))
1181 execute_command_line(
1182 vcalprefs.export_command, TRUE);
1184 if (vcal_meeting_export_freebusy(vcalprefs.export_freebusy_path,
1185 vcalprefs.export_freebusy_user,
1186 vcalprefs.export_freebusy_pass)) {
1187 debug_print("exporting freebusy\n");
1188 if (vcalprefs.export_freebusy_enable &&
1189 vcalprefs.export_freebusy_command &&
1190 strlen(vcalprefs.export_freebusy_command))
1191 execute_command_line(
1192 vcalprefs.export_freebusy_command, TRUE);
1194 vcal_folder_lock_count--;
1195 if (!need_scan && folder) {
1196 vcal_set_mtime(folder, folder->inbox);
1200 static void vcal_remove_event (Folder *folder, MsgInfo *msginfo)
1202 const gchar *uid = msginfo->msgid;
1203 VCalFolderItem *item = (VCalFolderItem *)msginfo->folder;
1206 gchar *file = vcal_manager_get_event_file(uid);
1211 if (!item || !item->batching)
1212 vcal_folder_export(folder);
1218 static void vcal_change_flags(Folder *folder, FolderItem *_item, MsgInfo *msginfo, MsgPermFlags newflags)
1222 if (newflags & MSG_DELETED) {
1223 /* delete the stuff */
1224 msginfo->flags.perm_flags |= MSG_DELETED;
1225 vcal_remove_event(folder, msginfo);
1229 /* accept the rest */
1230 msginfo->flags.perm_flags = newflags;
1233 msginfo->flags.perm_flags &= ~MSG_CLABEL_FLAG_MASK;
1235 date = event_to_today(NULL, msginfo->date_t);
1240 msginfo->flags.perm_flags |= MSG_COLORLABEL_TO_FLAGS(2); /* Red */
1242 case EVENT_TOMORROW:
1244 case EVENT_THISWEEK:
1249 if (msginfo->msgid) {
1250 if (!strcmp(msginfo->msgid, EVENT_TODAY_ID) ||
1251 !strcmp(msginfo->msgid, EVENT_TOMORROW_ID))
1252 msginfo->flags.perm_flags |= MSG_MARKED;
1256 void vcal_folder_gtk_init(void)
1258 vcal_fill_popup_menu_labels();
1260 folderview_register_popup(&vcal_popup);
1263 void vcal_folder_gtk_done(void)
1265 GSList *cur = created_files;
1267 gchar *file = (gchar *)cur->data;
1271 debug_print("removing %s\n", file);
1275 g_slist_free(created_files);
1276 folderview_unregister_popup(&vcal_popup);
1279 static void add_menuitems(GtkUIManager *ui_manager, FolderItem *item)
1281 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "NewMeeting", "FolderViewPopup/NewMeeting", GTK_UI_MANAGER_MENUITEM)
1282 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "ExportCal", "FolderViewPopup/ExportCal", GTK_UI_MANAGER_MENUITEM)
1283 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorVcal1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1284 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SubscribeCal", "FolderViewPopup/SubscribeCal", GTK_UI_MANAGER_MENUITEM)
1285 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "UnsubscribeCal", "FolderViewPopup/UnsubscribeCal", GTK_UI_MANAGER_MENUITEM)
1286 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorVcal2", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1287 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RenameFolder", "FolderViewPopup/RenameFolder", GTK_UI_MANAGER_MENUITEM)
1288 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorVcal3", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1289 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "CheckSubs", "FolderViewPopup/CheckSubs", GTK_UI_MANAGER_MENUITEM)
1290 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorVcal4", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1291 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "ListView", "FolderViewPopup/ListView", GTK_UI_MANAGER_MENUITEM)
1292 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "WeekView", "FolderViewPopup/WeekView", GTK_UI_MANAGER_MENUITEM)
1293 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MonthView", "FolderViewPopup/MonthView", GTK_UI_MANAGER_MENUITEM)
1294 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorVcal5", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1297 static gboolean setting_sensitivity = FALSE;
1298 static void set_sensitivity(GtkUIManager *ui_manager, FolderItem *fitem)
1300 VCalFolderItem *item = (VCalFolderItem *)fitem;
1302 #define SET_SENS(name, sens) \
1303 cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
1305 setting_sensitivity = TRUE;
1307 cm_toggle_menu_set_active_full(ui_manager, "Popup/FolderViewPopup/ListView", (item->use_cal_view == 0));
1308 cm_toggle_menu_set_active_full(ui_manager, "Popup/FolderViewPopup/WeekView", (item->use_cal_view == 1));
1309 cm_toggle_menu_set_active_full(ui_manager, "Popup/FolderViewPopup/MonthView", (item->use_cal_view == 2));
1310 SET_SENS("FolderViewPopup/NewMeeting", item->uri == NULL);
1311 SET_SENS("FolderViewPopup/ExportCal", TRUE);
1312 SET_SENS("FolderViewPopup/SubscribeCal", item->uri == NULL);
1313 SET_SENS("FolderViewPopup/UnsubscribeCal", item->uri != NULL);
1314 SET_SENS("FolderViewPopup/RenameFolder", folder_item_parent(fitem) != NULL);
1315 SET_SENS("FolderViewPopup/CheckSubs", TRUE);
1316 SET_SENS("FolderViewPopup/ListView", folder_item_parent(fitem) != NULL);
1317 SET_SENS("FolderViewPopup/WeekView", folder_item_parent(fitem) != NULL);
1318 SET_SENS("FolderViewPopup/MonthView", folder_item_parent(fitem) != NULL);
1319 setting_sensitivity = FALSE;
1323 static void new_meeting_cb(GtkAction *action, gpointer data)
1325 debug_print("new_meeting_cb\n");
1326 vcal_meeting_create(NULL);
1329 GSList * vcal_folder_get_waiting_events(void)
1331 Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
1332 return vcal_get_events_list(folder->inbox);
1335 typedef struct _get_webcal_data {
1340 static gboolean get_webcal_events_func(GNode *node, gpointer user_data)
1342 FolderItem *item = node->data;
1343 GetWebcalData *data = user_data;
1344 gboolean dummy = FALSE;
1345 GSList *list = NULL, *cur = NULL;
1347 if (data->item && data->item != item)
1350 feed_fetch(item, &list, &dummy);
1354 for (cur = ((VCalFolderItem *)item)->evtlist; cur; cur = cur->next) {
1355 IcalFeedData *fdata = (IcalFeedData *)cur->data;
1357 data->list = g_slist_prepend(data->list, fdata->event);
1362 GSList * vcal_folder_get_webcal_events(void)
1364 GetWebcalData *data = g_new0(GetWebcalData, 1);
1365 Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
1366 GSList *list = NULL;
1368 g_node_traverse(folder->node, G_PRE_ORDER,
1369 G_TRAVERSE_ALL, -1, get_webcal_events_func, data);
1374 return g_slist_reverse(list);
1377 static gboolean vcal_free_data_func(GNode *node, gpointer user_data)
1379 VCalFolderItem *item = node->data;
1382 icalcomponent_free(item->cal);
1385 if (item->numlist) {
1386 g_slist_free(item->numlist);
1387 item->numlist = NULL;
1390 if (item->evtlist) {
1391 slist_free_icalfeeddata(item->evtlist);
1392 g_slist_free(item->evtlist);
1393 item->evtlist = NULL;
1399 void vcal_folder_free_data(void)
1401 Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
1403 g_node_traverse(folder->node, G_PRE_ORDER,
1404 G_TRAVERSE_ALL, -1, vcal_free_data_func, NULL);
1407 GSList * vcal_folder_get_webcal_events_for_folder(FolderItem *item)
1409 GetWebcalData *data = g_new0(GetWebcalData, 1);
1410 Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
1411 GSList *list = NULL;
1413 g_node_traverse(folder->node, G_PRE_ORDER,
1414 G_TRAVERSE_ALL, -1, get_webcal_events_func, data);
1419 return g_slist_reverse(list);
1422 gchar* get_item_event_list_for_date(FolderItem *item, EventTime date)
1424 GSList *strs = NULL;
1426 gchar *result = NULL;
1427 gchar *datestr = NULL;
1429 if (((VCalFolderItem *)item)->uri) {
1430 for (cur = ((VCalFolderItem *)item)->evtlist; cur; cur = cur->next) {
1431 IcalFeedData *fdata = (IcalFeedData *)cur->data;
1433 struct icaltimetype itt;
1434 gchar *summary = NULL;
1438 prop = icalcomponent_get_first_property((icalcomponent *)fdata->event, ICAL_DTSTART_PROPERTY);
1442 itt = icalproperty_get_dtstart(prop);
1443 days = event_to_today(NULL, icaltime_as_timet(itt));
1446 prop = icalcomponent_get_first_property((icalcomponent *)fdata->event, ICAL_SUMMARY_PROPERTY);
1448 if (!g_utf8_validate(icalproperty_get_summary(prop), -1, NULL))
1449 summary = conv_codeset_strdup(icalproperty_get_summary(prop),
1450 conv_get_locale_charset_str(), CS_UTF_8);
1452 summary = g_strdup(icalproperty_get_summary(prop));
1454 summary = g_strdup("-");
1456 strs = g_slist_prepend(strs, summary);
1459 GSList *evtlist = vcal_folder_get_waiting_events();
1460 for (cur = evtlist; cur; cur = cur->next) {
1461 VCalEvent *event = (VCalEvent *)cur->data;
1463 days = event_to_today(event, 0);
1464 gchar *summary = NULL;
1466 summary = g_strdup(event->summary);
1467 strs = g_slist_prepend(strs, summary);
1469 vcal_manager_free_event(event);
1475 datestr=_("in the past");
1480 case EVENT_TOMORROW:
1481 datestr=_("tomorrow");
1483 case EVENT_THISWEEK:
1484 datestr=_("this week");
1491 result = g_strdup_printf(_("\nThese are the events planned %s:\n"),
1492 datestr?datestr:"never");
1494 strs = g_slist_reverse(strs);
1495 for (cur = strs; cur; cur = cur->next) {
1496 int e_len = strlen(result);
1497 int n_len = strlen((gchar *)cur->data);
1499 result = g_realloc(result, e_len+n_len+4);
1500 *(result+e_len) = '\n';
1501 strcpy(result+e_len+1, "- ");
1502 strcpy(result+e_len+3, (gchar *)cur->data);
1504 result = g_realloc(result, e_len+n_len+3);
1505 strcpy(result+e_len, "- ");
1506 strcpy(result+e_len+2, (gchar *)cur->data);
1509 slist_free_strings(strs);
1514 static void export_cal_cb(GtkAction *action, gpointer data)
1516 vcal_meeting_export_calendar(NULL, NULL, NULL, FALSE);
1523 static size_t curl_recv(void *buf, size_t size, size_t nmemb, void *stream)
1525 struct CBuf *buffer = (struct CBuf *)stream;
1527 gchar tmpbuf[size*nmemb + 1];
1529 memcpy(tmpbuf, buf, size*nmemb);
1530 tmpbuf[size*nmemb] = '\0';
1533 tmp = g_strconcat(buffer->str, tmpbuf, NULL);
1534 g_free(buffer->str);
1537 buffer->str = g_strdup(tmpbuf);
1543 void *url_read_thread(void *data)
1545 thread_data *td = (thread_data *)data;
1547 CURL *curl_ctx = NULL;
1549 struct CBuf buffer = { NULL };
1550 gchar *t_url = (gchar *)td->url;
1552 while (*t_url == ' ')
1554 if (strchr(t_url, ' '))
1555 *(strchr(t_url, ' ')) = '\0';
1558 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
1559 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
1562 curl_ctx = curl_easy_init();
1564 curl_easy_setopt(curl_ctx, CURLOPT_URL, t_url);
1565 curl_easy_setopt(curl_ctx, CURLOPT_WRITEFUNCTION, curl_recv);
1566 curl_easy_setopt(curl_ctx, CURLOPT_WRITEDATA, &buffer);
1567 curl_easy_setopt(curl_ctx, CURLOPT_TIMEOUT, prefs_common_get_prefs()->io_timeout_secs);
1568 curl_easy_setopt(curl_ctx, CURLOPT_NOSIGNAL, 1);
1569 #if LIBCURL_VERSION_NUM >= 0x070a00
1570 if(vcalprefs.ssl_verify_peer == FALSE) {
1571 curl_easy_setopt(curl_ctx, CURLOPT_SSL_VERIFYPEER, 0);
1572 curl_easy_setopt(curl_ctx, CURLOPT_SSL_VERIFYHOST, 0);
1575 curl_easy_setopt(curl_ctx, CURLOPT_USERAGENT,
1576 "Claws Mail vCalendar plugin "
1577 "(" PLUGINS_URI ")");
1578 curl_easy_setopt(curl_ctx, CURLOPT_FOLLOWLOCATION, 1);
1579 res = curl_easy_perform(curl_ctx);
1582 debug_print("res %d %s\n", res, curl_easy_strerror(res));
1583 td->error = g_strdup(curl_easy_strerror(res));
1585 if(res == CURLE_OPERATION_TIMEOUTED)
1586 log_error(LOG_PROTOCOL, _("Timeout (%d seconds) connecting to %s\n"),
1587 prefs_common_get_prefs()->io_timeout_secs, t_url);
1590 curl_easy_getinfo(curl_ctx, CURLINFO_RESPONSE_CODE, &response_code);
1591 if( response_code >= 400 && response_code < 500 ) {
1592 debug_print("VCalendar: got %ld\n", response_code);
1593 switch(response_code) {
1595 td->error = g_strdup(_("401 (Authorisation required)"));
1598 td->error = g_strdup(_("403 (Unauthorised)"));
1601 td->error = g_strdup(_("404 (Not found)"));
1604 td->error = g_strdup_printf(_("Error %ld"), response_code);
1608 curl_easy_cleanup(curl_ctx);
1610 td->result = g_strdup(buffer.str);
1614 td->done = TRUE; /* let the caller thread join() */
1615 return GINT_TO_POINTER(0);
1618 gchar *vcal_curl_read(const char *url, const gchar *label, gboolean verbose,
1619 void (*callback)(const gchar *url, gchar *data, gboolean verbose, gchar *error))
1629 gchar *error = NULL;
1631 td = g_new0(thread_data, 1);
1639 STATUSBAR_PUSH(mainwindow_get_mainwindow(), label);
1642 if (pthread_attr_init(&pta) != 0 ||
1643 pthread_attr_setdetachstate(&pta, PTHREAD_CREATE_JOINABLE) != 0 ||
1644 pthread_create(&pt, &pta,
1645 url_read_thread, td) != 0) {
1646 url_read_thread(td);
1652 pthread_join(pt, &res);
1654 url_read_thread(td);
1657 result = td->result;
1661 STATUSBAR_POP(mainwindow_get_mainwindow());
1664 callback(url, result, verbose, error);
1673 gboolean vcal_curl_put(gchar *url, FILE *fp, gint filesize, const gchar *user, const gchar *pass)
1675 gboolean res = TRUE;
1676 CURL *curl_ctx = curl_easy_init();
1677 long response_code = 0;
1679 gchar *userpwd = NULL;
1681 struct curl_slist * headers = curl_slist_append(NULL,
1682 "Content-Type: text/calendar; charset=\"utf-8\"" );
1684 while (*t_url == ' ')
1686 if (strchr(t_url, ' '))
1687 *(strchr(t_url, ' ')) = '\0';
1689 if (user && pass && *user && *pass) {
1690 userpwd = g_strdup_printf("%s:%s",user,pass);
1691 curl_easy_setopt(curl_ctx, CURLOPT_USERPWD, userpwd);
1693 curl_easy_setopt(curl_ctx, CURLOPT_URL, t_url);
1694 curl_easy_setopt(curl_ctx, CURLOPT_UPLOAD, 1);
1695 curl_easy_setopt(curl_ctx, CURLOPT_READFUNCTION, NULL);
1696 curl_easy_setopt(curl_ctx, CURLOPT_READDATA, fp);
1697 curl_easy_setopt(curl_ctx, CURLOPT_HTTPHEADER, headers);
1698 #if LIBCURL_VERSION_NUM >= 0x070a00
1699 if(vcalprefs.ssl_verify_peer == FALSE) {
1700 curl_easy_setopt(curl_ctx, CURLOPT_SSL_VERIFYPEER, 0);
1701 curl_easy_setopt(curl_ctx, CURLOPT_SSL_VERIFYHOST, 0);
1704 curl_easy_setopt(curl_ctx, CURLOPT_USERAGENT,
1705 "Claws Mail vCalendar plugin "
1706 "(http://www.claws-mail.org/plugins.php)");
1707 curl_easy_setopt(curl_ctx, CURLOPT_INFILESIZE, filesize);
1708 res = curl_easy_perform(curl_ctx);
1712 debug_print("res %d %s\n", res, curl_easy_strerror(res));
1717 curl_easy_getinfo(curl_ctx, CURLINFO_RESPONSE_CODE, &response_code);
1718 if (response_code < 200 || response_code >= 300) {
1719 g_warning("Can't export calendar, got code %ld\n", response_code);
1722 curl_easy_cleanup(curl_ctx);
1723 curl_slist_free_all(headers);
1727 static gboolean folder_item_find_func(GNode *node, gpointer data)
1729 FolderItem *item = node->data;
1731 const gchar *uri = d[0];
1733 if (!uri || !((VCalFolderItem *)item)->uri
1734 || strcmp(uri, ((VCalFolderItem *)item)->uri))
1742 static FolderItem *get_folder_item_for_uri(const gchar *uri)
1744 Folder *root = folder_find_from_name ("vCalendar", vcal_folder_get_class());
1750 d[0] = (gpointer)uri;
1752 g_node_traverse(root->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1753 folder_item_find_func, d);
1757 static gchar *feed_get_title(const gchar *str)
1759 gchar *title = NULL;
1760 if (strstr(str, "X-WR-CALNAME:")) {
1761 title = g_strdup(strstr(str, "X-WR-CALNAME:")+strlen("X-WR-CALNAME:"));
1762 if (strstr(title, "\n"))
1763 *(strstr(title, "\n")) = '\0';
1764 if (strstr(title, "\r"))
1765 *(strstr(title, "\r")) = '\0';
1766 } else if (strstr(str, "X-WR-CALDESC:")) {
1767 title = g_strdup(strstr(str, "X-WR-CALDESC:")+strlen("X-WR-CALDESC:"));
1768 if (strstr(title, "\n"))
1769 *(strstr(title, "\n")) = '\0';
1770 if (strstr(title, "\r"))
1771 *(strstr(title, "\r")) = '\0';
1777 static void update_subscription_finish(const gchar *uri, gchar *feed, gboolean verbose, gchar *error)
1779 Folder *root = folder_find_from_name ("vCalendar", vcal_folder_get_class());
1780 FolderItem *item = NULL;
1781 icalcomponent *cal = NULL;
1784 g_warning("can't get root folder\n");
1792 if (verbose && manual_update) {
1794 tmp = g_strdup(uri);
1795 if (strlen(uri) > 61) {
1803 alertpanel_error(_("Could not retrieve the Webcal URL:\n%s:\n\n%s"),
1804 tmp, error ? error:_("Unknown error"));
1807 log_error(LOG_PROTOCOL, _("Could not retrieve the Webcal URL:\n%s:\n\n%s\n"),
1808 uri, error ? error:_("Unknown error"));
1810 main_window_cursor_normal(mainwindow_get_mainwindow());
1816 if (strncmp(feed, "BEGIN:VCALENDAR", strlen("BEGIN:VCALENDAR"))) {
1817 if (verbose && manual_update) {
1818 alertpanel_error(_("This URL does not look like a WebCal URL:\n%s\n%s"),
1819 uri, error ? error:_("Unknown error"));
1821 log_error(LOG_PROTOCOL, _("This URL does not look like a WebCal URL:\n%s\n%s\n"),
1822 uri, error ? error:_("Unknown error"));
1825 main_window_cursor_normal(mainwindow_get_mainwindow());
1833 item = get_folder_item_for_uri(uri);
1835 gchar *title = feed_get_title(feed);
1836 if (title == NULL) {
1837 if (strstr(uri, "://"))
1838 title = g_strdup(strstr(uri,"://")+3);
1840 title = g_strdup(uri);
1841 subst_for_filename(title);
1842 if (strlen(title) > 32) {
1843 title[29]=title[30]=title[31]='.';
1847 item = folder_create_folder(root->node->data, title);
1848 debug_print("item done %s\n", title);
1849 ((VCalFolderItem *)item)->uri = g_strdup(uri);
1850 ((VCalFolderItem *)item)->feed = feed;
1853 if (((VCalFolderItem *)item)->feed)
1854 g_free(((VCalFolderItem *)item)->feed);
1856 ((VCalFolderItem *)item)->feed = feed;
1857 /* if title differs, update it */
1859 cal = icalparser_parse_string(feed);
1861 if (((VCalFolderItem *)item)->cal)
1862 icalcomponent_free(((VCalFolderItem *)item)->cal);
1864 ((VCalFolderItem *)item)->cal = cal;
1866 main_window_cursor_normal(mainwindow_get_mainwindow());
1867 ((VCalFolderItem *)item)->last_fetch = time(NULL);
1870 static void update_subscription(const gchar *uri, gboolean verbose)
1872 FolderItem *item = get_folder_item_for_uri(uri);
1875 if (prefs_common_get_prefs()->work_offline) {
1877 !inc_offline_should_override(TRUE,
1878 _("Claws Mail needs network access in order "
1879 "to update the Webcal feed.")))
1883 if (time(NULL) - ((VCalFolderItem *)(item))->last_fetch < 60 &&
1884 ((VCalFolderItem *)(item))->cal)
1887 main_window_cursor_wait(mainwindow_get_mainwindow());
1889 label = g_strdup_printf(_("Fetching calendar for %s..."),
1890 item && item->name ? item->name : _("new subscription"));
1891 vcal_curl_read(uri, label, verbose, update_subscription_finish);
1895 static void check_subs_cb(GtkAction *action, gpointer data)
1897 Folder *root = folder_find_from_name ("vCalendar", vcal_folder_get_class());
1899 if (prefs_common_get_prefs()->work_offline &&
1900 !inc_offline_should_override(TRUE,
1901 _("Claws Mail needs network access in order "
1902 "to update the subscription.")))
1905 folderview_check_new(root);
1908 static void subscribe_cal_cb(GtkAction *action, gpointer data)
1913 tmp = input_dialog(_("Subscribe to WebCal"), _("Enter the WebCal URL:"), NULL);
1917 if (!strncmp(tmp, "http", 4)) {
1919 } else if (!strncmp(tmp, "file://", 7)) {
1921 } else if (!strncmp(tmp, "webcal", 6)) {
1922 uri = g_strconcat("http", tmp+6, NULL);
1925 alertpanel_error(_("Could not parse the URL."));
1929 debug_print("uri %s\n", uri);
1931 update_subscription(uri, TRUE);
1932 folder_write_list();
1936 static void unsubscribe_cal_cb(GtkAction *action, gpointer data)
1938 FolderView *folderview = (FolderView *)data;
1939 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1946 if (!folderview->selected) return;
1948 item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
1949 g_return_if_fail(item != NULL);
1950 g_return_if_fail(item->path != NULL);
1951 g_return_if_fail(item->folder != NULL);
1953 message = g_strdup_printf
1954 (_("Do you really want to unsubscribe?"));
1955 avalue = alertpanel_full(_("Delete folder"), message,
1956 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL,
1957 FALSE, NULL, ALERT_WARNING, G_ALERTDEFAULT);
1959 if (avalue != G_ALERTALTERNATE) return;
1961 Xstrdup_a(old_path, item->path, return);
1962 old_id = folder_item_get_identifier(item);
1964 vcal_item_closed(item);
1966 if (folderview->opened == folderview->selected ||
1967 gtk_cmctree_is_ancestor(ctree,
1968 folderview->selected,
1969 folderview->opened)) {
1970 summary_clear_all(folderview->summaryview);
1971 folderview->opened = NULL;
1974 if (item->folder->klass->remove_folder(item->folder, item) < 0) {
1975 folder_item_scan(item);
1976 alertpanel_error(_("Can't remove the folder '%s'."), item->name);
1981 folder_write_list();
1983 prefs_filtering_delete_path(old_id);
1987 gboolean vcal_subscribe_uri(Folder *folder, const gchar *uri)
1990 if (folder->klass != vcal_folder_get_class())
1996 if (!strncmp(uri, "webcal", 6)) {
1997 tmp = g_strconcat("http", uri+6, NULL);
2001 debug_print("uri %s\n", tmp);
2003 update_subscription(tmp, FALSE);
2004 folder_write_list();
2008 static void rename_cb(GtkAction *action, gpointer data)
2010 FolderView *folderview = (FolderView *)data;
2016 item = folderview_get_selected_item(folderview);
2017 g_return_if_fail(item != NULL);
2018 g_return_if_fail(item->path != NULL);
2019 g_return_if_fail(item->folder != NULL);
2021 name = trim_string(item->name, 32);
2022 message = g_strdup_printf(_("Input new name for '%s':"), name);
2023 new_folder = input_dialog(_("Rename folder"), message, name);
2026 if (!new_folder) return;
2027 AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
2029 if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
2030 alertpanel_error(_("'%c' can't be included in folder name."),
2035 if (folder_find_child_item_by_name(folder_item_parent(item), new_folder)) {
2036 name = trim_string(new_folder, 32);
2037 alertpanel_error(_("The folder '%s' already exists."), name);
2042 if (folder_item_rename(item, new_folder) < 0) {
2043 alertpanel_error(_("The folder could not be renamed.\n"
2044 "The new folder name is not allowed."));
2048 folder_item_prefs_save_config_recursive(item);
2049 folder_write_list();
2052 static void set_view_cb(GtkAction *gaction, GtkRadioAction *current, gpointer data)
2054 FolderView *folderview = (FolderView *)data;
2055 gint action = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (current));
2056 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2057 FolderItem *item = NULL, *oitem = NULL;
2059 if (!folderview->selected) return;
2060 if (setting_sensitivity) return;
2062 oitem = gtk_cmctree_node_get_row_data(ctree, folderview->opened);
2063 item = gtk_cmctree_node_get_row_data(ctree, folderview->selected);
2065 if (((VCalFolderItem *)(item))->use_cal_view == action)
2067 debug_print("set view %d\n", action);
2068 if (oitem && item == oitem && oitem->folder->klass == vcal_folder_get_class())
2069 oitem->folder->klass->item_closed(oitem);
2070 ((VCalFolderItem *)(item))->use_cal_view = action;
2071 if (((VCalFolderItem *)(item))->use_cal_view) {
2072 if (oitem && item == oitem && oitem->folder->klass == vcal_folder_get_class())
2073 oitem->folder->klass->item_opened(oitem);
2077 gchar *vcal_get_event_as_ical_str(VCalEvent *event)
2080 icalcomponent *calendar = icalcomponent_vanew(
2081 ICAL_VCALENDAR_COMPONENT,
2082 icalproperty_new_version("2.0"),
2083 icalproperty_new_prodid(
2084 "-//Claws Mail//NONSGML Claws Mail Calendar//EN"),
2085 icalproperty_new_calscale("GREGORIAN"),
2087 vcal_manager_event_dump(event, FALSE, FALSE, calendar, FALSE);
2088 ical = g_strdup(icalcomponent_as_ical_string(calendar));
2089 icalcomponent_free(calendar);
2094 static gchar *get_name_from_property(icalproperty *p)
2098 if (p && icalproperty_get_parameter_as_string(p, "CN") != NULL)
2099 tmp = g_strdup(icalproperty_get_parameter_as_string(p, "CN"));
2104 static gchar *get_email_from_property(icalproperty *p)
2107 gchar *email = NULL;
2110 tmp = g_strdup(icalproperty_get_organizer(p));
2115 if (!strncasecmp(tmp, "MAILTO:", strlen("MAILTO:")))
2116 email = g_strdup(tmp+strlen("MAILTO:"));
2118 email = g_strdup(tmp);
2124 #define GET_PROP(comp,prop,kind) { \
2126 if (!(prop = icalcomponent_get_first_property(comp, kind))) { \
2128 ? icalcomponent_get_first_property(inner, kind) \
2133 #define GET_PROP_LIST(comp,list,kind) { \
2135 if (!(prop = icalcomponent_get_first_property(comp, kind))) { \
2137 ? icalcomponent_get_first_property(inner, kind) \
2140 list = g_slist_prepend(list, prop); \
2141 } while ((prop = icalcomponent_get_next_property(inner, kind)));\
2143 list = g_slist_prepend(list, prop); \
2144 } while ((prop = icalcomponent_get_next_property(comp, kind))); \
2147 #define TO_UTF8(string) { \
2148 if (string && !g_utf8_validate(string, -1, NULL)) { \
2149 gchar *tmp = conv_codeset_strdup(string, \
2150 charset ? charset:conv_get_locale_charset_str(),\
2157 VCalEvent *vcal_get_event_from_ical(const gchar *ical, const gchar *charset)
2159 VCalEvent *event = NULL;
2160 gchar *int_ical = g_strdup(ical);
2161 icalcomponent *comp = icalcomponent_new_from_string(int_ical);
2162 icalcomponent *inner = NULL;
2163 icalproperty *prop = NULL;
2164 GSList *list = NULL, *cur = NULL;
2166 gchar *location = NULL;
2167 gchar *summary = NULL;
2168 gchar *dtstart = NULL;
2169 gchar *dtend = NULL;
2170 gchar *org_email = NULL, *org_name = NULL;
2171 gchar *description = NULL;
2174 gchar *recur = NULL;
2176 enum icalproperty_method method = ICAL_METHOD_REQUEST;
2177 enum icalproperty_kind type = ICAL_VEVENT_COMPONENT;
2178 GSList *attendees = NULL;
2185 if ((inner = icalcomponent_get_inner(comp)) != NULL)
2186 type = icalcomponent_isa(inner);
2188 GET_PROP(comp, prop, ICAL_UID_PROPERTY);
2190 uid = g_strdup(icalproperty_get_uid(prop));
2192 icalproperty_free(prop);
2194 GET_PROP(comp, prop, ICAL_LOCATION_PROPERTY);
2196 location = g_strdup(icalproperty_get_location(prop));
2198 icalproperty_free(prop);
2200 GET_PROP(comp, prop, ICAL_SUMMARY_PROPERTY);
2202 summary = g_strdup(icalproperty_get_summary(prop));
2204 icalproperty_free(prop);
2206 GET_PROP(comp, prop, ICAL_DTSTART_PROPERTY);
2208 dtstart = g_strdup(icaltime_as_ical_string(icalproperty_get_dtstart(prop)));
2210 icalproperty_free(prop);
2212 GET_PROP(comp, prop, ICAL_DTEND_PROPERTY);
2214 dtend = g_strdup(icaltime_as_ical_string(icalproperty_get_dtend(prop)));
2216 icalproperty_free(prop);
2218 GET_PROP(comp, prop, ICAL_DURATION_PROPERTY);
2220 struct icaldurationtype duration = icalproperty_get_duration(prop);
2221 struct icaltimetype itt;
2222 icalproperty_free(prop);
2223 GET_PROP(comp, prop, ICAL_DTSTART_PROPERTY);
2225 itt = icalproperty_get_dtstart(prop);
2226 icalproperty_free(prop);
2227 dtend = g_strdup(icaltime_as_ical_string(icaltime_add(itt,duration)));
2232 GET_PROP(comp, prop, ICAL_SEQUENCE_PROPERTY);
2234 sequence = icalproperty_get_sequence(prop);
2235 icalproperty_free(prop);
2237 GET_PROP(comp, prop, ICAL_METHOD_PROPERTY);
2239 method = icalproperty_get_method(prop);
2240 icalproperty_free(prop);
2242 GET_PROP(comp, prop, ICAL_ORGANIZER_PROPERTY);
2244 org_email = get_email_from_property(prop);
2246 org_name = get_name_from_property(prop);
2248 icalproperty_free(prop);
2250 GET_PROP(comp, prop, ICAL_DESCRIPTION_PROPERTY);
2252 description = g_strdup(icalproperty_get_description(prop));
2253 TO_UTF8(description);
2254 icalproperty_free(prop);
2256 GET_PROP(comp, prop, ICAL_URL_PROPERTY);
2258 url = g_strdup(icalproperty_get_url(prop));
2260 icalproperty_free(prop);
2262 GET_PROP(comp, prop, ICAL_TZID_PROPERTY);
2264 tzid = g_strdup(icalproperty_get_tzid(prop));
2266 icalproperty_free(prop);
2268 GET_PROP(comp, prop, ICAL_RRULE_PROPERTY);
2270 struct icalrecurrencetype rrule = icalproperty_get_rrule(prop);
2271 recur = g_strdup(icalrecurrencetype_as_string(&rrule));
2273 icalproperty_free(prop);
2275 GET_PROP_LIST(comp, list, ICAL_ATTENDEE_PROPERTY);
2276 for (cur = list; cur; cur = cur->next) {
2277 enum icalparameter_partstat partstat = 0;
2278 enum icalparameter_cutype cutype = 0;
2279 icalparameter *param = NULL;
2280 gchar *email = NULL;
2282 Answer *answer = NULL;
2284 prop = (icalproperty *)(cur->data);
2286 email = get_email_from_property(prop);
2288 name = get_name_from_property(prop);
2291 param = icalproperty_get_first_parameter(prop, ICAL_PARTSTAT_PARAMETER);
2293 partstat = icalparameter_get_partstat(param);
2295 param = icalproperty_get_first_parameter(prop, ICAL_CUTYPE_PARAMETER);
2297 cutype= icalparameter_get_cutype(param);
2300 partstat = ICAL_PARTSTAT_NEEDSACTION;
2302 cutype = ICAL_CUTYPE_INDIVIDUAL;
2303 answer = answer_new(email, name, partstat, cutype);
2304 attendees = g_slist_prepend(attendees, answer);
2307 icalproperty_free(prop);
2311 event = vcal_manager_new_event (uid, org_email, org_name,
2312 location, summary, description,
2313 dtstart, dtend, recur,
2315 method, sequence, type);
2316 event->answers = attendees;
2324 g_free(description);
2329 icalcomponent_free(comp);
2333 gboolean vcal_event_exists(const gchar *id)
2335 MsgInfo *info = NULL;
2336 Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
2340 info = folder_item_get_msginfo_by_msgid(folder->inbox, id);
2342 procmsg_msginfo_free(info);
2348 void vcal_foreach_event(gboolean (*cb_func)(const gchar *vevent))
2350 GSList *list = vcal_folder_get_waiting_events();
2354 debug_print("calling cb_func...\n");
2355 for (cur = list; cur; cur = cur->next) {
2356 VCalEvent *event = (VCalEvent *)cur->data;
2357 gchar *tmp = vcal_get_event_as_ical_str(event);
2359 debug_print(" ...for event %s\n", event->uid);
2362 vcal_manager_free_event(event);
2367 /* please call vcalendar_refresh_folder_contents() after one or more
2368 * calls to this function */
2369 gboolean vcal_delete_event(const gchar *id)
2371 MsgInfo *info = NULL;
2372 Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
2376 info = folder_item_get_msginfo_by_msgid(folder->inbox, id);
2378 debug_print("removing event %s\n", id);
2379 vcal_remove_event(folder, info);
2380 procmsg_msginfo_free(info);
2381 folder_item_scan(folder->inbox);
2384 debug_print("not removing unexisting event %s\n", id);
2388 /* please call vcalendar_refresh_folder_contents() after one or more
2389 * calls to this function */
2390 gchar* vcal_add_event(const gchar *vevent)
2392 VCalEvent *event = vcal_get_event_from_ical(vevent, NULL);
2393 gchar *retVal = NULL;
2394 Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
2399 if (vcal_event_exists(event->uid)) {
2400 debug_print("event %s already exists\n", event->uid);
2401 vcal_manager_free_event(event);
2404 debug_print("adding event %s\n", event->uid);
2405 if (!account_find_from_address(event->organizer, FALSE) &&
2406 !vcal_manager_get_account_from_event(event)) {
2407 PrefsAccount *account = account_get_default();
2408 vcal_manager_update_answer(event, account->address,
2410 ICAL_PARTSTAT_ACCEPTED,
2411 ICAL_CUTYPE_INDIVIDUAL);
2412 debug_print("can't find our accounts in event, adding default\n");
2414 vcal_manager_save_event(event, TRUE);
2415 folder_item_scan(folder->inbox);
2416 retVal = vcal_get_event_as_ical_str(event);
2417 vcal_manager_free_event(event);
2423 /* please call vcalendar_refresh_folder_contents() after one or more
2424 * calls to this function */
2425 gchar* vcal_update_event(const gchar *vevent)
2427 VCalEvent *event = vcal_get_event_from_ical(vevent, NULL);
2430 r = vcal_delete_event(event->uid);
2431 vcal_manager_free_event(event);
2433 return vcal_add_event(vevent);