Mobile native

Calendar: Managing Calendar Events and Accessing the Calendar Database

This tutorial demonstrates how you can manage events and todo tasks, and convert calendar details to and from the vCalendar format.

This feature is supported in mobile applications only.

Warm-up

Become familiar with the Calendar API basics by learning about:

Initializing the Calendar

To initialize the Calendar Service:

  1. To use the functions and data types of the Calendar API, include the <calendar.h> header file in your application:

    #include <calendar.h>
    
  2. Most of API functions return error codes, so you must define at the beginning of your code the int type, which is used to store the error codes. Each time when a function returns error codes, verify the result of the operation.

  3. To connect to the Calendar Service, call the calendar_connect() function. Without this function, you cannot get access to the Calendar database.

    int error_code;
    error_code = calendar_connect();
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "calendar_connect: %x\n", error_code);

    When the Calendar APIs are no longer needed, disconnect from the service using the calendar_disconnect() function:

    error_code = calendar_disconnect();
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "calendar disconnect failed: %x\n", error_code);

Creating an Event

To define and create a new event handle (record), since the Calendar Service uses the event handler mechanism:

Use the calendar_record_create() function with the defined event handle as a parameter to create an event associated to the event handle and an _calendar_event._uri parameter for the event type.

Verify the status of the error code. If the event is created correctly, the function returns CALENDAR_ERROR_NONE. If an error is reported, you can check the error and take appropriate action or stop other operations on the database.

calendar_record_h event = NULL;
error_code = calendar_record_create(_calendar_event._uri, &event);
if (error_code != CALENDAR_ERROR_NONE)
   dlog_print(DLOG_ERROR, LOG_TAG, "calendar_record_create: %x\n", error_code);

Setting Event Properties

To set the event properties:

  1. Set the event subject.

    To set the subject, call calendar_record_set_str(). This function takes the event handle (created before), as the first argument, _calendar_event.summary for subject type, and the subject, which is a string value, as the third argument. The calendar_record_set_str() function returns the status code. If the function returns an error, take appropriate action, such as freeing memory, removing handles, and disconnecting from the service, if needed.

    error_code = calendar_record_set_str(event, _calendar_event.summary, "summary");
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "set record summary failed : %x\n", error_code);
  2. Set the event description.

    The calendar_record_set_str() function sets the description of the event when the second argument is _calendar_event.description. This function takes the event handle as the first argument, and the description, which is a string value, as the third argument. The description argument is taken from the UI part of the application. The function returns the status code. If the function returns an error, take appropriate action, such as freeing memory, removing handles, and disconnecting from the service, if needed.

    error_code = calendar_record_set_str(event, _calendar_event.description, "description");
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "set description failed : %x\n", error_code);
  3. Set the event time zone ID.

    The start and end time must be inserted in the event. If the time zone ID is not inserted, the time zone for the start and end time is considered to be UTC. The properties are in the calendar_view.h file.

    error_code = calendar_record_set_str(event, _calendar_event.start_tzid, "Asia/Seoul");
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "set start_tzid failed : %x\n", error_code);
    
    error_code = calendar_record_set_str(event, _calendar_event.end_tzid, "Asia/Seoul");
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "set end_tzid failed : %x\n", error_code);
  4. Set the event start and end dates.

    You can set the other properties similarly. To set the start date, call the calendar_record_set_caltime() functions and check the error codes.

    calendar_time_s starttime = {0};
    starttime.type = CALENDAR_TIME_UTIME;
    starttime.time.utime = 1404036000; // 2014/06/29 10:00:00 UTC
    error_code = calendar_record_set_caltime(event, _calendar_event.start_time, starttime);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "set start_time failed : %x\n", error_code);
    
    calendar_time_s endtime = {0};
    endtime.type = CALENDAR_TIME_UTIME;
    endtime.time.utime = 1404036000 + 3600; // 2014/06/29 11:00:00 UTC
    error_code = calendar_record_set_caltime(event, _calendar_event.end_time, endtime);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "set end_time failed : %x\n", error_code);

    The calendar_time_s has 2 types. For more information about the types, see the Calendar guide.

  5. Set the event frequency.

    To create recurring events, set the frequency property.

    error_code = calendar_record_set_int(event, _calendar_event.freq, CALENDAR_RECURRENCE_MONTHLY);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "set start_time failed : %x\n", error_code);
    
    error_code = calendar_record_set_int(event, _calendar_event.interval, 1);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "set start_time failed : %x\n", error_code);
    
    error_code = calendar_record_set_str(event, _calendar_event.bymonthday, "3,4,5");
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "set start_time failed : %x\n", error_code);
  6. Set the range of recurrence for the event.
    error_code = calendar_record_set_int(event, _calendar_event.range_type, CALENDAR_RANGE_COUNT);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "set range_type failed : %x\n", error_code);
    
    error_code = calendar_record_set_int(event, _calendar_event.count, 8);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "set count failed : %x\n", error_code);
  7. Add an alarm.

    To add an alarm, create an alarm handle and insert it as a child.

    calendar_record_h alarm = NULL;
    calendar_time_s ct;
    error_code = CALENDAR_ERROR_NONE;
    error_code += calendar_record_create(_calendar_alarm._uri, &alarm);
    error_code += calendar_record_set_int(alarm, _calendar_alarm.tick_unit, CALENDAR_ALARM_TIME_UNIT_SPECIFIC);
    ct.type = CALENDAR_TIME_UTIME;
    ct.time.utime = 1404036000 - 60; // 60 sec before starttime (1404036000)
    error_code += calendar_record_set_caltime(alarm, _calendar_alarm.alarm_time, ct);
    error_code += calendar_record_add_child_record(event, _calendar_event.calendar_alarm, alarm);
    
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "calendar add alarm failed \n");

    The following alarm tick units are available:

    • CALENDAR_ALARM_TIME_UNIT_MINUTE
    • CALENDAR_ALARM_TIME_UNIT_HOUR
    • CALENDAR_ALARM_TIME_UNIT_DAY
    • CALENDAR_ALARM_TIME_UNIT_WEEK
    • CALENDAR_ALARM_TIME_UNIT_MONTH (not recommended)
    • CALENDAR_ALARM_TIME_UNIT_SPECIFIC (must use specific unixtime)
  8. Add an attendee.

    To add an attendee, create an attendee handle and insert it as a child.

    calendar_record_h attendee = NULL;
    error_code = CALENDAR_ERROR_NONE;
    error_code += calendar_record_create(_calendar_attendee._uri, &attendee);
    error_code += calendar_record_set_str(attendee, _calendar_attendee.name, "John");
    error_code += calendar_record_add_child_record(event, _calendar_event.calendar_attendee, attendee);
    
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "calendar add alarm failed \n");

