[evolution-ews] Bug 654459 - Support recurrence task



commit dd753a52ad2e376470bd39c041a209c3f7530ac0
Author: Milan Crha <mcrha redhat com>
Date:   Wed Mar 21 11:17:50 2018 +0100

    Bug 654459 - Support recurrence task

 po/POTFILES.in                         |    1 +
 src/addressbook/e-book-backend-ews.c   |   28 +-
 src/calendar/e-cal-backend-ews-utils.c |  112 ++-
 src/calendar/e-cal-backend-ews-utils.h |   10 +-
 src/calendar/e-cal-backend-ews.c       |    4 +
 src/camel/camel-ews-folder.c           |   14 +-
 src/camel/camel-ews-store.c            |    7 +-
 src/server/e-ews-calendar-utils.c      | 1474 +++++++++++++++++++++++++++++++-
 src/server/e-ews-calendar-utils.h      |   17 +-
 src/server/e-ews-camel-common.c        |    7 +-
 src/server/e-ews-connection.c          |   69 ++-
 src/server/e-ews-connection.h          |    5 +-
 src/server/e-ews-item.c                |  568 ++++++++++++-
 src/server/e-ews-item.h                |   89 ++
 tests/ews-test-timezones.c             |    2 +-
 15 files changed, 2290 insertions(+), 117 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index a6a06da..6fc898a 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -26,6 +26,7 @@ src/configuration/e-mail-config-ews-gal.c
 src/configuration/e-mail-config-ews-ooo-page.c
 src/configuration/module-ews-configuration.error.xml
 src/server/camel-sasl-xoauth2-office365.c
+src/server/e-ews-calendar-utils.c
 src/server/e-ews-camel-common.c
 src/server/e-ews-connection.c
 src/server/e-ews-connection-utils.c
diff --git a/src/addressbook/e-book-backend-ews.c b/src/addressbook/e-book-backend-ews.c
index 79d6f34..65c1870 100644
--- a/src/addressbook/e-book-backend-ews.c
+++ b/src/addressbook/e-book-backend-ews.c
@@ -1343,9 +1343,10 @@ ebb_ews_write_dl_members (ESoapMessage *msg,
        e_soap_message_end_element (msg); /* Members */
 }
 
