Plumbing for iCalendar Period and Recurrence
authorShilpa Sodani <shilpa.a.sodani@intel.com>
Fri, 26 Jun 2015 23:37:55 +0000 (16:37 -0700)
committerSachin Agrawal <sachin.agrawal@intel.com>
Thu, 16 Jul 2015 05:23:14 +0000 (05:23 +0000)
Added the iotvticalendar.h file
Added function and unittest to parse period
Added function and unittest to parse recurrence rule
Added function and unittest to check if access is within
allowable period

Change-Id: Ic1236b96b9c786f3c74c61ddfcb7ab56c27bc320
Signed-off-by: Shilpa Sodani <shilpa.a.sodani@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/1434
Reviewed-by: Sachin Agrawal <sachin.agrawal@intel.com>
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
resource/csdk/security/SConscript
resource/csdk/security/include/iotvticalendar.h [new file with mode: 0644]
resource/csdk/security/src/iotvticalendar.c [new file with mode: 0644]
resource/csdk/security/unittest/SConscript
resource/csdk/security/unittest/iotvticalendartest.cpp [new file with mode: 0644]

index 4ddfa7b..68cc889 100644 (file)
@@ -94,6 +94,7 @@ libocsrm_src = [
        OCSRM_SRC + 'psinterface.c',
        OCSRM_SRC + 'srmresourcestrings.c',
        OCSRM_SRC + 'srmutility.c',
+       OCSRM_SRC + 'iotvticalendar.c',
        OCSRM_SRC + 'base64.c'
        ]
 
