Mon Oct 8 12:39:27 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 = "ac1f6a56484a8820659555499174e588" , .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 716 of file res_calendar_caldav.c.

static void __unreg_module ( void   )  [static]

Definition at line 716 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 333 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_free, 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().

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

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

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

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

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

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

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

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 508 of file res_calendar_caldav.c.

References ast_str_append(), and state.

Referenced by update_caldav().

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

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

Definition at line 476 of file res_calendar_caldav.c.

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

Referenced by update_caldav().

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

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

Definition at line 466 of file res_calendar_caldav.c.

References ast_str_reset(), and state.

Referenced by update_caldav().

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

static time_t icalfloat_to_timet ( icaltimetype  time  )  [static]

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

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

static int load_module ( void   )  [static]

Definition at line 694 of file res_calendar_caldav.c.

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

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

static int unload_module ( void   )  [static]

Definition at line 705 of file res_calendar_caldav.c.

References ast_calendar_unregister(), and caldav_tech.

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

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

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

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

Definition at line 562 of file res_calendar_caldav.c.

Referenced by caldav_load_calendar().

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


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

Definition at line 716 of file res_calendar_caldav.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 716 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 Oct 8 12:39:27 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7