#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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 715 of file res_calendar_caldav.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 715 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 334 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().
00335 { 00336 struct caldav_pvt *pvt = data; 00337 struct ast_calendar_event *event; 00338 icaltimezone *utc = icaltimezone_get_utc_timezone(); 00339 icaltimetype start, end, tmp; 00340 icalcomponent *valarm; 00341 icalproperty *prop; 00342 struct icaltriggertype trigger; 00343 00344 if (!(pvt && pvt->owner)) { 00345 ast_log(LOG_ERROR, "Require a private structure with an owner\n"); 00346 return; 00347 } 00348 00349 if (!(event = ast_calendar_event_alloc(pvt->owner))) { 00350 ast_log(LOG_ERROR, "Could not allocate an event!\n"); 00351 return; 00352 } 00353 00354 start = icalcomponent_get_dtstart(comp); 00355 end = icalcomponent_get_dtend(comp); 00356 00357 event->start = icaltime_get_tzid(start) ? span->start : icalfloat_to_timet(start); 00358 event->end = icaltime_get_tzid(end) ? span->end : icalfloat_to_timet(end); 00359 event->busy_state = span->is_busy ? AST_CALENDAR_BS_BUSY : AST_CALENDAR_BS_FREE; 00360 00361 if ((prop = icalcomponent_get_first_property(comp, ICAL_SUMMARY_PROPERTY))) { 00362 ast_string_field_set(event, summary, icalproperty_get_value_as_string(prop)); 00363 } 00364 00365 if ((prop = icalcomponent_get_first_property(comp, ICAL_DESCRIPTION_PROPERTY))) { 00366 ast_string_field_set(event, description, icalproperty_get_value_as_string(prop)); 00367 } 00368 00369 if ((prop = icalcomponent_get_first_property(comp, ICAL_ORGANIZER_PROPERTY))) { 00370 ast_string_field_set(event, organizer, icalproperty_get_value_as_string(prop)); 00371 } 00372 00373 if ((prop = icalcomponent_get_first_property(comp, ICAL_LOCATION_PROPERTY))) { 00374 ast_string_field_set(event, location, icalproperty_get_value_as_string(prop)); 00375 } 00376 00377 if ((prop = icalcomponent_get_first_property(comp, ICAL_CATEGORIES_PROPERTY))) { 00378 ast_string_field_set(event, categories, icalproperty_get_value_as_string(prop)); 00379 } 00380 00381 if ((prop = icalcomponent_get_first_property(comp, ICAL_PRIORITY_PROPERTY))) { 00382 event->priority = icalvalue_get_integer(icalproperty_get_value(prop)); 00383 } 00384 00385 if ((prop = icalcomponent_get_first_property(comp, ICAL_UID_PROPERTY))) { 00386 ast_string_field_set(event, uid, icalproperty_get_value_as_string(prop)); 00387 } else { 00388 ast_log(LOG_WARNING, "No UID found, but one is required. Generating, but updates may not be acurate\n"); 00389 if (!ast_strlen_zero(event->summary)) { 00390 ast_string_field_set(event, uid, event->summary); 00391 } else { 00392 char tmp[100]; 00393 snprintf(tmp, sizeof(tmp), "%lu", event->start); 00394 ast_string_field_set(event, uid, tmp); 00395 } 00396 } 00397 00398 /* Get the attendees */ 00399 for (prop = icalcomponent_get_first_property(comp, ICAL_ATTENDEE_PROPERTY); 00400 prop; prop = icalcomponent_get_next_property(comp, ICAL_ATTENDEE_PROPERTY)) { 00401 struct ast_calendar_attendee *attendee; 00402 const char *data; 00403 00404 if (!(attendee = ast_calloc(1, sizeof(*attendee)))) { 00405 event = ast_calendar_unref_event(event); 00406 return; 00407 } 00408 data = icalproperty_get_attendee(prop); 00409 if (!ast_strlen_zero(data)) { 00410 attendee->data = ast_strdup(data);; 00411 AST_LIST_INSERT_TAIL(&event->attendees, attendee, next); 00412 } 00413 } 00414 00415 00416 /* Only set values for alarm based on VALARM. Can be overriden in main/calendar.c by autoreminder 00417 * therefore, go ahead and add events even if their is no VALARM or it is malformed 00418 * Currently we are only getting the first VALARM and are handling repitition in main/calendar.c from calendar.conf */ 00419 if (!(valarm = icalcomponent_get_first_component(comp, ICAL_VALARM_COMPONENT))) { 00420 ao2_link(pvt->events, event); 00421 event = ast_calendar_unref_event(event); 00422 return; 00423 } 00424 00425 if (!(prop = icalcomponent_get_first_property(valarm, ICAL_TRIGGER_PROPERTY))) { 00426 ast_log(LOG_WARNING, "VALARM has no TRIGGER, skipping!\n"); 00427 ao2_link(pvt->events, event); 00428 event = ast_calendar_unref_event(event); 00429 return; 00430 } 00431 00432 trigger = icalproperty_get_trigger(prop); 00433 00434 if (icaltriggertype_is_null_trigger(trigger)) { 00435 ast_log(LOG_WARNING, "Bad TRIGGER for VALARM, skipping!\n"); 00436 ao2_link(pvt->events, event); 00437 event = ast_calendar_unref_event(event); 00438 return; 00439 } 00440 00441 if (!icaltime_is_null_time(trigger.time)) { /* This is an absolute time */ 00442 tmp = icaltime_convert_to_zone(trigger.time, utc); 00443 event->alarm = icaltime_as_timet_with_zone(tmp, utc); 00444 } else { /* Offset from either dtstart or dtend */ 00445 /* XXX Technically you can check RELATED to see if the event fires from the END of the event 00446 * But, I'm not sure I've ever seen anyone implement it in calendaring software, so I'm ignoring for now */ 00447 tmp = icaltime_add(start, trigger.duration); 00448 event->alarm = icaltime_as_timet_with_zone(tmp, utc); 00449 } 00450 00451 ao2_link(pvt->events, event); 00452 event = ast_calendar_unref_event(event); 00453 00454 return; 00455 }
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 265 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().
00266 { 00267 struct ast_str *body, *response; 00268 icaltimezone *utc = icaltimezone_get_utc_timezone(); 00269 icaltimetype start, end; 00270 const char *start_str, *end_str; 00271 00272 if (!(body = ast_str_create(512))) { 00273 ast_log(LOG_ERROR, "Could not allocate memory for body of request!\n"); 00274 return NULL; 00275 } 00276 00277 start = icaltime_from_timet_with_zone(start_time, 0, utc); 00278 end = icaltime_from_timet_with_zone(end_time, 0, utc); 00279 start_str = icaltime_as_ical_string(start); 00280 end_str = icaltime_as_ical_string(end); 00281 00282 /* If I was really being efficient, I would store a collection of event URIs and etags, 00283 * first doing a query of just the etag and seeing if anything had changed. If it had, 00284 * then I would do a request for each of the events that had changed, and only bother 00285 * updating those. Oh well. */ 00286 ast_str_append(&body, 0, 00287 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" 00288 "<C:calendar-query xmlns:D=\"DAV:\" xmlns:C=\"urn:ietf:params:xml:ns:caldav\">\n" 00289 " <D:prop>\n" 00290 " <C:calendar-data>\n" 00291 " <C:expand start=\"%s\" end=\"%s\"/>\n" 00292 " </C:calendar-data>\n" 00293 " </D:prop>\n" 00294 " <C:filter>\n" 00295 " <C:comp-filter name=\"VCALENDAR\">\n" 00296 " <C:comp-filter name=\"VEVENT\">\n" 00297 " <C:time-range start=\"%s\" end=\"%s\"/>\n" 00298 " </C:comp-filter>\n" 00299 " </C:comp-filter>\n" 00300 " </C:filter>\n" 00301 "</C:calendar-query>\n", start_str, end_str, start_str, end_str); 00302 00303 response = caldav_request(pvt, "REPORT", body, NULL, NULL); 00304 ast_free(body); 00305 00306 return response; 00307 }
static void * caldav_load_calendar | ( | void * | data | ) | [static] |
Definition at line 567 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().
00568 { 00569 struct caldav_pvt *pvt; 00570 const struct ast_config *cfg; 00571 struct ast_variable *v; 00572 struct ast_calendar *cal = void_data; 00573 ast_mutex_t refreshlock; 00574 00575 if (!(cal && (cfg = ast_calendar_config_acquire()))) { 00576 ast_log(LOG_ERROR, "You must enable calendar support for res_caldav to load\n"); 00577 return NULL; 00578 } 00579 00580 if (ao2_trylock(cal)) { 00581 if (cal->unloading) { 00582 ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n"); 00583 } else { 00584 ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n"); 00585 } 00586 ast_calendar_config_release(); 00587 return NULL; 00588 } 00589 00590 if (!(pvt = ao2_alloc(sizeof(*pvt), caldav_destructor))) { 00591 ast_log(LOG_ERROR, "Could not allocate caldav_pvt structure for calendar: %s\n", cal->name); 00592 ast_calendar_config_release(); 00593 return NULL; 00594 } 00595 00596 pvt->owner = cal; 00597 00598 if (!(pvt->events = ast_calendar_event_container_alloc())) { 00599 ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name); 00600 pvt = unref_caldav(pvt); 00601 ao2_unlock(cal); 00602 ast_calendar_config_release(); 00603 return NULL; 00604 } 00605 00606 if (ast_string_field_init(pvt, 32)) { 00607 ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name); 00608 pvt = unref_caldav(pvt); 00609 ao2_unlock(cal); 00610 ast_calendar_config_release(); 00611 return NULL; 00612 } 00613 00614 for (v = ast_variable_browse(cfg, cal->name); v; v = v->next) { 00615 if (!strcasecmp(v->name, "url")) { 00616 ast_string_field_set(pvt, url, v->value); 00617 } else if (!strcasecmp(v->name, "user")) { 00618 ast_string_field_set(pvt, user, v->value); 00619 } else if (!strcasecmp(v->name, "secret")) { 00620 ast_string_field_set(pvt, secret, v->value); 00621 } 00622 } 00623 00624 ast_calendar_config_release(); 00625 00626 if (ast_strlen_zero(pvt->url)) { 00627 ast_log(LOG_WARNING, "No URL was specified for CalDAV calendar '%s' - skipping.\n", cal->name); 00628 pvt = unref_caldav(pvt); 00629 ao2_unlock(cal); 00630 return NULL; 00631 } 00632 00633 if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) { 00634 ast_log(LOG_WARNING, "Could not parse url '%s' for CalDAV calendar '%s' - skipping.\n", pvt->url, cal->name); 00635 pvt = unref_caldav(pvt); 00636 ao2_unlock(cal); 00637 return NULL; 00638 } 00639 00640 if (pvt->uri.scheme == NULL) { 00641 pvt->uri.scheme = "http"; 00642 } 00643 00644 if (pvt->uri.port == 0) { 00645 pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme); 00646 } 00647 00648 pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port); 00649 ne_redirect_register(pvt->session); 00650 ne_set_server_auth(pvt->session, auth_credentials, pvt); 00651 if (!strcasecmp(pvt->uri.scheme, "https")) { 00652 ne_ssl_trust_default_ca(pvt->session); 00653 ne_ssl_set_verify(pvt->session, verify_cert, NULL); 00654 } 00655 00656 cal->tech_pvt = pvt; 00657 00658 ast_mutex_init(&refreshlock); 00659 00660 /* Load it the first time */ 00661 update_caldav(pvt); 00662 00663 ao2_unlock(cal); 00664 00665 /* The only writing from another thread will be if unload is true */ 00666 for (;;) { 00667 struct timeval tv = ast_tvnow(); 00668 struct timespec ts = {0,}; 00669 00670 ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh); 00671 00672 ast_mutex_lock(&refreshlock); 00673 while (!pvt->owner->unloading) { 00674 if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) { 00675 break; 00676 } 00677 } 00678 ast_mutex_unlock(&refreshlock); 00679 00680 if (pvt->owner->unloading) { 00681 ast_debug(10, "Skipping refresh since we got a shutdown signal\n"); 00682 return NULL; 00683 } 00684 00685 ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh); 00686 00687 update_caldav(pvt); 00688 } 00689 00690 return NULL; 00691 }
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 !(response = ast_str_create(512))) { 00186 ast_log(LOG_ERROR, "Could not allocate memory for request and response!\n"); 00187 goto write_cleanup; 00188 } 00189 00190 pvt = event->owner->tech_pvt; 00191 00192 if (ast_strlen_zero(event->uid)) { 00193 unsigned short val[8]; 00194 int x; 00195 for (x = 0; x < 8; x++) { 00196 val[x] = ast_random(); 00197 } 00198 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]); 00199 } 00200 00201 calendar = icalcomponent_new(ICAL_VCALENDAR_COMPONENT); 00202 icalcomponent_add_property(calendar, icalproperty_new_version("2.0")); 00203 icalcomponent_add_property(calendar, icalproperty_new_prodid("-//Digium, Inc.//res_caldav//EN")); 00204 00205 icalevent = icalcomponent_new(ICAL_VEVENT_COMPONENT); 00206 icalcomponent_add_property(icalevent, icalproperty_new_dtstamp(icaltime_current_time_with_zone(utc))); 00207 icalcomponent_add_property(icalevent, icalproperty_new_uid(event->uid)); 00208 icalcomponent_add_property(icalevent, icalproperty_new_dtstart(icaltime_from_timet_with_zone(event->start, 0, utc))); 00209 icalcomponent_add_property(icalevent, icalproperty_new_dtend(icaltime_from_timet_with_zone(event->end, 0, utc))); 00210 if (!ast_strlen_zero(event->organizer)) { 00211 icalcomponent_add_property(icalevent, icalproperty_new_organizer(event->organizer)); 00212 } 00213 if (!ast_strlen_zero(event->summary)) { 00214 icalcomponent_add_property(icalevent, icalproperty_new_summary(event->summary)); 00215 } 00216 if (!ast_strlen_zero(event->description)) { 00217 icalcomponent_add_property(icalevent, icalproperty_new_description(event->description)); 00218 } 00219 if (!ast_strlen_zero(event->location)) { 00220 icalcomponent_add_property(icalevent, icalproperty_new_location(event->location)); 00221 } 00222 if (!ast_strlen_zero(event->categories)) { 00223 icalcomponent_add_property(icalevent, icalproperty_new_categories(event->categories)); 00224 } 00225 if (event->priority > 0) { 00226 icalcomponent_add_property(icalevent, icalproperty_new_priority(event->priority)); 00227 } 00228 00229 switch (event->busy_state) { 00230 case AST_CALENDAR_BS_BUSY: 00231 icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_CONFIRMED)); 00232 break; 00233 00234 case AST_CALENDAR_BS_BUSY_TENTATIVE: 00235 icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_TENTATIVE)); 00236 break; 00237 00238 default: 00239 icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_NONE)); 00240 } 00241 00242 icalcomponent_add_component(calendar, icalevent); 00243 00244 ast_str_append(&body, 0, "%s", icalcomponent_as_ical_string(calendar)); 00245 ast_str_set(&subdir, 0, "%s%s.ics", pvt->url[strlen(pvt->url) - 1] == '/' ? "" : "/", event->uid); 00246 00247 response = caldav_request(pvt, "PUT", body, subdir, "text/calendar"); 00248 00249 ret = 0; 00250 00251 write_cleanup: 00252 if (body) { 00253 ast_free(body); 00254 } 00255 if (response) { 00256 ast_free(response); 00257 } 00258 if (subdir) { 00259 ast_free(subdir); 00260 } 00261 00262 return ret; 00263 }
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 507 of file res_calendar_caldav.c.
References ast_str_append(), and state.
Referenced by update_caldav().
00508 { 00509 struct xmlstate *state = data; 00510 xmlChar *tmp; 00511 00512 if (!state->in_caldata) { 00513 return; 00514 } 00515 00516 tmp = xmlStrndup(ch, len); 00517 ast_str_append(&state->cdata, 0, "%s", (char *)tmp); 00518 xmlFree(tmp); 00519 }
static void handle_end_element | ( | void * | data, | |
const xmlChar * | name | |||
) | [static] |
Definition at line 475 of file res_calendar_caldav.c.
References ast_str_buffer(), ast_str_strlen(), caldav_add_event(), and state.
Referenced by update_caldav().
00476 { 00477 struct xmlstate *state = data; 00478 struct icaltimetype start, end; 00479 icaltimezone *utc = icaltimezone_get_utc_timezone(); 00480 icalcomponent *iter; 00481 icalcomponent *comp; 00482 00483 if (xmlStrcasecmp(name, BAD_CAST "C:calendar-data")) { 00484 return; 00485 } 00486 00487 state->in_caldata = 0; 00488 if (!(state->cdata && ast_str_strlen(state->cdata))) { 00489 return; 00490 } 00491 /* XXX Parse the calendar blurb for recurrence events in the time range, 00492 * create an event, and add it to pvt->events */ 00493 start = icaltime_from_timet_with_zone(state->start, 0, utc); 00494 end = icaltime_from_timet_with_zone(state->end, 0, utc); 00495 comp = icalparser_parse_string(ast_str_buffer(state->cdata)); 00496 00497 for (iter = icalcomponent_get_first_component(comp, ICAL_VEVENT_COMPONENT); 00498 iter; 00499 iter = icalcomponent_get_next_component(comp, ICAL_VEVENT_COMPONENT)) 00500 { 00501 icalcomponent_foreach_recurrence(iter, start, end, caldav_add_event, state->pvt); 00502 } 00503 00504 icalcomponent_free(comp); 00505 }
static void handle_start_element | ( | void * | data, | |
const xmlChar * | fullname, | |||
const xmlChar ** | atts | |||
) | [static] |
Definition at line 465 of file res_calendar_caldav.c.
References ast_str_reset(), and state.
Referenced by update_caldav().
00466 { 00467 struct xmlstate *state = data; 00468 00469 if (!xmlStrcasecmp(fullname, BAD_CAST "C:calendar-data")) { 00470 state->in_caldata = 1; 00471 ast_str_reset(state->cdata); 00472 } 00473 }
static time_t icalfloat_to_timet | ( | icaltimetype | time | ) | [static] |
Definition at line 309 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().
00310 { 00311 struct ast_tm tm = {0,}; 00312 struct timeval tv; 00313 00314 tm.tm_mday = time.day; 00315 tm.tm_mon = time.month - 1; 00316 tm.tm_year = time.year - 1900; 00317 tm.tm_hour = time.hour; 00318 tm.tm_min = time.minute; 00319 tm.tm_sec = time.second; 00320 tm.tm_isdst = -1; 00321 tv = ast_mktime(&tm, NULL); 00322 00323 return tv.tv_sec; 00324 }
static int load_module | ( | void | ) | [static] |
Definition at line 693 of file res_calendar_caldav.c.
References ast_calendar_register(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and caldav_tech.
00694 { 00695 ne_sock_init(); 00696 if (ast_calendar_register(&caldav_tech)) { 00697 ne_sock_exit(); 00698 return AST_MODULE_LOAD_DECLINE; 00699 } 00700 00701 return AST_MODULE_LOAD_SUCCESS; 00702 }
static int unload_module | ( | void | ) | [static] |
Definition at line 704 of file res_calendar_caldav.c.
References ast_calendar_unregister(), and caldav_tech.
00705 { 00706 ast_calendar_unregister(&caldav_tech); 00707 ne_sock_exit(); 00708 return 0; 00709 }
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 521 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().
00522 { 00523 struct timeval now = ast_tvnow(); 00524 time_t start, end; 00525 struct ast_str *response; 00526 xmlSAXHandler saxHandler; 00527 struct xmlstate state = { 00528 .in_caldata = 0, 00529 .pvt = pvt 00530 }; 00531 00532 start = now.tv_sec; 00533 end = now.tv_sec + 60 * pvt->owner->timeframe; 00534 if (!(response = caldav_get_events_between(pvt, start, end))) { 00535 return -1; 00536 } 00537 00538 if (!(state.cdata = ast_str_create(512))) { 00539 ast_free(response); 00540 return -1; 00541 } 00542 00543 state.start = start; 00544 state.end = end; 00545 00546 memset(&saxHandler, 0, sizeof(saxHandler)); 00547 saxHandler.startElement = handle_start_element; 00548 saxHandler.endElement = handle_end_element; 00549 saxHandler.characters = handle_characters; 00550 00551 xmlSAXUserParseMemory(&saxHandler, &state, ast_str_buffer(response), ast_str_strlen(response)); 00552 00553 ast_calendar_merge_events(pvt->owner, pvt->events); 00554 00555 ast_free(response); 00556 ast_free(state.cdata); 00557 00558 return 0; 00559 }
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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, } [static] |
Definition at line 715 of file res_calendar_caldav.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 715 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().