Wed Apr 6 11:30:08 2011

Asterisk developer's documentation


res_calendar_caldav.c File Reference

Resource for handling CalDAV calendars. More...

#include "asterisk.h"
#include <libical/ical.h>
#include <ne_session.h>
#include <ne_uri.h>
#include <ne_request.h>
#include <ne_auth.h>
#include <ne_redirect.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include "asterisk/module.h"
#include "asterisk/calendar.h"
#include "asterisk/lock.h"
#include "asterisk/config.h"
#include "asterisk/astobj2.h"

Go to the source code of this file.

Data Structures

struct  caldav_pvt
struct  xmlstate

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int auth_credentials (void *userdata, const char *realm, int attempts, char *username, char *secret)
static void caldav_add_event (icalcomponent *comp, struct icaltime_span *span, void *data)
static void caldav_destructor (void *obj)
static struct ast_strcaldav_get_events_between (struct caldav_pvt *pvt, time_t start_time, time_t end_time)
static void * caldav_load_calendar (void *data)
static struct ast_strcaldav_request (struct caldav_pvt *pvt, const char *method, struct ast_str *req_body, struct ast_str *subdir, const char *content_type)
static int caldav_write_event (struct ast_calendar_event *event)
static int fetch_response_reader (void *data, const char *block, size_t len)
static void handle_characters (void *data, const xmlChar *ch, int len)
static void handle_end_element (void *data, const xmlChar *name)
static void handle_start_element (void *data, const xmlChar *fullname, const xmlChar **atts)
static time_t icalfloat_to_timet (icaltimetype time)
static int load_module (void)
static int unload_module (void)
static void * unref_caldav (void *obj)
static int update_caldav (struct caldav_pvt *pvt)
static int verify_cert (void *userdata, int failures, const ne_ssl_certificate *cert)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Asterisk CalDAV Calendar Integration" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, }
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_calendar_tech caldav_tech


Detailed Description

Resource for handling CalDAV calendars.

Definition in file res_calendar_caldav.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 713 of file res_calendar_caldav.c.

static void __unreg_module ( void   )  [static]

Definition at line 713 of file res_calendar_caldav.c.

static int auth_credentials ( void *  userdata,
const char *  realm,
int  attempts,
char *  username,
char *  secret 
) [static]

Definition at line 111 of file res_calendar_caldav.c.

References ast_log(), LOG_WARNING, ast_calendar::name, caldav_pvt::owner, caldav_pvt::secret, and caldav_pvt::user.

Referenced by caldav_load_calendar(), ewscal_load_calendar(), exchangecal_load_calendar(), and ical_load_calendar().

00112 {
00113    struct caldav_pvt *pvt = userdata;
00114 
00115    if (attempts > 1) {
00116       ast_log(LOG_WARNING, "Invalid username or password for CalDAV calendar '%s'\n", pvt->owner->name);
00117       return -1;
00118    }
00119 
00120    ne_strnzcpy(username, pvt->user, NE_ABUFSIZ);
00121    ne_strnzcpy(secret, pvt->secret, NE_ABUFSIZ);
00122 
00123    return 0;
00124 }

static void caldav_add_event ( icalcomponent *  comp,
struct icaltime_span *  span,
void *  data 
) [static]

Definition at line 332 of file res_calendar_caldav.c.

References ast_calendar_event::alarm, ao2_link, AST_CALENDAR_BS_BUSY, AST_CALENDAR_BS_FREE, ast_calendar_event_alloc(), ast_calendar_unref_event(), ast_calloc, AST_LIST_INSERT_TAIL, ast_log(), ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_calendar_event::attendees, ast_calendar_event::busy_state, ast_calendar_event::end, caldav_pvt::events, icalfloat_to_timet(), LOG_ERROR, LOG_WARNING, caldav_pvt::owner, ast_calendar_event::priority, ast_calendar_event::start, and ast_calendar_event::summary.

Referenced by handle_end_element().

