Initialize icaltimetype variables in Vcalendar's feed_fetch().
[claws.git] / src / plugins / vcalendar / vcal_folder.c
index 6ed463dce0b0e98a0b08501849cb3b56cc3a9162..97e7ded8de2b6d545a14a8a4362ce9ba04d0e4ec 100644 (file)
@@ -131,6 +131,7 @@ static void update_subscription(const gchar *uri, gboolean verbose);
 static void vcal_folder_set_batch      (Folder         *folder,
                                         FolderItem     *item,
                                         gboolean        batch);
+static void convert_to_utc(icalcomponent *calendar);
 
 gboolean vcal_subscribe_uri(Folder *folder, const gchar *uri);
 
@@ -235,7 +236,7 @@ static void vcal_fill_popup_menu_labels(void)
 
 static FolderViewPopup vcal_popup =
 {
-       "vCalendar",
+       PLUGIN_NAME,
        "<vCalendar>",
        vcal_popup_entries,
        G_N_ELEMENTS(vcal_popup_entries),
@@ -330,7 +331,7 @@ static void vcal_item_opened(FolderItem *item)
 
 void vcal_folder_refresh_cal(FolderItem *item)
 {
-       Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
+       Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
        if (item->folder != folder)
                return;
        if (((VCalFolderItem *)(item))->dw)
@@ -356,8 +357,8 @@ FolderClass *vcal_folder_get_class()
        if (vcal_class.idstr == NULL) {
                debug_print("register class\n");
                vcal_class.type = F_UNKNOWN;
-               vcal_class.idstr = "vCalendar";
-               vcal_class.uistr = "vCalendar";
+               vcal_class.idstr = PLUGIN_NAME;
+               vcal_class.uistr = PLUGIN_NAME;
 
                /* Folder functions */
                vcal_class.new_folder = vcal_folder_new;
@@ -609,7 +610,8 @@ add_new:
                        }
                        if (rprop && ritr) {
                                struct icaldurationtype ical_dur;
-                               struct icaltimetype dtstart, dtend;
+                               struct icaltimetype dtstart = icaltime_null_time();
+                               struct icaltimetype dtend = icaltime_null_time();
                                evt = icalcomponent_new_clone(evt);
                                prop = icalcomponent_get_first_property(evt, ICAL_RRULE_PROPERTY);
                                if (prop) {
@@ -619,9 +621,13 @@ add_new:
                                prop = icalcomponent_get_first_property(evt, ICAL_DTSTART_PROPERTY);
                                if (prop)
                                        dtstart = icalproperty_get_dtstart(prop);
+                               else
+                                       debug_print("event has no DTSTART!\n");
                                prop = icalcomponent_get_first_property(evt, ICAL_DTEND_PROPERTY);
                                if (prop)
                                        dtend = icalproperty_get_dtend(prop);
+                               else
+                                       debug_print("event has no DTEND!\n");
                                ical_dur = icaltime_subtract(dtend, dtstart);
                                next = icalrecur_iterator_next(ritr);
                                if (!icaltime_is_null_time(next) &&
@@ -790,7 +796,7 @@ GSList *vcal_get_events_list(FolderItem *item)
                                        next = icalrecur_iterator_next(ritr);
                                debug_print("next time is %snull\n", icaltime_is_null_time(next)?"":"not ");
                                while (!icaltime_is_null_time(next) && i < 100) {
-                                       gchar *new_start = NULL, *new_end = NULL;
+                                       const gchar *new_start = NULL, *new_end = NULL;
                                        VCalEvent *nevent = NULL;
                                        gchar *uid = g_strdup_printf("%s-%d", event->uid, i);
                                        new_start = icaltime_as_ical_string(next);
@@ -1347,7 +1353,7 @@ static void new_meeting_cb(GtkAction *action, gpointer data)
 
 GSList * vcal_folder_get_waiting_events(void)
 {
-       Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
+       Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
        return vcal_get_events_list(folder->inbox);
 }
 
@@ -1381,7 +1387,7 @@ static gboolean get_webcal_events_func(GNode *node, gpointer user_data)
 GSList * vcal_folder_get_webcal_events(void)
 {
        GetWebcalData *data = g_new0(GetWebcalData, 1);
-       Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
+       Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
        GSList *list = NULL;
        data->item = NULL;
        g_node_traverse(folder->node, G_PRE_ORDER,
@@ -1417,7 +1423,7 @@ static gboolean vcal_free_data_func(GNode *node, gpointer user_data)
 
 void vcal_folder_free_data(void)
 {
-       Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
+       Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
 
        g_node_traverse(folder->node, G_PRE_ORDER,
                        G_TRAVERSE_ALL, -1, vcal_free_data_func, NULL);
@@ -1426,7 +1432,7 @@ void vcal_folder_free_data(void)
 GSList * vcal_folder_get_webcal_events_for_folder(FolderItem *item)
 {
        GetWebcalData *data = g_new0(GetWebcalData, 1);
-       Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
+       Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
        GSList *list = NULL;
        data->item = item;
        g_node_traverse(folder->node, G_PRE_ORDER,
@@ -1758,7 +1764,7 @@ static gboolean folder_item_find_func(GNode *node, gpointer data)
 
 static FolderItem *get_folder_item_for_uri(const gchar *uri)
 {
-       Folder *root = folder_find_from_name ("vCalendar", vcal_folder_get_class());
+       Folder *root = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
        gpointer d[2];
        
        if (root == NULL)
@@ -1793,7 +1799,7 @@ static gchar *feed_get_title(const gchar *str)
 
 static void update_subscription_finish(const gchar *uri, gchar *feed, gboolean verbose, gchar *error)
 {
-       Folder *root = folder_find_from_name ("vCalendar", vcal_folder_get_class());
+       Folder *root = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
        FolderItem *item = NULL;
        icalcomponent *cal = NULL;
        
@@ -1806,9 +1812,10 @@ static void update_subscription_finish(const gchar *uri, gchar *feed, gboolean v
        }
 
        if (feed == NULL) {
+               gchar *err_msg = _("Could not retrieve the Webcal URL:\n%s:\n\n%s");
+
                if (verbose && manual_update) {
-                       gchar *tmp; 
-                       tmp = g_strdup(uri);
+                       gchar *tmp = g_strdup(uri);
                        if (strlen(uri) > 61) {
                                tmp[55]='[';
                                tmp[56]='.';
@@ -1817,12 +1824,12 @@ static void update_subscription_finish(const gchar *uri, gchar *feed, gboolean v
                                tmp[59]=']';
                                tmp[60]='\0';
                        } 
-                       alertpanel_error(_("Could not retrieve the Webcal URL:\n%s:\n\n%s"),
-                                       tmp, error ? error:_("Unknown error"));
+                       alertpanel_error(err_msg, tmp, error ? error:_("Unknown error"));
                        g_free(tmp);
                } else  {
-                       log_error(LOG_PROTOCOL, _("Could not retrieve the Webcal URL:\n%s:\n\n%s\n"),
-                                       uri, error ? error:_("Unknown error"));
+                       gchar *msg = g_strdup_printf("%s\n", err_msg);
+                       log_error(LOG_PROTOCOL, msg, uri, error ? error:_("Unknown error"));
+                       g_free(msg);
                }
                main_window_cursor_normal(mainwindow_get_mainwindow());
                g_free(feed);
@@ -1831,12 +1838,14 @@ static void update_subscription_finish(const gchar *uri, gchar *feed, gboolean v
                return;
        }
        if (strncmp(feed, "BEGIN:VCALENDAR", strlen("BEGIN:VCALENDAR"))) {
+               gchar *err_msg = _("This URL does not look like a Webcal URL:\n%s\n%s");
+
                if (verbose && manual_update) {
-                       alertpanel_error(_("This URL does not look like a Webcal URL:\n%s\n%s"),
-                                       uri, error ? error:_("Unknown error"));
+                       alertpanel_error(err_msg, uri, error ? error:_("Unknown error"));
                } else  {
-                       log_error(LOG_PROTOCOL, _("This URL does not look like a Webcal URL:\n%s\n%s\n"),
-                                       uri, error ? error:_("Unknown error"));
+                       gchar *msg = g_strdup_printf("%s\n", err_msg);
+                       log_error(LOG_PROTOCOL, msg, uri, error ? error:_("Unknown error"));
+                       g_free(msg);
                }
                g_free(feed);
                main_window_cursor_normal(mainwindow_get_mainwindow());
@@ -1883,6 +1892,8 @@ static void update_subscription_finish(const gchar *uri, gchar *feed, gboolean v
                /* if title differs, update it */
        }
        cal = icalparser_parse_string(feed);
+
+       convert_to_utc(cal);
        
        if (((VCalFolderItem *)item)->cal)
                icalcomponent_free(((VCalFolderItem *)item)->cal);
@@ -1920,7 +1931,7 @@ static void update_subscription(const gchar *uri, gboolean verbose)
 
 static void check_subs_cb(GtkAction *action, gpointer data)
 {
-       Folder *root = folder_find_from_name ("vCalendar", vcal_folder_get_class());
+       Folder *root = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
 
        if (prefs_common_get_prefs()->work_offline && 
            !inc_offline_should_override(TRUE,
@@ -2145,40 +2156,53 @@ static gchar *get_email_from_property(icalproperty *p)
        return email;
 }
 
-static void adjust_for_local_time_zone(icalproperty *eventtime, icalproperty *tzoffsetto, int dtstart)
+static void convert_to_utc(icalcomponent *calendar)
 {
-       int tzoffset;
-       int loctzoffset;
-       time_t loctime, gmttime, evttime;
-       struct icaltimetype icaltime;
-
-       /* calculate local UTC offset */
-       loctime = time(NULL);
-       loctime = mktime(localtime(&loctime));
-       gmttime = mktime(gmtime(&loctime));
-       loctzoffset = loctime - gmttime;
-
-       if (eventtime && tzoffsetto) {
-               tzoffset = icalproperty_get_tzoffsetto(tzoffsetto);
-               if (dtstart) {
-                       evttime = icaltime_as_timet(icalproperty_get_dtstart(eventtime));
-               }
-               else {
-                       evttime = icaltime_as_timet(icalproperty_get_dtend(eventtime));
+       icalcomponent *event;
+       icaltimezone *tz, *tzutc = icaltimezone_get_utc_timezone();
+       icalproperty *prop;
+       icalparameter *tzid;
+
+       cm_return_if_fail(calendar != NULL);
+
+       for (
+                       event = icalcomponent_get_first_component(calendar,
+                               ICAL_VEVENT_COMPONENT);
+                       event != NULL;
+                       event = icalcomponent_get_next_component(calendar,
+                               ICAL_VEVENT_COMPONENT)) {
+
+               /* DTSTART */
+               if ((prop = icalcomponent_get_first_property(event, ICAL_DTSTART_PROPERTY)) != NULL
+                               && (tzid = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER)) != NULL) {
+                       /* Event has its DTSTART with a timezone specification, let's convert
+                        * to UTC and remove the TZID parameter. */
+
+                       tz = icalcomponent_get_timezone(calendar, icalparameter_get_iana_value(tzid));
+                       if (tz != NULL) {
+                               debug_print("Converting DTSTART to UTC.\n");
+                               icaltimetype t = icalproperty_get_dtstart(prop);
+                               icaltimezone_convert_time(&t, tz, tzutc);
+                               icalproperty_set_dtstart(prop, t);
+                               icalproperty_remove_parameter_by_ref(prop, tzid);
+                       }
                }
 
-               /* convert to UTC */
-               evttime -= tzoffset;
-               /* and adjust for local time zone */
-               evttime += loctzoffset;
-               icaltime = icaltime_from_timet(evttime, 0);
-
-               if (dtstart) {
-                       icalproperty_set_dtstart(eventtime, icaltime);
+               /* DTEND */
+               if ((prop = icalcomponent_get_first_property(event, ICAL_DTEND_PROPERTY)) != NULL
+                               && (tzid = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER)) != NULL) {
+                       /* Event has its DTEND with a timezone specification, let's convert
+                        * to UTC and remove the TZID parameter. */
+
+                       tz = icalcomponent_get_timezone(calendar, icalparameter_get_iana_value(tzid));
+                       if (tz != NULL) {
+                               debug_print("Converting DTEND to UTC.\n");
+                               icaltimetype t = icalproperty_get_dtend(prop);
+                               icaltimezone_convert_time(&t, tz, tzutc);
+                               icalproperty_set_dtend(prop, t);
+                               icalproperty_remove_parameter_by_ref(prop, tzid);
+                       }
                }
-               else {
-                       icalproperty_set_dtend(eventtime, icaltime);
-               } 
        }
 }
 
@@ -2221,7 +2245,6 @@ VCalEvent *vcal_get_event_from_ical(const gchar *ical, const gchar *charset)
        gchar *int_ical = g_strdup(ical);
        icalcomponent *comp = icalcomponent_new_from_string(int_ical);
        icalcomponent *inner = NULL;
-       icalcomponent *tzcomp = NULL;
        icalproperty *prop = NULL;
        GSList *list = NULL, *cur = NULL;
        gchar *uid = NULL;
@@ -2265,31 +2288,9 @@ VCalEvent *vcal_get_event_from_ical(const gchar *ical, const gchar *charset)
                TO_UTF8(summary);
                icalproperty_free(prop);
        }
-       tzcomp = icalcomponent_get_first_component(comp, ICAL_VTIMEZONE_COMPONENT);
-       if (tzcomp) {
-               icalproperty *evtstart = NULL;
-               icalproperty *evtend = NULL;
-               icalproperty *tzoffsetto = NULL;
-               icalcomponent *tzstd = NULL;
-
-               tzstd = icalcomponent_get_first_component(tzcomp, ICAL_XSTANDARD_COMPONENT);
-               tzoffsetto = icalcomponent_get_first_property(tzstd, ICAL_TZOFFSETTO_PROPERTY);
 
-               GET_PROP(comp, evtstart, ICAL_DTSTART_PROPERTY);
-               adjust_for_local_time_zone(evtstart, tzoffsetto, TRUE);
+       convert_to_utc(comp);
 
-               GET_PROP(comp, evtend, ICAL_DTEND_PROPERTY);
-               adjust_for_local_time_zone(evtend, tzoffsetto, FALSE);
-
-               if (tzoffsetto)
-                       icalproperty_free(tzoffsetto);
-               if (evtstart)
-                       icalproperty_free(evtstart);
-               if (evtend)
-                       icalproperty_free(evtend);
-               if (tzstd)
-                       icalcomponent_free(tzstd);
-       }
        GET_PROP(comp, prop, ICAL_DTSTART_PROPERTY);
        if (prop) {
                dtstart = g_strdup(icaltime_as_ical_string(icalproperty_get_dtstart(prop)));
@@ -2420,7 +2421,7 @@ VCalEvent *vcal_get_event_from_ical(const gchar *ical, const gchar *charset)
 gboolean vcal_event_exists(const gchar *id)
 {
        MsgInfo *info = NULL;
-       Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
+       Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
        if (!folder)
                return FALSE;
 
@@ -2456,7 +2457,7 @@ void vcal_foreach_event(gboolean (*cb_func)(const gchar *vevent))
 gboolean vcal_delete_event(const gchar *id)
 {
        MsgInfo *info = NULL;
-       Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
+       Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
        if (!folder)
                return FALSE;
 
@@ -2478,7 +2479,7 @@ gchar* vcal_add_event(const gchar *vevent)
 {
        VCalEvent *event = vcal_get_event_from_ical(vevent, NULL);
        gchar *retVal = NULL;
-       Folder *folder = folder_find_from_name ("vCalendar", vcal_folder_get_class());
+       Folder *folder = folder_find_from_name (PLUGIN_NAME, vcal_folder_get_class());
        if (!folder)
                return NULL;