Asterisk - The Open Source Telephony Project GIT-master-f36a736
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/xmlreader.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 (xmlTextReaderPtr reader, struct xmlstate *state)
 
static void handle_end_element (xmlTextReaderPtr reader, struct xmlstate *state)
 
static void handle_start_element (xmlTextReaderPtr reader, struct xmlstate *state)
 
static time_t icalfloat_to_timet (icaltimetype time)
 
static int load_module (void)
 
static void parse_error_handler (void *arg, const char *msg, xmlParserSeverities severity, xmlTextReaderLocatorPtr locator)
 
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 792 of file res_calendar_caldav.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 792 of file res_calendar_caldav.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 792 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 113 of file res_calendar_caldav.c.

114{
115 struct caldav_pvt *pvt = userdata;
116
117 if (attempts > 1) {
118 ast_log(LOG_WARNING, "Invalid username or password for CalDAV calendar '%s'\n", pvt->owner->name);
119 return -1;
120 }
121
122 ne_strnzcpy(username, pvt->user, NE_ABUFSIZ);
123 ne_strnzcpy(secret, pvt->secret, NE_ABUFSIZ);
124
125 return 0;
126}
#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 352 of file res_calendar_caldav.c.

353{
354 struct caldav_pvt *pvt = data;
356 icaltimezone *utc = icaltimezone_get_utc_timezone();
357 icaltimetype start, end, tmp;
358 icalcomponent *valarm;
359 icalproperty *prop;
360 struct icaltriggertype trigger;
361
362 if (!(pvt && pvt->owner)) {
363 ast_log(LOG_ERROR, "Require a private structure with an owner\n");
364 return;
365 }
366
367 if (!(event = ast_calendar_event_alloc(pvt->owner))) {
368 ast_log(LOG_ERROR, "Could not allocate an event!\n");
369 return;
370 }
371
372 start = icalcomponent_get_dtstart(comp);
373 end = icalcomponent_get_dtend(comp);
374
375 event->start = icaltime_get_tzid(start) ? span->start : icalfloat_to_timet(start);
376 event->end = icaltime_get_tzid(end) ? span->end : icalfloat_to_timet(end);
377 event->busy_state = span->is_busy ? AST_CALENDAR_BS_BUSY : AST_CALENDAR_BS_FREE;
378
379 if ((prop = icalcomponent_get_first_property(comp, ICAL_SUMMARY_PROPERTY))) {
380 ast_string_field_set(event, summary, icalproperty_get_value_as_string(prop));
381 }
382
383 if ((prop = icalcomponent_get_first_property(comp, ICAL_DESCRIPTION_PROPERTY))) {
384 ast_string_field_set(event, description, icalproperty_get_value_as_string(prop));
385 }
386
387 if ((prop = icalcomponent_get_first_property(comp, ICAL_ORGANIZER_PROPERTY))) {
388 ast_string_field_set(event, organizer, icalproperty_get_value_as_string(prop));
389 }
390
391 if ((prop = icalcomponent_get_first_property(comp, ICAL_LOCATION_PROPERTY))) {
392 ast_string_field_set(event, location, icalproperty_get_value_as_string(prop));
393 }
394
395 if ((prop = icalcomponent_get_first_property(comp, ICAL_CATEGORIES_PROPERTY))) {
396 ast_string_field_set(event, categories, icalproperty_get_value_as_string(prop));
397 }
398
399 if ((prop = icalcomponent_get_first_property(comp, ICAL_PRIORITY_PROPERTY))) {
400 event->priority = icalvalue_get_integer(icalproperty_get_value(prop));
401 }
402
403 if ((prop = icalcomponent_get_first_property(comp, ICAL_UID_PROPERTY))) {
404 ast_string_field_set(event, uid, icalproperty_get_value_as_string(prop));
405 } else {
406 ast_log(LOG_WARNING, "No UID found, but one is required. Generating, but updates may not be accurate\n");
407 if (!ast_strlen_zero(event->summary)) {
408 ast_string_field_set(event, uid, event->summary);
409 } else {
410 char tmp[AST_TIME_T_LEN];
411 ast_time_t_to_string(event->start, tmp, sizeof(tmp));
413 }
414 }
415
416 /* Get the attendees */
417 for (prop = icalcomponent_get_first_property(comp, ICAL_ATTENDEE_PROPERTY);
418 prop; prop = icalcomponent_get_next_property(comp, ICAL_ATTENDEE_PROPERTY)) {
419 struct ast_calendar_attendee *attendee;
420 const char *data;
421
422 if (!(attendee = ast_calloc(1, sizeof(*attendee)))) {
424 return;
425 }
426 data = icalproperty_get_attendee(prop);
427 if (ast_strlen_zero(data)) {
428 ast_free(attendee);
429 continue;
430 }
431 attendee->data = ast_strdup(data);
432 AST_LIST_INSERT_TAIL(&event->attendees, attendee, next);
433 }
434
435
436 /* Only set values for alarm based on VALARM. Can be overriden in main/calendar.c by autoreminder
437 * therefore, go ahead and add events even if their is no VALARM or it is malformed
438 * Currently we are only getting the first VALARM and are handling repitition in main/calendar.c from calendar.conf */
439 if (!(valarm = icalcomponent_get_first_component(comp, ICAL_VALARM_COMPONENT))) {
440 ao2_link(pvt->events, event);
442 return;
443 }
444
445 if (!(prop = icalcomponent_get_first_property(valarm, ICAL_TRIGGER_PROPERTY))) {
446 ast_log(LOG_WARNING, "VALARM has no TRIGGER, skipping!\n");
447 ao2_link(pvt->events, event);
449 return;
450 }
451
452 trigger = icalproperty_get_trigger(prop);
453
454 if (icaltriggertype_is_null_trigger(trigger)) {
455 ast_log(LOG_WARNING, "Bad TRIGGER for VALARM, skipping!\n");
456 ao2_link(pvt->events, event);
458 return;
459 }
460
461 if (!icaltime_is_null_time(trigger.time)) { /* This is an absolute time */
462 tmp = icaltime_convert_to_zone(trigger.time, utc);
463 event->alarm = icaltime_as_timet_with_zone(tmp, utc);
464 } else { /* Offset from either dtstart or dtend */
465 /* XXX Technically you can check RELATED to see if the event fires from the END of the event
466 * But, I'm not sure I've ever seen anyone implement it in calendaring software, so I'm ignoring for now */
467 tmp = icaltime_add(start, trigger.duration);
468 event->alarm = icaltime_as_timet_with_zone(tmp, icaltime_get_timezone(start));
469 }
470
471 ao2_link(pvt->events, event);
473
474 return;
475}
#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 73 of file res_calendar_caldav.c.