00333 {
00334    struct caldav_pvt *pvt = data;
00335    struct ast_calendar_event *event;
00336    icaltimezone *utc = icaltimezone_get_utc_timezone();
00337    icaltimetype start, end, tmp;
00338    icalcomponent *valarm;
00339    icalproperty *prop;
00340    struct icaltriggertype trigger;
00341 
00342    if (!(pvt && pvt->owner)) {
00343       ast_log(LOG_ERROR, "Require a private structure with an owner\n");
00344       return;
00345    }
00346 
00347    if (!(event = ast_calendar_event_alloc(pvt->owner))) {
00348       ast_log(LOG_ERROR, "Could not allocate an event!\n");
00349       return;
00350    }
00351 
00352    start = icalcomponent_get_dtstart(comp);
00353    end = icalcomponent_get_dtend(comp);
00354 
00355    event->start = icaltime_get_tzid(start) ? span->start : icalfloat_to_timet(start);
00356    event->end = icaltime_get_tzid(end) ? span->end : icalfloat_to_timet(end);
00357    event->busy_state = span->is_busy ? AST_CALENDAR_BS_BUSY : AST_CALENDAR_BS_FREE;
00358 
00359    if ((prop = icalcomponent_get_first_property(comp, ICAL_SUMMARY_PROPERTY))) {
00360       ast_string_field_set(event, summary, icalproperty_get_value_as_string(prop));
00361    }
00362 
00363    if ((prop = icalcomponent_get_first_property(comp, ICAL_DESCRIPTION_PROPERTY))) {
00364       ast_string_field_set(event, description, icalproperty_get_value_as_string(prop));
00365    }
00366 
00367    if ((prop = icalcomponent_get_first_property(comp, ICAL_ORGANIZER_PROPERTY))) {
00368       ast_string_field_set(event, organizer, icalproperty_get_value_as_string(prop));
00369    }
00370 
00371    if ((prop = icalcomponent_get_first_property(comp, ICAL_LOCATION_PROPERTY))) {
00372       ast_string_field_set(event, location, icalproperty_get_value_as_string(prop));
00373    }
00374 
00375    if ((prop = icalcomponent_get_first_property(comp, ICAL_CATEGORIES_PROPERTY))) {
00376       ast_string_field_set(event, categories, icalproperty_get_value_as_string(prop));
00377    }
00378 
00379    if ((prop = icalcomponent_get_first_property(comp, ICAL_PRIORITY_PROPERTY))) {
00380       event->priority = icalvalue_get_integer(icalproperty_get_value(prop));
00381    }
00382 
00383    if ((prop = icalcomponent_get_first_property(comp, ICAL_UID_PROPERTY))) {
00384       ast_string_field_set(event, uid, icalproperty_get_value_as_string(prop));
00385    } else {
00386       ast_log(LOG_WARNING, "No UID found, but one is required. Generating, but updates may not be acurate\n");
00387       if (!ast_strlen_zero(event->summary)) {
00388          ast_string_field_set(event, uid, event->summary);
00389       } else {
00390          char tmp[100];
00391          snprintf(tmp, sizeof(tmp), "%lu", event->start);
00392          ast_string_field_set(event, uid, tmp);
00393       }
00394    }
00395 
00396    /* Get the attendees */
00397    for (prop = icalcomponent_get_first_property(comp, ICAL_ATTENDEE_PROPERTY);
00398          prop; prop = icalcomponent_get_next_property(comp, ICAL_ATTENDEE_PROPERTY)) {
00399       struct ast_calendar_attendee *attendee;
00400       const char *data;
00401 
00402       if (!(attendee = ast_calloc(1, sizeof(*attendee)))) {
00403          event = ast_calendar_unref_event(event);
00404          return;
00405       }
00406       data = icalproperty_get_attendee(prop);
00407       if (!ast_strlen_zero(data)) {
00408          attendee->data = ast_strdup(data);;
00409          AST_LIST_INSERT_TAIL(&event->attendees, attendee, next);
00410       }
00411    }
00412 
00413 
00414    /* Only set values for alarm based on VALARM.  Can be overriden in main/calendar.c by autoreminder
00415     * therefore, go ahead and add events even if their is no VALARM or it is malformed
00416     * Currently we are only getting the first VALARM and are handling repitition in main/calendar.c from calendar.conf */
00417    if (!(valarm = icalcomponent_get_first_component(comp, ICAL_VALARM_COMPONENT))) {
00418       ao2_link(pvt->events, event);
00419       event = ast_calendar_unref_event(event);
00420       return;
00421    }
00422 
00423    if (!(prop = icalcomponent_get_first_property(valarm, ICAL_TRIGGER_PROPERTY))) {
00424       ast_log(LOG_WARNING, "VALARM has no TRIGGER, skipping!\n");
00425       ao2_link(pvt->events, event);
00426       event = ast_calendar_unref_event(event);
00427       return;
00428    }
00429 
00430    trigger = icalproperty_get_trigger(prop);
00431 
00432    if (icaltriggertype_is_null_trigger(trigger)) {
00433       ast_log(LOG_WARNING, "Bad TRIGGER for VALARM, skipping!\n");
00434       ao2_link(pvt->events, event);
00435       event = ast_calendar_unref_event(event);
00436       return;
00437    }
00438 
00439    if (!icaltime_is_null_time(trigger.time)) { /* This is an absolute time */
00440       tmp = icaltime_convert_to_zone(trigger.time, utc);
00441       event->alarm = icaltime_as_timet_with_zone(tmp, utc);
00442    } else { /* Offset from either dtstart or dtend */
00443       /* XXX Technically you can check RELATED to see if the event fires from the END of the event
00444        * But, I'm not sure I've ever seen anyone implement it in calendaring software, so I'm ignoring for now */
00445       tmp = icaltime_add(start, trigger.duration);
00446       event->alarm = icaltime_as_timet_with_zone(tmp, utc);
00447    }
00448 
00449    ao2_link(pvt->events, event);
00450    event = ast_calendar_unref_event(event);
00451 
00452    return;
00453 }