Inserting an Event to the Database

To insert an event record:

  1. Use the calendar_db_insert_record() function to insert the newly created event into the Calendar database. The first argument is the event handle, the second is the record ID - a unique ID is assigned to the event you are adding and returned as the second argument. If the event is inserted successfully, the function returns CALENDAR_ERROR_NONE.
    int id = -1;
    error_code = calendar_db_insert_record(event, &id);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "db insert record failed: %x\n", error_code);
    
    dlog_print(DLOG_ERROR, LOG_TAG, "id: %d\n", id);
  2. After inserting, destroy the used structures:
    calendar_record_destroy(event, true);

Getting Events

To retrieve a single event or all events one by one. You can also filter the events by one of the properties:

  1. Get a single event record using its ID.
    calendar_record_h record;
    const int event_id = ... // Acquire event ID
    error_code = calendar_db_get_record(_calendar_event._uri, event_id, &record);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "db get record failed: %x\n", error_code);
  2. Get the event record list.

    To get all events without filtering, you need a record list:

    calendar_list_h list = NULL;
    error_code = calendar_db_get_all_records(_calendar_event._uri, 0, 0, &list);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "db get all records failed: %x\n", error_code);
  3. Filter the list.
    1. To get events with filtering, you need a record list and a query:

      calendar_list_h list = NULL;
      calendar_query_h query = NULL;
      
      error_code = calendar_query_create(_calendar_event._uri, &query);
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "create query failed: %x\n", error_code);
    2. Before retrieving the events, create a filter for the list. You can filter the list based on various parameters.
      calendar_filter_h filter = NULL;
      
      error_code = calendar_filter_create (_calendar_event._uri, &filter);
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "create filter failed: %x\n", error_code);
    3. Add a condition, such as summary:
      error_code = calendar_filter_add_str(filter, _calendar_event.summary, CALENDAR_MATCH_CONTAINS, "summary to find");
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "filter add string failed: %x\n", error_code);
    4. To add more conditions, define an operator between the conditions:
      error_code = calendar_filter_add_operator(filter, CALENDAR_FILTER_OPERATOR_AND);
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "filter add operator failed: %x\n", error_code);
      
      error_code = calendar_filter_add_str(filter, _calendar_event.description, CALENDAR_MATCH_CONTAINS, "description to find");
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "filter add string failed: %x\n", error_code);

      In the above example, only events which contain a summary "summary to find" and description "description to find" are retrieved.

      You can create a filter with integer and time conditions. For instance, to filter all day events which start after 1st January 2014, add the following filter:

      calendar_time_s time_to_compare = {0};
      time_to_compare.type = CALENDAR_TIME_LOCALTIME;
      time_to_compare.time.date.mday = 1;
      time_to_compare.time.date.month = 1;
      time_to_compare.time.date.year = 2014;
      error_code = calendar_filter_add_caltime(filter, _calendar_event.start_time, CALENDAR_MATCH_GREATER_THAN, time_to_compare);
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "filter add caltime failed: %x\n", error_code);

      The type parameter determines whether the event is a daily (CALENDAR_TIME_LOCALTIME) non-all-day event (CALENDAR_TIME_UTIME). To get the specified time period, use 2 conditions using CALENDAR_MATCH_GREATER_THAN and CALENDAR_MATCH_LESS_THAN with the operator CALENDAR_FILTER_OPERATOR_OR. You can also use CALENDAR_MATCH_EQUAL to set an equality condition.

    5. Connect the query with the list:
      error_code = calendar_query_set_filter(query, filter);
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "query set filter failed: %x\n", error_code);
      
      error_code = calendar_db_get_records_with_query(query, 0, 0, &list);
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "db get records with query failed: %x\n", error_code);

      The third parameter refers to a limit of the results. If 0 is passed, there are no limits. Remember that after all operations, the list must be released.

    6. Free the filter and query:
      calendar_filter_destroy(filter);
      calendar_query_destroy(query);
  4. Iterate the list and read the records.
    1. Get records from the list using calendar_list_get_current_record_p(), and calendar_list_next() or calendar_list_prev(). Inside the loop, get details of each record.

      Note on the returned values' ownership: some functions have the _p postfix. It means that the returned value must not be freed by the application, as it is a pointer to the data in an existing record.

      calendar_record_h record;
      while (calendar_list_get_current_record_p(list, &record) == CALENDAR_ERROR_NONE)
      {
         char* summary;
         calendar_record_get_str_p(record, _calendar_event.summary, &summary);
         dlog_print(DLOG_ERROR, LOG_TAG, "summary: %s\n", summary);
      
         error_code = calendar_list_next(list);
         if (error_code != CALENDAR_ERROR_NONE)
            break;
      }
    2. If you want to get more details of each record, use the calendar_gl_event_data_t structure like below:
      calendar_gl_event_data_t *gl_event_data = NULL;
      calendar_record_h record = NULL;
      while (calendar_list_get_current_record_p(list, &record) == CALENDAR_ERROR_NONE)
      {
         gl_event_data = _create_gl_event_data(record);
         // You can get, for example, summary:
         // gl_event_data->summary
      
         _free_gl_event_data(gl_event_data);
      
         error_code = calendar_list_next(list);
         if (error_code != CALENDAR_ERROR_NONE)
            break;
      }
    3. The memory for the record data is allocated, and the data is copied from the record by the functions listed further on in this document.
      typedef struct _calendar_gl_event_data
      {
         int id;
         char *summary;
         char *description;
         calendar_time_s start_time;
      } calendar_gl_event_data_t;
      
      static void _free_gl_event_data(calendar_gl_event_data_t *gl_event_data)
      {
         if (NULL == gl_event_data)
            return;
         free(gl_event_data->summary);
         free(gl_event_data->description);
         free(gl_event_data);
      }
      
      static calendar_gl_event_data_t *_create_gl_event_data(calendar_record_h record)
      {
         calendar_gl_event_data_t *gl_event_data;
         int error_code;
      
         gl_event_data = malloc(sizeof(calendar_gl_event_data_t));
         memset(gl_event_data, 0x0, sizeof(calendar_gl_event_data_t));
      
         error_code = calendar_record_get_str(record, _calendar_event.summary, &gl_event_data->summary);
         if (error_code != CALENDAR_ERROR_NONE)
         {
            dlog_print(DLOG_ERROR, LOG_TAG, "record get summary failed: %i\n", error_code);
            _free_gl_event_data(gl_event_data);
      
            return NULL;
         }
      
         error_code = calendar_record_get_str(record, _calendar_event.description, &gl_event_data->description);
         if (error_code != CALENDAR_ERROR_NONE)
         {
            dlog_print(DLOG_ERROR, LOG_TAG, "record get description failed: %i\n", error_code);
            _free_gl_event_data(gl_event_data);
      
            return NULL;
         }
      
         error_code = calendar_record_get_int(record, _calendar_event.id, &gl_event_data->id);
         if (error_code != CALENDAR_ERROR_NONE)
         {
            dlog_print(DLOG_ERROR, LOG_TAG, "record get id failed: %i\n", error_code);
            _free_gl_event_data(gl_event_data);
      
            return NULL;
         }
      
         error_code = calendar_record_get_caltime(record, _calendar_event.start_time, &gl_event_data->start_time);
         if (error_code != CALENDAR_ERROR_NONE)
         {
            dlog_print(DLOG_ERROR, LOG_TAG, "calendar get start time failed: %i\n", error_code);
            _free_gl_event_data(gl_event_data);
      
            return NULL;
         }
      
         return gl_event_data;
      }

      To get access to a specified data from the record, firstly it is necessary to get its child responsible for the requested type.

  5. Free the list:
    calendar_list_destroy(list, true);