diff --git a/resource/csdk/security/include/iotvticalendar.h b/resource/csdk/security/include/iotvticalendar.h
new file mode 100644 (file)
index 0000000..2d77be0
--- /dev/null
@@ -0,0 +1,191 @@
+//******************************************************************
+//
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#ifndef IOTVT_ICALENDAR_H
+#define IOTVT_ICALENDAR_H
+
+//Not supported on Arduino due lack of absolute time need to implement iCalendar
+#ifndef WITH_ARDUINO
+
+#include <stdint.h> // for uint8_t typedef
+#include <stdbool.h>
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define FREQ_DAILY (1)
+#define MAX_BYDAY_SIZE (7)     //7 days of week
+#define TM_YEAR_OFFSET (1900)  //tm_year field of c-lang tm date-time struct
+                               //represents number of years since 1900.
+#define TM_DST_OFFSET (1)      //c-lang tm struct Daylight Saving Time offset.
+#define TOTAL_HOURS (24)       //Total hours in a day.
+
+typedef struct IotvtICalRecur IotvtICalRecur_t;
+typedef struct IotvtICalPeriod IotvtICalPeriod_t;
+
+/*
+ *  date-time  = date "T" time
+ *
+ *  date               = date-value
+ *  date-value         = date-fullyear date-month date-mday
+ *  date-fullyear      = 4DIGIT
+ *  date-month         = 2DIGIT        ;01-12
+ *  date-mday          = 2DIGIT        ;01-28, 01-29, 01-30, 01-31
+ *                                     ;based on month/year
+ *
+ *  time               = time-hour time-minute time-second [time-utc]
+ *  time-hour          = 2DIGIT        ;00-23
+ *  time-minute        = 2DIGIT        ;00-59
+ *  time-second        = 2DIGIT        ;00-60
+ *                                     ;The "60" value is used to account for "leap" seconds.
+ *
+ *  Date-Time Forms:
+ *  1. Date with Local time
+ *      20150626T150000
+ */
+typedef struct tm IotvtICalDateTime_t; //c-lang tm date-time struct
+
+/*
+ * Bit mask for weekdays
+ */
+typedef enum
+{
+    NO_WEEKDAY  = 0X0,
+    SUNDAY      = (0x1 << 0),
+    MONDAY      = (0x1 << 1),
+    TUESDAY     = (0x1 << 2),
+    WEDNESDAY   = (0x1 << 3),
+    THURSDAY    = (0x1 << 4),
+    FRIDAY      = (0x1 << 5),
+    SATURDAY    = (0x1 << 6)
+}IotvtICalWeekdayBM_t;
+
+/*
+ * Result code for IotvtICalendar
+ */
+typedef enum
+{
+    IOTVTICAL_SUCCESS = 0,       //successfully completed operation
+    IOTVTICAL_VALID_ACCESS,      //access is within allowable time
+    IOTVTICAL_INVALID_ACCESS,    //access is not within allowable time
+    IOTVTICAL_INVALID_PARAMETER, //invalid method parameter
+    IOTVTICAL_INVALID_RRULE,     //rrule is not well form, missing FREQ
+    IOTVTICAL_INVALID_PERIOD,    //period is not well form, start-datetime is after end-datetime
+    IOTVTICAL_ERROR              //encounter error
+}IotvtICalResult_t;
+
+/*
+ *  Grammar for iCalendar data type PERIOD
+ *
+ *  period = date-time "/" date-time  ; start-time / end-time.
+ *                                    ;The start-time MUST be before the end-time.
+ *
+ */
+struct IotvtICalPeriod
+{
+    IotvtICalDateTime_t startDateTime;
+    IotvtICalDateTime_t endDateTime;
+};
+
+/*
+ * Grammar for iCalendar data type RECUR
+ *
+ * recur      = "FREQ"=freq *(
+ *            ( ";" "UNTIL" "=" enddate ) /
+ *            ( ";" "BYDAY" "=" bywdaylist ) /
+ *            )
+ *
+ * freq       = "DAILY"
+ * enddate    = date
+ * bywdaylist = weekday/ ( weekday *("," weekday) )
+ * weekday    = "SU" / "MO" / "TU" / "WE" / "TH" / "FR" / "SA"
+ *
+ * Example:
+ * 1."Allow access on every Monday, Wednesday & Friday between 3pm to 5pm"
+ *      PERIOD:20150626T150000/20150626T170000
+ *      RRULE: FREQ=DAILY; BYDAY=MO, WE, FR
+ * 2."Allow access every Monday, Wednesday & Friday from 3pm to 5pm until
+ *    July 3rd, 2015"
+ *      PERIOD:20150626T150000/20150626T170000
+ *      RRULE: FREQ=DAILY; UNTIL=20150703; BYDAY=MO, WE, FR
+ */
+struct IotvtICalRecur
+{
+    uint16_t                freq;
+    IotvtICalDateTime_t     until;
+    IotvtICalWeekdayBM_t    byDay;
+};
+
+/**
+ * This API is used by policy engine to checks if the
+ * request to access resource is within valid time.
+ *
+ * @param period string representing period.
+ * @param recur string representing recurrence rule
+ *
+ * @return  IOTVTICAL_VALID_ACCESS      -- if the request is within valid time period
+ *          IOTVTICAL_INVALID_ACCESS    -- if the request is not within valid time period
+ *          IOTVTICAL_INVALID_PARAMETER -- if parameter are invalid
+ *          IOTVTICAL_INVALID_PERIOD    -- if period string has invalid format
+ *          IOTVTICAL_INVALID_RRULE     -- if rrule string has invalid format
+ *
+ *Eg: if(IOTVTICAL_VALID_ACCESS == IsRequestWithinValidTime(period, recur))
+ *    {
+ *       //Access within allowable time
+ *    }
+ *    else
+ *    {
+ *      //Access is not within allowable time.
+ *    }
+ */
+IotvtICalResult_t IsRequestWithinValidTime(char *period, char *recur);
+
+/**
+ * Parses periodStr and populate struct IotvtICalPeriod_t
+ *
+ * @param periodStr string to be parsed.
+ * @param period    IotvtICalPeriod_t struct to be populated.
+ *
+ * @return  IOTVTICAL_INVALID_PARAMETER -- if parameter are invalid
+ *          IOTVTICAL_INVALID_PERIOD    -- if period string has invalid format
+ *          IOTVTICAL_INVALID_SUCCESS   -- if no error while parsing
+ */
+IotvtICalResult_t ParsePeriod(const char *periodStr, IotvtICalPeriod_t *period);
+
+/**
+ * Parses recurStr and populate struct IotvtICalRecur_t
+ *
+ * @param recurStr string to be parsed.
+ * @param recur    IotvtICalPeriod_t struct to be populated.
+ *
+ * @return  IOTVTICAL_INVALID_PARAMETER -- if parameter are invalid
+ *          IOTVTICAL_INVALID_PERIOD    -- if period string has invalid format
+ *          IOTVTICAL_INVALID_RRULE     -- if rrule string has invalid format
+ */
+IotvtICalResult_t ParseRecur(const char *recurStr, IotvtICalRecur_t *recur);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+#endif //IOTVT_ICALENDAR_H
diff --git a/resource/csdk/security/src/iotvticalendar.c b/resource/csdk/security/src/iotvticalendar.c
new file mode 100644 (file)
index 0000000..414c2aa
--- /dev/null
@@ -0,0 +1,419 @@
+//******************************************************************
+//
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+//Not supported on Arduino due lack of absolute time need to implement iCalendar
+#ifndef WITH_ARDUINO
+
+#define _XOPEN_SOURCE  //Needed by strptime
+#include <string.h>
+#include "iotvticalendar.h"
+#include "oic_string.h"
+
+static char dtFormat[] =  "%Y%m%dT%H%M%S"; //date-time format
+static char dFormat[] =  "%Y%m%d";         // date format
+
+static const char FREQ[]  = "FREQ";
+static const char UNTIL[] = "UNTIL";
+static const char BYDAY[] = "BYDAY";
+static const char DAILY[] = "DAILY";
+
+
+/**
+ * Parses periodStr and populate struct IotvtICalPeriod_t
+ *
+ * @param periodStr string to be parsed.
+ * @param period    IotvtICalPeriod_t struct to be populated.
+ *
+ * @return  IOTVTICAL_INVALID_PARAMETER -- if parameter are invalid
+ *          IOTVTICAL_INVALID_PERIOD    -- if period string has invalid format
+ *          IOTVTICAL_INVALID_SUCCESS   -- if no error while parsing
+ */
+IotvtICalResult_t ParsePeriod(const char *periodStr, IotvtICalPeriod_t *period)
+{
+    if((NULL == periodStr) || (NULL == period))
+    {
+        return IOTVTICAL_INVALID_PARAMETER;
+    }
+
+    char *endDTPos;
+    char *fmt = "";
+    int   startDTLen;
+    int   endDTLen;
+
+    //Finding length of startDateTime and endDateTime in period
+    //startDateTime and endDateTime can have form YYYYmmdd or YYYYmmddTHHMMSS
+    //startDateTime and endDateTime must be same form
+    //Eg: periodStr = "20150629T153050/20150630T203055"
+    //    periodStr = "20150629/20150630"
+    if(NULL == (endDTPos = strchr(periodStr, '/')))
+    {
+        return IOTVTICAL_INVALID_PERIOD;
+    }
+    endDTPos += 1;
+    startDTLen = endDTPos - periodStr - 1;
+    endDTLen   = strlen(endDTPos);
+
+    //Checking if both startDateTime and endDateTime are of same form
+    if(startDTLen == endDTLen)
+    {
+        if(8 == startDTLen) //YYYYmmdd
+        {
+            fmt = dFormat;
+        }
+        else if(15 == startDTLen) //YYYYmmddTHHMMSS
+        {
+            fmt = dtFormat;
+        }
+        else
+        {
+            return IOTVTICAL_INVALID_PERIOD;
+        }
+    }
+    else
+    {
+        return IOTVTICAL_INVALID_PERIOD;
+    }
+
+    //Checking if startDateTime has right format
+    if(NULL != strptime(periodStr, fmt, &period->startDateTime))
+    {
+        //Checking if endDateTime has right format
+        if(NULL != strptime(endDTPos, fmt, &period->endDateTime))
+        {
+            //Checking if endDateTime is after startDateTime
+            if(difftime(mktime(&period->endDateTime),
+                        mktime(&period->startDateTime)) > 0)
+            {
+                //mktime increases value of tm_hour by 1 if tm_isdst is set.
+                //The tm_hour value in period's startDateTime and endDatetime
+                //should remain same irrespective of daylight saving time.
+                if(period->startDateTime.tm_isdst)
+                {
+                    period->startDateTime.tm_hour =
+                   (period->startDateTime.tm_hour + TOTAL_HOURS - TM_DST_OFFSET) % TOTAL_HOURS;
+                }
+                if(period->endDateTime.tm_isdst)
+                {
+                    period->endDateTime.tm_hour =
+                   (period->endDateTime.tm_hour + TOTAL_HOURS - TM_DST_OFFSET) % TOTAL_HOURS;
+                }
+                return IOTVTICAL_SUCCESS;
+            }
+        }
+    }
+    return IOTVTICAL_INVALID_PERIOD;
+}
+
+
+/**
+ * Parses untilRule and populate "until" field of struct IotvtICalRecur_t
+ *
+ * @param untilRule  string to be parsed.
+ * @param recur      IotvtICalRecur_t struct to be populated.
+ *
+ * @return  IOTVTICAL_ERRRO             -- if untilRule has invalid format
+ *          IOTVTICAL_INVALID_SUCCESS   -- if no error while parsing
+ */
+static IotvtICalResult_t ParseDate(char *untilRule, IotvtICalRecur_t *recur)
+{
+    char *date = strchr(untilRule, '=');
+
+    if(NULL == date)
+    {
+        return IOTVTICAL_ERROR;
+    }
+    date += 1;
+
+    if(strlen(date) == 8) //YYYYmmdd
+    {
+        if(NULL != strptime(date, dFormat, &recur->until))
+        {
+            return IOTVTICAL_SUCCESS;
+        }
+    }
+    return IOTVTICAL_ERROR;
+}
+
+
+/**
+ * Parses bydayRule and populate "byDay" field of struct IotvtICalRecur_t
+ *
+ * @param bydayRule  string to be parsed.
+ * @param recur      IotvtICalRecur_t struct to be populated.
+ *
+ * @return  IOTVTICAL_ERRRO             -- if bydayRule has empty weekday list or invalid weekdays
+ *          IOTVTICAL_INVALID_SUCCESS   -- if no error while parsing
+ */
+static IotvtICalResult_t  ParseByday(char *bydayRule, IotvtICalRecur_t *recur)
+{
+    if(strstr(bydayRule, "SU"))
+    {
+        recur->byDay = recur->byDay | SUNDAY;
+    }
+    if(strstr(bydayRule, "MO"))
+    {
+        recur->byDay = recur->byDay | MONDAY;
+    }
+    if(strstr(bydayRule, "TU"))
+    {
+        recur->byDay = recur->byDay | TUESDAY;
+    }
+    if(strstr(bydayRule, "WE"))
+    {
+        recur->byDay = recur->byDay | WEDNESDAY;
+    }
+    if(strstr(bydayRule, "TH"))
+    {
+        recur->byDay = recur->byDay | THURSDAY;
+    }
+    if(strstr(bydayRule, "FR"))
+    {
+        recur->byDay = recur->byDay | FRIDAY;
+    }
+    if(strstr(bydayRule, "SA"))
+    {
+        recur->byDay = recur->byDay | SATURDAY;
+    }
+
+    //Checking if byDay list is empty or has inValid weekdays
+    if(recur->byDay == NO_WEEKDAY)
+    {
+        return IOTVTICAL_ERROR;
+    }
+
+    return IOTVTICAL_SUCCESS;
+}
+
+
+/**
+ * Parses recurStr and populate struct IotvtICalRecur_t
+ *
+ * @param recurStr string to be parsed.
+ * @param recur    IotvtICalPeriod_t struct to be populated.
+ *
+ * @return  IOTVTICAL_INVALID_PARAMETER -- if parameter are invalid
+ *          IOTVTICAL_INVALID_PERIOD    -- if period string has invalid format
+ *          IOTVTICAL_INVALID_RRULE     -- if rrule string has invalid format
+ */
+IotvtICalResult_t ParseRecur(const char *recurStr, IotvtICalRecur_t *recur)
+{
+
+    if((NULL == recurStr) || (NULL == recur))
+    {
+        return IOTVTICAL_INVALID_PARAMETER;
+    }
+
+    const char *startPos="";
+    const char *endPos="";
+    char        buf[50];
+    int         freqFlag = 0; //valid RRULE must have "FREQ" parameter.
+                              //flag to track if RRULE has "FREQ" or not
+
+    startPos = recurStr;
+    //Iterates though recurrence rule
+    //Eg, RRULE: FREQ=DAILY; UNTIL=20150703; BYDAY=MO, WE, FR
+    while('\0' != startPos)
+    {
+        endPos = strchr(startPos, ';');
+        if(endPos)
+        {
+            endPos += 1;
+        }
+        OICStrcpy(buf, (endPos - startPos), startPos);
+        if(NULL != strstr(buf, FREQ))
+        {
+            if(NULL != strstr(buf, DAILY))
+            {
+                recur->freq = FREQ_DAILY;
+                freqFlag = 1;
+            }
+            else
+            {
+                return IOTVTICAL_INVALID_RRULE;
+            }
+        }
+        else if(NULL != strstr(buf, UNTIL))
+        {
+            if(IOTVTICAL_SUCCESS != ParseDate(buf, recur))
+            {
+                return IOTVTICAL_INVALID_RRULE;
+            }
+        }
+        else if(NULL != strstr(buf, BYDAY))
+        {
+            if(IOTVTICAL_SUCCESS != ParseByday(buf, recur))
+            {
+                return IOTVTICAL_INVALID_RRULE;
+            };
+        }
+        startPos = endPos;
+    }
+
+    if(1 != freqFlag)
+    {
+        return IOTVTICAL_INVALID_RRULE;
+    }
+
+    return IOTVTICAL_SUCCESS;
+}
+
+
+/**
+ * Computes number of days between two dates.
+ *
+ * @param date1 earlier date.
+ * @param date2 later date.
+ *
+ * @return  number of days between date1 & date2.
+ */
+static int DiffDays(IotvtICalDateTime_t *date1, IotvtICalDateTime_t *date2)
+{
+    int days;
+    int leapDays=0;
+
+    if(date2->tm_year > date1->tm_year)
+    {
+        for(int y = date1->tm_year; y < date2->tm_year; y++)
+        {
+            y += TM_YEAR_OFFSET;
+            if(y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
+            {
+               leapDays += 1;
+            }
+        }
+    }
+
+    days = (365 * date2->tm_year + date2->tm_yday + leapDays) -
+           (365 * date1->tm_year + date1->tm_yday);
+
+    return days;
+}
+
+
+/**
+ * Computes number of seconds between two time.
+ *
+ * @param time1 earlier time.
+ * @param date2 later time.
+ *
+ * @return  number of seconds between time1 and time2.
+ */
+static int DiffSecs(IotvtICalDateTime_t *time1, IotvtICalDateTime_t *time2)
+{
+    return (3600 * time2->tm_hour + 60 * time2->tm_min + time2->tm_sec) -
+           (3600 * time1->tm_hour + 60 * time1->tm_min + time1->tm_sec);
+}
+
+
+/**
+ * This API is used by policy engine to checks if the
+ * request to access resource is within valid time.
+ *
+ * @param period string representing period.
+ * @param recur string representing recurrence rule
+ *
+ * @return  IOTVTICAL_VALID_ACCESS      -- if the request is within valid time period
+ *          IOTVTICAL_INVALID_ACCESS    -- if the request is not within valid time period
+ *          IOTVTICAL_INVALID_PARAMETER -- if parameter are invalid
+ *          IOTVTICAL_INVALID_PERIOD    -- if period string has invalid format
+ *          IOTVTICAL_INVALID_RRULE     -- if rrule string has invalid format
+ */
+
+IotvtICalResult_t IsRequestWithinValidTime(char *periodStr, char *recurStr)
+{
+    //NULL recur rule means no recurring patter exist.
+    //Period can't be null. Period is used with or without
+    //recur rule to compute allowable access time.
+    if(NULL == periodStr)
+    {
+        return IOTVTICAL_INVALID_PARAMETER;
+    }
+
+    IotvtICalPeriod_t period = {};
+    IotvtICalRecur_t recur = {};
+    IotvtICalResult_t ret = IOTVTICAL_INVALID_ACCESS;
+
+    time_t rawTime = time(0);
+    IotvtICalDateTime_t *currentTime = localtime(&rawTime);
+
+    ret  = ParsePeriod(periodStr, &period);
+    if(ret != IOTVTICAL_SUCCESS)
+    {
+        return ret;
+    }
+
+    //If recur is NULL then the access time is between period's startDate and endDate
+    if(NULL == recurStr)
+    {
+        if((0 <= DiffDays(&period.startDateTime, currentTime)) &&
+           (0 <= DiffDays(currentTime, &period.endDateTime)))
+        {
+            ret = IOTVTICAL_VALID_ACCESS;
+        }
+    }
+
+    //If recur is not NULL then the access time is between period's startTime and
+    //endTime on days specified in "BYDAY" list. The first instance of recurrence
+    //is computed from period's startDate and the last instance is computed from
+    //"UNTIL". If "UNTIL" is not specified then the recurrence goes for forever.
+    //Eg, RRULE: FREQ=DAILY; UNTIL=20150703; BYDAY=MO, WE, FR
+    if(NULL != recurStr)
+    {
+        ret = ParseRecur(recurStr, &recur);
+        if(ret != IOTVTICAL_SUCCESS)
+        {
+            return ret;
+        }
+
+        if((0 <= DiffSecs(&period.startDateTime, currentTime))&&
+           (0 <= DiffSecs(currentTime, &period.endDateTime)) &&
+           (0 <= DiffDays(&period.startDateTime, currentTime)))
+        {
+            IotvtICalDateTime_t emptyDT = {};
+            ret = IOTVTICAL_VALID_ACCESS;
+
+            //"UNTIL" is an optional parameter of RRULE, checking if until present in recur
+            if(0 != memcmp(&recur.until, &emptyDT, sizeof(IotvtICalDateTime_t)))
+            {
+                if(0 > DiffDays(currentTime, &recur.until))
+                {
+                    ret = IOTVTICAL_INVALID_ACCESS;
+                }
+            }
+
+            //"BYDAY" is an optional parameter of RRULE, checking if byday present in recur
+            if(NO_WEEKDAY != recur.byDay)
+            {
+
+                int isValidWD = (0x1 << currentTime->tm_wday) & recur.byDay; //Valid weekdays
+                if(!isValidWD)
+                {
+                    ret = IOTVTICAL_INVALID_ACCESS;
+                }
+             }
+        }
+        else
+        {
+            ret = IOTVTICAL_INVALID_ACCESS;
+        }
+    }
+    return ret;
+}
+#endif
index e14de0e..be35bb3 100644 (file)
@@ -75,6 +75,7 @@ unittest = srmtest_env.Program('unittest', ['aclresourcetest.cpp',
                                             'securityresourcemanager.cpp',
                                             'credentialresource.cpp',
                                             'srmutility.cpp',
+                                            'iotvticalendartest.cpp',
                                             'base64tests.cpp',
                                             'svcresourcetest.cpp',
                                             'srmtestcommon.cpp'])
diff --git a/resource/csdk/security/unittest/iotvticalendartest.cpp b/resource/csdk/security/unittest/iotvticalendartest.cpp
new file mode 100644 (file)
index 0000000..151de43
--- /dev/null
@@ -0,0 +1,296 @@
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+//Not supported on Arduino due lack of absolute time need to implement iCalendar
+#ifndef WITH_ARDUINO
+
+#include "gtest/gtest.h"
+#include "iotvticalendar.h"
+#include "logger.h"
+
+#define TAG  PCF("CALENDAR-UT")
+
+static void printPeriod(IotvtICalPeriod_t *period)
+{
+    OC_LOG_V(INFO, TAG, PCF("period->startDateTime.tm_year = %d"),period->startDateTime.tm_year);
+    OC_LOG_V(INFO, TAG, PCF("period->startDateTime.tm_mon = %d"),period->startDateTime.tm_mon);
+    OC_LOG_V(INFO, TAG, PCF("period->startDateTime.tm_mday = %d"),period->startDateTime.tm_mday);
+    OC_LOG_V(INFO, TAG, PCF("period->startDateTime.tm_hour = %d"),period->startDateTime.tm_hour);
+    OC_LOG_V(INFO, TAG, PCF("period->startDateTime.tm_min = %d"),period->startDateTime.tm_min);
+    OC_LOG_V(INFO, TAG, PCF("period->startDateTime.tm_sec = %d"),period->startDateTime.tm_sec);
+
+    OC_LOG_V(INFO, TAG, PCF("period->endDateTime.tm_year = %d"),period->endDateTime.tm_year);
+    OC_LOG_V(INFO, TAG, PCF("period->endDateTime.tm_mon = %d"),period->endDateTime.tm_mon);
+    OC_LOG_V(INFO, TAG, PCF("period->endDateTime.tm_mday = %d"),period->endDateTime.tm_mday);
+    OC_LOG_V(INFO, TAG, PCF("period->endDateTime.tm_hour = %d"),period->endDateTime.tm_hour);
+    OC_LOG_V(INFO, TAG, PCF("period->endDateTime.tm_min = %d"),period->endDateTime.tm_min);
+    OC_LOG_V(INFO, TAG, PCF("period->startDateTime.tm_sec = %d"),period->endDateTime.tm_sec);
+}
+
+static void printRecur(IotvtICalRecur_t *recur)
+{
+    OC_LOG_V(INFO, TAG, PCF("recur->freq = %d"), recur->freq);
+    OC_LOG_V(INFO, TAG, PCF("recur->until.tm_year = %d"), recur->until.tm_year);
+    OC_LOG_V(INFO, TAG, PCF("recur->until.tm_mon = %d"), recur->until.tm_mon);
+    OC_LOG_V(INFO, TAG, PCF("recur->until.tm_mday = %d"), recur->until.tm_mday);
+
+    if(recur->byDay & SUNDAY)
+    {
+        OC_LOG_V(INFO, TAG, PCF("recur->byDay = %s"), "Sunday");
+    }
+    if(recur->byDay & MONDAY)
+    {
+        OC_LOG_V(INFO, TAG, PCF("recur->byDay = %s"), "Monday");
+    }
+    if(recur->byDay & TUESDAY)
+    {
+        OC_LOG_V(INFO, TAG, PCF("recur->byDay = %s"), "Tuesday");
+    }
+    if(recur->byDay & WEDNESDAY)
+    {
+        OC_LOG_V(INFO, TAG, PCF("recur->byDay = %s"), "Wednesday");
+    }
+    if(recur->byDay & THURSDAY)
+    {
+        OC_LOG_V(INFO, TAG, PCF("recur->byDay = %s"), "Thursday");
+    }
+    if(recur->byDay & FRIDAY)
+    {
+        OC_LOG_V(INFO, TAG, PCF("recur->byDay = %s"), "Friday");
+    }
+    if(recur->byDay & SATURDAY)
+    {
+        OC_LOG_V(INFO, TAG, PCF("recur->byDay = %s"), "Saturday");
+    }
+}
+
+//ParsePeriod Tests
+TEST(ParsePeriodTest, ParsePeriodValidDateTime)
+{
+    char periodStr[] = "20150629T153050/20150630T233055";
+    IotvtICalPeriod_t period = {};
+    EXPECT_EQ(IOTVTICAL_SUCCESS, ParsePeriod(periodStr,&period));
+    printPeriod(&period);
+}
+
+TEST(ParsePeriodTest, ParsePeriodValidDate)
+{
+    char periodStr[] = "20150629/20150630";
+    IotvtICalPeriod_t period = {};
+    EXPECT_EQ(IOTVTICAL_SUCCESS, ParsePeriod(periodStr,&period));
+    printPeriod(&period);
+}
+
+TEST(ParsePeriodTest, ParsePeriodMismatchStartDTEndDT1)
+{
+    char periodStr[] = "20150629T153050/20150630";
+    IotvtICalPeriod_t period = {};
+    EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period));
+}
+
+TEST(ParsePeriodTest, ParsePeriodMismatchStartDTEndDT2)
+{
+    char periodStr[] = "20150629/20150630T203055";
+    IotvtICalPeriod_t period = {};
+    EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period));
+}
+
+TEST(ParsePeriodTest, ParsePeriodInvalidStartDT1)
+{
+    char periodStr[] = "20150629T1530/20150630T203055";
+    IotvtICalPeriod_t period = {};
+    EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period));
+}
+
+TEST(ParsePeriodTest, ParsePeriodInvalidEndtDT2)
+{
+    char periodStr[] = "20150629T153050/20150630203055";
+    IotvtICalPeriod_t period = {};
+    EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period));
+}
+
+TEST(ParsePeriodTest, ParsePeriodInvalidStartD3)
+{
+    char periodStr[] = "201506/20150630";
+    IotvtICalPeriod_t period = {};
+    EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period));
+}
+
+TEST(ParsePeriodTest, ParsePeriodInvalidEndD4)
+{
+    char periodStr[] = "20150629/201530";
+    IotvtICalPeriod_t period = {};
+    EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period));
+}
+
+TEST(ParsePeriodTest, ParsePeriodEndDTBeforeStartDT)
+{
+    char periodStr[] = "20150630T203055/20150629T153050";
+    IotvtICalPeriod_t period = {};
+    EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period));
+}
+TEST(ParsePeriodTest, ParsePeriodEndDBeforeStartD)
+{
+    char periodStr[] = "20150630/20150629";
+    IotvtICalPeriod_t period = {};
+    EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period));
+}
+
+TEST(ParseRecurTest, ParseRecurValid1)
+{
+    char recurStr[] = "FREQ=DAILY; UNTIL=20150703; BYDAY=MO, WE, FR";
+    IotvtICalRecur_t recur = {};
+    EXPECT_EQ(IOTVTICAL_SUCCESS, ParseRecur(recurStr, &recur));
+    printRecur(&recur);
+}
+
+TEST(ParseRecurTest, ParseRecurValid2)
+{
+    char recurStr[] = "FREQ=DAILY";
+    IotvtICalRecur_t recur = {};
+    EXPECT_EQ(IOTVTICAL_SUCCESS, ParseRecur(recurStr, &recur));
+    printRecur(&recur);
+}
+
+TEST(ParseRecurTest, ParseRecurInValidFreq1)
+{
+    char recurStr[] = "FREQ=WEEKLY; UNTIL=20150703; BYDAY=TU";
+    IotvtICalRecur_t recur = {};
+    EXPECT_EQ(IOTVTICAL_INVALID_RRULE, ParseRecur(recurStr, &recur));
+}
+
+TEST(ParseRecurTest, ParseRecurInValidFreq2)
+{
+    char recurStr[] = "UNTIL=20150703; BYDAY=TU";
+    IotvtICalRecur_t recur = {};
+    EXPECT_EQ(IOTVTICAL_INVALID_RRULE, ParseRecur(recurStr, &recur));
+}
+
+TEST(ParseRecurTest, ParseRecurInValidUntil)
+{
+    char recurStr[] = "FREQ=DAILY; UNTIL=20150703T095055; BYDAY=MO, WE, FR";
+    IotvtICalRecur_t recur = {};
+    EXPECT_EQ(IOTVTICAL_INVALID_RRULE, ParseRecur(recurStr, &recur));
+}
+
+TEST(ParseRecurTest, ParseRecurInValidByday)
+{
+    char recurStr[] = "FREQ=DAILY; UNTIL=20150703; BYDAY=";
+    IotvtICalRecur_t recur = {};
+    EXPECT_EQ(IOTVTICAL_INVALID_RRULE, ParseRecur(recurStr, &recur));
+}
+
+//FIXME: ALL IsRequestWithinValidTime tests will fail after 20151230
+TEST(IsRequestWithinValidTimeTest, IsRequestWithinValidTimeValidPeriod1)
+{
+    char periodStr[] = "20150630/20151230";
+    EXPECT_EQ(IOTVTICAL_VALID_ACCESS, IsRequestWithinValidTime(periodStr, NULL));
+}
+
+TEST(IsRequestWithinValidTimeTest, IsRequestWithinValidTimeValidPeriodAndRecur1)
+{
+    //Daily on days MO, WE & FR from 6:00:00am to 8:00:00pm until 20151230
+    char recurStr[] = "FREQ=DAILY; UNTIL=20151230; BYDAY=MO, WE, FR";
+    char periodStr[] = "20150630T060000/20150630T200000";
+
+    time_t rt = time(0);
+    IotvtICalDateTime_t *ct = localtime(&rt);
+
+    int byDay = MONDAY | WEDNESDAY | FRIDAY;
+    int isValidWD = (0x1 << ct->tm_wday) & byDay;
+
+    if(isValidWD && 6 <= ct->tm_hour && 20>= ct->tm_hour)
+    {
+        EXPECT_EQ(IOTVTICAL_VALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr));
+    }
+    else
+    {
+        EXPECT_EQ(IOTVTICAL_INVALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr));
+    }
+}
+
+TEST(IsRequestWithinValidTimeTest, IsRequestWithinValidTimeValidPeriodAndRecur2)
+{
+    //Daily forever from 6:00:00am to 8:00:00pm
+    char recurStr[] = "FREQ=DAILY";
+    char periodStr[] = "20150630T060000/20150630T200000";
+
+    time_t rt = time(0);
+    IotvtICalDateTime_t *ct = localtime(&rt);
+
+    if(6 <= ct->tm_hour && 20>= ct->tm_hour)
+    {
+        EXPECT_EQ(IOTVTICAL_VALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr));
+    }
+    else
+    {
+        EXPECT_EQ(IOTVTICAL_INVALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr));
+    }
+}
+
+TEST(IsRequestWithinValidTimeTest, IsRequestWithinValidTimeValidPeriodAndRecur3)
+{
+    //Daily until 20151230 from 6:00:00am to 8:00:00pm
+    char recurStr[] = "FREQ=DAILY; UNTIL=20151230";
+    char periodStr[] = "20150630T060000/20150630T200000";
+
+    time_t rt = time(0);
+    IotvtICalDateTime_t *ct = localtime(&rt);
+
+    if(6 <= ct->tm_hour && 20>= ct->tm_hour)
+    {
+        EXPECT_EQ(IOTVTICAL_VALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr));
+    }
+    else
+    {
+        EXPECT_EQ(IOTVTICAL_INVALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr));
+    }
+}
+
+TEST(IsRequestWithinValidTimeTest, IsRequestWithinValidTimeValidPeriodAndRecur4)
+{
+    //Daily forever on days MO, WE & Fr from 6:00:00am to 8:00:00pm
+    char recurStr[] = "FREQ=DAILY; BYDAY=MO, WE, FR";
+    char periodStr[] = "20150630T060000/20150630T200000";
+
+    time_t rt = time(0);
+    IotvtICalDateTime_t *ct = localtime(&rt);
+
+    int byDay = MONDAY | WEDNESDAY | FRIDAY;
+    int isValidWD = (0x1 << ct->tm_wday) & byDay;
+
+    if(isValidWD && 6 <= ct->tm_hour && 20>= ct->tm_hour)
+    {
+        EXPECT_EQ(IOTVTICAL_VALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr));
+    }
+    else
+    {
+        EXPECT_EQ(IOTVTICAL_INVALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr));
+    }
+}
+
+TEST(IsRequestWithinValidTimeTest, IsRequestWithinValidTimeInValidPeriodAndValidRecur)
+{
+    //Daily forever on days MO, WE & Fr
+    char recurStr[] = "FREQ=DAILY; BYDAY=MO, WE, FR";
+    char periodStr[] = "20150630/20150730";
+
+    EXPECT_EQ(IOTVTICAL_INVALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr));
+}
+
+#endif