74{
75 struct caldav_pvt *pvt = obj;
76
77 ast_debug(1, "Destroying pvt for CalDAV calendar %s\n", pvt->owner->name);
78 if (pvt->session) {
79 ne_session_destroy(pvt->session);
80 }
81 ne_uri_free(&pvt->uri);
83
85
86 ao2_ref(pvt->events, -1);
87}
#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 279 of file res_calendar_caldav.c.

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

643{
644 struct caldav_pvt *pvt;
645 const struct ast_config *cfg;
646 struct ast_variable *v;
647 struct ast_calendar *cal = void_data;
649
650 if (!(cal && (cfg = ast_calendar_config_acquire()))) {
651 ast_log(LOG_ERROR, "You must enable calendar support for res_caldav to load\n");
652 return NULL;
653 }
654
655 if (ao2_trylock(cal)) {
656 if (cal->unloading) {
657 ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n");
658 } else {
659 ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n");
660 }
662 return NULL;
663 }
664
665 if (!(pvt = ao2_alloc(sizeof(*pvt), caldav_destructor))) {
666 ast_log(LOG_ERROR, "Could not allocate caldav_pvt structure for calendar: %s\n", cal->name);
668 return NULL;
669 }
670
671 pvt->owner = cal;
672
674 ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name);
675 pvt = unref_caldav(pvt);
676 ao2_unlock(cal);
678 return NULL;
679 }
680
681 if (ast_string_field_init(pvt, 32)) {
682 ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name);
683 pvt = unref_caldav(pvt);
684 ao2_unlock(cal);
686 return NULL;
687 }
688
689 for (v = ast_variable_browse(cfg, cal->name); v; v = v->next) {
690 if (!strcasecmp(v->name, "url")) {
692 } else if (!strcasecmp(v->name, "user")) {
694 } else if (!strcasecmp(v->name, "secret")) {
695 ast_string_field_set(pvt, secret, v->value);
696 }
697 }
698
700
701 if (ast_strlen_zero(pvt->url)) {
702 ast_log(LOG_WARNING, "No URL was specified for CalDAV calendar '%s' - skipping.\n", cal->name);
703 pvt = unref_caldav(pvt);
704 ao2_unlock(cal);
705 return NULL;
706 }
707
708 if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) {
709 ast_log(LOG_WARNING, "Could not parse url '%s' for CalDAV calendar '%s' - skipping.\n", pvt->url, cal->name);
710 pvt = unref_caldav(pvt);
711 ao2_unlock(cal);
712 return NULL;
713 }
714
715 if (pvt->uri.scheme == NULL) {
716 pvt->uri.scheme = "http";
717 }
718
719 if (pvt->uri.port == 0) {
720 pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme);
721 }
722
723 pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port);
724 ne_redirect_register(pvt->session);
725 ne_set_server_auth(pvt->session, auth_credentials, pvt);
726 if (!strcasecmp(pvt->uri.scheme, "https")) {
727 ne_ssl_trust_default_ca(pvt->session);
728 ne_ssl_set_verify(pvt->session, verify_cert, NULL);
729 }
730
731 cal->tech_pvt = pvt;
732
734
735 /* Load it the first time */
736 update_caldav(pvt);
737
738 ao2_unlock(cal);
739
740 /* The only writing from another thread will be if unload is true */
741 for (;;) {
742 struct timeval tv = ast_tvnow();
743 struct timespec ts = {0,};
744
745 ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh);
746
748 while (!pvt->owner->unloading) {
749 if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) {
750 break;
751 }
752 }
754
755 if (pvt->owner->unloading) {
756 ast_debug(10, "Skipping refresh since we got a shutdown signal\n");
757 return NULL;
758 }
759
760 ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh);
761
762 update_caldav(pvt);
763 }
764
765 return NULL;
766}
#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 141 of file res_calendar_caldav.c.

142{
143 struct ast_str *response;
144 ne_request *req;
145 int ret;
146 char buf[1000];
147
148 if (!pvt) {
149 ast_log(LOG_ERROR, "There is no private!\n");
150 return NULL;
151 }
152
153 if (!(response = ast_str_create(512))) {
154 ast_log(LOG_ERROR, "Could not allocate memory for response.\n");
155 return NULL;
156 }
157
158 snprintf(buf, sizeof(buf), "%s%s", pvt->uri.path, subdir ? ast_str_buffer(subdir) : "");
159
160 req = ne_request_create(pvt->session, method, buf);
161 ne_add_response_body_reader(req, debug_response_handler, fetch_response_reader, &response);
162 ne_set_request_body_buffer(req, ast_str_buffer(req_body), ast_str_strlen(req_body));
163 ne_add_request_header(req, "Content-type", ast_strlen_zero(content_type) ? "text/xml" : content_type);
164 ne_add_request_header(req, "Depth", "1");
165
166 ret = ne_request_dispatch(req);
167 ne_request_destroy(req);
168
169 if (ret != NE_OK) {
170 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));
171 ast_free(response);
172 return NULL;
173 }
174
175 return response;
176}
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 178 of file res_calendar_caldav.c.

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

129{
130 if (st->code < 200 || st->code > 299) {
131 if (st->code == 401) {
132 ast_debug(1, "Got a 401 from the server but we expect this to happen when authenticating, %d: %s\n", st->code, st->reason_phrase);
133 } else {
134 ast_debug(1, "Unexpected response from server, %d: %s\n", st->code, st->reason_phrase);
135 }
136 return 0;
137 }
138 return 1;
139}

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

98{
99 struct ast_str **response = data;
100 unsigned char *tmp;
101
102 if (!(tmp = ast_malloc(len + 1))) {
103 return -1;
104 }
105 memcpy(tmp, block, len);
106 tmp[len] = '\0';
107 ast_str_append(response, 0, "%s", tmp);
108 ast_free(tmp);
109
110 return 0;
111}
#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 ( xmlTextReaderPtr  reader,
struct xmlstate state 
)
static

Definition at line 534 of file res_calendar_caldav.c.

535{
536 xmlChar *text;
537
538 if (!state->in_caldata) {
539 return;
540 }
541
542 text = xmlTextReaderValue(reader);
543 if (text) {
544 ast_str_append(&state->cdata, 0, "%s", text);
545 xmlFree(text);
546 }
547}
char * text
Definition: app_queue.c:1668

References ast_str_append(), and text.

Referenced by update_caldav().

◆ handle_end_element()

static void handle_end_element ( xmlTextReaderPtr  reader,
struct xmlstate state 
)
static

Definition at line 501 of file res_calendar_caldav.c.

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

Definition at line 488 of file res_calendar_caldav.c.

489{
490 const xmlChar *localname = xmlTextReaderConstLocalName(reader);
491 const xmlChar *uri = xmlTextReaderConstNamespaceUri(reader);
492
493 if (!xmlStrEqual(localname, caldav_node_localname) || !xmlStrEqual(uri, caldav_node_nsuri)) {
494 return;
495 }
496
497 state->in_caldata = 1;
498 ast_str_reset(state->cdata);
499}
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 327 of file res_calendar_caldav.c.

