]> www.infradead.org Git - users/dwmw2/ews-sync.git/commitdiff
Convert completely to using ical structures for building events
authorDavid Woodhouse <dwmw2@infradead.org>
Sun, 18 Jul 2010 21:24:23 +0000 (22:24 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Sun, 18 Jul 2010 21:25:29 +0000 (22:25 +0100)
ews2ical.c

index ed37688ceaaa621dd54b0980b44f84f2ff09a0ae..ce672bb158e7f2205c9fe3079e2fc5b498a92c00 100644 (file)
@@ -1,3 +1,4 @@
+#define _GNU_SOURCE /* for asprintf */
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 
 #include <libical/icaltimezone.h>
 FILE *calfile;
 
-
-int process_organizer(xmlNode *xml_node);
-int process_required_attendees(xmlNode *xml_node);
-int process_start(xmlNode *xml_node, icaltimezone *zone);
-int process_end(xmlNode *xml_node, icaltimezone *zone);
-int process_location(xmlNode *xml_node);
-int process_body(xmlNode *xml_node);
-int process_subject(xmlNode *xml_node);
-int process_recurrence(xmlNode *xml_node);
-int process_itemid(xmlNode *xmlnode);
+int process_relativeyearlyrecurrence(xmlNode *xml_node, struct icalrecurrencetype *ical_recur);
+int process_absoluteyearlyrecurrence(xmlNode *xml_node, struct icalrecurrencetype *ical_recur);
+int process_relativemonthlyrecurrence(xmlNode *xml_node, struct icalrecurrencetype *ical_recur);
+int process_absolutemonthlyrecurrence(xmlNode *xml_node, struct icalrecurrencetype *ical_recur);
+int process_weeklyrecurrence(xmlNode *xml_node, struct icalrecurrencetype *ical_recur);
+int process_dailyrecurrence(xmlNode *xml_node, struct icalrecurrencetype *ical_recur);
+
+int process_organizer(icalcomponent *comp, xmlNode *xml_node);
+int process_required_attendees(icalcomponent *comp, xmlNode *xml_node);
+int process_start(icalcomponent *comp, xmlNode *xml_node, icaltimezone *zone);
+int process_end(icalcomponent *comp, xmlNode *xml_node, icaltimezone *zone);
+int process_location(icalcomponent *comp, xmlNode *xml_node);
+int process_body(icalcomponent *comp, xmlNode *xml_node);
+int process_subject(icalcomponent *comp, xmlNode *xml_node);
+int process_recurrence(icalcomponent *comp, xmlNode *xml_node);
+int process_itemid(icalcomponent *comp, xmlNode *xmlnode);
 icaltimezone *get_timezone(xmlNode *xmlnode);
 icaltimezone *get_meeting_timezone(xmlNode *xml_node);
 
@@ -33,6 +40,7 @@ int main(int argc, char **argv)
        xmlDocPtr xml_doc;
        xmlNode *xml_node;
        icaltimezone *icaltz;
+       icalcomponent *comp;
        int xmlfd = 0; /* stdin */
        char buf[1];
 
@@ -141,36 +149,41 @@ int main(int argc, char **argv)
                fprintf(calfile, "%s", vtz);
                free(vtz);
        }