Updating an Event

To update an event record:

  1. Get the event record handle to update with the ID.
    calendar_record_h record;
    const int event_id = ... // Acquire event ID
    error_code = calendar_db_get_record(_calendar_event._uri, event_id, &record);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "db get record failed: %x\n", error_code);
  2. Set the properties to update.
    error_code = calendar_record_set_str(record, _calendar_event.summary, "summary updated");
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "record set summary failed: %x\n", error_code);
    
    error_code = calendar_record_set_str(record, _calendar_event.description, "description updated");
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "record set description failed: %x\n", error_code);
  3. To update the record, call the calendar_db_update_record() function.
    error_code = calendar_db_update_record(record);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "db update record failed: %x\n", error_code);
  4. When the event handle is no longer needed, use the calendar_record_destroy() function to destroy the event handle and free the allocated memory.
    calendar_record_destroy(record, true);

Deleting an Event

To delete an event, call the calendar_db_delete_record() function with _calendar_event._uri as the first parameter and event ID as the second one:

int event_id = ... // Acquire event ID
error_code = calendar_db_delete_record(_calendar_event._uri, event_id);
if (error_code != CALENDAR_ERROR_NONE)
   dlog_print(DLOG_ERROR, LOG_TAG, "db delete record failed: %x\n", error_code);

