#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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .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 |
Definition in file res_calendar_caldav.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 713 of file res_calendar_caldav.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 713 of file res_calendar_caldav.c.
static int auth_credentials | ( | void * | userdata, | |
const char * | realm, | |||
int | attempts, | |||
char * | username, | |||
char * | secret | |||
) | [static] |
Definition at line 111 of file res_calendar_caldav.c.
References ast_log(), LOG_WARNING, ast_calendar::name, caldav_pvt::owner, caldav_pvt::secret, and caldav_pvt::user.
Referenced by caldav_load_calendar(), ewscal_load_calendar(), exchangecal_load_calendar(), and ical_load_calendar().
00112 { 00113 struct caldav_pvt *pvt = userdata; 00114 00115 if (attempts > 1) { 00116 ast_log(LOG_WARNING, "Invalid username or password for CalDAV calendar '%s'\n", pvt->owner->name); 00117 return -1; 00118 } 00119 00120 ne_strnzcpy(username, pvt->user, NE_ABUFSIZ); 00121 ne_strnzcpy(secret, pvt->secret, NE_ABUFSIZ); 00122 00123 return 0; 00124 }
static void caldav_add_event | ( | icalcomponent * | comp, | |
struct icaltime_span * | span, | |||
void * | data | |||
) | [static] |
Definition at line 332 of file res_calendar_caldav.c.
References ast_calendar_event::alarm, ao2_link, AST_CALENDAR_BS_BUSY, AST_CALENDAR_BS_FREE, ast_calendar_event_alloc(), ast_calendar_unref_event(), ast_calloc, AST_LIST_INSERT_TAIL, ast_log(), ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_calendar_event::attendees, ast_calendar_event::busy_state, ast_calendar_event::end, caldav_pvt::events, icalfloat_to_timet(), LOG_ERROR, LOG_WARNING, caldav_pvt::owner, ast_calendar_event::priority, ast_calendar_event::start, and ast_calendar_event::summary.
Referenced by handle_end_element().
00333 { 00334 struct caldav_pvt *pvt = data; 00335 struct ast_calendar_event *event; 00336 icaltimezone *utc = icaltimezone_get_utc_timezone(); 00337 icaltimetype start, end, tmp; 00338 icalcomponent *valarm; 00339 icalproperty *prop; 00340 struct icaltriggertype trigger; 00341 00342 if (!(pvt && pvt->owner)) { 00343 ast_log(LOG_ERROR, "Require a private structure with an owner\n"); 00344 return; 00345 } 00346 00347 if (!(event = ast_calendar_event_alloc(pvt->owner))) { 00348 ast_log(LOG_ERROR, "Could not allocate an event!\n"); 00349 return; 00350 } 00351 00352 start = icalcomponent_get_dtstart(comp); 00353 end = icalcomponent_get_dtend(comp); 00354 00355 event->start = icaltime_get_tzid(start) ? span->start : icalfloat_to_timet(start); 00356 event->end = icaltime_get_tzid(end) ? span->end : icalfloat_to_timet(end); 00357 event->busy_state = span->is_busy ? AST_CALENDAR_BS_BUSY : AST_CALENDAR_BS_FREE; 00358 00359 if ((prop = icalcomponent_get_first_property(comp, ICAL_SUMMARY_PROPERTY))) { 00360 ast_string_field_set(event, summary, icalproperty_get_value_as_string(prop)); 00361 } 00362 00363 if ((prop = icalcomponent_get_first_property(comp, ICAL_DESCRIPTION_PROPERTY))) { 00364 ast_string_field_set(event, description, icalproperty_get_value_as_string(prop)); 00365 } 00366 00367 if ((prop = icalcomponent_get_first_property(comp, ICAL_ORGANIZER_PROPERTY))) { 00368 ast_string_field_set(event, organizer, icalproperty_get_value_as_string(prop)); 00369 } 00370 00371 if ((prop = icalcomponent_get_first_property(comp, ICAL_LOCATION_PROPERTY))) { 00372 ast_string_field_set(event, location, icalproperty_get_value_as_string(prop)); 00373 } 00374 00375 if ((prop = icalcomponent_get_first_property(comp, ICAL_CATEGORIES_PROPERTY))) { 00376 ast_string_field_set(event, categories, icalproperty_get_value_as_string(prop)); 00377 } 00378 00379 if ((prop = icalcomponent_get_first_property(comp, ICAL_PRIORITY_PROPERTY))) { 00380 event->priority = icalvalue_get_integer(icalproperty_get_value(prop)); 00381 } 00382 00383 if ((prop = icalcomponent_get_first_property(comp, ICAL_UID_PROPERTY))) { 00384 ast_string_field_set(event, uid, icalproperty_get_value_as_string(prop)); 00385 } else { 00386 ast_log(LOG_WARNING, "No UID found, but one is required. Generating, but updates may not be acurate\n"); 00387 if (!ast_strlen_zero(event->summary)) { 00388 ast_string_field_set(event, uid, event->summary); 00389 } else { 00390 char tmp[100]; 00391 snprintf(tmp, sizeof(tmp), "%lu", event->start); 00392 ast_string_field_set(event, uid, tmp); 00393 } 00394 } 00395 00396 /* Get the attendees */ 00397 for (prop = icalcomponent_get_first_property(comp, ICAL_ATTENDEE_PROPERTY); 00398 prop; prop = icalcomponent_get_next_property(comp, ICAL_ATTENDEE_PROPERTY)) { 00399 struct ast_calendar_attendee *attendee; 00400 const char *data; 00401 00402 if (!(attendee = ast_calloc(1, sizeof(*attendee)))) { 00403 event = ast_calendar_unref_event(event); 00404 return; 00405 } 00406 data = icalproperty_get_attendee(prop); 00407 if (!ast_strlen_zero(data)) { 00408 attendee->data = ast_strdup(data);; 00409 AST_LIST_INSERT_TAIL(&event->attendees, attendee, next); 00410 } 00411 } 00412 00413 00414 /* Only set values for alarm based on VALARM. Can be overriden in main/calendar.c by autoreminder 00415 * therefore, go ahead and add events even if their is no VALARM or it is malformed 00416 * Currently we are only getting the first VALARM and are handling repitition in main/calendar.c from calendar.conf */ 00417 if (!(valarm = icalcomponent_get_first_component(comp, ICAL_VALARM_COMPONENT))) { 00418 ao2_link(pvt->events, event); 00419 event = ast_calendar_unref_event(event); 00420 return; 00421 } 00422 00423 if (!(prop = icalcomponent_get_first_property(valarm, ICAL_TRIGGER_PROPERTY))) { 00424 ast_log(LOG_WARNING, "VALARM has no TRIGGER, skipping!\n"); 00425 ao2_link(pvt->events, event); 00426 event = ast_calendar_unref_event(event); 00427 return; 00428 } 00429 00430 trigger = icalproperty_get_trigger(prop); 00431 00432 if (icaltriggertype_is_null_trigger(trigger)) { 00433 ast_log(LOG_WARNING, "Bad TRIGGER for VALARM, skipping!\n"); 00434 ao2_link(pvt->events, event); 00435 event = ast_calendar_unref_event(event); 00436 return; 00437 } 00438 00439 if (!icaltime_is_null_time(trigger.time)) { /* This is an absolute time */ 00440 tmp = icaltime_convert_to_zone(trigger.time, utc); 00441 event->alarm = icaltime_as_timet_with_zone(tmp, utc); 00442 } else { /* Offset from either dtstart or dtend */ 00443 /* XXX Technically you can check RELATED to see if the event fires from the END of the event 00444 * But, I'm not sure I've ever seen anyone implement it in calendaring software, so I'm ignoring for now */ 00445 tmp = icaltime_add(start, trigger.duration); 00446 event->alarm = icaltime_as_timet_with_zone(tmp, utc); 00447 } 00448 00449 ao2_link(pvt->events, event); 00450 event = ast_calendar_unref_event(event); 00451 00452 return; 00453 }
static void caldav_destructor | ( | void * | obj | ) | [static] |
Definition at line 72 of file res_calendar_caldav.c.
References ao2_callback, ao2_ref, ast_debug, ast_string_field_free_memory, caldav_pvt::events, ast_calendar::name, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, caldav_pvt::owner, and caldav_pvt::session.
Referenced by caldav_load_calendar().
00073 { 00074 struct caldav_pvt *pvt = obj; 00075 00076 ast_debug(1, "Destroying pvt for CalDAV calendar %s\n", pvt->owner->name); 00077 if (pvt->session) { 00078 ne_session_destroy(pvt->session); 00079 } 00080 ast_string_field_free_memory(pvt); 00081 00082 ao2_callback(pvt->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL); 00083 00084 ao2_ref(pvt->events, -1); 00085 }
static struct ast_str* caldav_get_events_between | ( | struct caldav_pvt * | pvt, | |
time_t | start_time, | |||
time_t | end_time | |||
) | [static] |
Definition at line 263 of file res_calendar_caldav.c.
References ast_free, ast_log(), ast_str_append(), ast_str_create(), caldav_request(), and LOG_ERROR.
Referenced by update_caldav().
00264 { 00265 struct ast_str *body, *response; 00266 icaltimezone *utc = icaltimezone_get_utc_timezone(); 00267 icaltimetype start, end; 00268 const char *start_str, *end_str; 00269 00270 if (!(body = ast_str_create(512))) { 00271 ast_log(LOG_ERROR, "Could not allocate memory for body of request!\n"); 00272 return NULL; 00273 } 00274 00275 start = icaltime_from_timet_with_zone(start_time, 0, utc); 00276 end = icaltime_from_timet_with_zone(end_time, 0, utc); 00277 start_str = icaltime_as_ical_string(start); 00278 end_str = icaltime_as_ical_string(end); 00279 00280 /* If I was really being efficient, I would store a collection of event URIs and etags, 00281 * first doing a query of just the etag and seeing if anything had changed. If it had, 00282 * then I would do a request for each of the events that had changed, and only bother 00283 * updating those. Oh well. */ 00284 ast_str_append(&body, 0, 00285 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" 00286 "<C:calendar-query xmlns:D=\"DAV:\" xmlns:C=\"urn:ietf:params:xml:ns:caldav\">\n" 00287 " <D:prop>\n" 00288 " <C:calendar-data>\n" 00289 " <C:expand start=\"%s\" end=\"%s\"/>\n" 00290 " </C:calendar-data>\n" 00291 " </D:prop>\n" 00292 " <C:filter>\n" 00293 " <C:comp-filter name=\"VCALENDAR\">\n" 00294 " <C:comp-filter name=\"VEVENT\">\n" 00295 " <C:time-range start=\"%s\" end=\"%s\"/>\n" 00296 " </C:comp-filter>\n" 00297 " </C:comp-filter>\n" 00298 " </C:filter>\n" 00299 "</C:calendar-query>\n", start_str, end_str, start_str, end_str); 00300 00301 response = caldav_request(pvt, "REPORT", body, NULL, NULL); 00302 ast_free(body); 00303 00304 return response; 00305 }
static void * caldav_load_calendar | ( | void * | data | ) | [static] |
Definition at line 565 of file res_calendar_caldav.c.
References ao2_alloc, ao2_trylock, ao2_unlock, ast_calendar_config_acquire(), ast_calendar_config_release(), ast_calendar_event_container_alloc(), ast_cond_timedwait, ast_debug, ast_log(), ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_tvnow(), ast_variable_browse(), auth_credentials(), caldav_destructor(), LOG_ERROR, LOG_WARNING, ast_variable::name, ast_calendar::name, ast_variable::next, refreshlock, secret, ast_calendar::tech_pvt, tv, ast_calendar::unloading, unref_caldav(), update_caldav(), url, ast_variable::value, and verify_cert().
00566 { 00567 struct caldav_pvt *pvt; 00568 const struct ast_config *cfg; 00569 struct ast_variable *v; 00570 struct ast_calendar *cal = void_data; 00571 ast_mutex_t refreshlock; 00572 00573 if (!(cal && (cfg = ast_calendar_config_acquire()))) { 00574 ast_log(LOG_ERROR, "You must enable calendar support for res_caldav to load\n"); 00575 return NULL; 00576 } 00577 00578 if (ao2_trylock(cal)) { 00579 if (cal->unloading) { 00580 ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n"); 00581 } else { 00582 ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n"); 00583 } 00584 ast_calendar_config_release(); 00585 return NULL; 00586 } 00587 00588 if (!(pvt = ao2_alloc(sizeof(*pvt), caldav_destructor))) { 00589 ast_log(LOG_ERROR, "Could not allocate caldav_pvt structure for calendar: %s\n", cal->name); 00590 ast_calendar_config_release(); 00591 return NULL; 00592 } 00593 00594 pvt->owner = cal; 00595 00596 if (!(pvt->events = ast_calendar_event_container_alloc())) { 00597 ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name); 00598 pvt = unref_caldav(pvt); 00599 ao2_unlock(cal); 00600 ast_calendar_config_release(); 00601 return NULL; 00602 } 00603 00604 if (ast_string_field_init(pvt, 32)) { 00605 ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name); 00606 pvt = unref_caldav(pvt); 00607 ao2_unlock(cal); 00608 ast_calendar_config_release(); 00609 return NULL; 00610 } 00611 00612 for (v = ast_variable_browse(cfg, cal->name); v; v = v->next) { 00613 if (!strcasecmp(v->name, "url")) { 00614 ast_string_field_set(pvt, url, v->value); 00615 } else if (!strcasecmp(v->name, "user")) { 00616 ast_string_field_set(pvt, user, v->value); 00617 } else if (!strcasecmp(v->name, "secret")) { 00618 ast_string_field_set(pvt, secret, v->value); 00619 } 00620 } 00621 00622 ast_calendar_config_release(); 00623 00624 if (ast_strlen_zero(pvt->url)) { 00625 ast_log(LOG_WARNING, "No URL was specified for CalDAV calendar '%s' - skipping.\n", cal->name); 00626 pvt = unref_caldav(pvt); 00627 ao2_unlock(cal); 00628 return NULL; 00629 } 00630 00631 if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) { 00632 ast_log(LOG_WARNING, "Could not parse url '%s' for CalDAV calendar '%s' - skipping.\n", pvt->url, cal->name); 00633 pvt = unref_caldav(pvt); 00634 ao2_unlock(cal); 00635 return NULL; 00636 } 00637 00638 if (pvt->uri.scheme == NULL) { 00639 pvt->uri.scheme = "http"; 00640 } 00641 00642 if (pvt->uri.port == 0) { 00643 pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme); 00644 } 00645 00646 pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port); 00647 ne_redirect_register(pvt->session); 00648 ne_set_server_auth(pvt->session, auth_credentials, pvt); 00649 if (!strcasecmp(pvt->uri.scheme, "https")) { 00650 ne_ssl_trust_default_ca(pvt->session); 00651 ne_ssl_set_verify(pvt->session, verify_cert, NULL); 00652 } 00653 00654 cal->tech_pvt = pvt; 00655 00656 ast_mutex_init(&refreshlock); 00657 00658 /* Load it the first time */ 00659 update_caldav(pvt); 00660 00661 ao2_unlock(cal); 00662 00663 /* The only writing from another thread will be if unload is true */ 00664 for (;;) { 00665 struct timeval tv = ast_tvnow(); 00666 struct timespec ts = {0,}; 00667 00668 ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh); 00669 00670 ast_mutex_lock(&refreshlock); 00671 while (!pvt->owner->unloading) { 00672 if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) { 00673 break; 00674 } 00675 } 00676 ast_mutex_unlock(&refreshlock); 00677 00678 if (pvt->owner->unloading) { 00679 ast_debug(10, "Skipping refresh since we got a shutdown signal\n"); 00680 return NULL; 00681 } 00682 00683 ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh); 00684 00685 update_caldav(pvt); 00686 } 00687 00688 return NULL; 00689 }
static struct ast_str* caldav_request | ( | struct caldav_pvt * | pvt, | |
const char * | method, | |||
struct ast_str * | req_body, | |||
struct ast_str * | subdir, | |||
const char * | content_type | |||
) | [static] |
Definition at line 126 of file res_calendar_caldav.c.
References ast_free, ast_log(), ast_str_buffer(), ast_str_create(), ast_str_strlen(), ast_strlen_zero(), fetch_response_reader(), LOG_ERROR, LOG_WARNING, ast_calendar::name, caldav_pvt::owner, caldav_pvt::session, and caldav_pvt::uri.
Referenced by caldav_get_events_between(), and caldav_write_event().
00127 { 00128 struct ast_str *response; 00129 ne_request *req; 00130 int ret; 00131 char buf[1000]; 00132 00133 if (!pvt) { 00134 ast_log(LOG_ERROR, "There is no private!\n"); 00135 return NULL; 00136 } 00137 00138 if (!(response = ast_str_create(512))) { 00139 ast_log(LOG_ERROR, "Could not allocate memory for response.\n"); 00140 return NULL; 00141 } 00142 00143 snprintf(buf, sizeof(buf), "%s%s", pvt->uri.path, subdir ? ast_str_buffer(subdir) : ""); 00144 00145 req = ne_request_create(pvt->session, method, buf); 00146 ne_add_response_body_reader(req, ne_accept_2xx, fetch_response_reader, &response); 00147 ne_set_request_body_buffer(req, ast_str_buffer(req_body), ast_str_strlen(req_body)); 00148 ne_add_request_header(req, "Content-type", ast_strlen_zero(content_type) ? "text/xml" : content_type); 00149 00150 ret = ne_request_dispatch(req); 00151 ne_request_destroy(req); 00152 00153 if (ret != NE_OK || !ast_str_strlen(response)) { 00154 if (ret != NE_OK) { 00155 ast_log(LOG_WARNING, "Unknown response to CalDAV calendar %s, request %s to %s: %s\n", pvt->owner->name, method, buf, ne_get_error(pvt->session)); 00156 } 00157 ast_free(response); 00158 return NULL; 00159 } 00160 00161 return response; 00162 }
static int caldav_write_event | ( | struct ast_calendar_event * | event | ) | [static] |
Definition at line 164 of file res_calendar_caldav.c.
References AST_CALENDAR_BS_BUSY, AST_CALENDAR_BS_BUSY_TENTATIVE, ast_free, ast_log(), ast_random(), ast_str_append(), ast_str_create(), ast_str_set(), ast_string_field_build, ast_strlen_zero(), ast_calendar_event::busy_state, caldav_request(), ast_calendar_event::categories, ast_calendar_event::description, ast_calendar_event::end, ast_calendar_event::location, LOG_ERROR, LOG_WARNING, ast_calendar_event::organizer, ast_calendar_event::owner, ast_calendar_event::priority, ast_calendar_event::start, ast_calendar_event::summary, ast_calendar::tech_pvt, ast_calendar_event::uid, and caldav_pvt::url.
00165 { 00166 struct caldav_pvt *pvt; 00167 struct ast_str *body = NULL, *response = NULL, *subdir = NULL; 00168 icalcomponent *calendar, *icalevent; 00169 icaltimezone *utc = icaltimezone_get_utc_timezone(); 00170 int ret = -1; 00171 00172 if (!event) { 00173 ast_log(LOG_WARNING, "No event passed!\n"); 00174 return -1; 00175 } 00176 00177 if (!(event->start && event->end)) { 00178 ast_log(LOG_WARNING, "The event must contain a start and an end\n"); 00179 return -1; 00180 } 00181 if (!(body = ast_str_create(512)) || 00182 !(subdir = ast_str_create(32)) || 00183 !(response = ast_str_create(512))) { 00184 ast_log(LOG_ERROR, "Could not allocate memory for request and response!\n"); 00185 goto write_cleanup; 00186 } 00187 00188 pvt = event->owner->tech_pvt; 00189 00190 if (ast_strlen_zero(event->uid)) { 00191 unsigned short val[8]; 00192 int x; 00193 for (x = 0; x < 8; x++) { 00194 val[x] = ast_random(); 00195 } 00196 ast_string_field_build(event, uid, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]); 00197 } 00198 00199 calendar = icalcomponent_new(ICAL_VCALENDAR_COMPONENT); 00200 icalcomponent_add_property(calendar, icalproperty_new_version("2.0")); 00201 icalcomponent_add_property(calendar, icalproperty_new_prodid("-//Digium, Inc.//res_caldav//EN")); 00202 00203 icalevent = icalcomponent_new(ICAL_VEVENT_COMPONENT); 00204 icalcomponent_add_property(icalevent, icalproperty_new_dtstamp(icaltime_current_time_with_zone(utc))); 00205 icalcomponent_add_property(icalevent, icalproperty_new_uid(event->uid)); 00206 icalcomponent_add_property(icalevent, icalproperty_new_dtstart(icaltime_from_timet_with_zone(event->start, 0, utc))); 00207 icalcomponent_add_property(icalevent, icalproperty_new_dtend(icaltime_from_timet_with_zone(event->end, 0, utc))); 00208 if (!ast_strlen_zero(event->organizer)) { 00209 icalcomponent_add_property(icalevent, icalproperty_new_organizer(event->organizer)); 00210 } 00211 if (!ast_strlen_zero(event->summary)) { 00212 icalcomponent_add_property(icalevent, icalproperty_new_summary(event->summary)); 00213 } 00214 if (!ast_strlen_zero(event->description)) { 00215 icalcomponent_add_property(icalevent, icalproperty_new_description(event->description)); 00216 } 00217 if (!ast_strlen_zero(event->location)) { 00218 icalcomponent_add_property(icalevent, icalproperty_new_location(event->location)); 00219 } 00220 if (!ast_strlen_zero(event->categories)) { 00221 icalcomponent_add_property(icalevent, icalproperty_new_categories(event->categories)); 00222 } 00223 if (event->priority > 0) { 00224 icalcomponent_add_property(icalevent, icalproperty_new_priority(event->priority)); 00225 } 00226 00227 switch (event->busy_state) { 00228 case AST_CALENDAR_BS_BUSY: 00229 icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_CONFIRMED)); 00230 break; 00231 00232 case AST_CALENDAR_BS_BUSY_TENTATIVE: 00233 icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_TENTATIVE)); 00234 break; 00235 00236 default: 00237 icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_NONE)); 00238 } 00239 00240 icalcomponent_add_component(calendar, icalevent); 00241 00242 ast_str_append(&body, 0, "%s", icalcomponent_as_ical_string(calendar)); 00243 ast_str_set(&subdir, 0, "%s%s.ics", pvt->url[strlen(pvt->url) - 1] == '/' ? "" : "/", event->uid); 00244 00245 response = caldav_request(pvt, "PUT", body, subdir, "text/calendar"); 00246 00247 ret = 0; 00248 00249 write_cleanup: 00250 if (body) { 00251 ast_free(body); 00252 } 00253 if (response) { 00254 ast_free(response); 00255 } 00256 if (subdir) { 00257 ast_free(subdir); 00258 } 00259 00260 return ret; 00261 }
static int fetch_response_reader | ( | void * | data, | |
const char * | block, | |||
size_t | len | |||
) | [static] |
Definition at line 95 of file res_calendar_caldav.c.
References ast_free, ast_malloc, and ast_str_append().
Referenced by caldav_request(), exchangecal_request(), and fetch_icalendar().
00096 { 00097 struct ast_str **response = data; 00098 unsigned char *tmp; 00099 00100 if (!(tmp = ast_malloc(len + 1))) { 00101 return -1; 00102 } 00103 memcpy(tmp, block, len); 00104 tmp[len] = '\0'; 00105 ast_str_append(response, 0, "%s", tmp); 00106 ast_free(tmp); 00107 00108 return 0; 00109 }
static void handle_characters | ( | void * | data, | |
const xmlChar * | ch, | |||
int | len | |||
) | [static] |
Definition at line 505 of file res_calendar_caldav.c.
References ast_str_append(), and state.
Referenced by update_caldav().
00506 { 00507 struct xmlstate *state = data; 00508 xmlChar *tmp; 00509 00510 if (!state->in_caldata) { 00511 return; 00512 } 00513 00514 tmp = xmlStrndup(ch, len); 00515 ast_str_append(&state->cdata, 0, "%s", (char *)tmp); 00516 xmlFree(tmp); 00517 }
static void handle_end_element | ( | void * | data, | |
const xmlChar * | name | |||
) | [static] |
Definition at line 473 of file res_calendar_caldav.c.
References ast_str_buffer(), ast_str_strlen(), caldav_add_event(), and state.
Referenced by update_caldav().
00474 { 00475 struct xmlstate *state = data; 00476 struct icaltimetype start, end; 00477 icaltimezone *utc = icaltimezone_get_utc_timezone(); 00478 icalcomponent *iter; 00479 icalcomponent *comp; 00480 00481 if (xmlStrcasecmp(name, BAD_CAST "C:calendar-data")) { 00482 return; 00483 } 00484 00485 state->in_caldata = 0; 00486 if (!(state->cdata && ast_str_strlen(state->cdata))) { 00487 return; 00488 } 00489 /* XXX Parse the calendar blurb for recurrence events in the time range, 00490 * create an event, and add it to pvt->events */ 00491 start = icaltime_from_timet_with_zone(state->start, 0, utc); 00492 end = icaltime_from_timet_with_zone(state->end, 0, utc); 00493 comp = icalparser_parse_string(ast_str_buffer(state->cdata)); 00494 00495 for (iter = icalcomponent_get_first_component(comp, ICAL_VEVENT_COMPONENT); 00496 iter; 00497 iter = icalcomponent_get_next_component(comp, ICAL_VEVENT_COMPONENT)) 00498 { 00499 icalcomponent_foreach_recurrence(iter, start, end, caldav_add_event, state->pvt); 00500 } 00501 00502 icalcomponent_free(comp); 00503 }
static void handle_start_element | ( | void * | data, | |
const xmlChar * | fullname, | |||
const xmlChar ** | atts | |||
) | [static] |
Definition at line 463 of file res_calendar_caldav.c.
References ast_str_reset(), and state.
Referenced by update_caldav().
00464 { 00465 struct xmlstate *state = data; 00466 00467 if (!xmlStrcasecmp(fullname, BAD_CAST "C:calendar-data")) { 00468 state->in_caldata = 1; 00469 ast_str_reset(state->cdata); 00470 } 00471 }
static time_t icalfloat_to_timet | ( | icaltimetype | time | ) | [static] |
Definition at line 307 of file res_calendar_caldav.c.
References ast_mktime(), ast_tm::tm_hour, ast_tm::tm_isdst, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, and ast_tm::tm_year.
Referenced by caldav_add_event(), and icalendar_add_event().
00308 { 00309 struct ast_tm tm = {0,}; 00310 struct timeval tv; 00311 00312 tm.tm_mday = time.day; 00313 tm.tm_mon = time.month - 1; 00314 tm.tm_year = time.year - 1900; 00315 tm.tm_hour = time.hour; 00316 tm.tm_min = time.minute; 00317 tm.tm_sec = time.second; 00318 tm.tm_isdst = -1; 00319 tv = ast_mktime(&tm, NULL); 00320 00321 return tv.tv_sec; 00322 }
static int load_module | ( | void | ) | [static] |
Definition at line 691 of file res_calendar_caldav.c.
References ast_calendar_register(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and caldav_tech.
00692 { 00693 ne_sock_init(); 00694 if (ast_calendar_register(&caldav_tech)) { 00695 ne_sock_exit(); 00696 return AST_MODULE_LOAD_DECLINE; 00697 } 00698 00699 return AST_MODULE_LOAD_SUCCESS; 00700 }
static int unload_module | ( | void | ) | [static] |
Definition at line 702 of file res_calendar_caldav.c.
References ast_calendar_unregister(), and caldav_tech.
00703 { 00704 ast_calendar_unregister(&caldav_tech); 00705 ne_sock_exit(); 00706 return 0; 00707 }
static void * unref_caldav | ( | void * | obj | ) | [static] |
Definition at line 87 of file res_calendar_caldav.c.
References ao2_ref.
Referenced by caldav_load_calendar().
00088 { 00089 struct caldav_pvt *pvt = obj; 00090 00091 ao2_ref(pvt, -1); 00092 return NULL; 00093 }
static int update_caldav | ( | struct caldav_pvt * | pvt | ) | [static] |
Definition at line 519 of file res_calendar_caldav.c.
References ast_calendar_merge_events(), ast_free, ast_str_buffer(), ast_str_create(), ast_str_strlen(), ast_tvnow(), caldav_get_events_between(), caldav_pvt::events, handle_characters(), handle_end_element(), handle_start_element(), caldav_pvt::owner, xmlstate::pvt, state, and ast_calendar::timeframe.
Referenced by caldav_load_calendar().
00520 { 00521 struct timeval now = ast_tvnow(); 00522 time_t start, end; 00523 struct ast_str *response; 00524 xmlSAXHandler saxHandler; 00525 struct xmlstate state = { 00526 .in_caldata = 0, 00527 .pvt = pvt 00528 }; 00529 00530 start = now.tv_sec; 00531 end = now.tv_sec + 60 * pvt->owner->timeframe; 00532 if (!(response = caldav_get_events_between(pvt, start, end))) { 00533 return -1; 00534 } 00535 00536 if (!(state.cdata = ast_str_create(512))) { 00537 ast_free(response); 00538 return -1; 00539 } 00540 00541 state.start = start; 00542 state.end = end; 00543 00544 memset(&saxHandler, 0, sizeof(saxHandler)); 00545 saxHandler.startElement = handle_start_element; 00546 saxHandler.endElement = handle_end_element; 00547 saxHandler.characters = handle_characters; 00548 00549 xmlSAXUserParseMemory(&saxHandler, &state, ast_str_buffer(response), ast_str_strlen(response)); 00550 00551 ast_calendar_merge_events(pvt->owner, pvt->events); 00552 00553 ast_free(response); 00554 ast_free(state.cdata); 00555 00556 return 0; 00557 }
static int verify_cert | ( | void * | userdata, | |
int | failures, | |||
const ne_ssl_certificate * | cert | |||
) | [static] |
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Asterisk CalDAV Calendar Integration" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, } [static] |
Definition at line 713 of file res_calendar_caldav.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 713 of file res_calendar_caldav.c.
struct ast_calendar_tech caldav_tech [static] |
Definition at line 51 of file res_calendar_caldav.c.
Referenced by load_module(), and unload_module().