an iCal processing library

Files at this revision

API Documentation at this revision

Comitter:
WiredHome
Date:
Sat May 17 19:54:51 2014 +0000
Parent:
1:db274b9e40cc
Child:
3:fc5cdc930896
Commit message:
Working to improve the recurring event parsing

Changed in this revision

iCal.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/iCal.cpp	Sun Apr 20 16:34:18 2014 +0000
+++ b/iCal.cpp	Sat May 17 19:54:51 2014 +0000
@@ -1,9 +1,13 @@
-
+//
+// TODO
+//  Repeat parsing is quite weak right now. It handles repeating days w/in a week
+//      (e.g. repeat weekly, on Mon, Tue, Thu)
+//
 
 #include "iCal.h"
 #include <algorithm>
 
-//#define DEBUG "iCal"
+#define DEBUG "iCal"
 #include <cstdio>
 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
 #define DBG(x, ...)  std::printf("[DBG %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
@@ -70,7 +74,7 @@
 {
     time_t tStamp;
     struct tm t;
-    //INFO("ParseDateStamp(..., %s)\r\n", string);
+    INFO("ParseDateStamp(%s,%d)\r\n", string, tzoSec);
     t.tm_year = AtoIxN(string, 4) - 1900;
     t.tm_mon  = AtoIxN(string+4, 2) - 1;
     t.tm_mday = AtoIxN(string+6, 2);
@@ -78,8 +82,10 @@
     t.tm_min  = AtoIxN(string+11, 2);
     t.tm_sec  = AtoIxN(string+13, 2);
     tStamp = mktime(&t);
-    if (string[strlen(string)-1] == 'Z')
+    if (string[strlen(string)-1] == 'Z') {
+        INFO("Applying tzoSec %d", tzoSec);
         tStamp = tStamp + tzoSec;
+    }
     return tStamp;
     //int tm_sec //seconds after the minute – [0, 60][@1]    (public member object)
     //int tm_min  //minutes after the hour – [0, 59]    (public member object)
@@ -96,7 +102,7 @@
 {
     static char temp[4][80];
     static int i = 0;
-    
+
     i &= 3;
     strcpy(temp[i], ctime(&t));
     temp[i][strlen(temp[i])-1] = '\0';
@@ -107,7 +113,7 @@
 void ShowEventInfo(Event_T & Event)
 {
     char temp[80];
-    
+
     INFO("*** Summary: %s", Event.Summary);
     strcpy(temp, ctime(&Event.Start));
     temp[strlen(temp)-1] = '\0';
@@ -172,16 +178,45 @@
 
 time_t NextInterval(int repeatFreq, int interval)
 {
-    time_t secperday = 60*60*24;
-    const int repeatFactor[] = {1, 7, 30, 365};
+    const time_t secperday = 60*60*24;
+    const int repeatFactor[] = {0, 1, 7, 30, 365};
     INFO("freq %d, interval %d", repeatFreq, interval);
     return repeatFactor[repeatFreq-1] * interval * secperday;
 }
 
+
+// start1,end1 is the time range representing the visible grid
+// start2,end2 is the time range of the event being tested
+// Event is also the event being tested and permits testing the repeat information.
+//
+// If the event repeat pattern intersects with the display pattern, indicate this as "true"
+//
+bool RepeatMaskIntersects(time_t * start1, time_t * end1, time_t * start2, time_t * end2, Event_T & Event)
+{
+    bool intersects = false;
+    
+    if (Event.RepeatFreq == rptfWeekly) {
+        struct tm * timeinfo;
+        timeinfo = localtime(start1);
+        uint8_t daymask = Event.RepeatDays;
+        // now, check the tm_wday (0=Sunday, 1=Monday, ...) and see if we intersect with the event time
+        uint8_t testmask = 1 << timeinfo->tm_wday;
+        //INFO("Mask: Event mask: %02X, test mask: %02X", daymask, testmask);
+        if (daymask & testmask)
+            intersects = true;
+        else
+            intersects = false;
+        //INFO("  intersects: %02X", daymask & testmask);
+        return intersects;
+    }
+    //INFO("Mask: no handler, returning true");
+    return true;
+}
+
 bool RepeatIntersects(time_t * start1, time_t * end1, time_t * start2, time_t * end2, Event_T & Event)
 {
     if (Event.RepeatFreq) {
-        INFO("%s", Event.Summary);
+        INFO("Summary: %s", Event.Summary);
         INFO("** 1: (%s, %s)", FormatCTime(*start1), FormatCTime(*end1));
         INFO("   2: (%s, %s)", FormatCTime(*start2), FormatCTime(*end2));
         if (TimeIntersects(start1, end1, start2, end2)) {
@@ -194,10 +229,13 @@
                 INFO("** 1: (%s, %s)", FormatCTime(*start1), FormatCTime(*end1));
                 INFO("until (%24s, %s)", " ", FormatCTime(Event.Until));
                 INFO("   2: (%s, %s)", FormatCTime(*start2), FormatCTime(*end2));
+                if (!RepeatMaskIntersects(start1, end1, start2, end2, Event)) {
+                    continue;   // we're not on a repeat cycle (e.g. wrong day of the week)
+                }
                 if (TimeIntersects(start1, end1, start2, end2)) {
                     return true;
                 }
-            } while (*start1 < *end2 && *start1 < Event.Until); 
+            } while (*start1 < *end2 && *start1 < Event.Until);
         } else if (Event.Start < *start2 && Event.Count) {                      // Count=
             int count = Event.Count - 1;
             do {
@@ -206,10 +244,13 @@
                 *end1   = *end1   + interval;
                 INFO("** 1: (%s, %s) - %d", FormatCTime(*start1), FormatCTime(*end1), count);
                 INFO("   2: (%s, %s)", FormatCTime(*start2), FormatCTime(*end2));
+                if (!RepeatMaskIntersects(start1, end1, start2, end2, Event)) {
+                    continue;   // we're not on a repeat cycle (e.g. wrong day of the week)
+                }
                 if (TimeIntersects(start1, end1, start2, end2)) {
                     return true;
                 }
-            } while (--count); 
+            } while (--count);
         } else if (Event.Start < *start2) {                      // no Count= and no Until=
             do {
                 time_t interval = NextInterval(Event.RepeatFreq, (Event.Interval == 0) ? 1 : Event.Interval);
@@ -217,16 +258,126 @@
                 *end1   = *end1   + interval;
                 INFO("== 1: (%s, %s)", FormatCTime(*start1), FormatCTime(*end1));
                 INFO("   2: (%s, %s)", FormatCTime(*start2), FormatCTime(*end2));
+                if (!RepeatMaskIntersects(start1, end1, start2, end2, Event)) {
+                    continue;   // we're not on a repeat cycle (e.g. wrong day of the week)
+                }
                 if (TimeIntersects(start1, end1, start2, end2)) {
                     return true;
                 }
             } while (*start1 < *end2);
         }
     }
+    //INFO("  no intersection");
     return false;
 }
 