-static void
+static gboolean
 ebb_ews_convert_dl_to_xml_cb (ESoapMessage *msg,
-                             gpointer user_data)
+                             gpointer user_data,
+                             GError **error)
 {
        EContact *contact = user_data;
        EVCardAttribute *attribute;
@@ -1361,11 +1362,14 @@ ebb_ews_convert_dl_to_xml_cb (ESoapMessage *msg,
        ebb_ews_write_dl_members (msg, contact);
 
        e_soap_message_end_element (msg); /* DistributionList */
+
+       return TRUE;
 }
 
-static void
+static gboolean
 ebb_ews_convert_contact_to_xml_cb (ESoapMessage *msg,
-                                  gpointer user_data)
+                                  gpointer user_data,
+                                  GError **error)
 {
        EContact *contact = user_data;
        gint i, element_type;
@@ -1393,6 +1397,8 @@ ebb_ews_convert_contact_to_xml_cb (ESoapMessage *msg,
 
        /* end of "Contact" */
        e_soap_message_end_element (msg);
+
+       return TRUE;
 }
 
 typedef struct _ConvertData {
@@ -1405,9 +1411,10 @@ typedef struct _ConvertData {
        gchar *change_key;
 } ConvertData;
 
-static void
+static gboolean
 ebb_ews_convert_dl_to_updatexml_cb (ESoapMessage *msg,
-                                   gpointer user_data)
+                                   gpointer user_data,
+                                   GError **error)
 {
        ConvertData *cd = user_data;
        EContact *old_contact = cd->old_contact;
@@ -1421,11 +1428,14 @@ ebb_ews_convert_dl_to_updatexml_cb (ESoapMessage *msg,
        ebb_ews_write_dl_members (msg, new_contact);
        e_ews_message_end_set_item_field (msg);
        e_ews_message_end_item_change (msg);
+
+       return TRUE;
 }
 
-static void
+static gboolean
 ebb_ews_convert_contact_to_updatexml_cb (ESoapMessage *msg,
-                                        gpointer user_data)
+                                        gpointer user_data,
+                                        GError **error)
 {
        ConvertData *cd = user_data;
        EContact *old_contact = cd->old_contact;
@@ -1486,6 +1496,8 @@ ebb_ews_convert_contact_to_updatexml_cb (ESoapMessage *msg,
        }
 
        e_ews_message_end_item_change (msg);
+
+       return TRUE;
 }
 
 static EContact *
diff --git a/src/calendar/e-cal-backend-ews-utils.c b/src/calendar/e-cal-backend-ews-utils.c
index eec1544..738af3f 100644
--- a/src/calendar/e-cal-backend-ews-utils.c
+++ b/src/calendar/e-cal-backend-ews-utils.c
@@ -1059,9 +1059,10 @@ check_is_all_day_event (const struct icaltimetype dtstart,
        return ((secs_end - secs_start) % (24 * 60 * 60)) == 0 && (secs_start % 24 * 60 * 60) == 0;
 }
 
-static void
+static gboolean
 convert_vevent_calcomp_to_xml (ESoapMessage *msg,
-                               gpointer user_data)
+                               gpointer user_data,
+                              GError **error)
 {
        EwsCalendarConvertData *convert_data = user_data;
        icalcomponent *icalcomp = convert_data->icalcomp;
@@ -1213,11 +1214,14 @@ convert_vevent_calcomp_to_xml (ESoapMessage *msg,
        e_soap_message_end_element (msg); /* "CalendarItem" */
 
        g_object_unref (comp);
+
+       return TRUE;
 }
 
-static void
+static gboolean
 convert_vtodo_calcomp_to_xml (ESoapMessage *msg,
-                              gpointer user_data)
+                              gpointer user_data,
+                             GError **error)
 {
        EwsCalendarConvertData *convert_data = user_data;
        icalcomponent *icalcomp = convert_data->icalcomp;
@@ -1225,6 +1229,7 @@ convert_vtodo_calcomp_to_xml (ESoapMessage *msg,
        icaltimetype dt;
        gint value;
        gchar buffer[16];
+       gboolean success;
        /* gboolean has_alarms; */
 
        e_soap_message_start_element (msg, "Task", NULL, NULL);
@@ -1250,6 +1255,8 @@ convert_vtodo_calcomp_to_xml (ESoapMessage *msg,
                e_ews_message_write_string_parameter (msg, "PercentComplete", NULL, buffer);
        }
 
+       success = e_ews_cal_utils_set_recurrence (msg, icalcomp, FALSE, error);
+
        prop = icalcomponent_get_first_property (icalcomp, ICAL_DTSTART_PROPERTY);
        if (prop) {
                dt = icalproperty_get_dtstart (prop);
@@ -1287,11 +1294,14 @@ convert_vtodo_calcomp_to_xml (ESoapMessage *msg,
                e_ews_message_write_string_parameter (msg, "ReminderIsSet", NULL, "false");*/
 
        e_soap_message_end_element (msg); /* "Task" */
+
+       return success;
 }
 
-static void
+static gboolean
 convert_vjournal_calcomp_to_xml (ESoapMessage *msg,
-                                gpointer user_data)
+                                gpointer user_data,
+                                GError **error)
 {
        EwsCalendarConvertData *convert_data = user_data;
        icalcomponent *icalcomp = convert_data->icalcomp;
@@ -1312,28 +1322,34 @@ convert_vjournal_calcomp_to_xml (ESoapMessage *msg,
        convert_categories_calcomp_to_xml (msg, NULL, icalcomp);
 
        e_soap_message_end_element (msg); /* Message */
+
+       return TRUE;
 }
 
-void
+gboolean
 e_cal_backend_ews_convert_calcomp_to_xml (ESoapMessage *msg,
-                                         gpointer user_data)
+                                         gpointer user_data,
+                                         GError **error)
 {
        EwsCalendarConvertData *convert_data = user_data;
+       gboolean success = FALSE;
 
        switch (icalcomponent_isa (convert_data->icalcomp)) {
        case ICAL_VEVENT_COMPONENT:
-               convert_vevent_calcomp_to_xml (msg, convert_data);
+               success = convert_vevent_calcomp_to_xml (msg, convert_data, error);
                break;
        case ICAL_VTODO_COMPONENT:
-               convert_vtodo_calcomp_to_xml (msg, convert_data);
+               success = convert_vtodo_calcomp_to_xml (msg, convert_data, error);
                break;
        case ICAL_VJOURNAL_COMPONENT:
-               convert_vjournal_calcomp_to_xml (msg, convert_data);
+               success = convert_vjournal_calcomp_to_xml (msg, convert_data, error);
                break;
        default:
                g_warn_if_reached ();
                break;
        }
+
+       return success;
 }
 
 static void
@@ -1393,9 +1409,10 @@ convert_vevent_property_to_updatexml (ESoapMessage *msg,
        e_ews_message_end_set_item_field (msg);
 }
 
-static void
+static gboolean
 convert_vevent_component_to_updatexml (ESoapMessage *msg,
-                                       gpointer user_data)
+                                       gpointer user_data,
+                                      GError **error)
 {
        EwsCalendarConvertData *convert_data = user_data;
        icalcomponent *icalcomp = e_cal_component_get_icalcomponent (convert_data->comp);
@@ -1415,7 +1432,6 @@ convert_vevent_component_to_updatexml (ESoapMessage *msg,
        gboolean satisfies;
        gint alarm = 0, alarm_old = 0;
        gchar *recid;
-       GError *error = NULL;
 
        /* Modifying a recurring meeting ? */
        if (icalcomponent_get_first_property (icalcomp_old, ICAL_RRULE_PROPERTY) != NULL) {
@@ -1432,7 +1448,7 @@ convert_vevent_component_to_updatexml (ESoapMessage *msg,
                                        convert_data->default_zone,
                                        recid,
                                        icalcomp_old,
-                                       &error));
+                                       NULL));
                        g_free (recid);
                } else {
                        e_ews_message_start_item_change (
@@ -1515,8 +1531,9 @@ convert_vevent_component_to_updatexml (ESoapMessage *msg,
        org_email_address = e_ews_collect_organizer (icalcomp);
        if (org_email_address && convert_data->user_email && g_ascii_strcasecmp (org_email_address, 
convert_data->user_email)) {
                e_ews_message_end_item_change (msg);
-               return;
+               return TRUE;
        }
+
        /* Update other properties allowed only for meeting organizers*/
        /*meeting dates*/
        dtstart = icalcomponent_get_dtstart (icalcomp);
@@ -1697,6 +1714,8 @@ convert_vevent_component_to_updatexml (ESoapMessage *msg,
        }
 
        e_ews_message_end_item_change (msg);
+
+       return TRUE;
 }
 
 static void
@@ -1712,9 +1731,10 @@ convert_vtodo_property_to_updatexml (ESoapMessage *msg,
        e_ews_message_end_set_item_field (msg);
 }
 
-static void
+static gboolean
 convert_vtodo_component_to_updatexml (ESoapMessage *msg,
-                                      gpointer user_data)
+                                      gpointer user_data,
+                                     GError **error)
 {
        EwsCalendarConvertData *convert_data = user_data;
        icalcomponent *icalcomp = e_cal_component_get_icalcomponent (convert_data->comp);
@@ -1722,6 +1742,7 @@ convert_vtodo_component_to_updatexml (ESoapMessage *msg,
        icaltimetype dt;
        gint value;
        gchar buffer[16];
+       gboolean success = TRUE;
 
        e_ews_message_start_item_change (
                msg, E_EWS_ITEMCHANGE_TYPE_ITEM,
@@ -1762,6 +1783,17 @@ convert_vtodo_component_to_updatexml (ESoapMessage *msg,
                e_ews_message_end_set_item_field (msg);
        }
 
+       /* Recurrence */
+       value = icalcomponent_count_properties (e_cal_component_get_icalcomponent (convert_data->old_comp), 
ICAL_RRULE_PROPERTY);
+       if (icalcomponent_count_properties (icalcomp, ICAL_RRULE_PROPERTY) > 0 ||
+           (e_cal_util_find_x_property (icalcomp, X_EWS_TASK_REGENERATION) && value <= 0)) {
+               e_ews_message_start_set_item_field (msg, "Recurrence", "task", "Task");
+               success = success && e_ews_cal_utils_set_recurrence (msg, icalcomp, FALSE, error);
+               e_ews_message_end_set_item_field (msg); /* Recurrence */
+       } else if (value > 0) {
+               e_ews_message_add_delete_item_field (msg, "Recurrence", "task");
+       }
+
        prop = icalcomponent_get_first_property (icalcomp, ICAL_DTSTART_PROPERTY);
        if (prop) {
                dt = icalproperty_get_dtstart (prop);
@@ -1794,6 +1826,8 @@ convert_vtodo_component_to_updatexml (ESoapMessage *msg,
        convert_component_categories_to_updatexml (convert_data->comp, msg, "Task");
 
        e_ews_message_end_item_change (msg);
+
+       return success;
 }
 
 static void
@@ -1809,9 +1843,10 @@ convert_vjournal_property_to_updatexml (ESoapMessage *msg,
        e_ews_message_end_set_item_field (msg);
 }
 
-static void
+static gboolean
 convert_vjournal_component_to_updatexml (ESoapMessage *msg,
-                                        gpointer user_data)
+                                        gpointer user_data,
+                                        GError **error)
 {
        EwsCalendarConvertData *convert_data = user_data;
        icalcomponent *icalcomp = e_cal_component_get_icalcomponent (convert_data->comp);
@@ -1847,28 +1882,34 @@ convert_vjournal_component_to_updatexml (ESoapMessage *msg,
        convert_component_categories_to_updatexml (convert_data->comp, msg, "Message");
 
        e_ews_message_end_item_change (msg);
+
+       return TRUE;
 }
 
-void
+gboolean
 e_cal_backend_ews_convert_component_to_updatexml (ESoapMessage *msg,
-                                                 gpointer user_data)
+                                                 gpointer user_data,
+                                                 GError **error)
 {
        EwsCalendarConvertData *convert_data = user_data;
        icalcomponent *icalcomp = e_cal_component_get_icalcomponent (convert_data->comp);
+       gboolean success = FALSE;
 
        switch (icalcomponent_isa (icalcomp)) {
        case ICAL_VEVENT_COMPONENT:
-               convert_vevent_component_to_updatexml (msg, user_data);
+               success = convert_vevent_component_to_updatexml (msg, user_data, error);
                break;
        case ICAL_VTODO_COMPONENT:
-               convert_vtodo_component_to_updatexml (msg, user_data);
+               success = convert_vtodo_component_to_updatexml (msg, user_data, error);
                break;
        case ICAL_VJOURNAL_COMPONENT:
-               convert_vjournal_component_to_updatexml (msg, user_data);
+               success = convert_vjournal_component_to_updatexml (msg, user_data, error);
                break;
        default:
                break;
        }
+
+       return success;
 }
 
 guint
@@ -1910,9 +1951,10 @@ e_cal_backend_ews_rid_to_index (icaltimezone *timezone,
        return index;
 }
 
-void
+gboolean
 e_cal_backend_ews_clear_reminder_is_set (ESoapMessage *msg,
-                                        gpointer user_data)
+                                        gpointer user_data,
+                                        GError **error)
 {
        EwsCalendarConvertData *convert_data = user_data;
 
@@ -1930,11 +1972,14 @@ e_cal_backend_ews_clear_reminder_is_set (ESoapMessage *msg,
        e_ews_message_end_set_item_field (msg);
 
        e_ews_message_end_item_change (msg);
+
+       return TRUE;
 }
 
-void
+gboolean
 e_cal_backend_ews_prepare_set_free_busy_status (ESoapMessage *msg,
-                                               gpointer user_data)
+                                               gpointer user_data,
+                                               GError **error)
 {
        EwsCalendarConvertData *data = user_data;
 
@@ -1947,11 +1992,14 @@ e_cal_backend_ews_prepare_set_free_busy_status (ESoapMessage *msg,
        e_ews_message_end_set_item_field (msg);
 
        e_ews_message_end_item_change (msg);
+
+       return TRUE;
 }
 
-void
+gboolean
 e_cal_backend_ews_prepare_accept_item_request (ESoapMessage *msg,
-                                              gpointer user_data)
+                                              gpointer user_data,
+                                              GError **error)
 {
        EwsCalendarConvertData *data = user_data;
        const gchar *response_type = data->response_type;
@@ -1976,4 +2024,6 @@ e_cal_backend_ews_prepare_accept_item_request (ESoapMessage *msg,
 
        /* end of "AcceptItem" */
        e_soap_message_end_element (msg);
+
+       return TRUE;
 }
diff --git a/src/calendar/e-cal-backend-ews-utils.h b/src/calendar/e-cal-backend-ews-utils.h
index 4aea6d2..32493f6 100644
--- a/src/calendar/e-cal-backend-ews-utils.h
+++ b/src/calendar/e-cal-backend-ews-utils.h
@@ -71,11 +71,11 @@ const gchar *e_cal_backend_ews_tz_util_get_ical_equivalent (const gchar *msdn_tz
 void e_cal_backend_ews_populate_windows_zones (void);
 void e_cal_backend_ews_unref_windows_zones (void);
 
-void e_cal_backend_ews_convert_calcomp_to_xml (ESoapMessage *msg, gpointer user_data);
-void e_cal_backend_ews_convert_component_to_updatexml (ESoapMessage *msg, gpointer user_data);
-void e_cal_backend_ews_clear_reminder_is_set (ESoapMessage *msg, gpointer user_data);
-void e_cal_backend_ews_prepare_set_free_busy_status (ESoapMessage *msg,gpointer user_data);
-void e_cal_backend_ews_prepare_accept_item_request (ESoapMessage *msg, gpointer user_data);
+gboolean e_cal_backend_ews_convert_calcomp_to_xml (ESoapMessage *msg, gpointer user_data, GError **error);
+gboolean e_cal_backend_ews_convert_component_to_updatexml (ESoapMessage *msg, gpointer user_data, GError 
**error);
+gboolean e_cal_backend_ews_clear_reminder_is_set (ESoapMessage *msg, gpointer user_data, GError **error);
+gboolean e_cal_backend_ews_prepare_set_free_busy_status (ESoapMessage *msg,gpointer user_data, GError 
**error);
+gboolean e_cal_backend_ews_prepare_accept_item_request (ESoapMessage *msg, gpointer user_data, GError 
**error);
 
 guint e_cal_backend_ews_rid_to_index (icaltimezone *timezone, const gchar *rid, icalcomponent *comp, GError 
**error);
 
diff --git a/src/calendar/e-cal-backend-ews.c b/src/calendar/e-cal-backend-ews.c
index 447732e..1d48492 100644
--- a/src/calendar/e-cal-backend-ews.c
+++ b/src/calendar/e-cal-backend-ews.c
@@ -477,6 +477,9 @@ ecb_ews_item_to_component_sync (ECalBackendEws *cbews,
                        icalprop = icalproperty_new_priority (priority);
                        icalcomponent_add_property (icalcomp, icalprop);
 
+                       /* recurrence */
+                       e_ews_cal_utils_recurrence_to_rrule (item, icalcomp);
+
                        /* reminders */
                        /* The Exchange server stores start of the Task reminder and Start of the Task
                           itself in separate properties, which doesn't work for evolution at the moment. */
@@ -3702,6 +3705,7 @@ ecb_ews_get_backend_property (ECalBackend *cal_backend,
                        CAL_STATIC_CAPABILITY_ALL_DAY_EVENT_AS_TIME,
                        CAL_STATIC_CAPABILITY_TASK_DATE_ONLY,
                        CAL_STATIC_CAPABILITY_TASK_NO_ALARM,
+                       CAL_STATIC_CAPABILITY_TASK_CAN_RECUR,
                        e_cal_meta_backend_get_capabilities (E_CAL_META_BACKEND (cbews)),
                        NULL);
        } else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS)) {
diff --git a/src/camel/camel-ews-folder.c b/src/camel/camel-ews-folder.c
index e3157c5..cc1c266 100644
--- a/src/camel/camel-ews-folder.c
+++ b/src/camel/camel-ews-folder.c
@@ -991,9 +991,10 @@ ews_folder_search_free (CamelFolder *folder,
 
 /********************* folder functions*************************/
 
-static void
+static gboolean
 msg_update_flags (ESoapMessage *msg,
-                  gpointer user_data)
+                  gpointer user_data,
+                 GError **error)
 {
        /* the mi_list is owned by the caller */
        const GSList *mi_list = user_data, *iter;
@@ -1111,11 +1112,14 @@ msg_update_flags (ESoapMessage *msg,
                        camel_folder_summary_unlock (summary);
                g_clear_object (&summary);
        }
+
+       return TRUE;
 }
 
-static void
+static gboolean
 ews_suppress_read_receipt (ESoapMessage *msg,
-                          gpointer user_data)
+                          gpointer user_data,
+                          GError **error)
 {
        /* the mi_list is owned by the caller */
        const GSList *mi_list = user_data, *iter;
@@ -1154,6 +1158,8 @@ ews_suppress_read_receipt (ESoapMessage *msg,
                        camel_folder_summary_unlock (summary);
                g_clear_object (&summary);
        }
+
+       return TRUE;
 }
 
 static gboolean
diff --git a/src/camel/camel-ews-store.c b/src/camel/camel-ews-store.c
index d309277..5974754 100644
--- a/src/camel/camel-ews-store.c
+++ b/src/camel/camel-ews-store.c
@@ -2817,9 +2817,10 @@ struct _rename_cb_data {
        const gchar *folder_id;
 };
 
-static void
+static gboolean
 rename_folder_cb (ESoapMessage *msg,
-                  gpointer user_data)
+                  gpointer user_data,
+                 GError **error)
 {
        struct _rename_cb_data *rename_data = user_data;
 
@@ -2838,6 +2839,8 @@ rename_folder_cb (ESoapMessage *msg,
        e_soap_message_end_element (msg); /* SetFolderField */
 
        e_ews_message_end_item_change (msg);
+
+       return TRUE;
 }
 
 static gboolean
diff --git a/src/server/e-ews-calendar-utils.c b/src/server/e-ews-calendar-utils.c
index 6e84350..406e87c 100644
--- a/src/server/e-ews-calendar-utils.c
+++ b/src/server/e-ews-calendar-utils.c
@@ -19,10 +19,184 @@
 
 #include "evolution-ews-config.h"
 
+#include <glib/gi18n-lib.h>
+#include <libecal/libecal.h>
+
 #include "e-ews-message.h"
+#include "ews-errors.h"
 
 #include "e-ews-calendar-utils.h"
 
+static void
+e_ews_cal_util_encode_regeneration (EEwsRecurrence *in_recur,
+                                   icalcomponent *out_comp) /* not 'out' as such */
+{
+       gchar chr = 0;
+
+       g_return_if_fail (in_recur != NULL);
+       g_return_if_fail (out_comp != NULL);
+
+       switch (in_recur->type) {
+       case E_EWS_RECURRENCE_DAILY_REGENERATION:
+               chr = 'D';
+               break;
+       case E_EWS_RECURRENCE_WEEKLY_REGENERATION:
+               chr = 'W';
+               break;
+       case E_EWS_RECURRENCE_MONTHLY_REGENERATION:
+               chr = 'M';
+               break;
+       case E_EWS_RECURRENCE_YEARLY_REGENERATION:
+               chr = 'Y';
+               break;
+       default:
+               break;
+       }
+
+       if (chr && in_recur->end_type != E_EWS_RECURRENCE_END_UNKNOWN) {
+               gchar end_chr = 0;
+               gint64 end_num = 0;
+
+               switch (in_recur->end_type) {
+               case E_EWS_RECURRENCE_END_UNKNOWN:
+                       g_warn_if_reached ();
+                       break;
+               case E_EWS_RECURRENCE_END_NO_END:
+                       end_chr = 'X';
+                       end_num = 0;
+                       break;
+               case E_EWS_RECURRENCE_END_DATE:
+                       end_chr = 'D';
+                       end_num = (gint64) in_recur->end.utc_end_date;
+                       break;
+               case E_EWS_RECURRENCE_END_NUMBERED:
+                       end_chr = 'N';
+                       end_num = (gint64) in_recur->end.number_of_occurrences;
+                       break;
+               }
+
+               if (end_chr) {
+                       gchar *value;
+                       gint64 start_num;
+
+                       start_num = (gint64) in_recur->utc_start_date;
+
+                       value = g_strdup_printf ("%c.%d.%c.%" G_GINT64_FORMAT ".%" G_GINT64_FORMAT,
+                               chr,
+                               in_recur->recur.interval,
+                               end_chr,
+                               start_num,
+                               end_num);
+                       e_cal_util_set_x_property (out_comp, X_EWS_TASK_REGENERATION, value);
+                       g_free (value);
+               }
+       } else {
+               e_cal_util_remove_x_property (out_comp, X_EWS_TASK_REGENERATION);
+       }
+}
+
+static gboolean
+e_ews_cal_util_decode_regeneration_info_from_string (const gchar *value,
+                                                    gchar *out_recur_type_chr,
+                                                    gint *out_interval,
+                                                    gchar *out_end_type_chr,
+                                                    gint64 *out_start_num,
+                                                    gint64 *out_end_num)
+{
+       gchar **parts;
+
+       if (!value || !*value)
+               return FALSE;
+
+       parts = g_strsplit (value, ".", -1);
+
+       if (g_strv_length (parts) != 5) {
+               g_strfreev (parts);
+               return FALSE;
+       }
+
+       if (out_recur_type_chr)
+               *out_recur_type_chr = parts[0][0];
+
+       if (out_interval)
+               *out_interval = (gint) g_ascii_strtoll (parts[1], NULL, 10);
+
+       if (out_end_type_chr)
+               *out_end_type_chr = parts[2][0];
+
+       if (out_start_num)
+               *out_start_num = g_ascii_strtoll (parts[3], NULL, 10);
+
+       if (out_end_num)
+               *out_end_num = g_ascii_strtoll (parts[4], NULL, 10);
+
+       g_strfreev (parts);
+
+       return TRUE;
+}
+
+static void
+e_ews_cal_util_decode_regeneration (icalcomponent *in_comp,
+                                   EEwsRecurrence *out_recur)
+{
+       const gchar *value;
+       gchar recur_type_chr = 0, end_type_chr = 0;
+       gint interval = 0;
+       gint64 start_num = 0, end_num = 0;
+
+       g_return_if_fail (in_comp != NULL);
+       g_return_if_fail (out_recur != NULL);
+
+       value = e_cal_util_get_x_property (in_comp, X_EWS_TASK_REGENERATION);
+
+       if (e_ews_cal_util_decode_regeneration_info_from_string (value, &recur_type_chr, &interval, 
&end_type_chr, &start_num, &end_num)) {
+               EEwsRecurrenceType recur_type = E_EWS_RECURRENCE_UNKNOWN;
+               EEwsRecurrenceEndType end_type = E_EWS_RECURRENCE_END_UNKNOWN;
+
+               switch (recur_type_chr) {
+               case 'D':
+                       recur_type = E_EWS_RECURRENCE_DAILY_REGENERATION;
+                       break;
+               case 'W':
+                       recur_type = E_EWS_RECURRENCE_WEEKLY_REGENERATION;
+                       break;
+               case 'M':
+                       recur_type = E_EWS_RECURRENCE_MONTHLY_REGENERATION;
+                       break;
+               case 'Y':
+                       recur_type = E_EWS_RECURRENCE_YEARLY_REGENERATION;
+                       break;
+               }
+
+               switch (end_type_chr) {
+               case 'X':
+                       end_type = E_EWS_RECURRENCE_END_NO_END;
+                       break;
+               case 'D':
+                       end_type = E_EWS_RECURRENCE_END_DATE;
+                       break;
+               case 'N':
+                       end_type = E_EWS_RECURRENCE_END_NUMBERED;
+                       break;
+               }
+
+               if (recur_type != E_EWS_RECURRENCE_UNKNOWN && end_type != E_EWS_RECURRENCE_END_UNKNOWN &&
+                   start_num > 0 && (end_type == E_EWS_RECURRENCE_END_NO_END || end_num > 0) && interval > 
0) {
+                       out_recur->type = recur_type;
+                       out_recur->recur.interval = interval;
+                       out_recur->end_type = end_type;
+                       out_recur->utc_start_date = (time_t) start_num;
+
+                       if (end_type == E_EWS_RECURRENCE_END_DATE)
+                               out_recur->end.utc_end_date = (time_t) end_num;
+                       else if (end_type == E_EWS_RECURRENCE_END_NUMBERED)
+                               out_recur->end.number_of_occurrences = (gint) end_num;
+               }
+       } else if (value && *value) {
+               g_warning ("%s: Failed to decode value '%s'", G_STRFUNC, value);
+       }
+}
+
 static const gchar *
 number_to_weekday (gint num)
 {
@@ -165,16 +339,17 @@ ewscal_set_availability_timezone (ESoapMessage *msg,
        e_soap_message_end_element (msg); /* "TimeZone" */
 }
 
-void
+gboolean
 e_ews_cal_utils_prepare_free_busy_request (ESoapMessage *msg,
-                                          gpointer user_data)
+                                          gpointer user_data,
+                                          GError **error)
 {
        const EEWSFreeBusyData *fbdata = user_data;
        icaltimetype t_start, t_end;
        icaltimezone *utc_zone = icaltimezone_get_utc_timezone ();
        GSList *link;
 
-       g_return_if_fail (fbdata != NULL);
+       g_return_val_if_fail (fbdata != NULL, FALSE);
 
        ewscal_set_availability_timezone (msg, utc_zone);
 
@@ -210,6 +385,8 @@ e_ews_cal_utils_prepare_free_busy_request (ESoapMessage *msg,
        e_ews_message_write_string_parameter (msg, "RequestedView", NULL, "DetailedMerged");
 
        e_soap_message_end_element (msg); /* "FreeBusyViewOptions" */
+
+       return TRUE;
 }
 
 void
@@ -256,3 +433,1294 @@ e_ews_cal_utils_set_time (ESoapMessage *msg,
        g_free (tz_ident);
        g_free (str);
 }
+
+static gint
+e_ews_cal_util_recurrence_count_by_xxx (gshort *field,
+                                       gint max_elements)
+{
+       gint ii;
+
+       for (ii = 0; ii < max_elements; ii++)
+               if (field[ii] == ICAL_RECURRENCE_ARRAY_MAX)
+                       break;
+
+       return ii;
+}
+
+static EEwsRecurrenceDaysOfWeek
+e_ews_cal_util_month_index_to_days_of_week (gint month_index)
+{
+       switch (month_index) {
+       case 0:
+               return E_EWS_RECURRENCE_DAYS_OF_WEEK_SUNDAY;
+       case 1:
+               return E_EWS_RECURRENCE_DAYS_OF_WEEK_MONDAY;
+       case 2:
+               return E_EWS_RECURRENCE_DAYS_OF_WEEK_TUESDAY;
+       case 3:
+               return E_EWS_RECURRENCE_DAYS_OF_WEEK_WEDNESDAY;
+       case 4:
+               return E_EWS_RECURRENCE_DAYS_OF_WEEK_THURSDAY;
+       case 5:
+               return E_EWS_RECURRENCE_DAYS_OF_WEEK_FRIDAY;
+       case 6:
+               return E_EWS_RECURRENCE_DAYS_OF_WEEK_SATURDAY;
+       default:
+               g_warning ("%s: What is month_index:%d for the last day?", G_STRFUNC, month_index);
+               break;
+       }
+
+       return E_EWS_RECURRENCE_DAYS_OF_WEEK_UNKNOWN;
+}
+
+enum month_num_options {
+       MONTH_NUM_INVALID = -1,
+       MONTH_NUM_FIRST,
+       MONTH_NUM_SECOND,
+       MONTH_NUM_THIRD,
+       MONTH_NUM_FOURTH,
+       MONTH_NUM_FIFTH,
+       MONTH_NUM_LAST,
+       MONTH_NUM_DAY,
+       MONTH_NUM_OTHER
+};
+
+enum month_day_options {
+       MONTH_DAY_NTH,
+       MONTH_DAY_MON,
+       MONTH_DAY_TUE,
+       MONTH_DAY_WED,
+       MONTH_DAY_THU,
+       MONTH_DAY_FRI,
+       MONTH_DAY_SAT,
+       MONTH_DAY_SUN
+};
+
+static EEwsRecurrenceDayOfWeekIndex
+e_ews_cal_util_month_num_to_day_of_week_index (gint month_num)
+{
+       switch (month_num) {
+       case MONTH_NUM_FIRST:
+               return E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_FIRST;
+       case MONTH_NUM_SECOND:
+               return E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_SECOND;
+       case MONTH_NUM_THIRD:
+               return E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_THIRD;
+       case MONTH_NUM_FOURTH:
+               return E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_FOURTH;
+       case MONTH_NUM_FIFTH:
+       case MONTH_NUM_LAST:
+               return E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_LAST;
+       default:
+               break;
+       }
+
+       return E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_UNKNOWN;
+}
+
+static gboolean
+e_ews_cal_utils_convert_recurrence (icalcomponent *icalcomp,
+                                   EEwsRecurrence *out_recur,
+                                   GError **error)
+{
+       icalproperty *prop;
+       struct icalrecurrencetype rrule;
+       gint n_by_second, n_by_minute, n_by_hour;
+       gint n_by_day, n_by_month_day, n_by_year_day;
+       gint n_by_week_no, n_by_month, n_by_set_pos;
+
+       g_return_val_if_fail (icalcomp != NULL, FALSE);
+       g_return_val_if_fail (out_recur != NULL, FALSE);
+
+       prop = icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY);
+       if (!prop) {
+               e_ews_cal_util_decode_regeneration (icalcomp, out_recur);
+               return TRUE;
+       }
+
+       switch (icalcomponent_isa (icalcomp)) {
+       case ICAL_VEVENT_COMPONENT:
+       case ICAL_VTODO_COMPONENT:
+       case ICAL_VJOURNAL_COMPONENT:
+               break;
+       default:
+               return TRUE;
+       }
+
+       out_recur->type = E_EWS_RECURRENCE_UNKNOWN;
+       out_recur->end_type = E_EWS_RECURRENCE_END_UNKNOWN;
+
+       if (icalcomponent_count_properties (icalcomp, ICAL_RRULE_PROPERTY) != 1 ||
+           icalcomponent_count_properties (icalcomp, ICAL_RDATE_PROPERTY) != 0 ||
+           icalcomponent_count_properties (icalcomp, ICAL_EXRULE_PROPERTY) != 0)
+               goto custom;
+
+       rrule = icalproperty_get_rrule (prop);
+
+       switch (rrule.freq) {
+       case ICAL_DAILY_RECURRENCE:
+       case ICAL_WEEKLY_RECURRENCE:
+       case ICAL_MONTHLY_RECURRENCE:
+       case ICAL_YEARLY_RECURRENCE:
+               break;
+       default:
+               goto custom;
+
+       }
+
+#define N_HAS_BY(field) (e_ews_cal_util_recurrence_count_by_xxx (field, G_N_ELEMENTS (field)))
+
+       n_by_second = N_HAS_BY (rrule.by_second);
+       n_by_minute = N_HAS_BY (rrule.by_minute);
+       n_by_hour = N_HAS_BY (rrule.by_hour);
+       n_by_day = N_HAS_BY (rrule.by_day);
+       n_by_month_day = N_HAS_BY (rrule.by_month_day);
+       n_by_year_day = N_HAS_BY (rrule.by_year_day);
+       n_by_week_no = N_HAS_BY (rrule.by_week_no);
+       n_by_month = N_HAS_BY (rrule.by_month);
+       n_by_set_pos = N_HAS_BY (rrule.by_set_pos);
+
+#undef N_HAS_BY
+
+       if (n_by_second != 0 ||
+           n_by_minute != 0 ||
+           n_by_hour != 0)
+               goto custom;
+
+       switch (rrule.freq) {
+       case ICAL_DAILY_RECURRENCE:
+               if (n_by_day != 0 ||
+                   n_by_month_day != 0 ||
+                   n_by_year_day != 0 ||
+                   n_by_week_no != 0 ||
+                   n_by_month != 0 ||
+                   n_by_set_pos != 0)
+                       goto custom;
+
+               if (rrule.interval > 0) {
+                       out_recur->type = E_EWS_RECURRENCE_DAILY;
+                       out_recur->recur.interval = rrule.interval;
+               }
+               break;
+
+       case ICAL_WEEKLY_RECURRENCE: {
+               gint ii, ndays;
+               guint8 day_mask;
+
+               if (n_by_month_day != 0 ||
+                   n_by_year_day != 0 ||
+                   n_by_week_no != 0 ||
+                   n_by_month != 0 ||
+                   n_by_set_pos != 0)
+                       goto custom;
+
+               day_mask = 0;
+
+               for (ii = 0; ii < 8 && rrule.by_day[ii] != ICAL_RECURRENCE_ARRAY_MAX; ii++) {
+                       enum icalrecurrencetype_weekday weekday;
+                       gint pos;
+
+                       weekday = icalrecurrencetype_day_day_of_week (rrule.by_day[ii]);
+                       pos = icalrecurrencetype_day_position (rrule.by_day[ii]);
+
+                       if (pos != 0)
+                               goto custom;
+
+                       switch (weekday) {
+                       case ICAL_SUNDAY_WEEKDAY:
+                               day_mask |= 1 << 0;
+                               break;
+
+                       case ICAL_MONDAY_WEEKDAY:
+                               day_mask |= 1 << 1;
+                               break;
+
+                       case ICAL_TUESDAY_WEEKDAY:
+                               day_mask |= 1 << 2;
+                               break;
+
+                       case ICAL_WEDNESDAY_WEEKDAY:
+                               day_mask |= 1 << 3;
+                               break;
+
+                       case ICAL_THURSDAY_WEEKDAY:
+                               day_mask |= 1 << 4;
+                               break;
+
+                       case ICAL_FRIDAY_WEEKDAY:
+                               day_mask |= 1 << 5;
+                               break;
+
+                       case ICAL_SATURDAY_WEEKDAY:
+                               day_mask |= 1 << 6;
+                               break;
+
+                       default:
+                               break;
+                       }
+               }
+
+               if (ii == 0) {
+                       struct icaltimetype dtstart;
+
+                       dtstart = icalcomponent_get_dtstart (icalcomp);
+
+                       ii = icaltime_day_of_week (dtstart);
+                       if (ii >= 1)
+                               day_mask |= 1 << (ii - 1);
+               }
+
+               ndays = 0;
+
+               for (ii = 0; ii < 7; ii++) {
+                       if ((day_mask & (1 << ii)) != 0)
+                               ndays++;
+               }
+
+               out_recur->type = E_EWS_RECURRENCE_WEEKLY;
+               out_recur->recur.weekly.interval = rrule.interval;
+               out_recur->recur.weekly.days_of_week = 0;
+               out_recur->recur.weekly.first_day_of_week = G_DATE_BAD_WEEKDAY;
+
+               for (ii = 0; ii < 7 && ndays; ii++) {
+                       if ((day_mask & (1 << ii)) != 0) {
+                               switch (ii) {
+                               case 0:
+                                       out_recur->recur.weekly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_SUNDAY;
+                                       break;
+                               case 1:
+                                       out_recur->recur.weekly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_MONDAY;
+                                       break;
+                               case 2:
+                                       out_recur->recur.weekly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_TUESDAY;
+                                       break;
+                               case 3:
+                                       out_recur->recur.weekly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_WEDNESDAY;
+                                       break;
+                               case 4:
+                                       out_recur->recur.weekly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_THURSDAY;
+                                       break;
+                               case 5:
+                                       out_recur->recur.weekly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_FRIDAY;
+                                       break;
+                               case 6:
+                                       out_recur->recur.weekly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_SATURDAY;
+                                       break;
+                               default:
+                                       g_warn_if_reached ();
+                                       break;
+                               }
+                       }
+               }
+               break;
+       }
+
+       case ICAL_MONTHLY_RECURRENCE: {
+               gint month_index = 1;
+               enum month_day_options month_day;
+               enum month_num_options month_num;
+
+               if (n_by_year_day != 0 ||
+                   n_by_week_no != 0 ||
+                   n_by_month != 0 ||
+                   n_by_set_pos > 1)
+                       goto custom;
+
+               if (n_by_month_day == 1) {
+                       gint nth;
+
+                       if (n_by_set_pos != 0)
+                               goto custom;
+
+                       nth = rrule.by_month_day[0];
+                       if (nth < 1 && nth != -1)
+                               goto custom;
+
+                       if (nth == -1) {
+                               struct icaltimetype dtstart;
+
+                               dtstart = icalcomponent_get_dtstart (icalcomp);
+
+                               month_index = dtstart.day;
+                               month_num = MONTH_NUM_LAST;
+                       } else {
+                               month_index = nth;
+                               month_num = MONTH_NUM_DAY;
+                       }
+                       month_day = MONTH_DAY_NTH;
+
+               } else if (n_by_day == 1) {
+                       enum icalrecurrencetype_weekday weekday;
+                       gint pos;
+
+                       weekday = icalrecurrencetype_day_day_of_week (rrule.by_day[0]);
+                       pos = icalrecurrencetype_day_position (rrule.by_day[0]);
+
+                       if (pos == 0) {
+                               if (n_by_set_pos != 1)
+                                       goto custom;
+                               pos = rrule.by_set_pos[0];
+                       } else if (pos < 0) {
+                               goto custom;
+                       }
+
+                       switch (weekday) {
+                       case ICAL_MONDAY_WEEKDAY:
+                               month_day = MONTH_DAY_MON;
+                               break;
+
+                       case ICAL_TUESDAY_WEEKDAY:
+                               month_day = MONTH_DAY_TUE;
+                               break;
+
+                       case ICAL_WEDNESDAY_WEEKDAY:
+                               month_day = MONTH_DAY_WED;
+                               break;
+
+                       case ICAL_THURSDAY_WEEKDAY:
+                               month_day = MONTH_DAY_THU;
+                               break;
+
+                       case ICAL_FRIDAY_WEEKDAY:
+                               month_day = MONTH_DAY_FRI;
+                               break;
+
+                       case ICAL_SATURDAY_WEEKDAY:
+                               month_day = MONTH_DAY_SAT;
+                               break;
+
+                       case ICAL_SUNDAY_WEEKDAY:
+                               month_day = MONTH_DAY_SUN;
+                               break;
+
+                       default:
+                               goto custom;
+                       }
+
+                       if (pos == -1)
+                               month_num = MONTH_NUM_LAST;
+                       else
+                               month_num = pos - 1;
+               } else if (n_by_day > 1 && n_by_set_pos == 1 && n_by_month_day == 0) {
+                       gint ii, pos;
+
+                       pos = rrule.by_set_pos[0];
+                       if (pos == -1)
+                               month_num = MONTH_NUM_LAST;
+                       else
+                               month_num = pos - 1;
+
+                       out_recur->type = E_EWS_RECURRENCE_RELATIVE_MONTHLY;
+                       out_recur->recur.relative_monthly.interval = rrule.interval;
+                       out_recur->recur.relative_monthly.days_of_week = 0;
+                       out_recur->recur.relative_monthly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+
+                       for (ii = 0; rrule.by_day[ii] != ICAL_RECURRENCE_ARRAY_MAX; ii++) {
+                               enum icalrecurrencetype_weekday weekday;
+
+                               weekday = icalrecurrencetype_day_day_of_week (rrule.by_day[ii]);
+                               pos = icalrecurrencetype_day_position (rrule.by_day[ii]);
+
+                               if (pos != 0)
+                                       goto custom;
+
+                               switch (weekday) {
+                               case ICAL_SUNDAY_WEEKDAY:
+                                       out_recur->recur.relative_monthly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_SUNDAY;
+                                       break;
+                               case ICAL_MONDAY_WEEKDAY:
+                                       out_recur->recur.relative_monthly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_MONDAY;
+                                       break;
+                               case ICAL_TUESDAY_WEEKDAY:
+                                       out_recur->recur.relative_monthly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_TUESDAY;
+                                       break;
+                               case ICAL_WEDNESDAY_WEEKDAY:
+                                       out_recur->recur.relative_monthly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_WEDNESDAY;
+                                       break;
+                               case ICAL_THURSDAY_WEEKDAY:
+                                       out_recur->recur.relative_monthly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_THURSDAY;
+                                       break;
+                               case ICAL_FRIDAY_WEEKDAY:
+                                       out_recur->recur.relative_monthly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_FRIDAY;
+                                       break;
+                               case ICAL_SATURDAY_WEEKDAY:
+                                       out_recur->recur.relative_monthly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_SATURDAY;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+
+                       break;
+               } else {
+                       goto custom;
+               }
+
+               out_recur->type = E_EWS_RECURRENCE_RELATIVE_MONTHLY;
+               out_recur->recur.relative_monthly.interval = rrule.interval;
+               out_recur->recur.relative_monthly.days_of_week = E_EWS_RECURRENCE_DAYS_OF_WEEK_UNKNOWN;
+               out_recur->recur.relative_monthly.day_of_week_index = 
E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_UNKNOWN;
+
+               switch (month_day) {
+               case MONTH_DAY_NTH:
+                       if (month_num == MONTH_NUM_LAST) {
+                               out_recur->recur.relative_monthly.days_of_week = 
e_ews_cal_util_month_index_to_days_of_week (month_index);
+                               out_recur->recur.relative_monthly.day_of_week_index = 
E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_LAST;
+                       } else { /* month_num = MONTH_NUM_DAY; */
+                               out_recur->type = E_EWS_RECURRENCE_ABSOLUTE_MONTHLY;
+                               out_recur->recur.absolute_monthly.interval = rrule.interval;
+                               out_recur->recur.absolute_monthly.day_of_month = month_index;
+                       }
+                       break;
+               case MONTH_DAY_MON:
+                       out_recur->recur.relative_monthly.days_of_week = E_EWS_RECURRENCE_DAYS_OF_WEEK_MONDAY;
+                       out_recur->recur.relative_monthly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+                       break;
+               case MONTH_DAY_TUE:
+                       out_recur->recur.relative_monthly.days_of_week = 
E_EWS_RECURRENCE_DAYS_OF_WEEK_TUESDAY;
+                       out_recur->recur.relative_monthly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+                       break;
+               case MONTH_DAY_WED:
+                       out_recur->recur.relative_monthly.days_of_week = 
E_EWS_RECURRENCE_DAYS_OF_WEEK_WEDNESDAY;
+                       out_recur->recur.relative_monthly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+                       break;
+               case MONTH_DAY_THU:
+                       out_recur->recur.relative_monthly.days_of_week = 
E_EWS_RECURRENCE_DAYS_OF_WEEK_THURSDAY;
+                       out_recur->recur.relative_monthly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+                       break;
+               case MONTH_DAY_FRI:
+                       out_recur->recur.relative_monthly.days_of_week = E_EWS_RECURRENCE_DAYS_OF_WEEK_FRIDAY;
+                       out_recur->recur.relative_monthly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+                       break;
+               case MONTH_DAY_SAT:
+                       out_recur->recur.relative_monthly.days_of_week = 
E_EWS_RECURRENCE_DAYS_OF_WEEK_SATURDAY;
+                       out_recur->recur.relative_monthly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+                       break;
+               case MONTH_DAY_SUN:
+                       out_recur->recur.relative_monthly.days_of_week = E_EWS_RECURRENCE_DAYS_OF_WEEK_SUNDAY;
+                       out_recur->recur.relative_monthly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+                       break;
+               }
+
+               break;
+       }
+
+       case ICAL_YEARLY_RECURRENCE: {
+               gint month_index = 1;
+               enum month_day_options month_day;
+               enum month_num_options month_num;
+
+               if (n_by_year_day != 0 ||
+                   n_by_week_no != 0 ||
+                   n_by_set_pos > 1 ||
+                   rrule.interval > 1)
+                       goto custom;
+
+               if (n_by_month_day == 1) {
+                       gint nth;
+
+                       if (n_by_set_pos != 0)
+                               goto custom;
+
+                       nth = rrule.by_month_day[0];
+                       if (nth < 1 && nth != -1)
+                               goto custom;
+
+                       if (nth == -1) {
+                               struct icaltimetype dtstart;
+
+                               dtstart = icalcomponent_get_dtstart (icalcomp);
+
+                               month_index = dtstart.day;
+                               month_num = MONTH_NUM_LAST;
+                       } else {
+                               month_index = nth;
+                               month_num = MONTH_NUM_DAY;
+                       }
+                       month_day = MONTH_DAY_NTH;
+               }
+
+               if (n_by_day == 1) {
+                       enum icalrecurrencetype_weekday weekday;
+                       gint pos;
+
+                       weekday = icalrecurrencetype_day_day_of_week (rrule.by_day[0]);
+                       pos = icalrecurrencetype_day_position (rrule.by_day[0]);
+
+                       if (pos == 0) {
+                               if (n_by_set_pos != 1)
+                                       goto custom;
+                               pos = rrule.by_set_pos[0];
+                       } else if (pos < 0) {
+                               goto custom;
+                       }
+
+                       switch (weekday) {
+                       case ICAL_MONDAY_WEEKDAY:
+                               month_day = MONTH_DAY_MON;
+                               break;
+
+                       case ICAL_TUESDAY_WEEKDAY:
+                               month_day = MONTH_DAY_TUE;
+                               break;
+
+                       case ICAL_WEDNESDAY_WEEKDAY:
+                               month_day = MONTH_DAY_WED;
+                               break;
+
+                       case ICAL_THURSDAY_WEEKDAY:
+                               month_day = MONTH_DAY_THU;
+                               break;
+
+                       case ICAL_FRIDAY_WEEKDAY:
+                               month_day = MONTH_DAY_FRI;
+                               break;
+
+                       case ICAL_SATURDAY_WEEKDAY:
+                               month_day = MONTH_DAY_SAT;
+                               break;
+
+                       case ICAL_SUNDAY_WEEKDAY:
+                               month_day = MONTH_DAY_SUN;
+                               break;
+
+                       default:
+                               goto custom;
+                       }
+
+                       if (pos == -1)
+                               month_num = MONTH_NUM_LAST;
+                       else
+                               month_num = pos - 1;
+               }
+
+               out_recur->type = E_EWS_RECURRENCE_RELATIVE_YEARLY;
+               out_recur->recur.relative_yearly.days_of_week = E_EWS_RECURRENCE_DAYS_OF_WEEK_UNKNOWN;
+               out_recur->recur.relative_yearly.day_of_week_index = 
E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_UNKNOWN;
+               out_recur->recur.relative_yearly.month = rrule.by_month[0];
+
+               if (n_by_day > 1 &&
+                   n_by_month == 1 &&
+                   n_by_set_pos == 1 &&
+                   n_by_month_day == 0) {
+                       gint ii, pos;
+
+                       pos = rrule.by_set_pos[0];
+                       if (pos == -1)
+                               month_num = MONTH_NUM_LAST;
+                       else
+                               month_num = pos - 1;
+
+                       out_recur->recur.relative_yearly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+
+                       for (ii = 0; rrule.by_day[ii] != ICAL_RECURRENCE_ARRAY_MAX; ii++) {
+                               enum icalrecurrencetype_weekday weekday;
+
+                               weekday = icalrecurrencetype_day_day_of_week (rrule.by_day[ii]);
+                               pos = icalrecurrencetype_day_position (rrule.by_day[ii]);
+
+                               if (pos != 0)
+                                       goto custom;
+
+                               switch (weekday) {
+                               case ICAL_SUNDAY_WEEKDAY:
+                                       out_recur->recur.relative_yearly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_SUNDAY;
+                                       break;
+                               case ICAL_MONDAY_WEEKDAY:
+                                       out_recur->recur.relative_yearly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_MONDAY;
+                                       break;
+                               case ICAL_TUESDAY_WEEKDAY:
+                                       out_recur->recur.relative_yearly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_TUESDAY;
+                                       break;
+                               case ICAL_WEDNESDAY_WEEKDAY:
+                                       out_recur->recur.relative_yearly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_WEDNESDAY;
+                                       break;
+                               case ICAL_THURSDAY_WEEKDAY:
+                                       out_recur->recur.relative_yearly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_THURSDAY;
+                                       break;
+                               case ICAL_FRIDAY_WEEKDAY:
+                                       out_recur->recur.relative_yearly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_FRIDAY;
+                                       break;
+                               case ICAL_SATURDAY_WEEKDAY:
+                                       out_recur->recur.relative_yearly.days_of_week |= 
E_EWS_RECURRENCE_DAYS_OF_WEEK_SATURDAY;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+               } else if (n_by_month == 1 &&
+                          n_by_day == 1 &&
+                          n_by_month_day == 0) {
+                       switch (month_day) {
+                       case MONTH_DAY_NTH:
+                               if (month_num == MONTH_NUM_LAST) {
+                                       out_recur->recur.relative_yearly.days_of_week = 
e_ews_cal_util_month_index_to_days_of_week (month_index);
+                                       out_recur->recur.relative_yearly.day_of_week_index = 
E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_LAST;
+                               } else { /* month_num = MONTH_NUM_DAY; */
+                                       out_recur->type = E_EWS_RECURRENCE_ABSOLUTE_YEARLY;
+                                       out_recur->recur.absolute_yearly.day_of_month = month_index;
+                                       out_recur->recur.absolute_yearly.month = rrule.by_month[0];
+                               }
+                               break;
+                       case MONTH_DAY_MON:
+                               out_recur->recur.relative_yearly.days_of_week = 
E_EWS_RECURRENCE_DAYS_OF_WEEK_MONDAY;
+                               out_recur->recur.relative_yearly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+                               break;
+                       case MONTH_DAY_TUE:
+                               out_recur->recur.relative_yearly.days_of_week = 
E_EWS_RECURRENCE_DAYS_OF_WEEK_TUESDAY;
+                               out_recur->recur.relative_yearly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+                               break;
+                       case MONTH_DAY_WED:
+                               out_recur->recur.relative_yearly.days_of_week = 
E_EWS_RECURRENCE_DAYS_OF_WEEK_WEDNESDAY;
+                               out_recur->recur.relative_yearly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+                               break;
+                       case MONTH_DAY_THU:
+                               out_recur->recur.relative_yearly.days_of_week = 
E_EWS_RECURRENCE_DAYS_OF_WEEK_THURSDAY;
+                               out_recur->recur.relative_yearly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+                               break;
+                       case MONTH_DAY_FRI:
+                               out_recur->recur.relative_yearly.days_of_week = 
E_EWS_RECURRENCE_DAYS_OF_WEEK_FRIDAY;
+                               out_recur->recur.relative_yearly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+                               break;
+                       case MONTH_DAY_SAT:
+                               out_recur->recur.relative_yearly.days_of_week = 
E_EWS_RECURRENCE_DAYS_OF_WEEK_SATURDAY;
+                               out_recur->recur.relative_yearly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+                               break;
+                       case MONTH_DAY_SUN:
+                               out_recur->recur.relative_yearly.days_of_week = 
E_EWS_RECURRENCE_DAYS_OF_WEEK_SUNDAY;
+                               out_recur->recur.relative_yearly.day_of_week_index = 
e_ews_cal_util_month_num_to_day_of_week_index (month_num);
+                               break;
+                       }
+               } else if (n_by_month == 1 &&
+                          n_by_month_day == 1 &&
+                          n_by_day == 0) {
+                       if (month_num == MONTH_NUM_LAST) {
+                               out_recur->recur.relative_yearly.days_of_week = 
e_ews_cal_util_month_index_to_days_of_week (month_index);
+                               out_recur->recur.relative_yearly.day_of_week_index = 
E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_LAST;
+                       } else { /* month_num = MONTH_NUM_DAY; */
+                               out_recur->type = E_EWS_RECURRENCE_ABSOLUTE_YEARLY;
+                               out_recur->recur.absolute_yearly.day_of_month = month_index;
+                               out_recur->recur.absolute_yearly.month = rrule.by_month[0];
+                       }
+               } else if (n_by_day == 0 &&
+                          n_by_month_day == 0 &&
+                          n_by_month == 0) {
+                       struct icaltimetype dtstart;
+
+                       dtstart = icalcomponent_get_dtstart (icalcomp);
+                       if (icaltime_is_null_time (dtstart))
+                               goto custom;
+
+                       out_recur->type = E_EWS_RECURRENCE_ABSOLUTE_YEARLY;
+                       out_recur->recur.absolute_yearly.day_of_month = dtstart.day;
+                       out_recur->recur.absolute_yearly.month = dtstart.month;
+               } else {
+                       goto custom;
+               }
+               } break;
+
+       default:
+               break;
+       }
+
+       if (out_recur->type != E_EWS_RECURRENCE_UNKNOWN) {
+               struct icaltimetype dtstart;
+
+               dtstart = icalcomponent_get_dtstart (icalcomp);
+
+               out_recur->utc_start_date = icaltime_as_timet_with_zone (dtstart, 
icaltimezone_get_utc_timezone ());
+
+               if (rrule.count) {
+                       out_recur->end_type = E_EWS_RECURRENCE_END_NUMBERED;
+                       out_recur->end.number_of_occurrences = rrule.count;
+               } else if (rrule.until.year) {
+                       rrule.until.is_date = 1;
+
+                       out_recur->end_type = E_EWS_RECURRENCE_END_DATE;
+                       out_recur->end.utc_end_date = icaltime_as_timet_with_zone (rrule.until, 
icaltimezone_get_utc_timezone ());
+               } else {
+                       out_recur->end_type = E_EWS_RECURRENCE_END_NO_END;
+               }
+       }
+
+       return TRUE;
+
+ custom:
+
+       g_set_error (error, EWS_CONNECTION_ERROR, EWS_CONNECTION_ERROR_CALENDARINVALIDRECURRENCE,
+               _("Cannot store this recurrence. Change it to simple single daily, weekly, monthly or yearly 
recurrence without exceptions and with start date."));
+
+       return FALSE;
+}
+
+static void
+e_ews_cal_utils_write_days_of_week (ESoapMessage *msg,
+                                   guint32 days_of_week)
+{
+       GString *value;
+       guint32 weekdays, weekenddays;
+
+       g_return_if_fail (E_IS_SOAP_MESSAGE (msg));
+
+       if (days_of_week == E_EWS_RECURRENCE_DAYS_OF_WEEK_UNKNOWN)
+               return;
+
+       weekdays = E_EWS_RECURRENCE_DAYS_OF_WEEK_MONDAY |
+               E_EWS_RECURRENCE_DAYS_OF_WEEK_TUESDAY |
+               E_EWS_RECURRENCE_DAYS_OF_WEEK_WEDNESDAY |
+               E_EWS_RECURRENCE_DAYS_OF_WEEK_THURSDAY |
+               E_EWS_RECURRENCE_DAYS_OF_WEEK_FRIDAY;
+       weekenddays = E_EWS_RECURRENCE_DAYS_OF_WEEK_SUNDAY |
+               E_EWS_RECURRENCE_DAYS_OF_WEEK_SATURDAY;
+
+       if ((days_of_week & weekdays) == weekdays && !(days_of_week & ~weekdays))
+               days_of_week = E_EWS_RECURRENCE_DAYS_OF_WEEK_WEEKDAY;
+       else if ((days_of_week & weekenddays) == weekenddays && !(days_of_week & ~weekenddays))
+               days_of_week = E_EWS_RECURRENCE_DAYS_OF_WEEK_WEEKENDDAY;
+
+       /* Do not localize, these are values used in XML */
+       if ((days_of_week & E_EWS_RECURRENCE_DAYS_OF_WEEK_DAY) != 0) {
+               value = g_string_new ("Day");
+       } else if ((days_of_week & E_EWS_RECURRENCE_DAYS_OF_WEEK_WEEKDAY) != 0) {
+               value = g_string_new ("Weekday");
+       } else if ((days_of_week & E_EWS_RECURRENCE_DAYS_OF_WEEK_WEEKENDDAY) != 0) {
+               value = g_string_new ("WeekendDay");
+       } else {
+               struct _bits {
+                       EEwsRecurrenceDaysOfWeek n_bit;
+                       const gchar *value;
+               } bits[] = {
+                       { E_EWS_RECURRENCE_DAYS_OF_WEEK_SUNDAY, "Sunday" },
+                       { E_EWS_RECURRENCE_DAYS_OF_WEEK_MONDAY, "Monday" },
+                       { E_EWS_RECURRENCE_DAYS_OF_WEEK_TUESDAY, "Tuesday" },
+                       { E_EWS_RECURRENCE_DAYS_OF_WEEK_WEDNESDAY, "Wednesday" },
+                       { E_EWS_RECURRENCE_DAYS_OF_WEEK_THURSDAY, "Thursday" },
+                       { E_EWS_RECURRENCE_DAYS_OF_WEEK_FRIDAY, "Friday" },
+                       { E_EWS_RECURRENCE_DAYS_OF_WEEK_SATURDAY, "Saturday" }
+               };
+               gint ii;
+
+               value = g_string_new ("");
+
+               for (ii = 0; ii < G_N_ELEMENTS (bits); ii++) {
+                       if ((days_of_week & bits[ii].n_bit) != 0) {
+                               if (value->len)
+                                       g_string_append_c (value, ' ');
+
+                               g_string_append (value, bits[ii].value);
+                       }
+               }
+       }
+
+       if (value->len) {
+               e_soap_message_start_element (msg, "DaysOfWeek", NULL, NULL);
+               e_soap_message_write_string (msg, value->str);
+               e_soap_message_end_element (msg); /* DaysOfWeek */
+       }
+
+       g_string_free (value, TRUE);
+}
+
+static void
+e_ews_cal_utils_write_day_of_week_index (ESoapMessage *msg,
+                                        EEwsRecurrenceDayOfWeekIndex day_of_week_index)
+{
+       const gchar *value = NULL;
+
+       g_return_if_fail (E_IS_SOAP_MESSAGE (msg));
+
+       /* Do not localize, these are values used in XML */
+       switch (day_of_week_index) {
+       case E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_UNKNOWN:
+               break;
+       case E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_FIRST:
+               value = "First";
+               break;
+       case E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_SECOND:
+               value = "Second";
+               break;
+       case E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_THIRD:
+               value = "Third";
+               break;
+       case E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_FOURTH:
+               value = "Fourth";
+               break;
+       case E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_LAST:
+               value = "Last";
+               break;
+       }
+
+       if (value) {
+               e_soap_message_start_element (msg, "DayOfWeekIndex", NULL, NULL);
+               e_soap_message_write_string (msg, value);
+               e_soap_message_end_element (msg); /* DayOfWeekIndex */
+       }
+}
+
+static void
+e_ews_cal_utils_write_month (ESoapMessage *msg,
+                            GDateMonth month)
+{
+       const gchar *value = NULL;
+
+       g_return_if_fail (E_IS_SOAP_MESSAGE (msg));
+
+       /* Do not localize, these are values used in XML */
+       switch (month) {
+       case G_DATE_BAD_MONTH:
+               break;
+       case  G_DATE_JANUARY:
+               value = "January";
+               break;
+       case G_DATE_FEBRUARY:
+               value = "February";
+               break;
+       case G_DATE_MARCH:
+               value = "March";
+               break;
+       case G_DATE_APRIL:
+               value = "April";
+               break;
+       case G_DATE_MAY:
+               value = "May";
+               break;
+       case G_DATE_JUNE:
+               value = "June";
+               break;
+       case G_DATE_JULY:
+               value = "July";
+               break;
+       case G_DATE_AUGUST:
+               value = "August";
+               break;
+       case G_DATE_SEPTEMBER:
+               value = "September";
+               break;
+       case G_DATE_OCTOBER:
+               value = "October";
+               break;
+       case G_DATE_NOVEMBER:
+               value = "November";
+               break;
+       case G_DATE_DECEMBER:
+               value = "December";
+               break;
+       }
+
+       if (value) {
+               e_soap_message_start_element (msg, "Month", NULL, NULL);
+               e_soap_message_write_string (msg, value);
+               e_soap_message_end_element (msg); /* Month */
+       }
+}
+
+static void
+e_ews_cal_util_write_utc_date (ESoapMessage *msg,
+                              const gchar *name,
+                              time_t utc_date)
+{
+       struct icaltimetype itt;
+       gchar *value;
+
+       g_return_if_fail (E_IS_SOAP_MESSAGE (msg));
+       g_return_if_fail (name != NULL);
+
+       itt = icaltime_from_timet_with_zone (utc_date, 1, icaltimezone_get_utc_timezone ());
+       value = g_strdup_printf ("%04d-%02d-%02dZ", itt.year, itt.month, itt.day);
+
+       e_soap_message_start_element (msg, name, NULL, NULL);
+       e_soap_message_write_string (msg, value);
+       e_soap_message_end_element (msg);
+
+       g_free (value);
+}
+
+/* Writes 'Recurrence' element into the @msg. Sets the @error only if the RRULE
+   cannot be transformed into Recurrence */
+gboolean
+e_ews_cal_utils_set_recurrence (ESoapMessage *msg,
+                               icalcomponent *comp,
+                               gboolean server_satisfies_2013,
+                               GError **error)
+{
+       EEwsRecurrence recur;
+
+       g_return_val_if_fail (E_IS_SOAP_MESSAGE (msg), FALSE);
+       g_return_val_if_fail (comp != NULL, FALSE);
+
+       recur.type = E_EWS_RECURRENCE_UNKNOWN;
+       recur.end_type = E_EWS_RECURRENCE_END_UNKNOWN;
+
+       if (!e_ews_cal_utils_convert_recurrence (comp, &recur, error))
+               return FALSE;
+
+       if (recur.type == E_EWS_RECURRENCE_UNKNOWN ||
+           recur.end_type == E_EWS_RECURRENCE_END_UNKNOWN) {
+               return TRUE;
+       }
+
+       e_soap_message_start_element (msg, "Recurrence", NULL, NULL);
+
+       switch (recur.type) {
+       case E_EWS_RECURRENCE_UNKNOWN:
+               g_warn_if_reached ();
+               break;
+       case E_EWS_RECURRENCE_RELATIVE_YEARLY:
+               e_soap_message_start_element (msg, "RelativeYearlyRecurrence", NULL, NULL);
+               e_ews_cal_utils_write_days_of_week (msg, recur.recur.relative_yearly.days_of_week);
+               e_ews_cal_utils_write_day_of_week_index (msg, recur.recur.relative_yearly.day_of_week_index);
+               e_ews_cal_utils_write_month (msg, recur.recur.relative_yearly.month);
+               e_soap_message_end_element (msg); /* RelativeYearlyRecurrence */
+               break;
+       case E_EWS_RECURRENCE_ABSOLUTE_YEARLY:
+               e_soap_message_start_element (msg, "AbsoluteYearlyRecurrence", NULL, NULL);
+               e_soap_message_start_element (msg, "DayOfMonth", NULL, NULL);
+               e_soap_message_write_int (msg, recur.recur.absolute_yearly.day_of_month);
+               e_soap_message_end_element (msg); /* DayOfMonth */
+               e_ews_cal_utils_write_month (msg, recur.recur.absolute_yearly.month);
+               e_soap_message_end_element (msg); /* AbsoluteYearlyRecurrence */
+               break;
+       case E_EWS_RECURRENCE_RELATIVE_MONTHLY:
+               e_soap_message_start_element (msg, "RelativeMonthlyRecurrence", NULL, NULL);
+               e_soap_message_start_element (msg, "Interval", NULL, NULL);
+               e_soap_message_write_int (msg, recur.recur.relative_monthly.interval);
+               e_soap_message_end_element (msg); /* Interval */
+               e_ews_cal_utils_write_days_of_week (msg, recur.recur.relative_monthly.days_of_week);
+               e_ews_cal_utils_write_day_of_week_index (msg, recur.recur.relative_monthly.day_of_week_index);
+               e_soap_message_end_element (msg); /* RelativeMonthlyRecurrence */
+               break;
+       case E_EWS_RECURRENCE_ABSOLUTE_MONTHLY:
+               e_soap_message_start_element (msg, "AbsoluteMonthlyRecurrence", NULL, NULL);
+               e_soap_message_start_element (msg, "Interval", NULL, NULL);
+               e_soap_message_write_int (msg, recur.recur.absolute_monthly.interval);
+               e_soap_message_end_element (msg); /* Interval */
+               e_soap_message_start_element (msg, "DayOfMonth", NULL, NULL);
+               e_soap_message_write_int (msg, recur.recur.absolute_monthly.day_of_month);
+               e_soap_message_end_element (msg); /* DayOfMonth */
+               e_soap_message_end_element (msg); /* AbsoluteMonthlyRecurrence */
+               break;
+       case E_EWS_RECURRENCE_WEEKLY:
+               e_soap_message_start_element (msg, "WeeklyRecurrence", NULL, NULL);
+               e_soap_message_start_element (msg, "Interval", NULL, NULL);
+               e_soap_message_write_int (msg, recur.recur.weekly.interval);
+               e_soap_message_end_element (msg); /* Interval */
+               e_ews_cal_utils_write_days_of_week (msg, recur.recur.weekly.days_of_week);
+               if (server_satisfies_2013) {
+                       const gchar *value = NULL;
+
+                       switch (recur.recur.weekly.first_day_of_week) {
+                       case G_DATE_BAD_WEEKDAY:
+                               break;
+                       case G_DATE_MONDAY:
+                               value = "Monday";
+                               break;
+                       case G_DATE_TUESDAY:
+                               value = "Tuesday";
+                               break;
+                       case G_DATE_WEDNESDAY:
+                               value = "Wednesday";
+                               break;
+                       case G_DATE_THURSDAY:
+                               value = "Thursday";
+                               break;
+                       case G_DATE_FRIDAY:
+                               value = "Friday";
+                               break;
+                       case G_DATE_SATURDAY:
+                               value = "Saturday";
+                               break;
+                       case G_DATE_SUNDAY:
+                               value = "Sunday";
+                               break;
+                       }
+
+                       if (value) {
+                               e_soap_message_start_element (msg, "FirstDayOfWeek", NULL, NULL);
+                               e_soap_message_write_string (msg, value);
+                               e_soap_message_end_element (msg); /* FirstDayOfWeek */
+                       }
+               }
+               e_soap_message_end_element (msg); /* WeeklyRecurrence */
+               break;
+       case E_EWS_RECURRENCE_DAILY:
+               e_soap_message_start_element (msg, "DailyRecurrence", NULL, NULL);
+               e_soap_message_start_element (msg, "Interval", NULL, NULL);
+               e_soap_message_write_int (msg, recur.recur.interval);
+               e_soap_message_end_element (msg); /* Interval */
+               e_soap_message_end_element (msg); /* DailyRecurrence */
+               break;
+       case E_EWS_RECURRENCE_DAILY_REGENERATION:
+               e_soap_message_start_element (msg, "DailyRegeneration", NULL, NULL);
+               e_soap_message_start_element (msg, "Interval", NULL, NULL);
+               e_soap_message_write_int (msg, recur.recur.interval);
+               e_soap_message_end_element (msg); /* Interval */
+               e_soap_message_end_element (msg); /* DailyRegeneration */
+               break;
+       case E_EWS_RECURRENCE_WEEKLY_REGENERATION:
+               e_soap_message_start_element (msg, "WeeklyRegeneration", NULL, NULL);
+               e_soap_message_start_element (msg, "Interval", NULL, NULL);
+               e_soap_message_write_int (msg, recur.recur.interval);
+               e_soap_message_end_element (msg); /* Interval */
+               e_soap_message_end_element (msg); /* WeeklyRegeneration */
+               break;
+       case E_EWS_RECURRENCE_MONTHLY_REGENERATION:
+               e_soap_message_start_element (msg, "MonthlyRegeneration", NULL, NULL);
+               e_soap_message_start_element (msg, "Interval", NULL, NULL);
+               e_soap_message_write_int (msg, recur.recur.interval);
+               e_soap_message_end_element (msg); /* Interval */
+               e_soap_message_end_element (msg); /* MonthlyRegeneration */
+               break;
+       case E_EWS_RECURRENCE_YEARLY_REGENERATION:
+               e_soap_message_start_element (msg, "YearlyRegeneration", NULL, NULL);
+               e_soap_message_start_element (msg, "Interval", NULL, NULL);
+               e_soap_message_write_int (msg, recur.recur.interval);
+               e_soap_message_end_element (msg); /* Interval */
+               e_soap_message_end_element (msg); /* YearlyRegeneration */
+               break;
+       }
+
+       switch (recur.end_type) {
+       case E_EWS_RECURRENCE_END_UNKNOWN:
+               g_warn_if_reached ();
+               break;
+       case E_EWS_RECURRENCE_END_NO_END:
+               e_soap_message_start_element (msg, "NoEndRecurrence", NULL, NULL);
+               e_ews_cal_util_write_utc_date (msg, "StartDate", recur.utc_start_date);
+               e_soap_message_end_element (msg); /* NoEndRecurrence */
+               break;
+       case E_EWS_RECURRENCE_END_DATE:
+               e_soap_message_start_element (msg, "EndDateRecurrence", NULL, NULL);
+               e_ews_cal_util_write_utc_date (msg, "StartDate", recur.utc_start_date);
+               e_ews_cal_util_write_utc_date (msg, "EndDate", recur.end.utc_end_date);
+               e_soap_message_end_element (msg); /* EndDateRecurrence */
+               break;
+       case E_EWS_RECURRENCE_END_NUMBERED:
+               e_soap_message_start_element (msg, "NumberedRecurrence", NULL, NULL);
+               e_ews_cal_util_write_utc_date (msg, "StartDate", recur.utc_start_date);
+               e_soap_message_start_element (msg, "NumberOfOccurrences", NULL, NULL);
+               e_soap_message_write_int (msg, recur.end.number_of_occurrences);
+               e_soap_message_end_element (msg); /* NumberOfOccurrences */
+               e_soap_message_end_element (msg); /* NumberedRecurrence */
+               break;
+       }
+
+       e_soap_message_end_element (msg); /* Recurrence */
+
+       return TRUE;
+}
+
+static void
+e_ews_cal_utils_days_of_week_to_rrule (struct icalrecurrencetype *rrule,
+                                      guint32 days_of_week)
+{
+       struct _bits {
+               EEwsRecurrenceDaysOfWeek bit;
+               icalrecurrencetype_weekday week_day;
+       } bits[] = {
+               { E_EWS_RECURRENCE_DAYS_OF_WEEK_SUNDAY, ICAL_SUNDAY_WEEKDAY },
+               { E_EWS_RECURRENCE_DAYS_OF_WEEK_MONDAY, ICAL_MONDAY_WEEKDAY },
+               { E_EWS_RECURRENCE_DAYS_OF_WEEK_TUESDAY, ICAL_TUESDAY_WEEKDAY },
+               { E_EWS_RECURRENCE_DAYS_OF_WEEK_WEDNESDAY, ICAL_WEDNESDAY_WEEKDAY },
+               { E_EWS_RECURRENCE_DAYS_OF_WEEK_THURSDAY, ICAL_THURSDAY_WEEKDAY },
+               { E_EWS_RECURRENCE_DAYS_OF_WEEK_FRIDAY, ICAL_FRIDAY_WEEKDAY },
+               { E_EWS_RECURRENCE_DAYS_OF_WEEK_SATURDAY, ICAL_SATURDAY_WEEKDAY }
+       };
+       gint ii, idx;
+
+       g_return_if_fail (rrule != NULL);
+
+       if ((days_of_week & E_EWS_RECURRENCE_DAYS_OF_WEEK_WEEKDAY) != 0) {
+               days_of_week |= E_EWS_RECURRENCE_DAYS_OF_WEEK_MONDAY |
+                       E_EWS_RECURRENCE_DAYS_OF_WEEK_TUESDAY |
+                       E_EWS_RECURRENCE_DAYS_OF_WEEK_WEDNESDAY |
+                       E_EWS_RECURRENCE_DAYS_OF_WEEK_THURSDAY |
+                       E_EWS_RECURRENCE_DAYS_OF_WEEK_FRIDAY;
+       } else if ((days_of_week & E_EWS_RECURRENCE_DAYS_OF_WEEK_WEEKENDDAY) != 0) {
+               days_of_week |= E_EWS_RECURRENCE_DAYS_OF_WEEK_SUNDAY | E_EWS_RECURRENCE_DAYS_OF_WEEK_SATURDAY;
+       }
+
+       idx = 0;
+
+       for (ii = 0; ii < G_N_ELEMENTS (bits); ii++) {
+               if ((days_of_week & bits[ii].bit) != 0) {
+                       rrule->by_day[idx] = bits[ii].week_day;
+                       idx++;
+               }
+       }
+
+       rrule->by_day[idx] = ICAL_RECURRENCE_ARRAY_MAX;
+}
+
+static void
+e_ews_cal_utils_day_of_week_index_to_rrule (struct icalrecurrencetype *rrule,
+                                           EEwsRecurrenceDayOfWeekIndex day_of_week_index)
+{
+       g_return_if_fail (rrule != NULL);
+
+       switch (day_of_week_index) {
+       case E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_UNKNOWN:
+               break;
+       case E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_FIRST:
+               rrule->by_set_pos[0] = 1;
+               rrule->by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX;
+               break;
+       case E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_SECOND:
+               rrule->by_set_pos[0] = 2;
+               rrule->by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX;
+               break;
+       case E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_THIRD:
+               rrule->by_set_pos[0] = 3;
+               rrule->by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX;
+               break;
+       case E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_FOURTH:
+               rrule->by_set_pos[0] = 4;
+               rrule->by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX;
+               break;
+       case E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_LAST:
+               rrule->by_set_pos[0] = -1;
+               rrule->by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX;
+               break;
+       }
+}
+
+static void
+e_ews_cal_utils_month_to_rrule (struct icalrecurrencetype *rrule,
+                               GDateMonth month)
+{
+       g_return_if_fail (rrule != NULL);
+
+       if (month >= G_DATE_JANUARY && month <= G_DATE_DECEMBER) {
+               rrule->by_month[0] = month;
+               rrule->by_month[1] = ICAL_RECURRENCE_ARRAY_MAX;
+       }
+}
+
+/* Does nothing when the 'item' doesn't contain any recurrence */
+void
+e_ews_cal_utils_recurrence_to_rrule (EEwsItem *item,
+                                    icalcomponent *comp)
+{
+       EEwsRecurrence recur;
+       struct icalrecurrencetype rrule;
+       struct icaltimetype recur_start;
+       gboolean usable = FALSE;
+
+       g_return_if_fail (E_IS_EWS_ITEM (item));
+       g_return_if_fail (comp != NULL);
+
+       e_cal_util_remove_property_by_kind (comp, ICAL_RRULE_PROPERTY, TRUE);
+       e_cal_util_remove_property_by_kind (comp, ICAL_RDATE_PROPERTY, TRUE);
+       e_cal_util_remove_property_by_kind (comp, ICAL_EXRULE_PROPERTY, TRUE);
+       e_cal_util_remove_property_by_kind (comp, ICAL_EXDATE_PROPERTY, TRUE);
+       e_cal_util_remove_x_property (comp, X_EWS_TASK_REGENERATION);
+
+       if (!e_ews_item_get_recurrence (item, &recur))
+               return;
+
+       icalrecurrencetype_clear (&rrule);
+       recur_start = icaltime_from_timet_with_zone (recur.utc_start_date, 1, icaltimezone_get_utc_timezone 
());
+
+       switch (recur.end_type) {
+       case E_EWS_RECURRENCE_END_UNKNOWN:
+               break;
+       case E_EWS_RECURRENCE_END_NO_END:
+               rrule.until = icaltime_null_time ();
+               rrule.count = 0;
+               usable = TRUE;
+               break;
+       case E_EWS_RECURRENCE_END_DATE:
+               rrule.until = icaltime_from_timet_with_zone (recur.end.utc_end_date, 1, 
icaltimezone_get_utc_timezone ());
+               rrule.count = 0;
+               usable = !icaltime_is_null_time (rrule.until) && icaltime_is_valid_time (rrule.until);
+               break;
+       case E_EWS_RECURRENCE_END_NUMBERED:
+               rrule.until = icaltime_null_time ();
+               rrule.count = recur.end.number_of_occurrences;
+               usable = rrule.count > 0;
+               break;
+       }
+
+       if (!usable) {
+               g_warning ("%s: Cannot decode end condition in received recurrence", G_STRFUNC);
+               return;
+       }
+
+       usable = FALSE;
+
+       switch (recur.type) {
+       case E_EWS_RECURRENCE_UNKNOWN:
+               break;
+       case E_EWS_RECURRENCE_RELATIVE_YEARLY:
+               usable = TRUE;
+               rrule.freq = ICAL_YEARLY_RECURRENCE;
+               rrule.interval = 1;
+               e_ews_cal_utils_days_of_week_to_rrule (&rrule, recur.recur.relative_yearly.days_of_week);
+               e_ews_cal_utils_day_of_week_index_to_rrule (&rrule, 
recur.recur.relative_yearly.day_of_week_index);
+               e_ews_cal_utils_month_to_rrule (&rrule, recur.recur.relative_yearly.month);
+               break;
+       case E_EWS_RECURRENCE_ABSOLUTE_YEARLY:
+               usable = TRUE;
+               rrule.freq = ICAL_YEARLY_RECURRENCE;
+               rrule.interval = 1;
+               if (icaltime_is_valid_time (recur_start) &&
+                   recur_start.month == recur.recur.absolute_yearly.month &&
+                   recur_start.day == recur.recur.absolute_yearly.day_of_month) {
+                       /* This is how evolution uses it, derive date from the DTSTART */
+               } else {
+                       rrule.by_month_day[0] = recur.recur.absolute_yearly.day_of_month;
+                       rrule.by_month_day[1] = ICAL_RECURRENCE_ARRAY_MAX;
+                       e_ews_cal_utils_month_to_rrule (&rrule, recur.recur.absolute_yearly.month);
+               }
+               break;
+       case E_EWS_RECURRENCE_RELATIVE_MONTHLY:
+               usable = TRUE;
+               rrule.freq = ICAL_MONTHLY_RECURRENCE;
+               rrule.interval = recur.recur.relative_monthly.interval;
+               e_ews_cal_utils_days_of_week_to_rrule (&rrule, recur.recur.relative_monthly.days_of_week);
+               e_ews_cal_utils_day_of_week_index_to_rrule (&rrule, 
recur.recur.relative_monthly.day_of_week_index);
+               break;
+       case E_EWS_RECURRENCE_ABSOLUTE_MONTHLY:
+               usable = TRUE;
+               rrule.freq = ICAL_MONTHLY_RECURRENCE;
+               rrule.interval = recur.recur.absolute_monthly.interval;
+               rrule.by_month_day[0] = recur.recur.absolute_monthly.day_of_month;
+               rrule.by_month_day[1] = ICAL_RECURRENCE_ARRAY_MAX;
+               break;
+       case E_EWS_RECURRENCE_WEEKLY:
+               usable = TRUE;
+               rrule.freq = ICAL_WEEKLY_RECURRENCE;
+               rrule.interval = recur.recur.weekly.interval;
+               e_ews_cal_utils_days_of_week_to_rrule (&rrule, recur.recur.weekly.days_of_week);
+               break;
+       case E_EWS_RECURRENCE_DAILY:
+               usable = TRUE;
+               rrule.freq = ICAL_DAILY_RECURRENCE;
+               rrule.interval = recur.recur.interval;
+               break;
+       case E_EWS_RECURRENCE_DAILY_REGENERATION:
+       case E_EWS_RECURRENCE_WEEKLY_REGENERATION:
+       case E_EWS_RECURRENCE_MONTHLY_REGENERATION:
+       case E_EWS_RECURRENCE_YEARLY_REGENERATION:
+               e_ews_cal_util_encode_regeneration (&recur, comp);
+               return;
+       }
+
+       if (usable) {
+               struct icaltimetype itt;
+
+               itt = icaltime_from_timet_with_zone (recur.utc_start_date, 1, icaltimezone_get_utc_timezone 
());
+
+               if (!icaltime_is_null_time (itt) && icaltime_is_valid_time (itt)) {
+                       icalproperty *prop;
+
+                       icalcomponent_set_dtstart (comp, itt);
+
+                       prop = icalproperty_new_rrule (rrule);
+                       icalcomponent_add_property (comp, prop);
+               } else {
+                       g_warning ("%s: Cannot decode start date in received recurrence", G_STRFUNC);
+               }
+       } else {
+               g_warning ("%s: Cannot decode received recurrence", G_STRFUNC);
+       }
+}
diff --git a/src/server/e-ews-calendar-utils.h b/src/server/e-ews-calendar-utils.h
index 6419a7b..3cfe536 100644
--- a/src/server/e-ews-calendar-utils.h
+++ b/src/server/e-ews-calendar-utils.h
@@ -24,22 +24,35 @@
 #include <libical/ical.h>
 
 #include "server/e-soap-message.h"
+#include "server/e-ews-item.h"
 
 G_BEGIN_DECLS
 
+/* Custom property, because evolution cannot cope with it,
+   but it shouldn't lost it as well */
+#define X_EWS_TASK_REGENERATION "X-EWS-TASK-REGENERATION"
+
 typedef struct _EEWSFreeBusyData {
        time_t period_start;
        time_t period_end;
        GSList *user_mails; /* gchar * */
 } EEWSFreeBusyData;
 
-void           e_ews_cal_utils_prepare_free_busy_request
+gboolean       e_ews_cal_utils_prepare_free_busy_request
                                                (ESoapMessage *msg,
-                                                gpointer user_data); /* EEWSFreeBusyData * */
+                                                gpointer user_data, /* EEWSFreeBusyData * */
+                                                GError **error);
 void           e_ews_cal_utils_set_time        (ESoapMessage *msg,
                                                 const gchar *name,
                                                 icaltimetype *tt,
                                                 gboolean with_timezone);
+gboolean       e_ews_cal_utils_set_recurrence  (ESoapMessage *msg,
+                                                icalcomponent *comp,
+                                                gboolean server_satisfies_2013,
+                                                GError **error);
+void           e_ews_cal_utils_recurrence_to_rrule
+                                               (EEwsItem *item,
+                                                icalcomponent *comp);
 
 G_END_DECLS
 
diff --git a/src/server/e-ews-camel-common.c b/src/server/e-ews-camel-common.c
index ebdb529..71acba1 100644
--- a/src/server/e-ews-camel-common.c
+++ b/src/server/e-ews-camel-common.c
@@ -107,9 +107,10 @@ write_recipients (ESoapMessage *msg,
 #define MAPI_MSGFLAG_READ      0x01
 #define MAPI_MSGFLAG_UNSENT    0x08
 
-static void
+static gboolean
 create_mime_message_cb (ESoapMessage *msg,
-                        gpointer user_data)
+                        gpointer user_data,
+                       GError **error)
 {
        struct _create_mime_msg_data *create_data = user_data;
        CamelStream *mem, *filtered;
@@ -323,6 +324,8 @@ create_mime_message_cb (ESoapMessage *msg,
        e_soap_message_end_element (msg); /* Message */
 
        g_free (create_data);
+
+       return TRUE;
 }
 
 gboolean
diff --git a/src/server/e-ews-connection.c b/src/server/e-ews-connection.c
index a0bae8b..ca0913c 100644
--- a/src/server/e-ews-connection.c
+++ b/src/server/e-ews-connection.c
@@ -5322,6 +5322,8 @@ e_ews_connection_update_items (EEwsConnection *cnc,
        ESoapMessage *msg;
        GSimpleAsyncResult *simple;
        EwsAsyncData *async_data;
+       gboolean success;
+       GError *local_error = NULL;
 
        g_return_if_fail (cnc != NULL);
 
@@ -5360,7 +5362,7 @@ e_ews_connection_update_items (EEwsConnection *cnc,
 
        e_soap_message_start_element (msg, "ItemChanges", "messages", NULL);
 
-       create_cb (msg, create_user_data);
+       success = create_cb (msg, create_user_data, &local_error);
 
        e_soap_message_end_element (msg); /* ItemChanges */
 
@@ -5374,18 +5376,26 @@ e_ews_connection_update_items (EEwsConnection *cnc,
        g_simple_async_result_set_op_res_gpointer (
                simple, async_data, (GDestroyNotify) async_data_free);
 
+       if (!success) {
+               if (local_error)
+                       g_simple_async_result_take_error (simple, local_error);
+               g_simple_async_result_complete_in_idle (simple);
+               g_clear_object (&msg);
+
        /*
         * We need to check for both namespaces, because, the message is being wrote without use the types
         * namespace. Maybe it is wrong, but the server doesn't complain about that. But this is the reason
         * for the first check. The second one, is related to "how it should be" accord with EWS 
specifications.
         */
-       if (!element_has_child (msg, "/s:Envelope/s:Body/m:UpdateItem/m:ItemChanges/ItemChange/Updates") &&
-               !element_has_child (msg, 
"/s:Envelope/s:Body/m:UpdateItem/m:ItemChanges/t:ItemChange/t:Updates"))
+       } else if (!element_has_child (msg, 
"/s:Envelope/s:Body/m:UpdateItem/m:ItemChanges/ItemChange/Updates") &&
+               !element_has_child (msg, 
"/s:Envelope/s:Body/m:UpdateItem/m:ItemChanges/t:ItemChange/t:Updates")) {
                g_simple_async_result_complete_in_idle (simple);
-       else
+               g_clear_object (&msg);
+       } else {
                e_ews_connection_queue_request (
                        cnc, msg, get_items_response_cb,
                        pri, cancellable, simple);
+       }
 
        g_object_unref (simple);
 }
@@ -5487,6 +5497,8 @@ e_ews_connection_create_items (EEwsConnection *cnc,
        ESoapMessage *msg;
        GSimpleAsyncResult *simple;
        EwsAsyncData *async_data;
+       gboolean success;
+       GError *local_error = NULL;
 
        g_return_if_fail (cnc != NULL);
 
@@ -5519,7 +5531,7 @@ e_ews_connection_create_items (EEwsConnection *cnc,
 
        e_soap_message_start_element (msg, "Items", "messages", NULL);
 
-       create_cb (msg, create_user_data);
+       success = create_cb (msg, create_user_data, &local_error);
 
        e_soap_message_end_element (msg); /* Items */
 
@@ -5533,9 +5545,16 @@ e_ews_connection_create_items (EEwsConnection *cnc,
        g_simple_async_result_set_op_res_gpointer (
                simple, async_data, (GDestroyNotify) async_data_free);
 
-       e_ews_connection_queue_request (
-               cnc, msg, get_items_response_cb,
-               pri, cancellable, simple);
+       if (success) {
+               e_ews_connection_queue_request (
+                       cnc, msg, get_items_response_cb,
+                       pri, cancellable, simple);
+       } else {
+               if (local_error)
+                       g_simple_async_result_take_error (simple, local_error);
+               g_simple_async_result_complete_in_idle (simple);
+               g_clear_object (&msg);
+       }
 
        g_object_unref (simple);
 }
@@ -6102,6 +6121,8 @@ e_ews_connection_update_folder (EEwsConnection *cnc,
        ESoapMessage *msg;
        GSimpleAsyncResult *simple;
        EwsAsyncData *async_data;
+       gboolean success;
+       GError *local_error = NULL;
 
        g_return_if_fail (cnc != NULL);
 
@@ -6119,7 +6140,7 @@ e_ews_connection_update_folder (EEwsConnection *cnc,
 
        e_soap_message_start_element (msg, "FolderChanges", "messages", NULL);
 
-       create_cb (msg, create_user_data);
+       success = create_cb (msg, create_user_data, &local_error);
 
        e_soap_message_end_element (msg); /* FolderChanges */
 
@@ -6133,9 +6154,16 @@ e_ews_connection_update_folder (EEwsConnection *cnc,
        g_simple_async_result_set_op_res_gpointer (
                simple, async_data, (GDestroyNotify) async_data_free);
 
-       e_ews_connection_queue_request (
-               cnc, msg, update_folder_response_cb,
-               pri, cancellable, simple);
+       if (success) {
+               e_ews_connection_queue_request (
+                       cnc, msg, update_folder_response_cb,
+                       pri, cancellable, simple);
+       } else {
+               if (local_error)
+                       g_simple_async_result_take_error (simple, local_error);
+               g_simple_async_result_complete_in_idle (simple);
+               g_clear_object (&msg);
+       }
 
        g_object_unref (simple);
 }
@@ -7974,6 +8002,8 @@ e_ews_connection_get_free_busy (EEwsConnection *cnc,
        ESoapMessage *msg;
        GSimpleAsyncResult *simple;
        EwsAsyncData *async_data;
+       gboolean success;
+       GError *local_error = NULL;
 
        g_return_if_fail (cnc != NULL);
 
@@ -7989,7 +8019,7 @@ e_ews_connection_get_free_busy (EEwsConnection *cnc,
                        FALSE,
                        TRUE);
 
-       free_busy_cb (msg, free_busy_user_data);
+       success = free_busy_cb (msg, free_busy_user_data, &local_error);
 
        e_ews_message_write_footer (msg); /*GetUserAvailabilityRequest  */
 
@@ -8001,9 +8031,16 @@ e_ews_connection_get_free_busy (EEwsConnection *cnc,
        g_simple_async_result_set_op_res_gpointer (
                simple, async_data, (GDestroyNotify) async_data_free);
 
-       e_ews_connection_queue_request (
-               cnc, msg, get_free_busy_response_cb,
-               pri, cancellable, simple);
+       if (success) {
+               e_ews_connection_queue_request (
+                       cnc, msg, get_free_busy_response_cb,
+                       pri, cancellable, simple);
+       } else {
+               if (local_error)
+                       g_simple_async_result_take_error (simple, local_error);
+               g_simple_async_result_complete_in_idle (simple);
+               g_clear_object (&msg);
+       }
 
        g_object_unref (simple);
 }
diff --git a/src/server/e-ews-connection.h b/src/server/e-ews-connection.h
index 108205f..fbbad84 100644
--- a/src/server/e-ews-connection.h
+++ b/src/server/e-ews-connection.h
@@ -80,8 +80,9 @@ enum {
        EWS_PRIORITY_HIGH
 };
 
-typedef void   (*EEwsRequestCreationCallback)  (ESoapMessage *msg,
-                                                gpointer user_data);
+typedef gboolean(*EEwsRequestCreationCallback) (ESoapMessage *msg,
+                                                gpointer user_data,
+                                                GError **error);
 typedef void   (*EwsProgressFn)                (gpointer object,
                                                 gint percent);
 typedef void   (*EEwsResponseCallback)         (ESoapResponse *response,
diff --git a/src/server/e-ews-item.c b/src/server/e-ews-item.c
index e92475a..a5b99bf 100644
--- a/src/server/e-ews-item.c
+++ b/src/server/e-ews-item.c
@@ -29,6 +29,7 @@
 #include <glib/gstdio.h>
 #include <glib/gprintf.h>
 #include <libsoup/soup-misc.h>
+#include <libical/ical.h>
 #include "e-ews-item.h"
 #include "e-ews-item-change.h"
 
@@ -151,6 +152,7 @@ struct _EEwsItemPrivate {
        gboolean reminder_is_set;
        time_t reminder_due_by;
        gint reminder_minutes_before_start;
+       EEwsRecurrence recurrence;
 
        struct _EEwsContactFields *contact_fields;
        struct _EEwsTaskFields *task_fields;
@@ -312,6 +314,8 @@ e_ews_item_init (EEwsItem *item)
 
        item->priv->reminder_is_set = FALSE;
        item->priv->reminder_minutes_before_start = -1;
+       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+       item->priv->recurrence.end_type = E_EWS_RECURRENCE_END_UNKNOWN;
 }
 
 static void
@@ -376,24 +380,35 @@ ews_item_free_attendee (EwsAttendee *attendee)
 }
 
 static time_t
-ews_item_parse_date (const gchar *dtstring)
+ews_item_parse_date (ESoapParameter *param)
 {
        time_t t = 0;
        GTimeVal t_val;
+       gchar *dtstring;
+       gint len;
+
+       dtstring = e_soap_parameter_get_string_value (param);
 
        g_return_val_if_fail (dtstring != NULL, 0);
 
+       len = strlen (dtstring);
        if (g_time_val_from_iso8601 (dtstring, &t_val)) {
                t = (time_t) t_val.tv_sec;
-       } else if (strlen (dtstring) == 8) {
+       } else if (len == 8 || (len == 11 && dtstring[4] == '-' && dtstring[7] == '-' && dtstring[10] == 
'Z')) {
                /* It might be a date value */
-               GDate date;
-               struct tm tt;
                guint16 year;
                guint month;
                guint8 day;
 
-               g_date_clear (&date, 1);
+               if (len == 11) {
+                       dtstring[4] = dtstring[5];
+                       dtstring[5] = dtstring[6];
+                       dtstring[6] = dtstring[8];
+                       dtstring[7] = dtstring[9];
+                       dtstring[8] = dtstring[10];
+                       dtstring[9] = '\0';
+               }
+
 #define digit_at(x,y) (x[y] - '0')
                year = digit_at (dtstring, 0) * 1000
                        + digit_at (dtstring, 1) * 100
@@ -402,15 +417,33 @@ ews_item_parse_date (const gchar *dtstring)
                month = digit_at (dtstring, 4) * 10 + digit_at (dtstring, 5);
                day = digit_at (dtstring, 6) * 10 + digit_at (dtstring, 7);
 
-               g_date_set_year (&date, year);
-               g_date_set_month (&date, month);
-               g_date_set_day (&date, day);
+               if (len == 11) {
+                       struct icaltimetype itt;
 
-               g_date_to_struct_tm (&date, &tt);
-               t = mktime (&tt);
+                       itt = icaltime_null_time ();
+                       itt.year = year;
+                       itt.month = month;
+                       itt.day = day;
+                       itt.is_date = 1;
+                       itt.zone = icaltimezone_get_utc_timezone ();
 
+                       t = icaltime_as_timet_with_zone (itt, icaltimezone_get_utc_timezone ());
+               } else {
+                       GDate date;
+                       struct tm tt;
+
+                       g_date_clear (&date, 1);
+                       g_date_set_year (&date, year);
+                       g_date_set_month (&date, month);
+                       g_date_set_day (&date, day);
+
+                       g_date_to_struct_tm (&date, &tt);
+                       t = mktime (&tt);
+               }
        } else
-               g_warning ("Could not parse the string \n");
+               g_warning ("%s: Could not parse the string '%s'", G_STRFUNC, dtstring ? dtstring : "[null]");
+
+       g_free (dtstring);
 
        return t;
 }
@@ -766,7 +799,6 @@ parse_contact_field (EEwsItem *item,
                      ESoapParameter *subparam)
 {
        EEwsItemPrivate *priv = item->priv;
-       gchar *value = NULL;
 
        if (!g_ascii_strcasecmp (name, "Culture")) {
                priv->contact_fields->culture = e_soap_parameter_get_string_value (subparam);
@@ -790,9 +822,7 @@ parse_contact_field (EEwsItem *item,
        } else if (!g_ascii_strcasecmp (name, "AssistantName")) {
                priv->contact_fields->assistant_name = e_soap_parameter_get_string_value (subparam);
        } else if (!g_ascii_strcasecmp (name, "Birthday")) {
-               value = e_soap_parameter_get_string_value (subparam);
-               priv->contact_fields->birthday = ews_item_parse_date (value);
-               g_free (value);
+               priv->contact_fields->birthday = ews_item_parse_date (subparam);
        } else if (!g_ascii_strcasecmp (name, "BusinessHomePage")) {
                priv->contact_fields->business_homepage = e_soap_parameter_get_string_value (subparam);
        } else if (!g_ascii_strcasecmp (name, "Department")) {
@@ -817,9 +847,7 @@ parse_contact_field (EEwsItem *item,
        } else if (!g_ascii_strcasecmp (name, "MiddleName")) {
                priv->contact_fields->middlename = e_soap_parameter_get_string_value (subparam);
        } else if (!g_ascii_strcasecmp (name, "WeddingAnniversary")) {
-               value = e_soap_parameter_get_string_value (subparam);
-               priv->contact_fields->wedding_anniversary = ews_item_parse_date (value);
-               g_free (value);
+               priv->contact_fields->wedding_anniversary = ews_item_parse_date (subparam);
        } else if (!g_ascii_strcasecmp (name, "Body")) {
                /*
                 * For Exchange versions >= 2010_SP2 Notes property can be get
@@ -830,6 +858,460 @@ parse_contact_field (EEwsItem *item,
        }
 }
 
+static guint32 /* bit-or of EEwsRecurrenceDaysOfWeek */
+parse_recur_days_of_week (ESoapParameter *param)
+{
+       struct _keys {
+               const gchar *str_value;
+               EEwsRecurrenceDaysOfWeek bit_value;
+       } keys[] = {
+               /* Do not localize, these are values used in XML */
+               { "Sunday", E_EWS_RECURRENCE_DAYS_OF_WEEK_SUNDAY },
+               { "Monday", E_EWS_RECURRENCE_DAYS_OF_WEEK_MONDAY },
+               { "Tuesday", E_EWS_RECURRENCE_DAYS_OF_WEEK_TUESDAY },
+               { "Wednesday", E_EWS_RECURRENCE_DAYS_OF_WEEK_WEDNESDAY },
+               { "Thursday", E_EWS_RECURRENCE_DAYS_OF_WEEK_THURSDAY },
+               { "Friday", E_EWS_RECURRENCE_DAYS_OF_WEEK_FRIDAY },
+               { "Saturday", E_EWS_RECURRENCE_DAYS_OF_WEEK_SATURDAY },
+               { "Day", E_EWS_RECURRENCE_DAYS_OF_WEEK_DAY },
+               { "Weekday", E_EWS_RECURRENCE_DAYS_OF_WEEK_WEEKDAY },
+               { "WeekendDay", E_EWS_RECURRENCE_DAYS_OF_WEEK_WEEKENDDAY }
+       };
+       gchar *value, **split_value;
+       guint32 days_of_week = 0;
+       gint ii, jj;
+
+       g_return_val_if_fail (param != NULL, E_EWS_RECURRENCE_DAYS_OF_WEEK_UNKNOWN);
+
+       value = e_soap_parameter_get_string_value (param);
+       if (!value || !*value) {
+               g_free (value);
+               return E_EWS_RECURRENCE_DAYS_OF_WEEK_UNKNOWN;
+       }
+
+       split_value = g_strsplit (value, " ", -1);
+
+       for (ii = 0; split_value && split_value[ii]; ii++) {
+               const gchar *str = split_value[ii];
+
+               if (!str || !*str)
+                       continue;
+
+               for (jj = 0; jj < G_N_ELEMENTS (keys); jj++) {
+                       if (g_strcmp0 (str, keys[jj].str_value) == 0) {
+                               days_of_week |= keys[jj].bit_value;
+                               break;
+                       }
+               }
+       }
+
+       g_strfreev (split_value);
+       g_free (value);
+
+       return days_of_week;
+}
+
+static EEwsRecurrenceDayOfWeekIndex
+parse_recur_day_of_week_index (ESoapParameter *param)
+{
+       EEwsRecurrenceDayOfWeekIndex day_of_week_index = E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_UNKNOWN;
+       gchar *value;
+
+       g_return_val_if_fail (param != NULL, E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_UNKNOWN);
+
+       value = e_soap_parameter_get_string_value (param);
+       if (!value || !*value) {
+               g_free (value);
+               return E_EWS_RECURRENCE_DAYS_OF_WEEK_UNKNOWN;
+       }
+
+       /* Do not localize, these are values used in XML */
+       if (g_strcmp0 (value, "First") == 0)
+               day_of_week_index = E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_FIRST;
+       else if (g_strcmp0 (value, "Second") == 0)
+               day_of_week_index = E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_SECOND;
+       else if (g_strcmp0 (value, "Third") == 0)
+               day_of_week_index = E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_THIRD;
+       else if (g_strcmp0 (value, "Fourth") == 0)
+               day_of_week_index = E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_FOURTH;
+       else if (g_strcmp0 (value, "Last") == 0)
+               day_of_week_index = E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_LAST;
+
+       g_free (value);
+
+       return day_of_week_index;
+}
+
+static GDateMonth
+parse_recur_month (ESoapParameter *param)
+{
+       GDateMonth month = G_DATE_BAD_MONTH;
+       gchar *value;
+
+       g_return_val_if_fail (param != NULL, G_DATE_BAD_MONTH);
+
+       value = e_soap_parameter_get_string_value (param);
+       if (!value || !*value) {
+               g_free (value);
+               return G_DATE_BAD_MONTH;
+       }
+
+       /* Do not localize, these are values used in XML */
+       if (g_strcmp0 (value, "January") == 0)
+               month = G_DATE_JANUARY;
+       else if (g_strcmp0 (value, "February") == 0)
+               month = G_DATE_FEBRUARY;
+       else if (g_strcmp0 (value, "March") == 0)
+               month = G_DATE_MARCH;
+       else if (g_strcmp0 (value, "April") == 0)
+               month = G_DATE_APRIL;
+       else if (g_strcmp0 (value, "May") == 0)
+               month = G_DATE_MAY;
+       else if (g_strcmp0 (value, "June") == 0)
+               month = G_DATE_JUNE;
+       else if (g_strcmp0 (value, "July") == 0)
+               month = G_DATE_JULY;
+       else if (g_strcmp0 (value, "August") == 0)
+               month = G_DATE_AUGUST;
+       else if (g_strcmp0 (value, "September") == 0)
+               month = G_DATE_SEPTEMBER;
+       else if (g_strcmp0 (value, "October") == 0)
+               month = G_DATE_OCTOBER;
+       else if (g_strcmp0 (value, "November") == 0)
+               month = G_DATE_NOVEMBER;
+       else if (g_strcmp0 (value, "December") == 0)
+               month = G_DATE_DECEMBER;
+
+       g_free (value);
+
+       return month;
+}
+
+static GDateWeekday
+parse_recur_first_day_of_week (ESoapParameter *param)
+{
+       GDateWeekday first_day_of_week = G_DATE_BAD_WEEKDAY;
+       gchar *value;
+
+       g_return_val_if_fail (param != NULL, G_DATE_BAD_WEEKDAY);
+
+       value = e_soap_parameter_get_string_value (param);
+       if (!value || !*value) {
+               g_free (value);
+               return G_DATE_BAD_WEEKDAY;
+       }
+
+       /* Do not localize, these are values used in XML */
+       if (g_strcmp0 (value, "Sunday") == 0)
+               first_day_of_week = G_DATE_SUNDAY;
+       else if (g_strcmp0 (value, "Monday") == 0)
+               first_day_of_week = G_DATE_MONDAY;
+       else if (g_strcmp0 (value, "Tuesday") == 0)
+               first_day_of_week = G_DATE_TUESDAY;
+       else if (g_strcmp0 (value, "Wednesday") == 0)
+               first_day_of_week = G_DATE_WEDNESDAY;
+       else if (g_strcmp0 (value, "Thursday") == 0)
+               first_day_of_week = G_DATE_THURSDAY;
+       else if (g_strcmp0 (value, "Friday") == 0)
+               first_day_of_week = G_DATE_FRIDAY;
+       else if (g_strcmp0 (value, "Saturday") == 0)
+               first_day_of_week = G_DATE_SATURDAY;
+
+       g_free (value);
+
+       return first_day_of_week;
+}
+
+static void
+parse_recurrence_field (EEwsItem *item,
+                       ESoapParameter *param)
+{
+       ESoapParameter *subparam, *subparam1;
+
+       g_return_if_fail (item != NULL);
+       g_return_if_fail (param != NULL);
+
+       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+       item->priv->recurrence.end_type = E_EWS_RECURRENCE_END_UNKNOWN;
+
+       if ((subparam = e_soap_parameter_get_first_child_by_name (param, "RelativeYearlyRecurrence")) != 
NULL) {
+               item->priv->recurrence.type = E_EWS_RECURRENCE_RELATIVE_YEARLY;
+               item->priv->recurrence.recur.relative_yearly.days_of_week = 
E_EWS_RECURRENCE_DAYS_OF_WEEK_UNKNOWN;
+               item->priv->recurrence.recur.relative_yearly.day_of_week_index = 
E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_UNKNOWN;
+               item->priv->recurrence.recur.relative_yearly.month = G_DATE_BAD_MONTH;
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "DaysOfWeek");
+               if (subparam1) {
+                       item->priv->recurrence.recur.relative_yearly.days_of_week = parse_recur_days_of_week 
(subparam1);
+
+                       if (item->priv->recurrence.recur.relative_yearly.days_of_week == 
E_EWS_RECURRENCE_DAYS_OF_WEEK_UNKNOWN)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "DayOfWeekIndex");
+               if (subparam1) {
+                       item->priv->recurrence.recur.relative_yearly.day_of_week_index = 
parse_recur_day_of_week_index (subparam1);
+
+                       if (item->priv->recurrence.recur.relative_yearly.day_of_week_index == 
E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_UNKNOWN)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "Month");
+               if (subparam1) {
+                       item->priv->recurrence.recur.relative_yearly.month = parse_recur_month (subparam1);
+
+                       if (item->priv->recurrence.recur.relative_yearly.month == G_DATE_BAD_MONTH)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+       } else if ((subparam = e_soap_parameter_get_first_child_by_name (param, "AbsoluteYearlyRecurrence")) 
!= NULL) {
+               item->priv->recurrence.type = E_EWS_RECURRENCE_ABSOLUTE_YEARLY;
+               item->priv->recurrence.recur.absolute_yearly.day_of_month = 0;
+               item->priv->recurrence.recur.absolute_yearly.month = G_DATE_BAD_MONTH;
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "DayOfMonth");
+               if (subparam1) {
+                       item->priv->recurrence.recur.absolute_yearly.day_of_month = 
e_soap_parameter_get_int_value (subparam1);
+
+                       if (item->priv->recurrence.recur.absolute_yearly.day_of_month < 1 ||
+                           item->priv->recurrence.recur.absolute_yearly.day_of_month > 31)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               } else {
+                       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "Month");
+               if (subparam1) {
+                       item->priv->recurrence.recur.absolute_yearly.month = parse_recur_month (subparam1);
+
+                       if (item->priv->recurrence.recur.absolute_yearly.month == G_DATE_BAD_MONTH)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               } else {
+                       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+       } else if ((subparam = e_soap_parameter_get_first_child_by_name (param, "RelativeMonthlyRecurrence")) 
!= NULL) {
+               item->priv->recurrence.type = E_EWS_RECURRENCE_RELATIVE_MONTHLY;
+               item->priv->recurrence.recur.relative_monthly.interval = 0;
+               item->priv->recurrence.recur.relative_monthly.days_of_week = 
E_EWS_RECURRENCE_DAYS_OF_WEEK_UNKNOWN;
+               item->priv->recurrence.recur.relative_monthly.day_of_week_index = 
E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_UNKNOWN;
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "Interval");
+               if (subparam1) {
+                       item->priv->recurrence.recur.relative_monthly.interval = 
e_soap_parameter_get_int_value (subparam1);
+
+                       if (item->priv->recurrence.recur.relative_monthly.interval < 1)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               } else {
+                       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "DaysOfWeek");
+               if (subparam1) {
+                       item->priv->recurrence.recur.relative_monthly.days_of_week = parse_recur_days_of_week 
(subparam1);
+
+                       if (item->priv->recurrence.recur.relative_monthly.days_of_week == 
E_EWS_RECURRENCE_DAYS_OF_WEEK_UNKNOWN)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               } else {
+                       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "DayOfWeekIndex");
+               if (subparam1) {
+                       item->priv->recurrence.recur.relative_monthly.day_of_week_index = 
parse_recur_day_of_week_index (subparam1);
+
+                       if (item->priv->recurrence.recur.relative_monthly.day_of_week_index == 
E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_UNKNOWN)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               } else {
+                       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+       } else if ((subparam = e_soap_parameter_get_first_child_by_name (param, "AbsoluteMonthlyRecurrence")) 
!= NULL) {
+               item->priv->recurrence.type = E_EWS_RECURRENCE_ABSOLUTE_MONTHLY;
+               item->priv->recurrence.recur.absolute_monthly.interval = 0;
+               item->priv->recurrence.recur.absolute_monthly.day_of_month = 0;
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "Interval");
+               if (subparam1) {
+                       item->priv->recurrence.recur.absolute_monthly.interval = 
e_soap_parameter_get_int_value (subparam1);
+
+                       if (item->priv->recurrence.recur.absolute_monthly.interval < 1)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               } else {
+                       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "DayOfMonth");
+               if (subparam1) {
+                       item->priv->recurrence.recur.absolute_monthly.day_of_month = 
e_soap_parameter_get_int_value (subparam1);
+
+                       if (item->priv->recurrence.recur.absolute_monthly.day_of_month < 1 ||
+                           item->priv->recurrence.recur.absolute_monthly.day_of_month > 31)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               } else {
+                       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+       } else if ((subparam = e_soap_parameter_get_first_child_by_name (param, "WeeklyRecurrence")) != NULL) 
{
+               item->priv->recurrence.type = E_EWS_RECURRENCE_WEEKLY;
+               item->priv->recurrence.recur.weekly.interval = 0;
+               item->priv->recurrence.recur.weekly.days_of_week = E_EWS_RECURRENCE_DAYS_OF_WEEK_UNKNOWN;
+               item->priv->recurrence.recur.weekly.first_day_of_week = G_DATE_BAD_WEEKDAY;
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "Interval");
+               if (subparam1) {
+                       item->priv->recurrence.recur.weekly.interval = e_soap_parameter_get_int_value 
(subparam1);
+
+                       if (item->priv->recurrence.recur.weekly.interval < 1)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               } else {
+                       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "DaysOfWeek");
+               if (subparam1) {
+                       item->priv->recurrence.recur.weekly.days_of_week = parse_recur_days_of_week 
(subparam1);
+
+                       if (item->priv->recurrence.recur.weekly.days_of_week == 
E_EWS_RECURRENCE_DAYS_OF_WEEK_UNKNOWN)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               } else {
+                       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "FirstDayOfWeek");
+               if (subparam1) {
+                       item->priv->recurrence.recur.weekly.first_day_of_week = parse_recur_first_day_of_week 
(subparam1);
+
+                       if (item->priv->recurrence.recur.weekly.first_day_of_week == G_DATE_BAD_WEEKDAY)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               } else {
+                       /* It's okay, because 2007 doesn't support it */
+               }
+       } else if ((subparam = e_soap_parameter_get_first_child_by_name (param, "DailyRecurrence")) != NULL) {
+               item->priv->recurrence.type = E_EWS_RECURRENCE_DAILY;
+               item->priv->recurrence.recur.interval = 0;
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "Interval");
+               if (subparam1) {
+                       item->priv->recurrence.recur.interval = e_soap_parameter_get_int_value (subparam1);
+
+                       if (item->priv->recurrence.recur.interval < 1)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               } else {
+                       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+       } else if ((subparam = e_soap_parameter_get_first_child_by_name (param, "DailyRegeneration")) != 
NULL) {
+               item->priv->recurrence.type = E_EWS_RECURRENCE_DAILY_REGENERATION;
+               item->priv->recurrence.recur.interval = 0;
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "Interval");
+               if (subparam1) {
+                       item->priv->recurrence.recur.interval = e_soap_parameter_get_int_value (subparam1);
+
+                       if (item->priv->recurrence.recur.interval < 1)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               } else {
+                       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+       } else if ((subparam = e_soap_parameter_get_first_child_by_name (param, "WeeklyRegeneration")) != 
NULL) {
+               item->priv->recurrence.type = E_EWS_RECURRENCE_WEEKLY_REGENERATION;
+               item->priv->recurrence.recur.interval = 0;
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "Interval");
+               if (subparam1) {
+                       item->priv->recurrence.recur.interval = e_soap_parameter_get_int_value (subparam1);
+
+                       if (item->priv->recurrence.recur.interval < 1)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               } else {
+                       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+       } else if ((subparam = e_soap_parameter_get_first_child_by_name (param, "MonthlyRegeneration")) != 
NULL) {
+               item->priv->recurrence.type = E_EWS_RECURRENCE_MONTHLY_REGENERATION;
+               item->priv->recurrence.recur.interval = 0;
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "Interval");
+               if (subparam1) {
+                       item->priv->recurrence.recur.interval = e_soap_parameter_get_int_value (subparam1);
+
+                       if (item->priv->recurrence.recur.interval < 1)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               } else {
+                       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+       } else if ((subparam = e_soap_parameter_get_first_child_by_name (param, "YearlyRegeneration")) != 
NULL) {
+               item->priv->recurrence.type = E_EWS_RECURRENCE_YEARLY_REGENERATION;
+               item->priv->recurrence.recur.interval = 0;
+
+               subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "Interval");
+               if (subparam1) {
+                       item->priv->recurrence.recur.interval = e_soap_parameter_get_int_value (subparam1);
+
+                       if (item->priv->recurrence.recur.interval < 1)
+                               item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               } else {
+                       item->priv->recurrence.type = E_EWS_RECURRENCE_UNKNOWN;
+               }
+       }
+
+       if (item->priv->recurrence.type != E_EWS_RECURRENCE_UNKNOWN) {
+               if ((subparam = e_soap_parameter_get_first_child_by_name (param, "NoEndRecurrence")) != NULL) 
{
+                       subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "StartDate");
+                       if (subparam1) {
+                               item->priv->recurrence.end_type = E_EWS_RECURRENCE_END_NO_END;
+                               item->priv->recurrence.utc_start_date = ews_item_parse_date (subparam1);
+
+                               if (item->priv->recurrence.utc_start_date == (time_t) -1)
+                                       item->priv->recurrence.end_type = E_EWS_RECURRENCE_END_UNKNOWN;
+                       }
+               } else if ((subparam = e_soap_parameter_get_first_child_by_name (param, "EndDateRecurrence")) 
!= NULL) {
+                       item->priv->recurrence.end_type = E_EWS_RECURRENCE_END_DATE;
+
+                       subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "StartDate");
+                       if (subparam1) {
+                               item->priv->recurrence.utc_start_date = ews_item_parse_date (subparam1);
+
+                               if (item->priv->recurrence.utc_start_date == (time_t) -1)
+                                       item->priv->recurrence.end_type = E_EWS_RECURRENCE_END_UNKNOWN;
+                       } else {
+                               item->priv->recurrence.end_type = E_EWS_RECURRENCE_END_UNKNOWN;
+                       }
+
+                       subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "EndDate");
+                       if (subparam1) {
+                               item->priv->recurrence.end.utc_end_date = ews_item_parse_date (subparam1);
+
+                               if (item->priv->recurrence.end.utc_end_date == (time_t) -1)
+                                       item->priv->recurrence.end_type = E_EWS_RECURRENCE_END_UNKNOWN;
+                       } else {
+                               item->priv->recurrence.end_type = E_EWS_RECURRENCE_END_UNKNOWN;
+                       }
+               } else if ((subparam = e_soap_parameter_get_first_child_by_name (param, 
"NumberedRecurrence")) != NULL) {
+                       item->priv->recurrence.end_type = E_EWS_RECURRENCE_END_NUMBERED;
+
+                       subparam1 = e_soap_parameter_get_first_child_by_name (subparam, "StartDate");
+                       if (subparam1) {
+                               item->priv->recurrence.utc_start_date = ews_item_parse_date (subparam1);
+
+                               if (item->priv->recurrence.utc_start_date == (time_t) -1)
+                                       item->priv->recurrence.end_type = E_EWS_RECURRENCE_END_UNKNOWN;
+                       } else {
+                               item->priv->recurrence.end_type = E_EWS_RECURRENCE_END_UNKNOWN;
+                       }
+
+                       subparam1 = e_soap_parameter_get_first_child_by_name (subparam, 
"NumberOfOccurrences");
+                       if (subparam1) {
+                               item->priv->recurrence.end.number_of_occurrences = 
e_soap_parameter_get_int_value (subparam1);
+
+                               if (item->priv->recurrence.end.number_of_occurrences < 1)
+                                       item->priv->recurrence.end_type = E_EWS_RECURRENCE_END_UNKNOWN;
+                       } else {
+                               item->priv->recurrence.end_type = E_EWS_RECURRENCE_END_UNKNOWN;
+                       }
+               }
+       }
+
+       g_warn_if_fail (
+               (item->priv->recurrence.type == E_EWS_RECURRENCE_UNKNOWN &&  item->priv->recurrence.end_type 
== E_EWS_RECURRENCE_END_UNKNOWN) ||
+               (item->priv->recurrence.type != E_EWS_RECURRENCE_UNKNOWN &&  item->priv->recurrence.end_type 
!= E_EWS_RECURRENCE_END_UNKNOWN));
+}
+
 static gchar *
 strip_html_tags (const gchar *html_text)
 {
@@ -895,20 +1377,13 @@ parse_task_field (EEwsItem *item,
        } else if (!g_ascii_strcasecmp (name, "PercentComplete")) {
                priv->task_fields->percent_complete = e_soap_parameter_get_string_value (subparam);
        } else if (!g_ascii_strcasecmp (name, "DueDate")) {
-               value = e_soap_parameter_get_string_value (subparam);
-               priv->task_fields->due_date = ews_item_parse_date (value);
-               g_free (value);
+               priv->task_fields->due_date = ews_item_parse_date (subparam);
                priv->task_fields->has_due_date = TRUE;
        } else if (!g_ascii_strcasecmp (name, "StartDate")) {
-               value = e_soap_parameter_get_string_value (subparam);
-               priv->task_fields->start_date = ews_item_parse_date (value);
-               g_free (value);
+               priv->task_fields->start_date = ews_item_parse_date (subparam);
                priv->task_fields->has_start_date = TRUE;
-       }
-       else if (!g_ascii_strcasecmp (name, "CompleteDate")) {
-               value = e_soap_parameter_get_string_value (subparam);
-               priv->task_fields->complete_date = ews_item_parse_date (value);
-               g_free (value);
+       } else if (!g_ascii_strcasecmp (name, "CompleteDate")) {
+               priv->task_fields->complete_date = ews_item_parse_date (subparam);
                priv->task_fields->has_complete_date = TRUE;
        } else if (!g_ascii_strcasecmp (name, "Sensitivity")) {
                priv->task_fields->sensitivity = e_soap_parameter_get_string_value (subparam);
@@ -927,6 +1402,8 @@ parse_task_field (EEwsItem *item,
                        g_free (priv->task_fields->delegator);
                        priv->task_fields->delegator = NULL;
                }
+       } else if (!g_ascii_strcasecmp (name, "Recurrence")) {
+               parse_recurrence_field (item, subparam);
        }
 }
 
@@ -1069,9 +1546,7 @@ e_ews_item_set_from_soap_parameter (EEwsItem *item,
                                g_free (str);
                        }
                } else if (!g_ascii_strcasecmp (name, "DateTimeReceived")) {
-                       value = e_soap_parameter_get_string_value (subparam);
-                       priv->date_received = ews_item_parse_date (value);
-                       g_free (value);
+                       priv->date_received = ews_item_parse_date (subparam);
                } else if (!g_ascii_strcasecmp (name, "Size")) {
                        priv->size = e_soap_parameter_get_int_value (subparam);
                } else if (!g_ascii_strcasecmp (name, "Categories")) {
@@ -1081,13 +1556,9 @@ e_ews_item_set_from_soap_parameter (EEwsItem *item,
                } else if (!g_ascii_strcasecmp (name, "InReplyTo")) {
                        priv->in_replyto = e_soap_parameter_get_string_value (subparam);
                } else if (!g_ascii_strcasecmp (name, "DateTimeSent")) {
-                       value = e_soap_parameter_get_string_value (subparam);
-                       priv->date_sent = ews_item_parse_date (value);
-                       g_free (value);
+                       priv->date_sent = ews_item_parse_date (subparam);
                } else if (!g_ascii_strcasecmp (name, "DateTimeCreated")) {
-                       value = e_soap_parameter_get_string_value (subparam);
-                       priv->date_created = ews_item_parse_date (value);
-                       g_free (value);
+                       priv->date_created = ews_item_parse_date (subparam);
                } else if (!g_ascii_strcasecmp (name, "HasAttachments")) {
                        value = e_soap_parameter_get_string_value (subparam);
                        priv->has_attachments = (!g_ascii_strcasecmp (value, "true"));
@@ -1145,9 +1616,7 @@ e_ews_item_set_from_soap_parameter (EEwsItem *item,
                        priv->reminder_is_set = (!g_ascii_strcasecmp (value, "true"));
                        g_free (value);
                } else if (!g_ascii_strcasecmp (name, "ReminderDueBy")) {
-                       value = e_soap_parameter_get_string_value (subparam);
-                       priv->reminder_due_by = ews_item_parse_date (value);
-                       g_free (value);
+                       priv->reminder_due_by = ews_item_parse_date (subparam);
                } else if (!g_ascii_strcasecmp (name, "ReminderMinutesBeforeStart")) {
                        priv->reminder_minutes_before_start = e_soap_parameter_get_int_value (subparam);
                } else if (priv->item_type == E_EWS_ITEM_TYPE_TASK || priv->item_type == 
E_EWS_ITEM_TYPE_MEMO) {
@@ -1932,6 +2401,23 @@ e_ews_item_get_reminder_minutes_before_start (EEwsItem *item)
        return item->priv->reminder_minutes_before_start;
 }
 
+/* the out_recurrence is filled only if the function returns TRUE */
+gboolean
+e_ews_item_get_recurrence (EEwsItem *item,
+                          EEwsRecurrence *out_recurrence)
+{
+       g_return_val_if_fail (E_IS_EWS_ITEM (item), FALSE);
+       g_return_val_if_fail (out_recurrence != NULL, -1);
+
+       if (item->priv->recurrence.type == E_EWS_RECURRENCE_UNKNOWN ||
+           item->priv->recurrence.end_type == E_EWS_RECURRENCE_END_UNKNOWN)
+               return FALSE;
+
+       *out_recurrence = item->priv->recurrence;
+
+       return TRUE;
+}
+
 const gchar *
 e_ews_item_get_fileas (EEwsItem *item)
 {
diff --git a/src/server/e-ews-item.h b/src/server/e-ews-item.h
index a2f3ce1..9c4f8c8 100644
--- a/src/server/e-ews-item.h
+++ b/src/server/e-ews-item.h
@@ -162,6 +162,93 @@ typedef struct {
        guint32 rights;                         /* EEwsPermissionBits for the user */
 } EEwsPermission;
 
+typedef enum {
+       E_EWS_RECURRENCE_UNKNOWN = 0,
+       E_EWS_RECURRENCE_RELATIVE_YEARLY,
+       E_EWS_RECURRENCE_ABSOLUTE_YEARLY,
+       E_EWS_RECURRENCE_RELATIVE_MONTHLY,
+       E_EWS_RECURRENCE_ABSOLUTE_MONTHLY,
+       E_EWS_RECURRENCE_WEEKLY,
+       E_EWS_RECURRENCE_DAILY,
+       E_EWS_RECURRENCE_DAILY_REGENERATION,
+       E_EWS_RECURRENCE_WEEKLY_REGENERATION,
+       E_EWS_RECURRENCE_MONTHLY_REGENERATION,
+       E_EWS_RECURRENCE_YEARLY_REGENERATION
+} EEwsRecurrenceType;
+
+typedef enum {
+       E_EWS_RECURRENCE_DAYS_OF_WEEK_UNKNOWN           = 0,
+       E_EWS_RECURRENCE_DAYS_OF_WEEK_SUNDAY            = 1 << 0,
+       E_EWS_RECURRENCE_DAYS_OF_WEEK_MONDAY            = 1 << 1,
+       E_EWS_RECURRENCE_DAYS_OF_WEEK_TUESDAY           = 1 << 2,
+       E_EWS_RECURRENCE_DAYS_OF_WEEK_WEDNESDAY         = 1 << 3,
+       E_EWS_RECURRENCE_DAYS_OF_WEEK_THURSDAY          = 1 << 4,
+       E_EWS_RECURRENCE_DAYS_OF_WEEK_FRIDAY            = 1 << 5,
+       E_EWS_RECURRENCE_DAYS_OF_WEEK_SATURDAY          = 1 << 6,
+       E_EWS_RECURRENCE_DAYS_OF_WEEK_DAY               = 1 << 7,
+       E_EWS_RECURRENCE_DAYS_OF_WEEK_WEEKDAY           = 1 << 8,
+       E_EWS_RECURRENCE_DAYS_OF_WEEK_WEEKENDDAY        = 1 << 9
+} EEwsRecurrenceDaysOfWeek;
+
+typedef enum {
+       E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_UNKNOWN = 0,
+       E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_FIRST,
+       E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_SECOND,
+       E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_THIRD,
+       E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_FOURTH,
+       E_EWS_RECURRENCE_DAY_OF_WEEK_INDEX_LAST
+} EEwsRecurrenceDayOfWeekIndex;
+
+typedef enum {
+       E_EWS_RECURRENCE_END_UNKNOWN = 0,
+       E_EWS_RECURRENCE_END_NO_END,
+       E_EWS_RECURRENCE_END_DATE,
+       E_EWS_RECURRENCE_END_NUMBERED
+} EEwsRecurrenceEndType;
+
+typedef struct {
+       EEwsRecurrenceType type;
+       union _recur {
+               struct _relative_yearly {
+                       guint32 days_of_week; /* bit-or of EEwsRecurrenceDaysOfWeek */
+                       EEwsRecurrenceDayOfWeekIndex day_of_week_index;
+                       GDateMonth month; /* 1..12 */
+               } relative_yearly;
+
+               struct _absolute_yearly {
+                       gint day_of_month; /* 1..31 */
+                       GDateMonth month; /* 1..12 */
+               } absolute_yearly;
+
+               struct _relative_monthly {
+                       gint interval; /* 1..99 */
+                       guint32 days_of_week; /* bit-or of EEwsRecurrenceDaysOfWeek */
+                       EEwsRecurrenceDayOfWeekIndex day_of_week_index;
+               } relative_monthly;
+
+               struct _absolute_monthly {
+                       gint interval; /* 1..99 */
+                       gint day_of_month; /* 1..31 */
+               } absolute_monthly;
+
+               struct _weekly {
+                       gint interval; /* 1..99 */
+                       guint32 days_of_week; /* bit-or of EEwsRecurrenceDaysOfWeek */
+                       GDateWeekday first_day_of_week; /* Exchange 2013 server and above */
+               } weekly;
+
+               /* Used for daily, daily_regeneration, weekly_regeneration, monthly_regeneration and 
yearly_regeneration */
+               gint interval; /* 1..999 */
+       } recur;
+
+       EEwsRecurrenceEndType end_type;
+       time_t utc_start_date;
+       union _end {
+               time_t utc_end_date;
+               gint number_of_occurrences;
+       } end;
+} EEwsRecurrence;
+
 GType          e_ews_item_get_type (void);
 EEwsItem *     e_ews_item_new_from_soap_parameter
                                                (ESoapParameter *param);
@@ -214,6 +301,8 @@ gboolean    e_ews_item_get_reminder_is_set  (EEwsItem *item);
 time_t         e_ews_item_get_reminder_due_by  (EEwsItem *item);
 gint           e_ews_item_get_reminder_minutes_before_start
                                                (EEwsItem *item);
+gboolean       e_ews_item_get_recurrence       (EEwsItem *item,
+                                                EEwsRecurrence *out_recurrence);
 EwsMailbox *
                e_ews_item_mailbox_from_soap_param
                                                (ESoapParameter *param);
diff --git a/tests/ews-test-timezones.c b/tests/ews-test-timezones.c
index 1ac64b1..7f18173 100644
--- a/tests/ews-test-timezones.c
+++ b/tests/ews-test-timezones.c
@@ -26,7 +26,7 @@
 
 void (* populate_windows_zones) (void);
 const gchar * (* ical_to_msdn_equivalent) (const gchar *);
-void (* convert_calcomp_to_xml) (ESoapMessage *, gpointer);
+gboolean (* convert_calcomp_to_xml) (ESoapMessage *, gpointer, GError **);
 
 const gchar *str_comp =
        "BEGIN:VEVENT\n"


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]