Asterisk - The Open Source Telephony Project GIT-master-7e7a603
Data Structures | Functions | Variables
res_calendar_caldav.c File Reference

Resource for handling CalDAV calendars. More...

#include "asterisk.h"
#include <libical/ical.h>
#include <ne_session.h>
#include <ne_uri.h>
#include <ne_request.h>
#include <ne_auth.h>
#include <ne_redirect.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/calendar.h"
#include "asterisk/lock.h"
#include "asterisk/config.h"
#include "asterisk/astobj2.h"
Include dependency graph for res_calendar_caldav.c:

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)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int auth_credentials (void *userdata, const char *realm, int attempts, char *username, char *secret)
 
static void caldav_add_event (icalcomponent *comp, struct icaltime_span *span, void *data)
 
static void caldav_destructor (void *obj)
 
static struct ast_strcaldav_get_events_between (struct caldav_pvt *pvt, time_t start_time, time_t end_time)
 
static void * caldav_load_calendar (void *data)
 
static struct ast_strcaldav_request (struct caldav_pvt *pvt, const char *method, struct ast_str *req_body, struct ast_str *subdir, const char *content_type)
 
static int caldav_write_event (struct ast_calendar_event *event)
 
static int debug_response_handler (void *userdata, ne_request *req, const ne_status *st)
 
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 *localname, const xmlChar *prefix, const xmlChar *uri)
 
static void handle_start_element (void *data, const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes)
 
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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, .requires = "res_calendar", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static const xmlChar * caldav_node_localname = BAD_CAST "calendar-data"
 
static const xmlChar * caldav_node_nsuri = BAD_CAST "urn:ietf:params:xml:ns:caldav"
 
static struct ast_calendar_tech caldav_tech
 

Detailed Description

Resource for handling CalDAV calendars.

Definition in file res_calendar_caldav.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 757 of file res_calendar_caldav.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 757 of file res_calendar_caldav.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 757 of file res_calendar_caldav.c.

◆ auth_credentials()

static int auth_credentials ( void *  userdata,
const char *  realm,
int  attempts,
char *  username,
char *  secret 
)
static

Definition at line 114 of file res_calendar_caldav.c.

115{
116 struct caldav_pvt *pvt = userdata;
117
118 if (attempts > 1) {
119 ast_log(LOG_WARNING, "Invalid username or password for CalDAV calendar '%s'\n", pvt->owner->name);
120 return -1;
121 }
122
123 ne_strnzcpy(username, pvt->user, NE_ABUFSIZ);
124 ne_strnzcpy(secret, pvt->secret, NE_ABUFSIZ);
125
126 return 0;
127}
#define ast_log
Definition: astobj2.c:42
#define LOG_WARNING
const ast_string_field name
Definition: calendar.h:129
struct ast_calendar * owner
const ast_string_field user
const ast_string_field secret

References ast_log, LOG_WARNING, ast_calendar::name, caldav_pvt::owner, caldav_pvt::secret, and caldav_pvt::user.

Referenced by caldav_load_calendar().

◆ caldav_add_event()

static void caldav_add_event ( icalcomponent *  comp,
struct icaltime_span *  span,
void *  data 
)
static

Definition at line 349 of file res_calendar_caldav.c.

