Mon Aug 31 12:30:42 2015

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

static void __unreg_module ( void   )  [static]

Definition at line 719 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, caldav_pvt::owner, caldav_pvt::secret, and caldav_pvt::user.

Referenced by caldav_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 336 of file res_calendar_caldav.c.

References 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_attendee::data, ast_calendar_event::end, caldav_pvt::events, icalfloat_to_timet(), LOG_ERROR, LOG_WARNING, caldav_pvt::owner, and ast_calendar_event::start.

Referenced by handle_end_element().

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

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, 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, read]

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

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

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

Definition at line 571 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(), caldav_pvt::events, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, caldav_pvt::owner, ast_calendar::refresh, refreshlock, secret, caldav_pvt::session, ast_calendar::tech_pvt, ast_calendar::unload, ast_calendar::unloading, unref_caldav(), update_caldav(), caldav_pvt::uri, caldav_pvt::url, url, ast_variable::value, and verify_cert().

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

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, read]

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

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

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

References ast_str_append(), xmlstate::cdata, and xmlstate::in_caldata.

Referenced by update_caldav().

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

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

Definition at line 479 of file res_calendar_caldav.c.

References ast_str_buffer(), ast_str_strlen(), caldav_add_event(), xmlstate::cdata, xmlstate::end, xmlstate::in_caldata, xmlstate::pvt, and xmlstate::start.

Referenced by update_caldav().

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

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

Definition at line 469 of file res_calendar_caldav.c.

References ast_str_reset(), xmlstate::cdata, and xmlstate::in_caldata.

Referenced by update_caldav().

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

static time_t icalfloat_to_timet ( icaltimetype  time  )  [static]

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

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

static int load_module ( void   )  [static]

Definition at line 697 of file res_calendar_caldav.c.

References ast_calendar_register(), AST_MODULE_LOAD_DECLINE, and AST_MODULE_LOAD_SUCCESS.

00698 {
00699    ne_sock_init();
00700    if (ast_calendar_register(&caldav_tech)) {
00701       ne_sock_exit();
00702       return AST_MODULE_LOAD_DECLINE;
00703    }
00704 
00705    return AST_MODULE_LOAD_SUCCESS;
00706 }

static int unload_module ( void   )  [static]

Definition at line 708 of file res_calendar_caldav.c.

References ast_calendar_unregister().

00709 {
00710    ast_calendar_unregister(&caldav_tech);
00711    ne_sock_exit();
00712    return 0;
00713 }

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 525 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(), xmlstate::cdata, xmlstate::end, caldav_pvt::events, handle_characters(), handle_end_element(), handle_start_element(), xmlstate::in_caldata, caldav_pvt::owner, xmlstate::start, and ast_calendar::timeframe.

Referenced by caldav_load_calendar().

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

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

Definition at line 565 of file res_calendar_caldav.c.

Referenced by caldav_load_calendar().

00566 {
00567    /* Verify all certs */
00568    return 0;
00569 }


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

Definition at line 719 of file res_calendar_caldav.c.

struct ast_calendar_tech caldav_tech [static]

Definition at line 53 of file res_calendar_caldav.c.


Generated on 31 Aug 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1