static void caldav_destructor ( void *  obj  )  [static]

Definition at line 72 of file res_calendar_caldav.c.

References ao2_callback, ao2_ref, ast_debug, ast_string_field_free_memory, caldav_pvt::events, ast_calendar::name, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, caldav_pvt::owner, and caldav_pvt::session.

Referenced by caldav_load_calendar().

00073 {
00074    struct caldav_pvt *pvt = obj;
00075 
00076    ast_debug(1, "Destroying pvt for CalDAV calendar %s\n", pvt->owner->name);
00077    if (pvt->session) {
00078       ne_session_destroy(pvt->session);
00079    }
00080    ast_string_field_free_memory(pvt);
00081 
00082    ao2_callback(pvt->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
00083 
00084    ao2_ref(pvt->events, -1);
00085 }

static struct ast_str* caldav_get_events_between ( struct caldav_pvt pvt,
time_t  start_time,
time_t  end_time 
) [static]

Definition at line 263 of file res_calendar_caldav.c.

References ast_free, ast_log(), ast_str_append(), ast_str_create(), caldav_request(), and LOG_ERROR.

Referenced by update_caldav().

00264 {
00265    struct ast_str *body, *response;
00266    icaltimezone *utc = icaltimezone_get_utc_timezone();
00267    icaltimetype start, end;
00268    const char *start_str, *end_str;
00269 
00270    if (!(body = ast_str_create(512))) {
00271       ast_log(LOG_ERROR, "Could not allocate memory for body of request!\n");
00272       return NULL;
00273    }
00274 
00275    start = icaltime_from_timet_with_zone(start_time, 0, utc);
00276    end = icaltime_from_timet_with_zone(end_time, 0, utc);
00277    start_str = icaltime_as_ical_string(start);
00278    end_str = icaltime_as_ical_string(end);
00279 
00280    /* If I was really being efficient, I would store a collection of event URIs and etags,
00281     * first doing a query of just the etag and seeing if anything had changed.  If it had,
00282     * then I would do a request for each of the events that had changed, and only bother
00283     * updating those.  Oh well. */
00284    ast_str_append(&body, 0,
00285       "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
00286       "<C:calendar-query xmlns:D=\"DAV:\" xmlns:C=\"urn:ietf:params:xml:ns:caldav\">\n"
00287       "  <D:prop>\n"
00288       "    <C:calendar-data>\n"
00289       "      <C:expand start=\"%s\" end=\"%s\"/>\n"
00290       "    </C:calendar-data>\n"
00291       "  </D:prop>\n"
00292       "  <C:filter>\n"
00293       "    <C:comp-filter name=\"VCALENDAR\">\n"
00294       "      <C:comp-filter name=\"VEVENT\">\n"
00295       "        <C:time-range start=\"%s\" end=\"%s\"/>\n"
00296       "      </C:comp-filter>\n"
00297       "    </C:comp-filter>\n"
00298       "  </C:filter>\n"
00299       "</C:calendar-query>\n", start_str, end_str, start_str, end_str);
00300 
00301    response = caldav_request(pvt, "REPORT", body, NULL, NULL);
00302    ast_free(body);
00303 
00304    return response;
00305 }

static void * caldav_load_calendar ( void *  data  )  [static]

Definition at line 565 of file res_calendar_caldav.c.

References ao2_alloc, ao2_trylock, ao2_unlock, ast_calendar_config_acquire(), ast_calendar_config_release(), ast_calendar_event_container_alloc(), ast_cond_timedwait, ast_debug, ast_log(), ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_tvnow(), ast_variable_browse(), auth_credentials(), caldav_destructor(), LOG_ERROR, LOG_WARNING, ast_variable::name, ast_calendar::name, ast_variable::next, refreshlock, secret, ast_calendar::tech_pvt, tv, ast_calendar::unloading, unref_caldav(), update_caldav(), url, ast_variable::value, and verify_cert().

00566 {
00567    struct caldav_pvt *pvt;
00568    const struct ast_config *cfg;
00569    struct ast_variable *v;
00570    struct ast_calendar *cal = void_data;
00571    ast_mutex_t refreshlock;
00572 
00573    if (!(cal && (cfg = ast_calendar_config_acquire()))) {
00574       ast_log(LOG_ERROR, "You must enable calendar support for res_caldav to load\n");
00575       return NULL;
00576    }
00577 
00578    if (ao2_trylock(cal)) {
00579       if (cal->unloading) {
00580          ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n");
00581       } else {
00582          ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n");
00583       }
00584       ast_calendar_config_release();
00585       return NULL;
00586    }
00587 
00588    if (!(pvt = ao2_alloc(sizeof(*pvt), caldav_destructor))) {
00589       ast_log(LOG_ERROR, "Could not allocate caldav_pvt structure for calendar: %s\n", cal->name);
00590       ast_calendar_config_release();
00591       return NULL;
00592    }
00593 
00594    pvt->owner = cal;
00595 
00596    if (!(pvt->events = ast_calendar_event_container_alloc())) {
00597       ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name);
00598       pvt = unref_caldav(pvt);
00599       ao2_unlock(cal);
00600       ast_calendar_config_release();
00601       return NULL;
00602    }
00603 
00604    if (ast_string_field_init(pvt, 32)) {
00605       ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name);
00606       pvt = unref_caldav(pvt);
00607       ao2_unlock(cal);
00608       ast_calendar_config_release();
00609       return NULL;
00610    }
00611 
00612    for (v = ast_variable_browse(cfg, cal->name); v; v = v->next) {
00613       if (!strcasecmp(v->name, "url")) {
00614          ast_string_field_set(pvt, url, v->value);
00615       } else if (!strcasecmp(v->name, "user")) {
00616          ast_string_field_set(pvt, user, v->value);
00617       } else if (!strcasecmp(v->name, "secret")) {
00618          ast_string_field_set(pvt, secret, v->value);
00619       }
00620    }
00621 
00622    ast_calendar_config_release();
00623 
00624    if (ast_strlen_zero(pvt->url)) {
00625       ast_log(LOG_WARNING, "No URL was specified for CalDAV calendar '%s' - skipping.\n", cal->name);
00626       pvt = unref_caldav(pvt);
00627       ao2_unlock(cal);
00628       return NULL;
00629    }
00630 
00631    if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) {
00632       ast_log(LOG_WARNING, "Could not parse url '%s' for CalDAV calendar '%s' - skipping.\n", pvt->url, cal->name);
00633       pvt = unref_caldav(pvt);
00634       ao2_unlock(cal);
00635       return NULL;
00636    }
00637 
00638    if (pvt->uri.scheme == NULL) {
00639       pvt->uri.scheme = "http";
00640    }
00641 
00642    if (pvt->uri.port == 0) {
00643       pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme);
00644    }
00645 
00646    pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port);
00647    ne_redirect_register(pvt->session);
00648    ne_set_server_auth(pvt->session, auth_credentials, pvt);
00649    if (!strcasecmp(pvt->uri.scheme, "https")) {
00650       ne_ssl_trust_default_ca(pvt->session);
00651       ne_ssl_set_verify(pvt->session, verify_cert, NULL);
00652    }
00653 
00654    cal->tech_pvt = pvt;
00655 
00656    ast_mutex_init(&refreshlock);
00657 
00658    /* Load it the first time */
00659    update_caldav(pvt);
00660 
00661    ao2_unlock(cal);
00662 
00663    /* The only writing from another thread will be if unload is true */
00664    for (;;) {
00665       struct timeval tv = ast_tvnow();
00666       struct timespec ts = {0,};
00667 
00668       ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh);
00669 
00670       ast_mutex_lock(&refreshlock);
00671       while (!pvt->owner->unloading) {
00672          if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) {
00673             break;
00674          }
00675       }
00676       ast_mutex_unlock(&refreshlock);
00677 
00678       if (pvt->owner->unloading) {
00679          ast_debug(10, "Skipping refresh since we got a shutdown signal\n");
00680          return NULL;
00681       }
00682 
00683       ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh);
00684 
00685       update_caldav(pvt);
00686    }
00687 
00688    return NULL;
00689 }