350{
351 struct caldav_pvt *pvt = data;
353 icaltimezone *utc = icaltimezone_get_utc_timezone();
354 icaltimetype start, end, tmp;
355 icalcomponent *valarm;
356 icalproperty *prop;
357 struct icaltriggertype trigger;
358
359 if (!(pvt && pvt->owner)) {
360 ast_log(LOG_ERROR, "Require a private structure with an owner\n");
361 return;
362 }
363
364 if (!(event = ast_calendar_event_alloc(pvt->owner))) {
365 ast_log(LOG_ERROR, "Could not allocate an event!\n");
366 return;
367 }
368
369 start = icalcomponent_get_dtstart(comp);
370 end = icalcomponent_get_dtend(comp);
371
372 event->start = icaltime_get_tzid(start) ? span->start : icalfloat_to_timet(start);
373 event->end = icaltime_get_tzid(end) ? span->end : icalfloat_to_timet(end);
374 event->busy_state = span->is_busy ? AST_CALENDAR_BS_BUSY : AST_CALENDAR_BS_FREE;
375
376 if ((prop = icalcomponent_get_first_property(comp, ICAL_SUMMARY_PROPERTY))) {
377 ast_string_field_set(event, summary, icalproperty_get_value_as_string(prop));
378 }
379
380 if ((prop = icalcomponent_get_first_property(comp, ICAL_DESCRIPTION_PROPERTY))) {
381 ast_string_field_set(event, description, icalproperty_get_value_as_string(prop));
382 }
383
384 if ((prop = icalcomponent_get_first_property(comp, ICAL_ORGANIZER_PROPERTY))) {
385 ast_string_field_set(event, organizer, icalproperty_get_value_as_string(prop));
386 }
387
388 if ((prop = icalcomponent_get_first_property(comp, ICAL_LOCATION_PROPERTY))) {
389 ast_string_field_set(event, location, icalproperty_get_value_as_string(prop));
390 }
391
392 if ((prop = icalcomponent_get_first_property(comp, ICAL_CATEGORIES_PROPERTY))) {
393 ast_string_field_set(event, categories, icalproperty_get_value_as_string(prop));
394 }
395
396 if ((prop = icalcomponent_get_first_property(comp, ICAL_PRIORITY_PROPERTY))) {
397 event->priority = icalvalue_get_integer(icalproperty_get_value(prop));
398 }
399
400 if ((prop = icalcomponent_get_first_property(comp, ICAL_UID_PROPERTY))) {
401 ast_string_field_set(event, uid, icalproperty_get_value_as_string(prop));
402 } else {
403 ast_log(LOG_WARNING, "No UID found, but one is required. Generating, but updates may not be accurate\n");
404 if (!ast_strlen_zero(event->summary)) {
405 ast_string_field_set(event, uid, event->summary);
406 } else {
407 char tmp[AST_TIME_T_LEN];
408 ast_time_t_to_string(event->start, tmp, sizeof(tmp));
410 }
411 }
412
413 /* Get the attendees */
414 for (prop = icalcomponent_get_first_property(comp, ICAL_ATTENDEE_PROPERTY);
415 prop; prop = icalcomponent_get_next_property(comp, ICAL_ATTENDEE_PROPERTY)) {
416 struct ast_calendar_attendee *attendee;
417 const char *data;
418
419 if (!(attendee = ast_calloc(1, sizeof(*attendee)))) {
421 return;
422 }
423 data = icalproperty_get_attendee(prop);
424 if (ast_strlen_zero(data)) {
425 ast_free(attendee);
426 continue;
427 }
428 attendee->data = ast_strdup(data);
429 AST_LIST_INSERT_TAIL(&event->attendees, attendee, next);
430 }
431
432
433 /* Only set values for alarm based on VALARM. Can be overriden in main/calendar.c by autoreminder
434 * therefore, go ahead and add events even if their is no VALARM or it is malformed
435 * Currently we are only getting the first VALARM and are handling repitition in main/calendar.c from calendar.conf */
436 if (!(valarm = icalcomponent_get_first_component(comp, ICAL_VALARM_COMPONENT))) {
437 ao2_link(pvt->events, event);
439 return;
440 }
441
442 if (!(prop = icalcomponent_get_first_property(valarm, ICAL_TRIGGER_PROPERTY))) {
443 ast_log(LOG_WARNING, "VALARM has no TRIGGER, skipping!\n");
444 ao2_link(pvt->events, event);
446 return;
447 }
448
449 trigger = icalproperty_get_trigger(prop);
450
451 if (icaltriggertype_is_null_trigger(trigger)) {
452 ast_log(LOG_WARNING, "Bad TRIGGER for VALARM, skipping!\n");
453 ao2_link(pvt->events, event);
455 return;
456 }
457
458 if (!icaltime_is_null_time(trigger.time)) { /* This is an absolute time */
459 tmp = icaltime_convert_to_zone(trigger.time, utc);
460 event->alarm = icaltime_as_timet_with_zone(tmp, utc);
461 } else { /* Offset from either dtstart or dtend */
462 /* XXX Technically you can check RELATED to see if the event fires from the END of the event
463 * But, I'm not sure I've ever seen anyone implement it in calendaring software, so I'm ignoring for now */
464 tmp = icaltime_add(start, trigger.duration);
465 event->alarm = icaltime_as_timet_with_zone(tmp, icaltime_get_timezone(start));
466 }
467
468 ao2_link(pvt->events, event);
470
471 return;
472}
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
static int tmp()
Definition: bt_open.c:389
@ AST_CALENDAR_BS_FREE
Definition: calendar.h:84
@ AST_CALENDAR_BS_BUSY
Definition: calendar.h:86
struct ast_calendar_event * ast_calendar_event_alloc(struct ast_calendar *cal)
Allocate an astobj2 ast_calendar_event object.
Definition: res_calendar.c:669
struct ast_calendar_event * ast_calendar_unref_event(struct ast_calendar_event *event)
Unreference an ast_calendar_event.
Definition: res_calendar.c:323
char * end
Definition: eagi_proxy.c:73
#define LOG_ERROR
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
static time_t icalfloat_to_timet(icaltimetype time)
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
struct ast_calendar_attendee * next
Definition: calendar.h:91
Calendar events.
Definition: calendar.h:95
struct ao2_container * events
Definition: astman.c:222
struct association categories[]
int ast_time_t_to_string(time_t time, char *buf, size_t length)
Converts to a string representation of a time_t as decimal seconds since the epoch....
Definition: time.c:152
#define AST_TIME_T_LEN
Definition: time.h:45

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_TIME_T_LEN, ast_time_t_to_string(), categories, ast_calendar_attendee::data, end, caldav_pvt::events, icalfloat_to_timet(), LOG_ERROR, LOG_WARNING, ast_calendar_attendee::next, caldav_pvt::owner, ast_calendar_event::start, and tmp().

Referenced by handle_end_element().

◆ caldav_destructor()

static void caldav_destructor ( void *  obj)
static

Definition at line 74 of file res_calendar_caldav.c.

75{
76 struct caldav_pvt *pvt = obj;
77
78 ast_debug(1, "Destroying pvt for CalDAV calendar %s\n", pvt->owner->name);
79 if (pvt->session) {
80 ne_session_destroy(pvt->session);
81 }
82 ne_uri_free(&pvt->uri);
84
86
87 ao2_ref(pvt->events, -1);
88}
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ OBJ_UNLINK
Definition: astobj2.h:1039
#define ast_debug(level,...)
Log a DEBUG message.
#define NULL
Definition: resample.c:96
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
ne_session * session

References ao2_callback, ao2_ref, ast_debug, ast_string_field_free_memory, caldav_pvt::events, ast_calendar::name, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, caldav_pvt::owner, caldav_pvt::session, and caldav_pvt::uri.

Referenced by caldav_load_calendar().

◆ caldav_get_events_between()

static struct ast_str * caldav_get_events_between ( struct caldav_pvt pvt,
time_t  start_time,
time_t  end_time 
)
static

Definition at line 276 of file res_calendar_caldav.c.

277{
278 struct ast_str *body, *response;
279 icaltimezone *utc = icaltimezone_get_utc_timezone();
280 icaltimetype start, end;
281 const char *start_str, *end_str;
282
283 if (!(body = ast_str_create(512))) {
284 ast_log(LOG_ERROR, "Could not allocate memory for body of request!\n");
285 return NULL;
286 }
287
288 start = icaltime_from_timet_with_zone(start_time, 0, utc);
289 end = icaltime_from_timet_with_zone(end_time, 0, utc);
290 start_str = icaltime_as_ical_string(start);
291 end_str = icaltime_as_ical_string(end);
292
293 /* If I was really being efficient, I would store a collection of event URIs and etags,
294 * first doing a query of just the etag and seeing if anything had changed. If it had,
295 * then I would do a request for each of the events that had changed, and only bother
296 * updating those. Oh well. */
297 ast_str_append(&body, 0,
298 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
299 "<C:calendar-query xmlns:D=\"DAV:\" xmlns:C=\"urn:ietf:params:xml:ns:caldav\">\n"
300 " <D:prop>\n"
301 " <C:calendar-data>\n"
302 " <C:expand start=\"%s\" end=\"%s\"/>\n"
303 " </C:calendar-data>\n"
304 " </D:prop>\n"
305 " <C:filter>\n"
306 " <C:comp-filter name=\"VCALENDAR\">\n"
307 " <C:comp-filter name=\"VEVENT\">\n"
308 " <C:time-range start=\"%s\" end=\"%s\"/>\n"
309 " </C:comp-filter>\n"
310 " </C:comp-filter>\n"
311 " </C:filter>\n"
312 "</C:calendar-query>\n", start_str, end_str, start_str, end_str);
313
314 response = caldav_request(pvt, "REPORT", body, NULL, NULL);
315 ast_free(body);
316 if (response && !ast_str_strlen(response)) {
317 ast_free(response);
318 return NULL;
319 }
320
321 return response;
322}
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)
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
Support for dynamic strings.
Definition: strings.h:623

References ast_free, ast_log, ast_str_append(), ast_str_create, ast_str_strlen(), caldav_request(), end, LOG_ERROR, and NULL.

Referenced by update_caldav().

◆ caldav_load_calendar()

static void * caldav_load_calendar ( void *  data)
static

Definition at line 607 of file res_calendar_caldav.c.

608{
609 struct caldav_pvt *pvt;
610 const struct ast_config *cfg;
611 struct ast_variable *v;
612 struct ast_calendar *cal = void_data;
614
615 if (!(cal && (cfg = ast_calendar_config_acquire()))) {
616 ast_log(LOG_ERROR, "You must enable calendar support for res_caldav to load\n");
617 return NULL;
618 }
619
620 if (ao2_trylock(cal)) {
621 if (cal->unloading) {
622 ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n");
623 } else {
624 ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n");
625 }
627 return NULL;
628 }
629
630 if (!(pvt = ao2_alloc(sizeof(*pvt), caldav_destructor))) {
631 ast_log(LOG_ERROR, "Could not allocate caldav_pvt structure for calendar: %s\n", cal->name);
633 return NULL;
634 }
635
636 pvt->owner = cal;
637
639 ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name);
640 pvt = unref_caldav(pvt);
641 ao2_unlock(cal);
643 return NULL;
644 }
645
646 if (ast_string_field_init(pvt, 32)) {
647 ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name);
648 pvt = unref_caldav(pvt);
649 ao2_unlock(cal);
651 return NULL;
652 }
653
654 for (v = ast_variable_browse(cfg, cal->name); v; v = v->next) {
655 if (!strcasecmp(v->name, "url")) {
657 } else if (!strcasecmp(v->name, "user")) {
659 } else if (!strcasecmp(v->name, "secret")) {
660 ast_string_field_set(pvt, secret, v->value);
661 }
662 }
663
665
666 if (ast_strlen_zero(pvt->url)) {
667 ast_log(LOG_WARNING, "No URL was specified for CalDAV calendar '%s' - skipping.\n", cal->name);
668 pvt = unref_caldav(pvt);
669 ao2_unlock(cal);
670 return NULL;
671 }
672
673 if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) {
674 ast_log(LOG_WARNING, "Could not parse url '%s' for CalDAV calendar '%s' - skipping.\n", pvt->url, cal->name);
675 pvt = unref_caldav(pvt);
676 ao2_unlock(cal);
677 return NULL;
678 }
679
680 if (pvt->uri.scheme == NULL) {
681 pvt->uri.scheme = "http";
682 }
683
684 if (pvt->uri.port == 0) {
685 pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme);
686 }
687
688 pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port);
689 ne_redirect_register(pvt->session);
690 ne_set_server_auth(pvt->session, auth_credentials, pvt);
691 if (!strcasecmp(pvt->uri.scheme, "https")) {
692 ne_ssl_trust_default_ca(pvt->session);
693 ne_ssl_set_verify(pvt->session, verify_cert, NULL);
694 }
695
696 cal->tech_pvt = pvt;
697
699
700 /* Load it the first time */
701 update_caldav(pvt);
702
703 ao2_unlock(cal);
704
705 /* The only writing from another thread will be if unload is true */
706 for (;;) {
707 struct timeval tv = ast_tvnow();
708 struct timespec ts = {0,};
709
710 ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh);
711
713 while (!pvt->owner->unloading) {
714 if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) {
715 break;
716 }
717 }
719
720 if (pvt->owner->unloading) {
721 ast_debug(10, "Skipping refresh since we got a shutdown signal\n");
722 return NULL;
723 }
724
725 ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh);
726
727 update_caldav(pvt);
728 }
729
730 return NULL;
731}
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_trylock(a)
Definition: astobj2.h:739
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
void ast_calendar_config_release(void)
Release the calendar config.
Definition: res_calendar.c:272
struct ao2_container * ast_calendar_event_container_alloc(void)
Allocate an astobj2 container for ast_calendar_event objects.
Definition: res_calendar.c:691
const struct ast_config * ast_calendar_config_acquire(void)
Grab and lock pointer to the calendar config (read only)
Definition: res_calendar.c:260
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:206
#define ast_mutex_init(pmutex)
Definition: lock.h:186
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
static ast_mutex_t refreshlock
Definition: res_calendar.c:227
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)
static void caldav_destructor(void *obj)
static int auth_credentials(void *userdata, const char *realm, int attempts, char *username, char *secret)
static char url[512]
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
Asterisk calendar structure.
Definition: calendar.h:119
void * tech_pvt
Definition: calendar.h:121
ast_cond_t unload
Definition: calendar.h:137
unsigned int unloading
Definition: calendar.h:138
Structure for mutex and tracking information.
Definition: lock.h:135
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
const ast_string_field url
structure to hold users read from users.conf
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

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_calendar::name, ast_variable::name, ast_variable::next, NULL, caldav_pvt::owner, ast_calendar::refresh, refreshlock, 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().

◆ caldav_request()

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

139{
140 struct ast_str *response;
141 ne_request *req;
142 int ret;
143 char buf[1000];
144
145 if (!pvt) {
146 ast_log(LOG_ERROR, "There is no private!\n");
147 return NULL;
148 }
149
150 if (!(response = ast_str_create(512))) {
151 ast_log(LOG_ERROR, "Could not allocate memory for response.\n");
152 return NULL;
153 }
154
155 snprintf(buf, sizeof(buf), "%s%s", pvt->uri.path, subdir ? ast_str_buffer(subdir) : "");
156
157 req = ne_request_create(pvt->session, method, buf);
158 ne_add_response_body_reader(req, debug_response_handler, fetch_response_reader, &response);
159 ne_set_request_body_buffer(req, ast_str_buffer(req_body), ast_str_strlen(req_body));
160 ne_add_request_header(req, "Content-type", ast_strlen_zero(content_type) ? "text/xml" : content_type);
161 ne_add_request_header(req, "Depth", "1");
162
163 ret = ne_request_dispatch(req);
164 ne_request_destroy(req);
165
166 if (ret != NE_OK) {
167 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));
168 ast_free(response);
169 return NULL;
170 }
171
172 return response;
173}
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int debug_response_handler(void *userdata, ne_request *req, const ne_status *st)
static int fetch_response_reader(void *data, const char *block, size_t len)
const char * method
Definition: res_pjsip.c:1279
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761

References ast_free, ast_log, ast_str_buffer(), ast_str_create, ast_str_strlen(), ast_strlen_zero(), buf, debug_response_handler(), fetch_response_reader(), LOG_ERROR, LOG_WARNING, method, ast_calendar::name, NULL, caldav_pvt::owner, caldav_pvt::session, and caldav_pvt::uri.

Referenced by caldav_get_events_between(), and caldav_write_event().

◆ caldav_write_event()

static int caldav_write_event ( struct ast_calendar_event event)
static

Definition at line 175 of file res_calendar_caldav.c.