-
+// All the stuff between
+// BEGIN:VEVENT
+// ...
+// END:VEVENT
+//
+void ParseEvent(Event_T * Event, char * pStart, int32_t tzoSec)
+{
+    if (strncmp(pStart, "DTSTART:", 8) == 0) {
+        Event->Start = ParseDateStamp(pStart+8, tzoSec);
+        //INFO("  Start: %d\r\n", mktime(&Event->eventStart));
+    } else if (strncmp(pStart, "DTSTART;", 8) == 0) {
+        char * p = strrchr(pStart, ':');
+        if (p) {
+            Event->Start = ParseDateStamp(p+1, tzoSec);
+            //INFO("  Start: %d\r\n", mktime(&Event->eventStart));
+        }
+    } else if (strncmp(pStart, "DTEND:", 6) == 0) {
+        Event->End = ParseDateStamp(pStart+6, tzoSec);
+        //INFO("    End: %d\r\n", mktime(&Event->eventEnd));
+    } else if (strncmp(pStart, "DTEND;", 6) == 0) {
+        char * p = strrchr(pStart, ':');
+        if (p) {
+            Event->End = ParseDateStamp(p+1, tzoSec);
+            //INFO("    End: %d\r\n", mktime(&Event->eventEnd));
+        }
+    } else if (strncmp(pStart, "SUMMARY:", 8) == 0) {
+        strncpy(Event->Summary, pStart+8, SUMMARY_CHARS-1);
+        Event->Summary[SUMMARY_CHARS-1] = '\0';
+        //INFO(" Summary: %s\r\n", Event->Summary);
+    } else if (strncmp(pStart, "LOCATION:", 9) == 0) {
+        strncpy(Event->Location, pStart+9, LOCATION_CHARS-1);
+        Event->Location[LOCATION_CHARS-1] = '\0';
+        //INFO(" Location: %s\r\n", Event->Location);
+    } else if (strncmp(pStart, "PRIORITY:", 9) == 0) {
+        Event->Priority = *(pStart+9) - '0';
+        //INFO("  Priority: %d\r\n", Event->Priority);
+    } else if (strncmp(pStart, "CATEGORIES:", 11) == 0) {
+        strncpy(Event->Category, pStart+11, CATEGORY_CHARS-1);
+        Event->Category[CATEGORY_CHARS-1] = '\0';
+        //INFO(" Category: %s\r\n", Event->Category);
+    } else if (strncmp(pStart, "RRULE:", 6) == 0) {
+        //RRULE:FREQ=WEEKLY;UNTIL=20140502T180000;BYDAY=MO,TU,WE,TH,FR
+        char * p1, *p2;
+        //INFO("%s", pStart);
+        p1 = pStart + 6;                        // p1 = FREQ=WEEKLY;UNTIL=20140502T180000;BYDAY=MO,TU,WE,TH,FR
+        p2 = strchr(p1, ';');
+        if (p2)
+            *p2++ = '\0';
+        while (*p1) {
+            //INFO("%s", p1);
+            if (strncmp(p1, "FREQ=", 5) == 0) {
+                //INFO("%s", p1);
+                p1 += 5;                            // p1 = WEEKLY;UNTIL=20140502T180000;BYDAY=MO,TU,WE,TH,FR
+                if (strncmp(p1, "WEEKLY", 6) == 0) {
+                    //INFO("  %s", p1);
+                    Event->RepeatFreq = rptfWeekly;
+                    p1 += 6;
+                } else if (strncmp(p1, "DAILY", 5) == 0) {
+                    //INFO("  %s", p1);
+                    Event->RepeatFreq = rptfDaily;
+                    p1 += 5;
+                } else if (strncmp(p1, "MONTHLY", 7) == 0) {
+                    //INFO("  %s", p1);
+                    Event->RepeatFreq = rptfMonthly;
+                    p1 += 7;
+                } else if (strncmp(p1, "YEARLY", 6) == 0) {
+                    //INFO("  %s", p1);
+                    Event->RepeatFreq = rptfYearly;
+                    p1 += 7;
+                }
+            } else if (strncmp(p1, "INTERVAL=", 9) == 0) { // INTERVAL=2
+                //INFO("%s", p1);
+                p1 += 9;
+                Event->Interval = atoi(p1);
+            } else if (strncmp(p1, "COUNT=", 6) == 0) { // COUNT=12;
+                //INFO("%s", p1);
+                p1 += 6;                // p1 =
+                Event->Count = atoi(p1);
+            } else if (strncmp(p1, "UNTIL=", 6) == 0) {
+                //INFO("%s", p1);
+                p1 += 6;                // p1 = 20140502T180000;BYDAY=MO,TU,WE,TH,FR
+                Event->Until = ParseDateStamp(p1, tzoSec);
+            } else if (strncmp(p1, "BYDAY=", 6) == 0) {
+                //INFO("%s", p1);
+                p1 += 6;        // p1 = MO,TU,WE,TH,FR
+                while (*p1 >= ' ') {
+                    //INFO("  %s", p1);
+                    for (int d=0; d<7; d++) {
+                        if (strncmp(p1,RepeatDayAbbrev(d),2) == 0) {
+                            Event->RepeatDays |= (1 << d);
+                            //INFO("    %s %02X", RepeatDayAbbrev(d), Event->RepeatDays);
+                            break;
+                        }
+                    }
+                    p1 += 3;
+                }
+                //INFO("  RepeatDay: %02X", Event->RepeatDays);
+            }
+            if (!p2)
+                break;
+            p1 = p2;
+            p2 = strchr(p1, ';');
+            if (p2)
+                *p2++ = '\0';
+        }
+    }
+}
 
 void ParseICalStream(char * pStart, time_t gridStartTime, time_t gridEndTime, int32_t tzoSec)
 {
@@ -236,7 +387,7 @@
     typedef enum { idle, inTimeZone, inEvent } seekstate_t;
     seekstate_t seeking = idle;
     EventCount = 0;
-    
+
     while (pStart && EventCount < EVENT_COUNT) {
         pEnd = strchr(pStart, '\n');
         if (pEnd) {
@@ -288,108 +439,12 @@
                         if (1 || Event.Start >= gridStartTime && Event.Start < gridEndTime
                                 || Event.End >= gridStartTime && Event.End < gridEndTime) {
                             EventList[EventCount++] = Event;
-                            INFO(" ++++++++++++ Added Event %d", EventCount);
+                            INFO(" ++++++++++++ Added Event %d: %s", EventCount, Event.Summary);
                         }
                         seeking = idle;
-                    } else if (strncmp(pStart, "DTSTART:", 8) == 0) {
-                        Event.Start = ParseDateStamp(pStart+8, tzoSec);
-                        //INFO("  Start: %d\r\n", mktime(&Event.eventStart));
-                    } else if (strncmp(pStart, "DTSTART;", 8) == 0) {
-                        char * p = strrchr(pStart, ':');
-                        if (p) {
-                            Event.Start = ParseDateStamp(p+1, tzoSec);
-                            //INFO("  Start: %d\r\n", mktime(&Event.eventStart));
-                        }
-                    } else if (strncmp(pStart, "DTEND:", 6) == 0) {
-                        Event.End = ParseDateStamp(pStart+6, tzoSec);
-                        //INFO("    End: %d\r\n", mktime(&Event.eventEnd));
-                    } else if (strncmp(pStart, "DTEND;", 6) == 0) {
-                        char * p = strrchr(pStart, ':');
-                        if (p) {
-                            Event.End = ParseDateStamp(p+1, tzoSec);
-                            //INFO("    End: %d\r\n", mktime(&Event.eventEnd));
-                        }
-                    } else if (strncmp(pStart, "SUMMARY:", 8) == 0) {
-                        strncpy(Event.Summary, pStart+8, SUMMARY_CHARS-1);
-                        Event.Summary[SUMMARY_CHARS-1] = '\0';
-                        //INFO(" Summary: %s\r\n", Event.Summary);
-                    } else if (strncmp(pStart, "LOCATION:", 9) == 0) {
-                        strncpy(Event.Location, pStart+9, LOCATION_CHARS-1);
-                        Event.Location[LOCATION_CHARS-1] = '\0';
-                        //INFO(" Location: %s\r\n", Event.Location);
-                    } else if (strncmp(pStart, "PRIORITY:", 9) == 0) {
-                        Event.Priority = *(pStart+9) - '0';
-                        //INFO("  Priority: %d\r\n", Event.Priority);
-                    } else if (strncmp(pStart, "CATEGORIES:", 11) == 0) {
-                        strncpy(Event.Category, pStart+11, CATEGORY_CHARS-1);
-                        Event.Category[CATEGORY_CHARS-1] = '\0';
-                        //INFO(" Category: %s\r\n", Event.Category);
-                    } else if (strncmp(pStart, "RRULE:", 6) == 0) {
-                        //RRULE:FREQ=WEEKLY;UNTIL=20140502T180000;BYDAY=MO,TU,WE,TH,FR
-                        char * p1, *p2;
-                        INFO("%s", pStart);
-                        p1 = pStart + 6;                        // p1 = FREQ=WEEKLY;UNTIL=20140502T180000;BYDAY=MO,TU,WE,TH,FR
-                        p2 = strchr(p1, ';');
-                        if (p2)
-                            *p2++ = '\0';
-                        while (*p1) {
-                            INFO("%s", p1);
-                            if (strncmp(p1, "FREQ=", 5) == 0) {
-                                INFO("%s", p1);
-                                p1 += 5;                            // p1 = WEEKLY;UNTIL=20140502T180000;BYDAY=MO,TU,WE,TH,FR
-                                if (strncmp(p1, "WEEKLY", 6) == 0) {
-                                    INFO("  %s", p1);
-                                    Event.RepeatFreq = rptfWeekly;
-                                    p1 += 6;
-                                } else if (strncmp(p1, "DAILY", 5) == 0) {
-                                    INFO("  %s", p1);
-                                    Event.RepeatFreq = rptfDaily;
-                                    p1 += 5;
-                                } else if (strncmp(p1, "MONTHLY", 7) == 0) {
-                                    INFO("  %s", p1);
-                                    Event.RepeatFreq = rptfMonthly;
-                                    p1 += 7;
-                                } else if (strncmp(p1, "YEARLY", 6) == 0) {
-                                    INFO("  %s", p1);
-                                    Event.RepeatFreq = rptfYearly;
-                                    p1 += 7;
-                                }
-                            } else if (strncmp(p1, "INTERVAL=", 9) == 0) { // INTERVAL=2
-                                INFO("%s", p1);
-                                p1 += 9;
-                                Event.Interval = atoi(p1);
-                            } else if (strncmp(p1, "COUNT=", 6) == 0) { // COUNT=12;
-                                INFO("%s", p1);
-                                p1 += 6;                // p1 = 
-                                Event.Count = atoi(p1);
-                            } else if (strncmp(p1, "UNTIL=", 6) == 0) {
-                                INFO("%s", p1);
-                                p1 += 6;                // p1 = 20140502T180000;BYDAY=MO,TU,WE,TH,FR
-                                Event.Until = ParseDateStamp(p1, tzoSec);
-                            } else if (strncmp(p1, "BYDAY=", 6) == 0) {
-                                INFO("%s", p1);
-                                p1 += 6;        // p1 = MO,TU,WE,TH,FR
-                                while (*p1 >= ' ') {
-                                    INFO("  %s", p1);
-                                    for (int d=0; d<7; d++) {
-                                        if (strncmp(p1,RepeatDayAbbrev(d),2) == 0) {
-                                            Event.RepeatDays |= (1 << d);
-                                            INFO("    %s %02X", RepeatDayAbbrev(d), Event.RepeatDays);
-                                            break;
-                                        }
-                                    }
-                                    p1 += 3;
-                                }
-                                INFO("  RepeatDay: %02X", Event.RepeatDays);
-                            }
-                            if (!p2)
-                                break;
-                            p1 = p2;
-                            p2 = strchr(p1, ';');
-                            if (p2)
-                                *p2++ = '\0';
-                        }
-                    }                        
+                    } else {
+                        ParseEvent(&Event, pStart, tzoSec);
+                    }
                     // End of inEvent
                     break;
                 default: