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