176{
177 struct caldav_pvt *pvt;
178 struct ast_str *body = NULL, *response = NULL, *subdir = NULL;
179 icalcomponent *calendar, *icalevent;
180 icaltimezone *utc = icaltimezone_get_utc_timezone();
181 int ret = -1;
182
183 if (!event) {
184 ast_log(LOG_WARNING, "No event passed!\n");
185 return -1;
186 }
187
188 if (!(event->start && event->end)) {
189 ast_log(LOG_WARNING, "The event must contain a start and an end\n");
190 return -1;
191 }
192 if (!(body = ast_str_create(512)) ||
193 !(subdir = ast_str_create(32))) {
194 ast_log(LOG_ERROR, "Could not allocate memory for request!\n");
195 goto write_cleanup;
196 }
197
198 pvt = event->owner->tech_pvt;
199
200 if (ast_strlen_zero(event->uid)) {
201 unsigned short val[8];
202 int x;
203 for (x = 0; x < 8; x++) {
204 val[x] = ast_random();
205 }
206 ast_string_field_build(event, uid, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
207 (unsigned)val[0], (unsigned)val[1], (unsigned)val[2],
208 (unsigned)val[3], (unsigned)val[4], (unsigned)val[5],
209 (unsigned)val[6], (unsigned)val[7]);
210 }
211
212 calendar = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
213 icalcomponent_add_property(calendar, icalproperty_new_version("2.0"));
214 icalcomponent_add_property(calendar, icalproperty_new_prodid("-//Digium, Inc.//res_caldav//EN"));
215
216 icalevent = icalcomponent_new(ICAL_VEVENT_COMPONENT);
217 icalcomponent_add_property(icalevent, icalproperty_new_dtstamp(icaltime_current_time_with_zone(utc)));
218 icalcomponent_add_property(icalevent, icalproperty_new_uid(event->uid));
219 icalcomponent_add_property(icalevent, icalproperty_new_dtstart(icaltime_from_timet_with_zone(event->start, 0, utc)));
220 icalcomponent_add_property(icalevent, icalproperty_new_dtend(icaltime_from_timet_with_zone(event->end, 0, utc)));
221 if (!ast_strlen_zero(event->organizer)) {
222 icalcomponent_add_property(icalevent, icalproperty_new_organizer(event->organizer));
223 }
224 if (!ast_strlen_zero(event->summary)) {
225 icalcomponent_add_property(icalevent, icalproperty_new_summary(event->summary));
226 }
227 if (!ast_strlen_zero(event->description)) {
228 icalcomponent_add_property(icalevent, icalproperty_new_description(event->description));
229 }
230 if (!ast_strlen_zero(event->location)) {
231 icalcomponent_add_property(icalevent, icalproperty_new_location(event->location));
232 }
233 if (!ast_strlen_zero(event->categories)) {
234 icalcomponent_add_property(icalevent, icalproperty_new_categories(event->categories));
235 }
236 if (event->priority > 0) {
237 icalcomponent_add_property(icalevent, icalproperty_new_priority(event->priority));
238 }
239
240 switch (event->busy_state) {
242 icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_CONFIRMED));
243 break;
244
246 icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_TENTATIVE));
247 break;
248
249 default:
250 icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_NONE));
251 }
252
253 icalcomponent_add_component(calendar, icalevent);
254
255 ast_str_append(&body, 0, "%s", icalcomponent_as_ical_string(calendar));
256 ast_str_set(&subdir, 0, "%s%s.ics", pvt->url[strlen(pvt->url) - 1] == '/' ? "" : "/", event->uid);
257
258 if ((response = caldav_request(pvt, "PUT", body, subdir, "text/calendar"))) {
259 ret = 0;
260 }
261
262write_cleanup:
263 if (body) {
264 ast_free(body);
265 }
266 if (response) {
267 ast_free(response);
268 }
269 if (subdir) {
270 ast_free(subdir);
271 }
272
273 return ret;
274}
@ AST_CALENDAR_BS_BUSY_TENTATIVE
Definition: calendar.h:85
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:555
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
Definition: ast_expr2.c:325
long int ast_random(void)
Definition: utils.c:2312

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(), caldav_request(), LOG_ERROR, LOG_WARNING, NULL, caldav_pvt::owner, ast_calendar::tech_pvt, and caldav_pvt::url.

◆ debug_response_handler()

static int debug_response_handler ( void *  userdata,
ne_request *  req,
const ne_status *  st 
)
static

Definition at line 129 of file res_calendar_caldav.c.

130{
131 if (st->code < 200 || st->code > 299) {
132 ast_debug(1, "Unexpected response from server, %d: %s\n", st->code, st->reason_phrase);
133 return 0;
134 }
135 return 1;
136}

References ast_debug.

Referenced by caldav_request().

◆ fetch_response_reader()

static int fetch_response_reader ( void *  data,
const char *  block,
size_t  len 
)
static

Definition at line 98 of file res_calendar_caldav.c.

99{
100 struct ast_str **response = data;
101 unsigned char *tmp;
102
103 if (!(tmp = ast_malloc(len + 1))) {
104 return -1;
105 }
106 memcpy(tmp, block, len);
107 tmp[len] = '\0';
108 ast_str_append(response, 0, "%s", tmp);
109 ast_free(tmp);
110
111 return 0;
112}
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)

References ast_free, ast_malloc, ast_str_append(), len(), and tmp().

Referenced by caldav_request().

◆ handle_characters()

static void handle_characters ( void *  data,
const xmlChar *  ch,
int  len 
)
static

Definition at line 533 of file res_calendar_caldav.c.

534{
535 struct xmlstate *state = data;
536 xmlChar *tmp;
537
538 if (!state->in_caldata) {
539 return;
540 }
541
542 tmp = xmlStrndup(ch, len);
543 ast_str_append(&state->cdata, 0, "%s", (char *)tmp);
544 xmlFree(tmp);
545}