Setting Exceptions when Inserting Events

To set an exception date to an event record when creating the event:

  1. Create a recurring event.

    The following example creates an event record with the following properties:

    • Frequency: CALENDAR_RECURRENCE_MONTHLY
    • Interval: 1
    • Bymonthday: "3, 4, 5"
    • Range type: count
    • Count: 8
    int error_code = CALENDAR_ERROR_NONE;
    
    calendar_record_h event = NULL;
    error_code += calendar_record_create(_calendar_event._uri, &event);
    error_code += calendar_record_set_str(event, _calendar_event.summary, "test");
    error_code += calendar_record_set_str(event, _calendar_event.start_tzid, "Asia/Seoul");
    error_code += calendar_record_set_str(event, _calendar_event.end_tzid, "Asia/Seoul");
    
    calendar_time_s st = {0};
    st.type = CALENDAR_TIME_UTIME;
    st.time.utime = 1349226000;
    error_code += calendar_record_set_caltime(event, _calendar_event.start_time, st);
    
    calendar_time_s et = {0};
    et.type = CALENDAR_TIME_UTIME;
    et.time.utime = 1354582800;
    error_code += calendar_record_set_caltime(event, _calendar_event.end_time, et);
    
    error_code += calendar_record_set_int(event, _calendar_event.freq, CALENDAR_RECURRENCE_MONTHLY);
    error_code += calendar_record_set_int(event, _calendar_event.interval, 1);
    error_code += calendar_record_set_str(event, _calendar_event.bymonthday, "3,4,5");
    
    error_code += calendar_record_set_int(event, _calendar_event.range_type, CALENDAR_RANGE_COUNT);
    error_code += calendar_record_set_int(event, _calendar_event.count, 8);
    
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "calendar record create failed: \n");

    The created event has 8 instances.

    Table: Event instances
    unixtime Date time
    1349226000
    1349312400
    1349398800
    1351904400
    1351990800
    1352077200
    1354496400
    1354582800
    2012-10-03 01:00:00
    2012-10-04 01:00:00
    2012-10-05 01:00:00
    2012-11-03 01:00:00
    2012-11-04 01:00:00
    2012-11-05 01:00:00
    2012-12-03 01:00:00
    2012-12-04 01:00:00
  2. Set the exdate property to create the exception.

    In vcalendar 2.0 (RFC 2445), exdate is used to identify a deleted instance. If multiple instances are deleted, datetimes are added with a comma (such as 20121104T010000Z, 20121105T010000Z, 20121203T010000Z).

    error_code = calendar_record_set_str(event, _calendar_event.exdate, "20121104T010000Z");
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "calendar record set string failed: %x\n", error_code);
  3. Insert the record.

    Use the calendar_db_insert_record() function to insert the event into the Calendar database.

    int event_id;
    error_code = calendar_db_insert_record(event, &event_id);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "calendar db insert record failed: %x\n", error_code);
    
    calendar_record_destroy(event, true);