328{
329 struct ast_tm tm = {0,};
330 struct timeval tv;
331
332 tm.tm_mday = time.day;
333 tm.tm_mon = time.month - 1;
334 tm.tm_year = time.year - 1900;
335 tm.tm_hour = time.hour;
336 tm.tm_min = time.minute;
337 tm.tm_sec = time.second;
338 tm.tm_isdst = -1;
339 tv = ast_mktime(&tm, NULL);
340
341 return tv.tv_sec;
342}
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 768 of file res_calendar_caldav.c.

769{
770 ne_sock_init();
772 ne_sock_exit();
774 }
775
777}
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.

◆ parse_error_handler()

static void parse_error_handler ( void *  arg,
const char *  msg,
xmlParserSeverities  severity,
xmlTextReaderLocatorPtr  locator 
)
static

Definition at line 549 of file res_calendar_caldav.c.

551{
552 switch (severity) {
553 case XML_PARSER_SEVERITY_VALIDITY_WARNING:
554 case XML_PARSER_SEVERITY_WARNING:
555 ast_log(LOG_WARNING, "While parsing CalDAV response at line %d: %s\n",
556 xmlTextReaderLocatorLineNumber(locator),
557 msg);
558 break;
559 case XML_PARSER_SEVERITY_VALIDITY_ERROR:
560 case XML_PARSER_SEVERITY_ERROR:
561 default:
562 ast_log(LOG_ERROR, "While parsing CalDAV response at line %d: %s\n",
563 xmlTextReaderLocatorLineNumber(locator),
564 msg);
565 break;
566 }
567}
enum ast_security_event_severity severity

References ast_log, LOG_ERROR, LOG_WARNING, and severity.

Referenced by update_caldav().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 779 of file res_calendar_caldav.c.

780{
782 ne_sock_exit();
783 return 0;
784}
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 89 of file res_calendar_caldav.c.

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

References ao2_ref, and NULL.

Referenced by caldav_load_calendar().

◆ update_caldav()

static int update_caldav ( struct caldav_pvt pvt)
static

Definition at line 569 of file res_calendar_caldav.c.

570{
571 struct timeval now = ast_tvnow();
572 time_t start, end;
573 struct ast_str *response;
574 xmlTextReaderPtr reader;
575 struct xmlstate state = {
576 .in_caldata = 0,
577 .pvt = pvt
578 };
579
580 start = now.tv_sec;
581 end = now.tv_sec + 60 * pvt->owner->timeframe;
582 if (!(response = caldav_get_events_between(pvt, start, end))) {
583 return -1;
584 }
585
586 if (!(state.cdata = ast_str_create(512))) {
587 ast_free(response);
588 return -1;
589 }
590
591 state.start = start;
592 state.end = end;
593
594 reader = xmlReaderForMemory(
595 ast_str_buffer(response),
596 ast_str_strlen(response),
597 NULL,
598 NULL,
599 0);
600
601 if (reader) {
602 int res;
603
604 xmlTextReaderSetErrorHandler(reader, parse_error_handler, NULL);
605
606 res = xmlTextReaderRead(reader);
607 while (res == 1) {
608 int node_type = xmlTextReaderNodeType(reader);
609 switch (node_type) {
610 case XML_READER_TYPE_ELEMENT:
611 handle_start_element(reader, &state);
612 break;
613 case XML_READER_TYPE_END_ELEMENT:
614 handle_end_element(reader, &state);
615 break;
616 case XML_READER_TYPE_TEXT:
617 case XML_READER_TYPE_CDATA:
618 handle_characters(reader, &state);
619 break;
620 default:
621 break;
622 }
623 res = xmlTextReaderRead(reader);
624 }
625 xmlFreeTextReader(reader);
626 }
627
629
630 ast_free(response);
631 ast_free(state.cdata);
632
633 return 0;
634}
node_type
Definition: ast_expr2.c:333
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_start_element(xmlTextReaderPtr reader, struct xmlstate *state)
static struct ast_str * caldav_get_events_between(struct caldav_pvt *pvt, time_t start_time, time_t end_time)
static void handle_characters(xmlTextReaderPtr reader, struct xmlstate *state)
static void handle_end_element(xmlTextReaderPtr reader, struct xmlstate *state)
static void parse_error_handler(void *arg, const char *msg, xmlParserSeverities severity, xmlTextReaderLocatorPtr locator)
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(), NULL, caldav_pvt::owner, parse_error_handler(), 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 636 of file res_calendar_caldav.c.

637{
638 /* Verify all certs */
639 return 0;
640}

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

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 792 of file res_calendar_caldav.c.

◆ caldav_node_localname

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

Definition at line 485 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 486 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 52 of file res_calendar_caldav.c.

Referenced by load_module(), and unload_module().