References ast_str_append(), len(), and tmp().

Referenced by update_caldav().

◆ handle_end_element()

static void handle_end_element ( void *  data,
const xmlChar *  localname,
const xmlChar *  prefix,
const xmlChar *  uri 
)
static

Definition at line 500 of file res_calendar_caldav.c.

502{
503 struct xmlstate *state = data;
504 struct icaltimetype start, end;
505 icaltimezone *utc = icaltimezone_get_utc_timezone();
506 icalcomponent *iter;
507 icalcomponent *comp;
508
509 if (xmlStrcmp(localname, caldav_node_localname) || xmlStrcmp(uri, caldav_node_nsuri)) {
510 return;
511 }
512
513 state->in_caldata = 0;
514 if (!(state->cdata && ast_str_strlen(state->cdata))) {
515 return;
516 }
517 /* XXX Parse the calendar blurb for recurrence events in the time range,
518 * create an event, and add it to pvt->events */
519 start = icaltime_from_timet_with_zone(state->start, 0, utc);
520 end = icaltime_from_timet_with_zone(state->end, 0, utc);
521 comp = icalparser_parse_string(ast_str_buffer(state->cdata));
522
523 for (iter = icalcomponent_get_first_component(comp, ICAL_VEVENT_COMPONENT);
524 iter;
525 iter = icalcomponent_get_next_component(comp, ICAL_VEVENT_COMPONENT))
526 {
527 icalcomponent_foreach_recurrence(iter, start, end, caldav_add_event, state->pvt);
528 }
529
530 icalcomponent_free(comp);
531}
static void caldav_add_event(icalcomponent *comp, struct icaltime_span *span, void *data)
static const xmlChar * caldav_node_nsuri
static const xmlChar * caldav_node_localname

References ast_str_buffer(), ast_str_strlen(), caldav_add_event(), caldav_node_localname, caldav_node_nsuri, and end.

Referenced by update_caldav().

◆ handle_start_element()

static void handle_start_element ( void *  data,
const xmlChar *  localname,
const xmlChar *  prefix,
const xmlChar *  uri,
int  nb_namespaces,
const xmlChar **  namespaces,
int  nb_attributes,
int  nb_defaulted,
const xmlChar **  attributes 
)
static

Definition at line 485 of file res_calendar_caldav.c.

489{
490 struct xmlstate *state = data;
491
492 if (xmlStrcmp(localname, caldav_node_localname) || xmlStrcmp(uri, caldav_node_nsuri)) {
493 return;
494 }
495
496 state->in_caldata = 1;
497 ast_str_reset(state->cdata);
498}
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:693

References ast_str_reset(), caldav_node_localname, and caldav_node_nsuri.

Referenced by update_caldav().

◆ icalfloat_to_timet()

static time_t icalfloat_to_timet ( icaltimetype  time)
static

Definition at line 324 of file res_calendar_caldav.c.

325{
326 struct ast_tm tm = {0,};
327 struct timeval tv;
328
329 tm.tm_mday = time.day;
330 tm.tm_mon = time.month - 1;
331 tm.tm_year = time.year - 1900;
332 tm.tm_hour = time.hour;
333 tm.tm_min = time.minute;
334 tm.tm_sec = time.second;
335 tm.tm_isdst = -1;
336 tv = ast_mktime(&tm, NULL);
337
338 return tv.tv_sec;
339}
struct timeval ast_mktime(struct ast_tm *const tmp, const char *zone)
Timezone-independent version of mktime(3).
Definition: localtime.c:2357
int tm_mday
Definition: localtime.h:39
int tm_sec
Definition: localtime.h:36
int tm_hour
Definition: localtime.h:38
int tm_isdst
Definition: localtime.h:44
int tm_min
Definition: localtime.h:37
int tm_year
Definition: localtime.h:41
int tm_mon
Definition: localtime.h:40

References ast_mktime(), NULL, 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().

◆ load_module()

static int load_module ( void  )
static

Definition at line 733 of file res_calendar_caldav.c.

734{
735 ne_sock_init();
737 ne_sock_exit();
739 }
740
742}
int ast_calendar_register(struct ast_calendar_tech *tech)
Register a new calendar technology.
Definition: res_calendar.c:551
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static struct ast_calendar_tech caldav_tech