Adding an Exception Date for an Existing Event

To add an exception date to an existing event:

  1. Make sure you have an existing event.
  2. Clone the existing event record and set new properties for the exception.

    Cloning means that the new record has the original event's properties. In vcalendar 2.0 (RFC 2445), the recurrence ID is used to identify the modified instance (exception).

    calendar_record_h clone = NULL;
    error_code = CALENDAR_ERROR_NONE;
    
    error_code += calendar_record_clone(event, &clone);
    error_code += calendar_record_set_int(clone, _calendar_event.original_event_id, event_id);
    error_code += calendar_record_set_str(clone, _calendar_event.recurrence_id, "20121005T010000Z");
    
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "calendar record clone failed: %x\n", error_code);
  3. Insert the new record.

    Use the calendar_db_insert_record() function to insert the new event record into the Calendar database.

    int exdate_event_id = 0;
    error_code = calendar_db_insert_record(clone, &exdate_event_id);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "calendar db insert record failed: %x\n", error_code);
    
    calendar_record_destroy(clone, true);
    calendar_record_destroy(event, true);

Monitoring Event Changes

To register a callback function that listens for event changes:

  1. Register the callback function.
    error_code = calendar_db_add_changed_cb(_calendar_event._uri, _event_changed_callback, NULL);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "db add changed cb failed: %x\n", error_code);
  2. Define the callback function.

    The callback function is called when an event changes. The code below shows how to get the new event details.

    static calendar_gl_event_data_t *_gl_event_data = ...
    static void _event_changed_callback(const char *view_uri, void *user_data)
    {
       if (0 != strcmp(view_uri, _calendar_event._uri))
          return;
    
       if (NULL == _gl_event_data)
          return;
    
       int event_id = _gl_event_data->id;
       _free_gl_event_data(_gl_event_data);
       _gl_event_data = NULL;
    
       calendar_record_h record = NULL;
       int error_code;
       error_code = calendar_db_get_record(_calendar_event._uri, event_id, &record);
       if (error_code != CALENDAR_ERROR_NONE)
          return;
    
        _gl_event_data = _create_gl_event_data(record);
       // Use _gl_event_data
    
       calendar_record_destroy(record, true);
    }

Creating a Todo

To define and create a new todo handle record, since the Calendar Service uses a todo handler mechanism:

Use the calendar_record_create() function with the defined todo handle as a parameter to create a todo associated with the todo handle and a _calendar_todo._uri parameter for the todo type.

Verify the status of the error code. If the todo handle is created correctly, the function returns CALENDAR_ERROR_NONE. If an error is reported, check the error and take appropriate action, or stop other operations on the database.

calendar_record_h todo = NULL;
error_code = calendar_record_create(_calendar_todo._uri, &todo);
if (error_code != CALENDAR_ERROR_NONE)
   dlog_print(DLOG_ERROR, LOG_TAG, "calendar_record_create: %x\n", error_code);

Setting Todo Properties

