Mon Mar 19 11:30:53 2012

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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 715 of file res_calendar_caldav.c.

static void __unreg_module ( void   )  [static]

Definition at line 715 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 113 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().

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

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

Definition at line 334 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().

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

static void caldav_destructor ( void *  obj  )  [static]

Definition at line 74 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().

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

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

Definition at line 265 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().

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

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

Definition at line 567 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().

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

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 128 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().

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

static int caldav_write_event ( struct ast_calendar_event event  )  [static]

Definition at line 166 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.

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

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

Definition at line 97 of file res_calendar_caldav.c.

References ast_free, ast_malloc, and ast_str_append().

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

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

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

Definition at line 507 of file res_calendar_caldav.c.

References ast_str_append(), and state.

Referenced by update_caldav().

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

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

Definition at line 475 of file res_calendar_caldav.c.

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

Referenced by update_caldav().

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

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

Definition at line 465 of file res_calendar_caldav.c.

References ast_str_reset(), and state.

Referenced by update_caldav().

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

static time_t icalfloat_to_timet ( icaltimetype  time  )  [static]

Definition at line 309 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().

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

static int load_module ( void   )  [static]

Definition at line 693 of file res_calendar_caldav.c.

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

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

static int unload_module ( void   )  [static]

Definition at line 704 of file res_calendar_caldav.c.

References ast_calendar_unregister(), and caldav_tech.

00705 {
00706    ast_calendar_unregister(&caldav_tech);
00707    ne_sock_exit();
00708    return 0;
00709 }

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

Definition at line 89 of file res_calendar_caldav.c.

References ao2_ref.

Referenced by caldav_load_calendar().

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

static int update_caldav ( struct caldav_pvt pvt  )  [static]

Definition at line 521 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().

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

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

Definition at line 561 of file res_calendar_caldav.c.

Referenced by caldav_load_calendar().

00562 {
00563    /* Verify all certs */
00564    return 0;
00565 }


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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, } [static]

Definition at line 715 of file res_calendar_caldav.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 715 of file res_calendar_caldav.c.

struct ast_calendar_tech caldav_tech [static]

Definition at line 53 of file res_calendar_caldav.c.

Referenced by load_module(), and unload_module().


Generated on Mon Mar 19 11:30:53 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7