References ast_calendar_register(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and caldav_tech.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 744 of file res_calendar_caldav.c.

745{
747 ne_sock_exit();
748 return 0;
749}
void ast_calendar_unregister(struct ast_calendar_tech *tech)
Unregister a new calendar technology.
Definition: res_calendar.c:589

References ast_calendar_unregister(), and caldav_tech.

◆ unref_caldav()

static void * unref_caldav ( void *  obj)
static

Definition at line 90 of file res_calendar_caldav.c.

91{
92 struct caldav_pvt *pvt = obj;
93
94 ao2_ref(pvt, -1);
95 return NULL;
96}

References ao2_ref, and NULL.

Referenced by caldav_load_calendar().

◆ update_caldav()

static int update_caldav ( struct caldav_pvt pvt)
static

Definition at line 547 of file res_calendar_caldav.c.

548{
549 struct timeval now = ast_tvnow();
550 time_t start, end;
551 struct ast_str *response;
552 xmlSAXHandler saxHandler;
553 struct xmlstate state = {
554 .in_caldata = 0,
555 .pvt = pvt
556 };
557
558 start = now.tv_sec;
559 end = now.tv_sec + 60 * pvt->owner->timeframe;
560 if (!(response = caldav_get_events_between(pvt, start, end))) {
561 return -1;
562 }
563
564 if (!(state.cdata = ast_str_create(512))) {
565 ast_free(response);
566 return -1;
567 }
568
569 state.start = start;
570 state.end = end;
571
572 /*
573 * We want SAX2, so you assume that we want to call xmlSAXVersion() here, and
574 * that certainly seems like the right thing to do, but the default SAX
575 * handling functions assume that the 'data' pointer is going to be a
576 * xmlParserCtxtPtr, not a user data pointer, so we have to make sure that we
577 * are only calling the handlers that we control.
578 *
579 * So instead we hack things up a bit, clearing the struct and then assigning
580 * the magic number manually.
581 *
582 * There may be a cleaner way to do this, but frankly the libxml2 docs are
583 * pretty sparse.
584 */
585 memset(&saxHandler, 0, sizeof(saxHandler));
586 saxHandler.initialized = XML_SAX2_MAGIC;
587 saxHandler.startElementNs = handle_start_element;
588 saxHandler.endElementNs = handle_end_element;
589 saxHandler.characters = handle_characters;
590
591 xmlSAXUserParseMemory(&saxHandler, &state, ast_str_buffer(response), ast_str_strlen(response));
592
594
595 ast_free(response);
596 ast_free(state.cdata);
597
598 return 0;
599}
void ast_calendar_merge_events(struct ast_calendar *cal, struct ao2_container *new_events)
Add an event to the list of events for a calendar.
static void handle_end_element(void *data, const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri)
static struct ast_str * caldav_get_events_between(struct caldav_pvt *pvt, time_t start_time, time_t end_time)
static void handle_characters(void *data, const xmlChar *ch, int len)
static void handle_start_element(void *data, const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes)
int timeframe
Definition: calendar.h:135
struct caldav_pvt * pvt

References ast_calendar_merge_events(), ast_free, ast_str_buffer(), ast_str_create, ast_str_strlen(), ast_tvnow(), caldav_get_events_between(), end, caldav_pvt::events, handle_characters(), handle_end_element(), handle_start_element(), caldav_pvt::owner, xmlstate::pvt, xmlstate::start, and ast_calendar::timeframe.

Referenced by caldav_load_calendar().

◆ verify_cert()

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

Definition at line 601 of file res_calendar_caldav.c.

602{
603 /* Verify all certs */
604 return 0;
605}

Referenced by caldav_load_calendar().

Variable Documentation

◆ __mod_info

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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, .requires = "res_calendar", }
static

Definition at line 757 of file res_calendar_caldav.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 757 of file res_calendar_caldav.c.

◆ caldav_node_localname

const xmlChar* caldav_node_localname = BAD_CAST "calendar-data"
static

Definition at line 482 of file res_calendar_caldav.c.

Referenced by handle_end_element(), and handle_start_element().

◆ caldav_node_nsuri

const xmlChar* caldav_node_nsuri = BAD_CAST "urn:ietf:params:xml:ns:caldav"
static

Definition at line 483 of file res_calendar_caldav.c.

Referenced by handle_end_element(), and handle_start_element().

◆ caldav_tech

struct ast_calendar_tech caldav_tech
static

Definition at line 53 of file res_calendar_caldav.c.

Referenced by load_module(), and unload_module().