To set the todo properties:

  1. Set the todo subject.

    To set the subject, call calendar_record_set_str(). This function takes the todo handle (created before) as the first argument, _calendar_todo.summary for the subject type, and the subject, which is string value, as the third argument. The calendar_record_set_str() function returns the status code. If the function returns an error, take appropriate action, such as freeing memory, removing handles, and disconnecting from the service, if needed.

    error_code = calendar_record_set_str(todo, _calendar_todo.summary, "summary");
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "set summary failed : %x\n", error_code);
  2. Set the todo description.

    The calendar_record_set_uri() function sets the description of the todo when the second argument is _calendar_todo.description. This function takes the todo handle as the first argument, and the description, which is string value, as the third argument. The description argument is taken from the UI part of the application. The function returns the status code. If the function returns an error, take appropriate action, such as freeing memory, removing handles, and disconnecting from the service, if needed.

    error_code = calendar_record_set_str(todo, _calendar_todo.description, "description");
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "set description failed : %x\n", error_code);
  3. Set the todo due date.

    To set the due date, call the calendar_record_set_caltime function and check the error codes.

    calendar_time_s duetime = {0};
    duetime.type = CALENDAR_TIME_UTIME;
    duetime.time.utime = 1404036000; // 2014/06/29 11:00:00 UTC
    
    error_code = calendar_record_set_caltime(todo, _calendar_todo.due_time, duetime);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "set due_time failed : %x\n", error_code);
  4. Set the todo status.

    You can set the other properties similarly. To set the todo status, call the calendar_record_set_int() function and check the error codes.

    error_code = calendar_record_set_int(todo, _calendar_todo.todo_status, CALENDAR_TODO_STATUS_COMPLETED);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "set todo_status failed : %x\n", error_code);

Inserting a Todo to the Database

To insert a todo record:

  1. Use the calendar_db_insert_record() function to insert a newly created todo into the Calendar database. The first argument is the todo handle, the second is the record ID. A unique ID is assigned to the record you are adding, and is returned as the third argument of the called function. If the todo is inserted successfully, the function returns CALENDAR_ERROR_NONE.
    int id;
    error_code = calendar_db_insert_record(todo, &id);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "db insert record failed: %x\n", error_code);
  2. After inserting, destroy the used structures:
    calendar_record_destroy(todo, true);

Getting Todos