static struct ast_str* caldav_request ( struct caldav_pvt pvt,
const char *  method,
struct ast_str req_body,
struct ast_str subdir,
const char *  content_type 
) [static]

Definition at line 126 of file res_calendar_caldav.c.

References ast_free, ast_log(), ast_str_buffer(), ast_str_create(), ast_str_strlen(), ast_strlen_zero(), fetch_response_reader(), LOG_ERROR, LOG_WARNING, ast_calendar::name, caldav_pvt::owner, caldav_pvt::session, and caldav_pvt::uri.

Referenced by caldav_get_events_between(), and caldav_write_event().

00127 {
00128    struct ast_str *response;
00129    ne_request *req;
00130    int ret;
00131    char buf[1000];
00132 
00133    if (!pvt) {
00134       ast_log(LOG_ERROR, "There is no private!\n");
00135       return NULL;
00136    }
00137 
00138    if (!(response = ast_str_create(512))) {
00139       ast_log(LOG_ERROR, "Could not allocate memory for response.\n");
00140       return NULL;
00141    }
00142 
00143    snprintf(buf, sizeof(buf), "%s%s", pvt->uri.path, subdir ? ast_str_buffer(subdir) : "");
00144 
00145    req = ne_request_create(pvt->session, method, buf);
00146    ne_add_response_body_reader(req, ne_accept_2xx, fetch_response_reader, &response);
00147    ne_set_request_body_buffer(req, ast_str_buffer(req_body), ast_str_strlen(req_body));
00148    ne_add_request_header(req, "Content-type", ast_strlen_zero(content_type) ? "text/xml" : content_type);
00149 
00150    ret = ne_request_dispatch(req);
00151    ne_request_destroy(req);
00152 
00153    if (ret != NE_OK || !ast_str_strlen(response)) {
00154       if (ret != NE_OK) {
00155          ast_log(LOG_WARNING, "Unknown response to CalDAV calendar %s, request %s to %s: %s\n", pvt->owner->name, method, buf, ne_get_error(pvt->session));
00156       }
00157       ast_free(response);
00158       return NULL;
00159    }
00160 
00161    return response;
00162 }