-       fprintf(calfile, "BEGIN:VEVENT\n");
+       comp = icalcomponent_new(ICAL_VEVENT_COMPONENT);
 
        for (xml_node = xml_node->children; xml_node; xml_node = xml_node->next) {
                if (xml_node->type != XML_ELEMENT_NODE)
                        continue;
                if (!strcmp((char *)xml_node->name, "Organizer"))
-                       process_organizer(xml_node);
+                       process_organizer(comp, xml_node);
                else if (!strcmp((char *)xml_node->name, "RequiredAttendees"))
-                       process_required_attendees(xml_node);
+                       process_required_attendees(comp, xml_node);
                else if (!strcmp((char *)xml_node->name, "Start"))
-                       process_start(xml_node, icaltz);
+                       process_start(comp, xml_node, icaltz);
                else if (!strcmp((char *)xml_node->name, "End"))
-                       process_end(xml_node, icaltz);
+                       process_end(comp, xml_node, icaltz);
                else if (!strcmp((char *)xml_node->name, "Body"))
-                       process_body(xml_node);
+                       process_body(comp, xml_node);
                else if (!strcmp((char *)xml_node->name, "Location"))
-                       process_location(xml_node);
+                       process_location(comp, xml_node);
                else if (!strcmp((char *)xml_node->name, "Subject"))
-                       process_subject(xml_node);
+                       process_subject(comp, xml_node);
                else if (!strcmp((char *)xml_node->name, "Recurrence"))
-                       process_recurrence(xml_node);
+                       process_recurrence(comp, xml_node);
                else if (!strcmp((char *)xml_node->name, "ItemId"))
-                       process_itemid(xml_node);
+                       process_itemid(comp, xml_node);
 #if 0
                else
                        fprintf(stderr, "Unhandled node type '%s'\n", xml_node->name);
 #endif
        }
-       fprintf(calfile, "END:VEVENT\n");
+       if (1) {
+               char *vtz = icalcomponent_as_ical_string_r(comp);
+               fprintf(calfile, "%s", vtz);
+               free(vtz);
+       }
        fprintf(calfile, "END:VCALENDAR\n");
+
        return 0;
 }
 
@@ -202,52 +215,74 @@ int process_mailbox(xmlNode *xml_node, const char **r_name, const char **r_email
        return 0;
 }
 
-int process_organizer(xmlNode *xml_node)
+int process_organizer(icalcomponent *comp, xmlNode *xml_node)
 {
+       icalproperty *prop;
+       icalparameter *param;
+
        for (xml_node = xml_node->children; xml_node; xml_node = xml_node->next) {
                if (xml_node->type != XML_ELEMENT_NODE)
                        continue;
                if (!strcmp((char *)xml_node->name, "Mailbox")) {
                        const char *name = NULL, *email = NULL;
+                       char *mailtoname;
                        if (process_mailbox(xml_node, &name, &email))
                                return -1;
-                       fprintf(calfile, "ORGANIZER;CN=\"%s\":MAILTO:%s\n",
-                               name, email);
+
+                       asprintf(&mailtoname, "mailto:%s", email);
+                       
+                       prop = icalproperty_new_organizer(mailtoname);
+                       free(mailtoname);
+                       param = icalparameter_new_cn(name);
+                       icalproperty_add_parameter(prop, param);
+                       icalcomponent_add_property(comp, prop);
                }
        }
        return 0;
 }
 
-int process_required_attendee(xmlNode *xml_node)
+int process_required_attendee(icalcomponent *comp, xmlNode *xml_node)
 {
+       icalproperty *prop;
+       icalparameter *param;
+
        for (xml_node = xml_node->children; xml_node; xml_node = xml_node->next) {
                if (xml_node->type != XML_ELEMENT_NODE)
                        continue;
                if (!strcmp((char *)xml_node->name, "Mailbox")) {
                        const char *name = NULL, *email = NULL;
+                       char *mailtoname;
                        if (process_mailbox(xml_node, &name, &email))
                                return -1;
-                       fprintf(calfile, "ATTENDEE;ROLE=REQ-PARTICIPANT;CN=\"%s\":MAILTO:%s\n",
-                               name, email);
+
+                       asprintf(&mailtoname, "mailto:%s", email);
+                       
+                       prop = icalproperty_new_organizer(mailtoname);
+                       free(mailtoname);
+                       param = icalparameter_new_cn(name);
+                       icalproperty_add_parameter(prop, param);
+                       param = icalparameter_new_role(ICAL_ROLE_REQPARTICIPANT);
+                       icalproperty_add_parameter(prop, param);
+                       icalcomponent_add_property(comp, prop);
                }
        }
        return 0;
 }
 
-int process_required_attendees(xmlNode *xml_node)
+int process_required_attendees(icalcomponent *comp, xmlNode *xml_node)
 {
        for (xml_node = xml_node->children; xml_node; xml_node = xml_node->next) {
                if (xml_node->type != XML_ELEMENT_NODE)
                        continue;
                if (!strcmp((char *)xml_node->name, "Attendee")) {
-                       if (process_required_attendee(xml_node))
+                       if (process_required_attendee(comp, xml_node))
                                { }
                }
        }
        return 0;
 }
 