To retrieve a single todo or all todos one by one. You can also filter the todos by one of the properties:

  1. Get a single todo record using its ID.
    calendar_record_h record;
    const int todo_id = ... // Acquire todo ID
    error_code = calendar_db_get_record(_calendar_todo._uri, todo_id, &record);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "db get record failed: %x\n", error_code);
  2. Get the todo record list.

    To get all todos without filtering, you need a record list:

    calendar_list_h list = NULL;
    error_code = calendar_db_get_all_records(_calendar_todo._uri, 0, 0, &list);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "db get all records failed: %x\n", error_code);
  3. Filter the list.
    1. To get todos with filtering, you need a record list and a query:
      calendar_list_h list = NULL;
      calendar_query_h query = NULL;
      
      error_code = calendar_query_create(_calendar_todo._uri, &query);
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "create query failed: %x\n", error_code);
    2. Before retrieving the todos, create a filter for the list. You can filter the list based on various parameters.
      calendar_filter_h filter = NULL;
      
      error_code = calendar_filter_create (_calendar_todo._uri, &filter);
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "create filter failed: %x\n", error_code);
    3. Add a condition, such as summary:
      error_code = calendar_filter_add_str(filter, _calendar_todo.summary, CALENDAR_MATCH_CONTAINS, "summary to find");
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "filter add string failed: %x\n", error_code);
    4. To add more conditions, define an operator between the conditions:
      error_code = calendar_filter_add_operator(filter, CALENDAR_FILTER_OPERATOR_AND);
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "filter add operator failed: %x\n", error_code);
      
      error_code = calendar_filter_add_str(filter, _calendar_todo.description, CALENDAR_MATCH_CONTAINS, "description to find");
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "filter add string failed: %x\n", error_code);

      In the above example, only todos which contain a summary "summary to find" and description "description to find" are retrieved.

      You can create a filter with integer and time conditions. For instance, to filter all todos which are completed, add the following filter:

      error_code = calendar_filter_add_int(filter, _calendar_todo.todo_status, CALENDAR_MATCH_EQUAL, CALENDAR_TODO_STATUS_COMPLETED);
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "filter add integer failed: %x\n", error_code);
    5. Connect the query with the list:
      error_code = calendar_query_set_filter(query, filter);
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "query set filter failed: %x\n", error_code);
      
      error_code = calendar_db_get_records_with_query(query, 0, 0, &list);
      if (error_code != CALENDAR_ERROR_NONE)
         dlog_print(DLOG_ERROR, LOG_TAG, "db get records with query failed: %x\n", error_code);

      The third parameter refers to a limit of the results. If 0 is passed, there are no limits. Remember that after all operations, the list must be released.

    6. Free the filter and query:
      calendar_filter_destroy(filter);
      calendar_query_destroy(query);
  4. Iterate the list and read the records.
    1. Get records from the list using calendar_list_get_current_record_p(), and calendar_list_next() or calendar_list_prev(). Inside the loop, get details of each record.

      Note on the returned values' ownership: some functions have the _p postfix. It means that the returned value must not be freed by the application, as it is a pointer to the data in an existing record.

      calendar_record_h record;
      while (calendar_list_get_current_record_p(list, &record) == CALENDAR_ERROR_NONE)
      {
         char* summary;
         calendar_record_get_str_p(record, _calendar_todo.summary, &summary);
         dlog_print(DLOG_ERROR, LOG_TAG, "summary: %s\n", summary);
      
         error_code = calendar_list_next(list);
         if (error_code != CALENDAR_ERROR_NONE)
            break;
      }
    2. If you want to get more details of each record, use the calendar_gl_todo_data_t structure like below:
      calendar_gl_todo_data_t *gl_todo_data = NULL;
      calendar_record_h record = NULL;
      while (calendar_list_get_current_record_p(list, &record) == CALENDAR_ERROR_NONE)
      {
         gl_todo_data = _create_gl_todo_data(record);
         // You can get, for example, summary:
         // gl_todo_data->summary
      
         _free_gl_todo_data(gl_todo_data);
      
         error_code = calendar_list_next(list);
         if (error_code != CALENDAR_ERROR_NONE)
            break;
      }
    3. The memory for the record data is allocated, and the data is copied from the record by the functions listed further on in this document.
      typedef struct _calendar_gl_todo_data
      {
         int id;
         char *summary;
         char *description;
         calendar_time_s due_time;
      } calendar_gl_todo_data_t;
      
      static void _free_gl_todo_data(calendar_gl_todo_data_t *gl_todo_data)
      {
         if (NULL == gl_todo_data)
            return;
         free(gl_todo_data->summary);
         free(gl_todo_data->description);
         free(gl_todo_data);
      }
      
      static calendar_gl_todo_data_t *_create_gl_todo_data(calendar_record_h record)
      {
         calendar_gl_todo_data_t *gl_todo_data;
         int error_code;
      
         gl_todo_data = malloc(sizeof(calendar_gl_todo_data_t));
         memset(gl_todo_data, 0x0, sizeof(calendar_gl_todo_data_t));
      
         error_code = calendar_record_get_str(record, _calendar_todo.summary, &gl_todo_data->summary);
         if (error_code != CALENDAR_ERROR_NONE)
         {
            dlog_print(DLOG_ERROR, LOG_TAG, "record get summary failed: %x\n", error_code);
            _free_gl_todo_data(gl_todo_data);
      
            return NULL;
         }
      
         error_code = calendar_record_get_str(record, _calendar_todo.description, &gl_todo_data->description);
         if (error_code != CALENDAR_ERROR_NONE)
         {
            dlog_print(DLOG_ERROR, LOG_TAG, "record get description failed: %x\n", error_code);
            _free_gl_todo_data(gl_todo_data);
      
            return NULL;
         }
      
         error_code = calendar_record_get_int(record, _calendar_todo.id, &gl_todo_data->id);
         if (error_code != CALENDAR_ERROR_NONE)
         {
            dlog_print(DLOG_ERROR, LOG_TAG, "record get id failed: %x\n", error_code);
            _free_gl_todo_data(gl_todo_data);
      
            return NULL;
         }
      
         error_code = calendar_record_get_caltime(record, _calendar_todo.due_time, &gl_todo_data->due_time);
         if (error_code != CALENDAR_ERROR_NONE)
         {
            dlog_print(DLOG_ERROR, LOG_TAG, "calendar get due time failed: %x\n", error_code);
            _free_gl_todo_data(gl_todo_data);
      
            return NULL;
         }
      
         return gl_todo_data;
      }

      To get access to a specified data from the record, firstly you must get its child responsible for the requested type. Data returned by any function with the _p suffix must not be passed to _free_gl_todo_data().

  5. Free the list:
    calendar_list_destroy(list, true);

Updating a Todo