static int caldav_write_event ( struct ast_calendar_event event  )  [static]

Definition at line 164 of file res_calendar_caldav.c.

References AST_CALENDAR_BS_BUSY, AST_CALENDAR_BS_BUSY_TENTATIVE, ast_free, ast_log(), ast_random(), ast_str_append(), ast_str_create(), ast_str_set(), ast_string_field_build, ast_strlen_zero(), ast_calendar_event::busy_state, caldav_request(), ast_calendar_event::categories, ast_calendar_event::description, ast_calendar_event::end, ast_calendar_event::location, LOG_ERROR, LOG_WARNING, ast_calendar_event::organizer, ast_calendar_event::owner, ast_calendar_event::priority, ast_calendar_event::start, ast_calendar_event::summary, ast_calendar::tech_pvt, ast_calendar_event::uid, and caldav_pvt::url.

00165 {
00166    struct caldav_pvt *pvt;
00167    struct ast_str *body = NULL, *response = NULL, *subdir = NULL;
00168    icalcomponent *calendar, *icalevent;
00169    icaltimezone *utc = icaltimezone_get_utc_timezone();
00170    int ret = -1;
00171 
00172    if (!event) {
00173       ast_log(LOG_WARNING, "No event passed!\n");
00174       return -1;
00175    }
00176 
00177    if (!(event->start && event->end)) {
00178       ast_log(LOG_WARNING, "The event must contain a start and an end\n");
00179       return -1;
00180    }
00181    if (!(body = ast_str_create(512)) ||
00182       !(subdir = ast_str_create(32)) ||
00183       !(response = ast_str_create(512))) {
00184       ast_log(LOG_ERROR, "Could not allocate memory for request and response!\n");
00185       goto write_cleanup;
00186    }
00187 
00188    pvt = event->owner->tech_pvt;
00189 
00190    if (ast_strlen_zero(event->uid)) {
00191       unsigned short val[8];
00192       int x;
00193       for (x = 0; x < 8; x++) {
00194          val[x] = ast_random();
00195       }
00196       ast_string_field_build(event, uid, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]);
00197    }
00198 
00199    calendar = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
00200    icalcomponent_add_property(calendar, icalproperty_new_version("2.0"));
00201    icalcomponent_add_property(calendar, icalproperty_new_prodid("-//Digium, Inc.//res_caldav//EN"));
00202 
00203    icalevent = icalcomponent_new(ICAL_VEVENT_COMPONENT);
00204    icalcomponent_add_property(icalevent, icalproperty_new_dtstamp(icaltime_current_time_with_zone(utc)));
00205    icalcomponent_add_property(icalevent, icalproperty_new_uid(event->uid));
00206    icalcomponent_add_property(icalevent, icalproperty_new_dtstart(icaltime_from_timet_with_zone(event->start, 0, utc)));
00207    icalcomponent_add_property(icalevent, icalproperty_new_dtend(icaltime_from_timet_with_zone(event->end, 0, utc)));
00208    if (!ast_strlen_zero(event->organizer)) {
00209       icalcomponent_add_property(icalevent, icalproperty_new_organizer(event->organizer));
00210    }
00211    if (!ast_strlen_zero(event->summary)) {
00212       icalcomponent_add_property(icalevent, icalproperty_new_summary(event->summary));
00213    }
00214    if (!ast_strlen_zero(event->description)) {
00215       icalcomponent_add_property(icalevent, icalproperty_new_description(event->description));
00216    }
00217    if (!ast_strlen_zero(event->location)) {
00218       icalcomponent_add_property(icalevent, icalproperty_new_location(event->location));
00219    }
00220    if (!ast_strlen_zero(event->categories)) {
00221       icalcomponent_add_property(icalevent, icalproperty_new_categories(event->categories));
00222    }
00223    if (event->priority > 0) {
00224       icalcomponent_add_property(icalevent, icalproperty_new_priority(event->priority));
00225    }
00226 
00227    switch (event->busy_state) {
00228    case AST_CALENDAR_BS_BUSY:
00229       icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_CONFIRMED));
00230       break;
00231 
00232    case AST_CALENDAR_BS_BUSY_TENTATIVE:
00233       icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_TENTATIVE));
00234       break;
00235 
00236    default:
00237       icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_NONE));
00238    }
00239 
00240    icalcomponent_add_component(calendar, icalevent);
00241 
00242    ast_str_append(&body, 0, "%s", icalcomponent_as_ical_string(calendar));
00243    ast_str_set(&subdir, 0, "%s%s.ics", pvt->url[strlen(pvt->url) - 1] == '/' ? "" : "/", event->uid);
00244 
00245    response = caldav_request(pvt, "PUT", body, subdir, "text/calendar");
00246 
00247    ret = 0;
00248 
00249 write_cleanup:
00250    if (body) {
00251       ast_free(body);
00252    }
00253    if (response) {
00254       ast_free(response);
00255    }
00256    if (subdir) {
00257       ast_free(subdir);
00258    }
00259 
00260    return ret;
00261 }

