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_str * | caldav_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_str * | caldav_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_info * | ast_module_info = &__mod_info |
static struct ast_calendar_tech | caldav_tech |
Resource for handling CalDAV calendars.
Definition in file res_calendar_caldav.c.
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().
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.
struct ast_module_info* ast_module_info = &__mod_info [static] |
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.