To update a todo record:

  1. Get the todo record handle to update with the ID.
    calendar_record_h record;
    const int todo_id = ... // Acquire todo ID
    error_code = calendar_db_get_record(_calendar_todo._uri, todo_id, &record);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "db get record failed: %x\n", error_code);
  2. Set the properties to update.
    error_code = calendar_record_set_str(record, _calendar_todo.summary, "summary updated");
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "record set summary failed: %x\n", error_code);
    
    error_code = calendar_record_set_str(record, _calendar_todo.description, "description updated");
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "record set description failed: %x\n", error_code);
  3. To update record, call the calendar_db_update_record() function.
    error_code = calendar_db_update_record(record);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "db update record failed: %x\n", error_code);
  4. When the todo handle is no longer needed, use the calendar_record_destroy() function to destroy the todo handle and free the allocated memory.
    calendar_record_destroy(record, true);

Deleting a Todo

To delete a todo, use the calendar_db_delete_record() function with _calendar_todo._uri as the first parameter and the todo ID as the second one.

int todo_id = ... // Acquire todo ID
error_code = calendar_db_delete_record(_calendar_todo._uri, todo_id);
if (error_code != CALENDAR_ERROR_NONE)
   dlog_print(DLOG_ERROR, LOG_TAG, "db delete record failed: %x\n", error_code);

Monitoring Todo Changes

To register a callback function that listens for todo changes:

  1. Register the callback function.
    error_code = calendar_db_add_changed_cb(_calendar_todo._uri, _todo_changed_callback, NULL);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "db add changed cb failed: %x\n", error_code);
  2. Define the callback function.

    The callback function is called when a todo changes. The code below shows how to get the new todo details.

    static calendar_gl_todo_data_t *_gl_todo_data = ...
    static void _todo_changed_callback(const char *view_uri, void *user_data)
    {
       if (0 != strcmp(view_uri, _calendar_todo._uri))
          return;
    
       if (NULL == _gl_todo_data)
          return;
    
       int todo_id = _gl_todo_data->id;
       _free_gl_todo_data(_gl_todo_data);
       _gl_todo_data = NULL;
    
       calendar_record_h record = NULL;
       calendar_error_e error_code;
       error_code = calendar_db_get_record(_calendar_todo._uri, todo_id, &record);
       if (error_code != CALENDAR_ERROR_NONE)
          return;
    
       _gl_todo_data = _create_gl_todo_data(record);
       // Use _gl_todo_data
    
       calendar_record_destroy(record, true);
    }

Making a vCalendar

To make a vCalendar stream from an event record:

  1. Get the event record by the event ID.
    int event_id = ... // Acquire event ID
    calendar_record_h record = NULL;
    error_code = calendar_db_get_record(_calendar_event._uri, event_id, &record);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "db get record failed: %x\n", error_code);
  2. Make the vCalendar stream by the event record.
    char *vcalendar_stream = NULL;
    calendar_list_h list = NULL;
    
    error_code = calendar_list_create(&list);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "list create failed: %x\n", error_code);
    
    error_code = calendar_list_add(list, record);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "list add failed: %x\n", error_code);
    
    error_code = calendar_vcalendar_make_from_records(list, &vcalendar_stream);
    if (error_code != CALENDAR_ERROR_NONE)
       dlog_print(DLOG_ERROR, LOG_TAG, "vcalendar make from records failed: %x\n", error_code);
  3. When the list handle is no longer needed, use the calendar_list_destroy() function to destroy the list handle and free the allocated memory.
    free(vcalendar_stream);
    calendar_list_destroy(list, true);

Parsing a vCalendar

To parse a vCalendar from a file and insert to the database:

char vcalendar_file_path[512] = {0};
char *resource_path = app_get_resource_path();
snprintf(vcalendar_file_path, sizeof(vcalendar_file_path), "%s/%s", resource_path, "vcalendar.ics");
free(resource_path);

error_code = calendar_vcalendar_parse_to_calendar_foreach(vcalendar_file_path, // File path of vCalendar
                                                          _vcalendar_parse_cb, // Callback function to invoke
                                                          NULL); // User data to be passed to the callback function

The vCalendar stream contains multiple event or todo objects. The callback function is called after parsing each event or todo. If you return false on the callback function, parsing stops.

static bool _vcalendar_parse_cb(calendar_record_h record, void *user_data)
{
   if (NULL == record)
      return false;

   int id = -1;
   error_code = calendar_db_insert_record(record, &id);
   if (error_code != CALENDAR_ERROR_NONE)
   {
      dlog_print(DLOG_ERROR, LOG_TAG, "db insert record failed: %x\n", error_code);

      return false;
   }
   dlog_print(DLOG_ERROR, LOG_TAG, "inserted id: %d\n", id);
   // Use record

   return true;
}
Go to top