static int fetch_response_reader ( void *  data,
const char *  block,
size_t  len 
) [static]

Definition at line 95 of file res_calendar_caldav.c.

References ast_free, ast_malloc, and ast_str_append().

Referenced by caldav_request(), exchangecal_request(), and fetch_icalendar().

00096 {
00097    struct ast_str **response = data;
00098    unsigned char *tmp;
00099 
00100    if (!(tmp = ast_malloc(len + 1))) {
00101       return -1;
00102    }
00103    memcpy(tmp, block, len);
00104    tmp[len] = '\0';
00105    ast_str_append(response, 0, "%s", tmp);
00106    ast_free(tmp);
00107 
00108    return 0;
00109 }

static void handle_characters ( void *  data,
const xmlChar *  ch,
int  len 
) [static]

Definition at line 505 of file res_calendar_caldav.c.

References ast_str_append(), and state.

Referenced by update_caldav().

00506 {
00507    struct xmlstate *state = data;
00508    xmlChar *tmp;
00509 
00510    if (!state->in_caldata) {
00511       return;
00512    }
00513 
00514    tmp = xmlStrndup(ch, len);
00515    ast_str_append(&state->cdata, 0, "%s", (char *)tmp);
00516    xmlFree(tmp);
00517 }

static void handle_end_element ( void *  data,
const xmlChar *  name 
) [static]