-int process_time(xmlNode *xml_node, const char *name, icaltimezone *zone)
+int process_time(icalcomponent *comp, xmlNode *xml_node, int dtend, icaltimezone *zone)
 {
        char *ews_time = (char *)xmlNodeGetContent(xml_node);
        struct icaltimetype ical_time;
@@ -258,75 +293,70 @@ int process_time(xmlNode *xml_node, const char *name, icaltimezone *zone)
        if (zone)
                ical_time = icaltime_convert_to_zone(ical_time, zone);
 
-       fprintf(calfile, "%s", name);
-
-       if (zone)
-               fprintf(calfile, ";TZID=\"%s\"", icaltimezone_get_tzid(zone));
-       fprintf(calfile, ":%04d%02d%02dT%02d%02d%02d%s\n",
-               ical_time.year, ical_time.month, ical_time.day,
-               ical_time.hour, ical_time.minute, ical_time.second,
-               zone?"":"Z");
+       if (dtend)
+               icalcomponent_set_dtend(comp, ical_time);
+       else
+               icalcomponent_set_dtstart(comp, ical_time);
        return 0;
 }
 
-int process_start(xmlNode *xml_node, icaltimezone *zone)
+int process_start(icalcomponent *comp, xmlNode *xml_node, icaltimezone *zone)
 {
-       return process_time(xml_node, "DTSTART", zone);
+       return process_time(comp, xml_node, 0, zone);
 }
 
-int process_end(xmlNode *xml_node, icaltimezone *zone)
+int process_end(icalcomponent *comp, xmlNode *xml_node, icaltimezone *zone)
 {
-       return process_time(xml_node, "DTEND", zone);
+       return process_time(comp, xml_node, 1, zone);
 }
 
-int process_location (xmlNode *xml_node)
+int process_location (icalcomponent *comp, xmlNode *xml_node)
 {
-       const char *dur = (char *)xmlNodeGetContent(xml_node);
-       if (!dur)
+       const char *loc = (char *)xmlNodeGetContent(xml_node);
+
+       if (!loc)
                return -1;
-       fprintf(calfile, "LOCATION: %s\n", dur);
+       icalcomponent_set_location(comp, loc);
        return 0;
 }
 