Definition at line 473 of file res_calendar_caldav.c.

References ast_str_buffer(), ast_str_strlen(), caldav_add_event(), and state.

Referenced by update_caldav().

00474 {
00475    struct xmlstate *state = data;
00476    struct icaltimetype start, end;
00477    icaltimezone *utc = icaltimezone_get_utc_timezone();
00478    icalcomponent *iter;
00479    icalcomponent *comp;
00480 
00481    if (xmlStrcasecmp(name, BAD_CAST "C:calendar-data")) {
00482       return;
00483    }
00484 
00485    state->in_caldata = 0;
00486    if (!(state->cdata && ast_str_strlen(state->cdata))) {
00487       return;
00488    }
00489    /* XXX Parse the calendar blurb for recurrence events in the time range,
00490     * create an event, and add it to pvt->events */
00491    start = icaltime_from_timet_with_zone(state->start, 0, utc);
00492    end = icaltime_from_timet_with_zone(state->end, 0, utc);
00493    comp = icalparser_parse_string(ast_str_buffer(state->cdata));
00494 
00495    for (iter = icalcomponent_get_first_component(comp, ICAL_VEVENT_COMPONENT);
00496         iter;
00497         iter = icalcomponent_get_next_component(comp, ICAL_VEVENT_COMPONENT))
00498    {
00499       icalcomponent_foreach_recurrence(iter, start, end, caldav_add_event, state->pvt);
00500    }
00501 
00502    icalcomponent_free(comp);
00503 }

static void handle_start_element ( void *  data,
const xmlChar *  fullname,
const xmlChar **  atts 
) [static]

Definition at line 463 of file res_calendar_caldav.c.

References ast_str_reset(), and state.

Referenced by update_caldav().

00464 {
00465    struct xmlstate *state = data;
00466 
00467    if (!xmlStrcasecmp(fullname, BAD_CAST "C:calendar-data")) {
00468       state->in_caldata = 1;
00469       ast_str_reset(state->cdata);
00470    }
00471 }

static time_t icalfloat_to_timet ( icaltimetype  time  )  [static]

Definition at line 307 of file res_calendar_caldav.c.

References ast_mktime(), ast_tm::tm_hour, ast_tm::tm_isdst, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, and ast_tm::tm_year.

Referenced by caldav_add_event(), and icalendar_add_event().

00308 {
00309    struct ast_tm tm = {0,};
00310    struct timeval tv;
00311 
00312    tm.tm_mday = time.day;
00313    tm.tm_mon = time.month - 1;
00314    tm.tm_year = time.year - 1900;
00315    tm.tm_hour = time.hour;
00316    tm.tm_min = time.minute;
00317    tm.tm_sec = time.second;
00318    tm.tm_isdst = -1;
00319    tv = ast_mktime(&tm, NULL);
00320 
00321    return tv.tv_sec;
00322 }

static int load_module ( void   )  [static]

Definition at line 691 of file res_calendar_caldav.c.

References ast_calendar_register(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and caldav_tech.

00692 {
00693    ne_sock_init();
00694    if (ast_calendar_register(&caldav_tech)) {
00695       ne_sock_exit();
00696       return AST_MODULE_LOAD_DECLINE;
00697    }
00698 
00699    return AST_MODULE_LOAD_SUCCESS;
00700 }

static int unload_module ( void   )  [static]

Definition at line 702 of file res_calendar_caldav.c.

References ast_calendar_unregister(), and caldav_tech.

00703 {
00704    ast_calendar_unregister(&caldav_tech);
00705    ne_sock_exit();
00706    return 0;
00707 }

static void * unref_caldav ( void *  obj  )  [static]

Definition at line 87 of file res_calendar_caldav.c.

References ao2_ref.

Referenced by caldav_load_calendar().

00088 {
00089    struct caldav_pvt *pvt = obj;
00090 
00091    ao2_ref(pvt, -1);
00092    return NULL;
00093 }

static int update_caldav ( struct caldav_pvt pvt  )  [static]

Definition at line 519 of file res_calendar_caldav.c.

References ast_calendar_merge_events(), ast_free, ast_str_buffer(), ast_str_create(), ast_str_strlen(), ast_tvnow(), caldav_get_events_between(), caldav_pvt::events, handle_characters(), handle_end_element(), handle_start_element(), caldav_pvt::owner, xmlstate::pvt, state, and ast_calendar::timeframe.

Referenced by caldav_load_calendar().

00520 {
00521    struct timeval now = ast_tvnow();
00522    time_t start, end;
00523    struct ast_str *response;
00524    xmlSAXHandler saxHandler;
00525    struct xmlstate state = {
00526       .in_caldata = 0,
00527       .pvt = pvt
00528    };
00529 
00530    start = now.tv_sec;
00531    end = now.tv_sec + 60 * pvt->owner->timeframe;
00532    if (!(response = caldav_get_events_between(pvt, start, end))) {
00533       return -1;
00534    }
00535 
00536    if (!(state.cdata = ast_str_create(512))) {
00537       ast_free(response);
00538       return -1;
00539    }
00540 
00541    state.start = start;
00542    state.end = end;
00543 
00544    memset(&saxHandler, 0, sizeof(saxHandler));
00545    saxHandler.startElement = handle_start_element;
00546    saxHandler.endElement = handle_end_element;
00547    saxHandler.characters = handle_characters;
00548 
00549    xmlSAXUserParseMemory(&saxHandler, &state, ast_str_buffer(response), ast_str_strlen(response));
00550 
00551    ast_calendar_merge_events(pvt->owner, pvt->events);
00552 
00553    ast_free(response);
00554    ast_free(state.cdata);
00555 
00556    return 0;
00557 }

static int verify_cert ( void *  userdata,
int  failures,
const ne_ssl_certificate *  cert 
) [static]

Definition at line 559 of file res_calendar_caldav.c.

Referenced by caldav_load_calendar().

00560 {
00561    /* Verify all certs */
00562    return 0;
00563 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Asterisk CalDAV Calendar Integration" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, } [static]

Definition at line 713 of file res_calendar_caldav.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 713 of file res_calendar_caldav.c.

struct ast_calendar_tech caldav_tech [static]

Definition at line 51 of file res_calendar_caldav.c.

Referenced by load_module(), and unload_module().


Generated on Wed Apr 6 11:30:08 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7