-int process_body(xmlNode *xml_node)
+int process_body(icalcomponent *comp, xmlNode *xml_node)
 {
        const char *body = (char *)xmlNodeGetContent(xml_node);
-       int col;
 
        if (!body)
                return -1;
 
-       col = fprintf(calfile, "DESCRIPTION:");
+       if (!strncasecmp(body, "<html", 5)) {
+#if 0 /* XX: libical doesn't seem to escape this properly */
+               icalproperty *prop;
+               icalparameter *param;
 
-       while (*body) {
-               switch (*body) {
-               case '\n':
-                       col += fprintf(calfile, "\\n");
-                       break;
-               case ',':
-               case '"':
-                       col++; fputc('\\', calfile);
-               default:
-                       col++; fputc(*body, calfile);
-                       break;
-               }
-               body++;
-               if (col >= 76) {
-                       fprintf(calfile, "\n ");
-                       col = 1;
-               }
+               prop = icalproperty_new_x(body);
+               icalproperty_set_x_name(prop, "X-ALT-DESC");
+
+               param = icalparameter_new_fmttype("text/html");
+               icalproperty_add_parameter(prop, param);
+               icalcomponent_add_property(comp, prop);
+#endif
+               /* FIXME: html2text */
+               icalcomponent_set_description(comp, body);
+       } else {
+               icalcomponent_set_description(comp, body);
        }
-       fputc('\n', calfile);
+
+
        return 0;
 }
 
-int process_subject(xmlNode *xml_node)
+int process_subject(icalcomponent *comp, xmlNode *xml_node)
 {
        const char *subject = (char *)xmlNodeGetContent(xml_node);
+
        if (!subject)
                return -1;
 
-       fprintf(calfile, "SUMMARY:\"%s\"\n", subject);
+       icalcomponent_set_summary(comp, subject);
        return 0;
 }
 
@@ -350,7 +380,9 @@ static int weekday_to_number(const char *day)
 {
        static char *days[] = {
                "Sunday", "Monday", "Tuesday", "Wednesday",
-               "Thursday", "Friday", "Saturday"
+               "Thursday", "Friday", "Saturday",
+               /* "Day", "Weekday", "WeekendDay" */
+
        };
        int daynr;
        for (daynr = 0; daynr < 7; daynr++) {
@@ -362,32 +394,6 @@ static int weekday_to_number(const char *day)
        return 0;
 }
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
-static const char *weekday_to_ical(const char *weekday)
-{
-       static struct {
-               const char *exch;
-               const char *ical;
-       } table[] = {
-               { "Sunday", "SU" },
-               { "Monday", "MO" },
-               { "Tuesday", "TU" },
-               { "Wednesday", "WE" },
-               { "Thursday", "TH" },
-               { "Friday", "FR" },
-               { "Saturday", "SA" },
-               { "Day", "SU,MO,TU,WE,TH,FR,SA" },
-               { "Weekday", "MO,TU,WE,TH,FR" },
-               { "WeekendDay", "SA,SU" },
-       };
-       int i;
-
-       for (i=0 ; i < ARRAY_SIZE(table); i++) {
-               if (!strcmp(weekday, table[i].exch))
-                       return table[i].ical;
-       }
-       fprintf(stderr, "Unrecognised DaysOfWeek '%s'\n", weekday);
-       return NULL;
-}
 
 static int weekindex_to_ical(const char *week)
 {
@@ -411,84 +417,36 @@ static int weekindex_to_ical(const char *week)
        return 0;
 }      
                
-int process_recurrence(xmlNode *xml_node)
+int process_recurrence(icalcomponent *comp, xmlNode *xml_node)
 {
+       struct icalrecurrencetype ical_recur;
+       char *end_date = NULL, *nr_occurrences = NULL;
+       icalproperty *prop;
        xmlNode *xml_node2;
-       const char *weekly_interval = NULL;
-       const char *weekday = NULL;
-       const char *daily_interval = NULL;
-       const char *monthly_interval = NULL;
-       const char *day_of_month = NULL;
-       const char *month = NULL;
-       const char *week_index = NULL;
-       const char *end_date = NULL;
-       const char *nr_recurrences = NULL;
+
+       ical_recur.freq = ICAL_NO_RECURRENCE;
 
        for (xml_node = xml_node->children; xml_node; xml_node = xml_node->next) {
                if (xml_node->type != XML_ELEMENT_NODE)
                        continue;
                if (!strcmp((char *)xml_node->name, "WeeklyRecurrence")) {
-                       for (xml_node2 = xml_node->children; xml_node2;
-                            xml_node2 = xml_node2->next) {
-                               if (xml_node2->type != XML_ELEMENT_NODE)
-                                       continue;
-                               if (!strcmp((char *)xml_node2->name, "Interval"))
-                                       weekly_interval = (char *)xmlNodeGetContent(xml_node2);
-                               else if (!strcmp((char *)xml_node2->name, "DaysOfWeek"))
-                                       weekday = (char *)xmlNodeGetContent(xml_node2);
-                       }
+                       if (process_weeklyrecurrence(xml_node, &ical_recur))
+                               return -1;
                } else if (!strcmp((char *)xml_node->name, "DailyRecurrence")) {
-                       for (xml_node2 = xml_node->children; xml_node2;
-                            xml_node2 = xml_node2->next) {
-                               if (xml_node2->type != XML_ELEMENT_NODE)
-                                       continue;
-                               if (!strcmp((char *)xml_node2->name, "Interval"))
-                                       daily_interval = (char *)xmlNodeGetContent(xml_node2);
-                       }
+                       if (process_dailyrecurrence(xml_node, &ical_recur))
+                               return -1;
                } else if (!strcmp((char *)xml_node->name, "AbsoluteYearlyRecurrence")) {
-                       for (xml_node2 = xml_node->children; xml_node2;
-                            xml_node2 = xml_node2->next) {
-                               if (xml_node2->type != XML_ELEMENT_NODE)
-                                       continue;
-                               if (!strcmp((char *)xml_node2->name, "DayOfMonth"))
-                                       day_of_month = (char *)xmlNodeGetContent(xml_node2);
-                               else if (!strcmp((char *)xml_node2->name, "Month"))
-                                       month = (char *)xmlNodeGetContent(xml_node2);
-                       }
+                       if (process_absoluteyearlyrecurrence(xml_node, &ical_recur))
+                               return -1;
                } else if (!strcmp((char *)xml_node->name, "RelativeYearlyRecurrence")) {
-                       for (xml_node2 = xml_node->children; xml_node2;
-                            xml_node2 = xml_node2->next) {
-                               if (xml_node2->type != XML_ELEMENT_NODE)
-                                       continue;
-                               if (!strcmp((char *)xml_node2->name, "DaysOfWeek"))
-                                       weekday = (char *)xmlNodeGetContent(xml_node2);
-                               else if (!strcmp((char *)xml_node2->name, "Month"))
-                                       month = (char *)xmlNodeGetContent(xml_node2);
-                               else if (!strcmp((char *)xml_node2->name, "DayOfWeekIndex"))
-                                       week_index = (char *)xmlNodeGetContent(xml_node2);
-                       }
+                       if (process_relativeyearlyrecurrence(xml_node, &ical_recur))
+                               return -1;
                } else if (!strcmp((char *)xml_node->name, "AbsoluteMonthlyRecurrence")) {
-                       for (xml_node2 = xml_node->children; xml_node2;
-                            xml_node2 = xml_node2->next) {
-                               if (xml_node2->type != XML_ELEMENT_NODE)
-                                       continue;
-                               if (!strcmp((char *)xml_node2->name, "DayOfMonth"))
-                                       day_of_month = (char *)xmlNodeGetContent(xml_node2);
-                               else if (!strcmp((char *)xml_node2->name, "Interval"))
-                                       monthly_interval = (char *)xmlNodeGetContent(xml_node2);
-                       }
+                       if (process_absolutemonthlyrecurrence(xml_node, &ical_recur))
+                               return -1;
                } else if (!strcmp((char *)xml_node->name, "RelativeMonthlyRecurrence")) {
-                       for (xml_node2 = xml_node->children; xml_node2;
-                            xml_node2 = xml_node2->next) {
-                               if (xml_node2->type != XML_ELEMENT_NODE)
-                                       continue;
-                               if (!strcmp((char *)xml_node2->name, "DaysOfWeek"))
-                                       weekday = (char *)xmlNodeGetContent(xml_node2);
-                               else if (!strcmp((char *)xml_node2->name, "Interval"))
-                                       monthly_interval = (char *)xmlNodeGetContent(xml_node2);
-                               else if (!strcmp((char *)xml_node2->name, "DayOfWeekIndex"))
-                                       week_index = (char *)xmlNodeGetContent(xml_node2);
-                       }
+                       if (process_relativemonthlyrecurrence(xml_node, &ical_recur))
+                               return -1;
                } else if (!strcmp((char *)xml_node->name, "EndDateRecurrence")) {
                        for (xml_node2 = xml_node->children; xml_node2;
                             xml_node2 = xml_node2->next) {
@@ -503,69 +461,42 @@ int process_recurrence(xmlNode *xml_node)
                                if (xml_node2->type != XML_ELEMENT_NODE)
                                        continue;
                                if (!strcmp((char *)xml_node2->name, "NumberOfOccurrences")) 
-                                       nr_recurrences = (char *)xmlNodeGetContent(xml_node2);
+                                       nr_occurrences = (char *)xmlNodeGetContent(xml_node2);
                        }
                }
        }
-       if (daily_interval) {
-               fprintf(calfile, "RRULE:FREQ=DAILY;INTERVAL=%s", daily_interval);
-       } else if (weekday && month && week_index) {
-               int monthnr = month_to_number(month);
-               int week = weekindex_to_ical(week_index);
-               const char *weekday_ical = weekday_to_ical(weekday);
-               if (!monthnr || !week || !weekday_ical)
-                       return -1;
-
-               fprintf(calfile, "RRULE:FREQ=YEARLY;MONTH=%d;BYDAY=%d%s",
-                       monthnr, week, weekday_ical);
-               /* Relative Yearly */
-       } else if (monthly_interval && weekday && week_index) {
-               int week = weekindex_to_ical(week_index);
-               const char *weekday_ical = weekday_to_ical(weekday);
-               if (!week || !weekday_ical)
-                       return -1;
-               fprintf(calfile, "RRULE:FREQ=MONTHLY;INTERVAL=%s;BYDAY=%d%s",
-                       monthly_interval, week, weekday_ical);
-       } else if (day_of_month && month) {
-               int monthnr = month_to_number(month);
-               if (!monthnr)
-                       return -1;
-               fprintf(calfile, "RRULE:FREQ=YEARLY;BYMONTH=%d;BYMONTHDAY=%s",
-                       monthnr, day_of_month);
-       } else if (monthly_interval && day_of_month) {
-               fprintf(calfile, "RRULE:FREQ=MONTHLY;INTERVAL=%s;BYMONTHDAY=%s",
-                       monthly_interval, day_of_month);
-       } else if (weekly_interval && weekday) {
-               char day[3];
-               day[0] = toupper(weekday[0]);
-               day[1] = toupper(weekday[1]);
-               day[2] = 0;
-
-               fprintf(calfile, "RRULE:FREQ=WEEKLY;INTERVAL=%s;BYDAY=%s;WKST=SU",
-                       weekly_interval, day);
-       } else {
-               fprintf(stderr, "Unknown Recurrence type\n");
+       if (ical_recur.freq == ICAL_NO_RECURRENCE) {
+               fprintf(stderr, "No recognised Recurrence type\n");
                return -1;
        }
 
        if (end_date) {
-               fprintf(calfile, ";UNTIL=%.4s%.2s%.2sT235959Z",
-                       end_date, end_date + 5, end_date + 8);
-       } else if (nr_recurrences) {
-               fprintf(calfile, ";COUNT=%s", nr_recurrences);
+               if (strlen(end_date) != 11 || end_date[4] != '-' ||
+                   end_date[7] != '-' || end_date[10] != 'Z') {
+                       fprintf(stderr, "Failed to parse Recurrence EndDate '%s'\n",
+                               end_date);
+                       return -1;
+               }
+               end_date = strdup(end_date);
+               end_date[10] = 0;
+               ical_recur.until = icaltime_from_string(end_date);
+               printf("parsed as %04d-%02d-%02d\n",
+                      ical_recur.until.year, ical_recur.until.month, ical_recur.until.day);
+       } else if (nr_occurrences) {
+               ical_recur.count = strtol(nr_occurrences, NULL, 10);
        }
-
-       fputc('\n', calfile);
+       prop = icalproperty_new_rrule(ical_recur);
+       icalcomponent_add_property(comp, prop);
        return 0;
 }
 
-int process_itemid(xmlNode *xml_node)
+int process_itemid(icalcomponent *comp, xmlNode *xml_node)
 {
        const char *id = (char *)xmlGetProp(xml_node, (unsigned char *)"Id");
        if (!id)
                return -1;
 
-       fprintf(calfile, "UID:%s\n", id);
+       icalcomponent_set_uid(comp, id);
        return 0;
 }
 
@@ -778,7 +709,7 @@ int process_relativeyearlyrecurrence(xmlNode *xml_node, struct icalrecurrencetyp
                }
        }
        if (!week || !month || !weekday) {
-               fprintf(stderr, "RelativeWeeklyRecurrence missing essential fields (%s,%s,%s)\n",
+               fprintf(stderr, "RelativeYearlyRecurrence missing essential fields (%s,%s,%s)\n",
                        week, month, weekday);
                return -1;
        }
@@ -804,7 +735,194 @@ int process_relativeyearlyrecurrence(xmlNode *xml_node, struct icalrecurrencetyp
 
        return 0;
 }
+int process_absoluteyearlyrecurrence(xmlNode *xml_node, struct icalrecurrencetype *ical_recur)
+{
+       const char *day_of_month = NULL;
+       const char *month = NULL;
+       int daynr, monthnr;
+
+       for (xml_node = xml_node->children; xml_node;
+            xml_node = xml_node->next) {
+               if (xml_node->type != XML_ELEMENT_NODE)
+                       continue;
+               if (!strcmp((char *)xml_node->name, "DayOfMonth"))
+                       day_of_month = (char *)xmlNodeGetContent(xml_node);
+               else if (!strcmp((char *)xml_node->name, "Month"))
+                       month = (char *)xmlNodeGetContent(xml_node);
+       }
+       if (!day_of_month || !month) {
+               fprintf(stderr, "AbsoluteYearlyRecurrence missing essential fields (%s,%s)\n",
+                       day_of_month, month);
+               return -1;
+       }
+       daynr = strtol(day_of_month, NULL, 10);
+       if (!daynr) {
+               fprintf(stderr, "Failed to parse DayOfMonth '%s'\n", day_of_month);
+               return -1;
+       }
+       monthnr = month_to_number(month);
+       if (!month)
+               return -1;
+
+       icalrecurrencetype_clear(ical_recur);
+       ical_recur->freq = ICAL_YEARLY_RECURRENCE;
+       ical_recur->by_month[0] = monthnr;
+       ical_recur->by_month_day[0] = daynr;
+       return 0;
+}
+
+int process_relativemonthlyrecurrence(xmlNode *xml_node, struct icalrecurrencetype *ical_recur)
+{
+       const char *week = NULL, *interval = NULL, *weekday = NULL;
+       int weeknr, intervalnr, daynr;
+
+       for (xml_node = xml_node->children; xml_node; xml_node = xml_node->next) {
+               if (xml_node->type != XML_ELEMENT_NODE)
+                       continue;
+               if (!strcmp((char *)xml_node->name, "DaysOfWeek")) {
+                       weekday = (char *)xmlNodeGetContent(xml_node);
+               } else if (!strcmp((char *)xml_node->name, "Interval")) {
+                       interval = (char *)xmlNodeGetContent(xml_node);
+               } else if (!strcmp((char *)xml_node->name, "DayOfWeekIndex")) {
+                       week = (char *)xmlNodeGetContent(xml_node);
+               }
+       }
+       if (!week || !interval || !weekday) {
+               fprintf(stderr, "RelativeMonthlyRecurrence missing essential fields (%s,%s,%s)\n",
+                       week, interval, weekday);
+               return -1;
+       }
+       intervalnr = strtol(interval, NULL, 10);
+       if (!intervalnr) {
+               fprintf(stderr, "Failed to parse Interval '%s'\n", interval);
+               return -1;
+       }
+       weeknr = weekindex_to_ical(week);
+       if (!weeknr)
+               return -1;
+
+       daynr = weekday_to_number(weekday);
+       if (!daynr)
+               return -1;
+
+       icalrecurrencetype_clear(ical_recur);
+       ical_recur->freq = ICAL_MONTHLY_RECURRENCE;
+       ical_recur->interval = intervalnr;
+       if (weeknr > 0)
+               ical_recur->by_day[0] = daynr + (weeknr * 8);
+       else
+               ical_recur->by_day[0] = -8 - daynr;
+
+       return 0;
+}
+int process_absolutemonthlyrecurrence(xmlNode *xml_node, struct icalrecurrencetype *ical_recur)
+{
+       const char *interval = NULL, *monthday = NULL;
+       int intervalnr, monthdaynr;
+
+       for (xml_node = xml_node->children; xml_node; xml_node = xml_node->next) {
+               if (xml_node->type != XML_ELEMENT_NODE)
+                       continue;
+               if (!strcmp((char *)xml_node->name, "DayOfMonth")) {
+                       monthday = (char *)xmlNodeGetContent(xml_node);
+               } else if (!strcmp((char *)xml_node->name, "Interval")) {
+                       interval = (char *)xmlNodeGetContent(xml_node);
+               }
+       }
+       if (!interval || !monthday) {
+               fprintf(stderr, "AbsoluteMonthlyRecurrence missing essential fields (%s,%s)\n",
+                       interval, monthday);
+               return -1;
+       }
+       intervalnr = strtol(interval, NULL, 10);
+       if (!intervalnr) {
+               fprintf(stderr, "Failed to parse Interval '%s'\n", interval);
+               return -1;
+       }
+       monthdaynr = strtol(monthday, NULL, 10);
+       if (!monthday) {
+               fprintf(stderr, "Failed to parse DayOfMonth '%s'\n", monthday);
+               return -1;
+       }
+
+       icalrecurrencetype_clear(ical_recur);
+       ical_recur->freq = ICAL_MONTHLY_RECURRENCE;
+       ical_recur->interval = intervalnr;
+       ical_recur->by_month_day[0] = monthdaynr;
+       return 0;
+}
+
+int process_weeklyrecurrence(xmlNode *xml_node, struct icalrecurrencetype *ical_recur)
+{
+       const char *interval = NULL, *weekday = NULL, *firstday = NULL;
+       int intervalnr, daynr, firstdaynr;
+
+       for (xml_node = xml_node->children; xml_node; xml_node = xml_node->next) {
+               if (xml_node->type != XML_ELEMENT_NODE)
+                       continue;
+               if (!strcmp((char *)xml_node->name, "DaysOfWeek")) {
+                       weekday = (char *)xmlNodeGetContent(xml_node);
+               } else if (!strcmp((char *)xml_node->name, "Interval")) {
+                       interval = (char *)xmlNodeGetContent(xml_node);
+               } else if (!strcmp((char *)xml_node->name, "FirstDayOfWeek")) {
+                       firstday = (char *)xmlNodeGetContent(xml_node);
+               }
+       }
+       if (!interval || !weekday) {
+               fprintf(stderr, "WeeklyRecurrence missing essential fields (%s,%s)\n",
+                       interval, weekday);
+               return -1;
+       }
+       intervalnr = strtol(interval, NULL, 10);
+       if (!intervalnr) {
+               fprintf(stderr, "Failed to parse Interval '%s'\n", interval);
+               return -1;
+       }
+       daynr = weekday_to_number(weekday);
+       if (!daynr)
+               return -1;
+       
+       if (firstday)
+               firstdaynr = weekday_to_number(firstday);
+       else
+               firstdaynr = 0;
+
+       icalrecurrencetype_clear(ical_recur);
+       ical_recur->freq = ICAL_WEEKLY_RECURRENCE;
+       ical_recur->interval = intervalnr;
+       ical_recur->by_day[0] = daynr;
+       ical_recur->week_start = firstdaynr;
+       return 0;
+}
+int process_dailyrecurrence(xmlNode *xml_node, struct icalrecurrencetype *ical_recur)
+{
+       const char *interval = NULL;
+       int intervalnr;
 
+       for (xml_node = xml_node->children; xml_node; xml_node = xml_node->next) {
+               if (xml_node->type != XML_ELEMENT_NODE)
+                       continue;
+               if (!strcmp((char *)xml_node->name, "Interval")) {
+                       interval = (char *)xmlNodeGetContent(xml_node);
+               }
+       }
+       if (!interval) {
+               fprintf(stderr, "DailyRecurrence missing essential fields (%s)\n",
+                       interval);
+               return -1;
+       }
+       intervalnr = strtol(interval, NULL, 10);
+       if (!intervalnr) {
+               fprintf(stderr, "Failed to parse Interval '%s'\n", interval);
+               return -1;
+       }
+
+       icalrecurrencetype_clear(ical_recur);
+       ical_recur->freq = ICAL_DAILY_RECURRENCE;
+       ical_recur->interval = intervalnr;
+
+       return 0;
+}
 icalcomponent *process_timezone_rule(xmlNode *xml_node,
                          icalcomponent_kind kind, int *offset)
 {