Wed Jan 8 2020 09:50:18

Asterisk developer's documentation


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/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_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 fetch_response_reader (void *data, const char *block, size_t len)
 
static void handle_characters (void *data, const xmlChar *ch, int len)
 
static void handle_end_element (void *data, const xmlChar *name)
 
static void handle_start_element (void *data, const xmlChar *fullname, const xmlChar **atts)
 
static time_t icalfloat_to_timet (icaltimetype time)
 
static int load_module (void)
 
static int unload_module (void)
 
static void * unref_caldav (void *obj)
 
static int update_caldav (struct caldav_pvt *pvt)
 
static int verify_cert (void *userdata, int failures, const ne_ssl_certificate *cert)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Asterisk CalDAV Calendar Integration" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, }
 
static struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_calendar_tech caldav_tech
 

Detailed Description

Resource for handling CalDAV calendars.

Definition in file res_calendar_caldav.c.

Function Documentation

static void __reg_module ( void  )
static

Definition at line 719 of file res_calendar_caldav.c.

static void __unreg_module ( void  )
static

Definition at line 719 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().

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 LOG_WARNING
Definition: logger.h:144
const ast_string_field name
Definition: calendar.h:127
const ast_string_field secret
struct ast_calendar * owner
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static char secret[50]
Definition: chan_h323.c:148
const ast_string_field user
static void caldav_add_event ( icalcomponent *  comp,
struct icaltime_span *  span,
void *  data 
)
static

Definition at line 336 of file res_calendar_caldav.c.

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_calendar_event::attendees, ast_calendar_attendee::data, ast_calendar_event::end, caldav_pvt::events, icalfloat_to_timet(), LOG_ERROR, LOG_WARNING, ast_calendar_attendee::next, caldav_pvt::owner, ast_calendar_event::start, and ast_calendar_event::summary.

Referenced by handle_end_element().

337 {
338  struct caldav_pvt *pvt = data;
339  struct ast_calendar_event *event;
340  icaltimezone *utc = icaltimezone_get_utc_timezone();
341  icaltimetype start, end, tmp;
342  icalcomponent *valarm;
343  icalproperty *prop;
344  struct icaltriggertype trigger;
345 
346  if (!(pvt && pvt->owner)) {
347  ast_log(LOG_ERROR, "Require a private structure with an owner\n");
348  return;
349  }
350 
351  if (!(event = ast_calendar_event_alloc(pvt->owner))) {
352  ast_log(LOG_ERROR, "Could not allocate an event!\n");
353  return;
354  }
355 
356  start = icalcomponent_get_dtstart(comp);
357  end = icalcomponent_get_dtend(comp);
358 
359  event->start = icaltime_get_tzid(start) ? span->start : icalfloat_to_timet(start);
360  event->end = icaltime_get_tzid(end) ? span->end : icalfloat_to_timet(end);
361  event->busy_state = span->is_busy ? AST_CALENDAR_BS_BUSY : AST_CALENDAR_BS_FREE;
362 
363  if ((prop = icalcomponent_get_first_property(comp, ICAL_SUMMARY_PROPERTY))) {
364  ast_string_field_set(event, summary, icalproperty_get_value_as_string(prop));
365  }
366 
367  if ((prop = icalcomponent_get_first_property(comp, ICAL_DESCRIPTION_PROPERTY))) {
368  ast_string_field_set(event, description, icalproperty_get_value_as_string(prop));
369  }
370 
371  if ((prop = icalcomponent_get_first_property(comp, ICAL_ORGANIZER_PROPERTY))) {
372  ast_string_field_set(event, organizer, icalproperty_get_value_as_string(prop));
373  }
374 
375  if ((prop = icalcomponent_get_first_property(comp, ICAL_LOCATION_PROPERTY))) {
376  ast_string_field_set(event, location, icalproperty_get_value_as_string(prop));
377  }
378 
379  if ((prop = icalcomponent_get_first_property(comp, ICAL_CATEGORIES_PROPERTY))) {
380  ast_string_field_set(event, categories, icalproperty_get_value_as_string(prop));
381  }
382 
383  if ((prop = icalcomponent_get_first_property(comp, ICAL_PRIORITY_PROPERTY))) {
384  event->priority = icalvalue_get_integer(icalproperty_get_value(prop));
385  }
386 
387  if ((prop = icalcomponent_get_first_property(comp, ICAL_UID_PROPERTY))) {
388  ast_string_field_set(event, uid, icalproperty_get_value_as_string(prop));
389  } else {
390  ast_log(LOG_WARNING, "No UID found, but one is required. Generating, but updates may not be acurate\n");
391  if (!ast_strlen_zero(event->summary)) {
392  ast_string_field_set(event, uid, event->summary);
393  } else {
394  char tmp[100];
395  snprintf(tmp, sizeof(tmp), "%ld", event->start);
396  ast_string_field_set(event, uid, tmp);
397  }
398  }
399 
400  /* Get the attendees */
401  for (prop = icalcomponent_get_first_property(comp, ICAL_ATTENDEE_PROPERTY);
402  prop; prop = icalcomponent_get_next_property(comp, ICAL_ATTENDEE_PROPERTY)) {
403  struct ast_calendar_attendee *attendee;
404  const char *data;
405 
406  if (!(attendee = ast_calloc(1, sizeof(*attendee)))) {
407  event = ast_calendar_unref_event(event);
408  return;
409  }
410  data = icalproperty_get_attendee(prop);
411  if (ast_strlen_zero(data)) {
412  ast_free(attendee);
413  continue;
414  }
415  attendee->data = ast_strdup(data);
416  AST_LIST_INSERT_TAIL(&event->attendees, attendee, next);
417  }
418 
419 
420  /* Only set values for alarm based on VALARM. Can be overriden in main/calendar.c by autoreminder
421  * therefore, go ahead and add events even if their is no VALARM or it is malformed
422  * Currently we are only getting the first VALARM and are handling repitition in main/calendar.c from calendar.conf */
423  if (!(valarm = icalcomponent_get_first_component(comp, ICAL_VALARM_COMPONENT))) {
424  ao2_link(pvt->events, event);
425  event = ast_calendar_unref_event(event);
426  return;
427  }
428 
429  if (!(prop = icalcomponent_get_first_property(valarm, ICAL_TRIGGER_PROPERTY))) {
430  ast_log(LOG_WARNING, "VALARM has no TRIGGER, skipping!\n");
431  ao2_link(pvt->events, event);
432  event = ast_calendar_unref_event(event);
433  return;
434  }
435 
436  trigger = icalproperty_get_trigger(prop);
437 
438  if (icaltriggertype_is_null_trigger(trigger)) {
439  ast_log(LOG_WARNING, "Bad TRIGGER for VALARM, skipping!\n");
440  ao2_link(pvt->events, event);
441  event = ast_calendar_unref_event(event);
442  return;
443  }
444 
445  if (!icaltime_is_null_time(trigger.time)) { /* This is an absolute time */
446  tmp = icaltime_convert_to_zone(trigger.time, utc);
447  event->alarm = icaltime_as_timet_with_zone(tmp, utc);
448  } else { /* Offset from either dtstart or dtend */
449  /* XXX Technically you can check RELATED to see if the event fires from the END of the event
450  * But, I'm not sure I've ever seen anyone implement it in calendaring software, so I'm ignoring for now */
451  tmp = icaltime_add(start, trigger.duration);
452  event->alarm = icaltime_as_timet_with_zone(tmp, utc);
453  }
454 
455  ao2_link(pvt->events, event);
456  event = ast_calendar_unref_event(event);
457 
458  return;
459 }
#define ao2_link(arg1, arg2)
Definition: astobj2.h:785
static time_t icalfloat_to_timet(icaltimetype time)
#define ast_strdup(a)
Definition: astmm.h:109
#define LOG_WARNING
Definition: logger.h:144
struct ast_calendar_attendee * next
Definition: calendar.h:89
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
struct ast_calendar_event * ast_calendar_event_alloc(struct ast_calendar *cal)
Allocate an astobj2 ast_calendar_event object.
Definition: res_calendar.c:603
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
struct ast_calendar * owner
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_free(a)
Definition: astmm.h:97
struct ast_calendar_event * ast_calendar_unref_event(struct ast_calendar_event *event)
Unreference an ast_calendar_event.
Definition: res_calendar.c:300
struct ast_calendar_event::attendees attendees
#define ast_calloc(a, b)
Definition: astmm.h:82
const ast_string_field summary
Definition: calendar.h:101
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:344
struct ao2_container * events
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().

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  }
83 
84  ao2_callback(pvt->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
85 
86  ao2_ref(pvt->events, -1);
87 }
ne_session * session
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:910
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define ao2_ref(o, delta)
Definition: astobj2.h:472
const ast_string_field name
Definition: calendar.h:127
struct ast_calendar * owner
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:253
struct ao2_container * events
static struct ast_str* caldav_get_events_between ( struct caldav_pvt pvt,
time_t  start_time,
time_t  end_time 
)
static

Definition at line 267 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().

268 {
269  struct ast_str *body, *response;
270  icaltimezone *utc = icaltimezone_get_utc_timezone();
271  icaltimetype start, end;
272  const char *start_str, *end_str;
273 
274  if (!(body = ast_str_create(512))) {
275  ast_log(LOG_ERROR, "Could not allocate memory for body of request!\n");
276  return NULL;
277  }
278 
279  start = icaltime_from_timet_with_zone(start_time, 0, utc);
280  end = icaltime_from_timet_with_zone(end_time, 0, utc);
281  start_str = icaltime_as_ical_string(start);
282  end_str = icaltime_as_ical_string(end);
283 
284  /* If I was really being efficient, I would store a collection of event URIs and etags,
285  * first doing a query of just the etag and seeing if anything had changed. If it had,
286  * then I would do a request for each of the events that had changed, and only bother
287  * updating those. Oh well. */
288  ast_str_append(&body, 0,
289  "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
290  "<C:calendar-query xmlns:D=\"DAV:\" xmlns:C=\"urn:ietf:params:xml:ns:caldav\">\n"
291  " <D:prop>\n"
292  " <C:calendar-data>\n"
293  " <C:expand start=\"%s\" end=\"%s\"/>\n"
294  " </C:calendar-data>\n"
295  " </D:prop>\n"
296  " <C:filter>\n"
297  " <C:comp-filter name=\"VCALENDAR\">\n"
298  " <C:comp-filter name=\"VEVENT\">\n"
299  " <C:time-range start=\"%s\" end=\"%s\"/>\n"
300  " </C:comp-filter>\n"
301  " </C:comp-filter>\n"
302  " </C:filter>\n"
303  "</C:calendar-query>\n", start_str, end_str, start_str, end_str);
304 
305  response = caldav_request(pvt, "REPORT", body, NULL, NULL);
306  ast_free(body);
307 
308  return response;
309 }
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:900
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
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)
#define LOG_ERROR
Definition: logger.h:155
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_free(a)
Definition: astmm.h:97
static void * caldav_load_calendar ( void *  data)
static

Definition at line 571 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(), caldav_pvt::events, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_calendar::name, ast_variable::next, caldav_pvt::owner, ast_calendar::refresh, refreshlock, secret, 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().

572 {
573  struct caldav_pvt *pvt;
574  const struct ast_config *cfg;
575  struct ast_variable *v;
576  struct ast_calendar *cal = void_data;
578 
579  if (!(cal && (cfg = ast_calendar_config_acquire()))) {
580  ast_log(LOG_ERROR, "You must enable calendar support for res_caldav to load\n");
581  return NULL;
582  }
583 
584  if (ao2_trylock(cal)) {
585  if (cal->unloading) {
586  ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n");
587  } else {
588  ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n");
589  }
591  return NULL;
592  }
593 
594  if (!(pvt = ao2_alloc(sizeof(*pvt), caldav_destructor))) {
595  ast_log(LOG_ERROR, "Could not allocate caldav_pvt structure for calendar: %s\n", cal->name);
597  return NULL;
598  }
599 
600  pvt->owner = cal;
601 
602  if (!(pvt->events = ast_calendar_event_container_alloc())) {
603  ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name);
604  pvt = unref_caldav(pvt);
605  ao2_unlock(cal);
607  return NULL;
608  }
609 
610  if (ast_string_field_init(pvt, 32)) {
611  ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name);
612  pvt = unref_caldav(pvt);
613  ao2_unlock(cal);
615  return NULL;
616  }
617 
618  for (v = ast_variable_browse(cfg, cal->name); v; v = v->next) {
619  if (!strcasecmp(v->name, "url")) {
620  ast_string_field_set(pvt, url, v->value);
621  } else if (!strcasecmp(v->name, "user")) {
622  ast_string_field_set(pvt, user, v->value);
623  } else if (!strcasecmp(v->name, "secret")) {
625  }
626  }
627 
629 
630  if (ast_strlen_zero(pvt->url)) {
631  ast_log(LOG_WARNING, "No URL was specified for CalDAV calendar '%s' - skipping.\n", cal->name);
632  pvt = unref_caldav(pvt);
633  ao2_unlock(cal);
634  return NULL;
635  }
636 
637  if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) {
638  ast_log(LOG_WARNING, "Could not parse url '%s' for CalDAV calendar '%s' - skipping.\n", pvt->url, cal->name);
639  pvt = unref_caldav(pvt);
640  ao2_unlock(cal);
641  return NULL;
642  }
643 
644  if (pvt->uri.scheme == NULL) {
645  pvt->uri.scheme = "http";
646  }
647 
648  if (pvt->uri.port == 0) {
649  pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme);
650  }
651 
652  pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port);
653  ne_redirect_register(pvt->session);
654  ne_set_server_auth(pvt->session, auth_credentials, pvt);
655  if (!strcasecmp(pvt->uri.scheme, "https")) {
656  ne_ssl_trust_default_ca(pvt->session);
657  ne_ssl_set_verify(pvt->session, verify_cert, NULL);
658  }
659 
660  cal->tech_pvt = pvt;
661 
662  ast_mutex_init(&refreshlock);
663 
664  /* Load it the first time */
665  update_caldav(pvt);
666 
667  ao2_unlock(cal);
668 
669  /* The only writing from another thread will be if unload is true */
670  for (;;) {
671  struct timeval tv = ast_tvnow();
672  struct timespec ts = {0,};
673 
674  ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh);
675 
676  ast_mutex_lock(&refreshlock);
677  while (!pvt->owner->unloading) {
678  if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) {
679  break;
680  }
681  }
682  ast_mutex_unlock(&refreshlock);
683 
684  if (pvt->owner->unloading) {
685  ast_debug(10, "Skipping refresh since we got a shutdown signal\n");
686  return NULL;
687  }
688 
689  ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh);
690 
691  update_caldav(pvt);
692  }
693 
694  return NULL;
695 }
ast_cond_t unload
Definition: calendar.h:133
int unloading
Definition: calendar.h:134
static int auth_credentials(void *userdata, const char *realm, int attempts, char *username, char *secret)
ne_session * session
#define LOG_WARNING
Definition: logger.h:144
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
Definition: config.c:597
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
#define ast_mutex_lock(a)
Definition: lock.h:155
#define ao2_unlock(a)
Definition: astobj2.h:497
struct ast_config * ast_calendar_config_acquire(void)
Grab and lock pointer to the calendar config (read only)
Definition: res_calendar.c:237
void * tech_pvt
Definition: calendar.h:119
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
const char * value
Definition: config.h:79
static void caldav_destructor(void *obj)
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:249
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
struct ao2_container * ast_calendar_event_container_alloc(void)
Allocate an astobj2 container for ast_calendar_event objects.
Definition: res_calendar.c:625
const char * name
Definition: config.h:77
const ast_string_field name
Definition: calendar.h:127
static int update_caldav(struct caldav_pvt *pvt)
#define LOG_ERROR
Definition: logger.h:155
struct ast_calendar * owner
#define ao2_trylock(a)
Definition: astobj2.h:506
static ast_mutex_t refreshlock
Definition: res_calendar.c:204
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:430
static void * unref_caldav(void *obj)
structure to hold users read from users.conf
static int verify_cert(void *userdata, int failures, const ne_ssl_certificate *cert)
static char secret[50]
Definition: chan_h323.c:148
const ast_string_field url
struct timeval tv
struct ast_variable * next
Definition: config.h:82
#define ast_mutex_init(pmutex)
Definition: lock.h:152
Asterisk calendar structure.
Definition: calendar.h:117
void ast_calendar_config_release(void)
Release the calendar config.
Definition: res_calendar.c:249
static char url[512]
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:172
Structure for mutex and tracking information.
Definition: lock.h:121
#define ast_mutex_unlock(a)
Definition: lock.h:156
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:344
struct ao2_container * events
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().

129 {
130  struct ast_str *response;
131  ne_request *req;
132  int ret;
133  char buf[1000];
134 
135  if (!pvt) {
136  ast_log(LOG_ERROR, "There is no private!\n");
137  return NULL;
138  }
139 
140  if (!(response = ast_str_create(512))) {
141  ast_log(LOG_ERROR, "Could not allocate memory for response.\n");
142  return NULL;
143  }
144 
145  snprintf(buf, sizeof(buf), "%s%s", pvt->uri.path, subdir ? ast_str_buffer(subdir) : "");
146 
147  req = ne_request_create(pvt->session, method, buf);
148  ne_add_response_body_reader(req, ne_accept_2xx, fetch_response_reader, &response);
149  ne_set_request_body_buffer(req, ast_str_buffer(req_body), ast_str_strlen(req_body));
150  ne_add_request_header(req, "Content-type", ast_strlen_zero(content_type) ? "text/xml" : content_type);
151 
152  ret = ne_request_dispatch(req);
153  ne_request_destroy(req);
154 
155  if (ret != NE_OK || !ast_str_strlen(response)) {
156  if (ret != NE_OK) {
157  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));
158  }
159  ast_free(response);
160  return NULL;
161  }
162 
163  return response;
164 }
ne_session * session
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
static int fetch_response_reader(void *data, const char *block, size_t len)
const ast_string_field name
Definition: calendar.h:127
#define LOG_ERROR
Definition: logger.h:155
struct ast_calendar * owner
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_free(a)
Definition: astmm.h:97
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:471
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, caldav_pvt::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.

167 {
168  struct caldav_pvt *pvt;
169  struct ast_str *body = NULL, *response = NULL, *subdir = NULL;
170  icalcomponent *calendar, *icalevent;
171  icaltimezone *utc = icaltimezone_get_utc_timezone();
172  int ret = -1;
173 
174  if (!event) {
175  ast_log(LOG_WARNING, "No event passed!\n");
176  return -1;
177  }
178 
179  if (!(event->start && event->end)) {
180  ast_log(LOG_WARNING, "The event must contain a start and an end\n");
181  return -1;
182  }
183  if (!(body = ast_str_create(512)) ||
184  !(subdir = ast_str_create(32))) {
185  ast_log(LOG_ERROR, "Could not allocate memory for request!\n");
186  goto write_cleanup;
187  }
188 
189  pvt = event->owner->tech_pvt;
190 
191  if (ast_strlen_zero(event->uid)) {
192  unsigned short val[8];
193  int x;
194  for (x = 0; x < 8; x++) {
195  val[x] = ast_random();
196  }
197  ast_string_field_build(event, uid, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
198  (unsigned)val[0], (unsigned)val[1], (unsigned)val[2],
199  (unsigned)val[3], (unsigned)val[4], (unsigned)val[5],
200  (unsigned)val[6], (unsigned)val[7]);
201  }
202 
203  calendar = icalcomponent_new(ICAL_VCALENDAR_COMPONENT);
204  icalcomponent_add_property(calendar, icalproperty_new_version("2.0"));
205  icalcomponent_add_property(calendar, icalproperty_new_prodid("-//Digium, Inc.//res_caldav//EN"));
206 
207  icalevent = icalcomponent_new(ICAL_VEVENT_COMPONENT);
208  icalcomponent_add_property(icalevent, icalproperty_new_dtstamp(icaltime_current_time_with_zone(utc)));
209  icalcomponent_add_property(icalevent, icalproperty_new_uid(event->uid));
210  icalcomponent_add_property(icalevent, icalproperty_new_dtstart(icaltime_from_timet_with_zone(event->start, 0, utc)));
211  icalcomponent_add_property(icalevent, icalproperty_new_dtend(icaltime_from_timet_with_zone(event->end, 0, utc)));
212  if (!ast_strlen_zero(event->organizer)) {
213  icalcomponent_add_property(icalevent, icalproperty_new_organizer(event->organizer));
214  }
215  if (!ast_strlen_zero(event->summary)) {
216  icalcomponent_add_property(icalevent, icalproperty_new_summary(event->summary));
217  }
218  if (!ast_strlen_zero(event->description)) {
219  icalcomponent_add_property(icalevent, icalproperty_new_description(event->description));
220  }
221  if (!ast_strlen_zero(event->location)) {
222  icalcomponent_add_property(icalevent, icalproperty_new_location(event->location));
223  }
224  if (!ast_strlen_zero(event->categories)) {
225  icalcomponent_add_property(icalevent, icalproperty_new_categories(event->categories));
226  }
227  if (event->priority > 0) {
228  icalcomponent_add_property(icalevent, icalproperty_new_priority(event->priority));
229  }
230 
231  switch (event->busy_state) {
233  icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_CONFIRMED));
234  break;
235 
237  icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_TENTATIVE));
238  break;
239 
240  default:
241  icalcomponent_add_property(icalevent, icalproperty_new_status(ICAL_STATUS_NONE));
242  }
243 
244  icalcomponent_add_component(calendar, icalevent);
245 
246  ast_str_append(&body, 0, "%s", icalcomponent_as_ical_string(calendar));
247  ast_str_set(&subdir, 0, "%s%s.ics", pvt->url[strlen(pvt->url) - 1] == '/' ? "" : "/", event->uid);
248 
249  response = caldav_request(pvt, "PUT", body, subdir, "text/calendar");
250 
251  ret = 0;
252 
253 write_cleanup:
254  if (body) {
255  ast_free(body);
256  }
257  if (response) {
258  ast_free(response);
259  }
260  if (subdir) {
261  ast_free(subdir);
262  }
263 
264  return ret;
265 }
Definition: ast_expr2.c:325
#define LOG_WARNING
Definition: logger.h:144
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:900
const ast_string_field uid
Definition: calendar.h:101
enum ast_calendar_busy_state busy_state
Definition: calendar.h:107
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
const ast_string_field description
Definition: calendar.h:101
const ast_string_field organizer
Definition: calendar.h:101
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:874
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)
void * tech_pvt
Definition: calendar.h:119
const ast_string_field location
Definition: calendar.h:101
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
long int ast_random(void)
Definition: utils.c:1640
#define LOG_ERROR
Definition: logger.h:155
struct ast_calendar * owner
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_free(a)
Definition: astmm.h:97
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:367
const ast_string_field categories
Definition: calendar.h:101
const ast_string_field url
const ast_string_field summary
Definition: calendar.h:101
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, ast_str_append(), and len().

Referenced by caldav_request().

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 }
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:900
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define ast_free(a)
Definition: astmm.h:97
#define ast_malloc(a)
Definition: astmm.h:91
static void handle_characters ( void *  data,
const xmlChar *  ch,
int  len 
)
static

Definition at line 511 of file res_calendar_caldav.c.

References ast_str_append(), xmlstate::cdata, and xmlstate::in_caldata.

Referenced by update_caldav().

512 {
513  struct xmlstate *state = data;
514  xmlChar *tmp;
515 
516  if (!state->in_caldata) {
517  return;
518  }
519 
520  tmp = xmlStrndup(ch, len);
521  ast_str_append(&state->cdata, 0, "%s", (char *)tmp);
522  xmlFree(tmp);
523 }
struct ast_str * cdata
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:900
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static void handle_end_element ( void *  data,
const xmlChar *  name 
)
static

Definition at line 479 of file res_calendar_caldav.c.

References ast_str_buffer(), ast_str_strlen(), caldav_add_event(), xmlstate::cdata, xmlstate::end, xmlstate::in_caldata, xmlstate::pvt, and xmlstate::start.

Referenced by update_caldav().

480 {
481  struct xmlstate *state = data;
482  struct icaltimetype start, end;
483  icaltimezone *utc = icaltimezone_get_utc_timezone();
484  icalcomponent *iter;
485  icalcomponent *comp;
486 
487  if (xmlStrcasecmp(name, BAD_CAST "C:calendar-data")) {
488  return;
489  }
490 
491  state->in_caldata = 0;
492  if (!(state->cdata && ast_str_strlen(state->cdata))) {
493  return;
494  }
495  /* XXX Parse the calendar blurb for recurrence events in the time range,
496  * create an event, and add it to pvt->events */
497  start = icaltime_from_timet_with_zone(state->start, 0, utc);
498  end = icaltime_from_timet_with_zone(state->end, 0, utc);
499  comp = icalparser_parse_string(ast_str_buffer(state->cdata));
500 
501  for (iter = icalcomponent_get_first_component(comp, ICAL_VEVENT_COMPONENT);
502  iter;
503  iter = icalcomponent_get_next_component(comp, ICAL_VEVENT_COMPONENT))
504  {
505  icalcomponent_foreach_recurrence(iter, start, end, caldav_add_event, state->pvt);
506  }
507 
508  icalcomponent_free(comp);
509 }
struct ast_str * cdata
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
struct caldav_pvt * pvt
static const char name[]
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:471
static void caldav_add_event(icalcomponent *comp, struct icaltime_span *span, void *data)
static void handle_start_element ( void *  data,
const xmlChar *  fullname,
const xmlChar **  atts 
)
static

Definition at line 469 of file res_calendar_caldav.c.

References ast_str_reset(), xmlstate::cdata, and xmlstate::in_caldata.

Referenced by update_caldav().

470 {
471  struct xmlstate *state = data;
472 
473  if (!xmlStrcasecmp(fullname, BAD_CAST "C:calendar-data")) {
474  state->in_caldata = 1;
475  ast_str_reset(state->cdata);
476  }
477 }
struct ast_str * cdata
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:436
static time_t icalfloat_to_timet ( icaltimetype  time)
static

Definition at line 311 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().

312 {
313  struct ast_tm tm = {0,};
314  struct timeval tv;
315 
316  tm.tm_mday = time.day;
317  tm.tm_mon = time.month - 1;
318  tm.tm_year = time.year - 1900;
319  tm.tm_hour = time.hour;
320  tm.tm_min = time.minute;
321  tm.tm_sec = time.second;
322  tm.tm_isdst = -1;
323  tv = ast_mktime(&tm, NULL);
324 
325  return tv.tv_sec;
326 }
int tm_year
Definition: localtime.h:41
int tm_mon
Definition: localtime.h:40
int tm_mday
Definition: localtime.h:39
int tm_hour
Definition: localtime.h:38
int tm_sec
Definition: localtime.h:36
struct timeval ast_mktime(struct ast_tm *const tmp, const char *zone)
Timezone-independent version of mktime(3).
Definition: localtime.c:2185
int tm_isdst
Definition: localtime.h:44
struct timeval tv
int tm_min
Definition: localtime.h:37
static int load_module ( void  )
static

Definition at line 697 of file res_calendar_caldav.c.

References ast_calendar_register(), AST_MODULE_LOAD_DECLINE, and AST_MODULE_LOAD_SUCCESS.

698 {
699  ne_sock_init();
701  ne_sock_exit();
703  }
704 
706 }
int ast_calendar_register(struct ast_calendar_tech *tech)
Register a new calendar technology.
Definition: res_calendar.c:490
static struct ast_calendar_tech caldav_tech
static int unload_module ( void  )
static

Definition at line 708 of file res_calendar_caldav.c.

References ast_calendar_unregister().

709 {
711  ne_sock_exit();
712  return 0;
713 }
static struct ast_calendar_tech caldav_tech
void ast_calendar_unregister(struct ast_calendar_tech *tech)
Unregister a new calendar technology.
Definition: res_calendar.c:523
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().

90 {
91  struct caldav_pvt *pvt = obj;
92 
93  ao2_ref(pvt, -1);
94  return NULL;
95 }
#define ao2_ref(o, delta)
Definition: astobj2.h:472
static int update_caldav ( struct caldav_pvt pvt)
static

Definition at line 525 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(), xmlstate::cdata, xmlstate::end, caldav_pvt::events, handle_characters(), handle_end_element(), handle_start_element(), xmlstate::in_caldata, caldav_pvt::owner, xmlstate::start, and ast_calendar::timeframe.

Referenced by caldav_load_calendar().

526 {
527  struct timeval now = ast_tvnow();
528  time_t start, end;
529  struct ast_str *response;
530  xmlSAXHandler saxHandler;
531  struct xmlstate state = {
532  .in_caldata = 0,
533  .pvt = pvt
534  };
535 
536  start = now.tv_sec;
537  end = now.tv_sec + 60 * pvt->owner->timeframe;
538  if (!(response = caldav_get_events_between(pvt, start, end))) {
539  return -1;
540  }
541 
542  if (!(state.cdata = ast_str_create(512))) {
543  ast_free(response);
544  return -1;
545  }
546 
547  state.start = start;
548  state.end = end;
549 
550  memset(&saxHandler, 0, sizeof(saxHandler));
551  saxHandler.startElement = handle_start_element;
552  saxHandler.endElement = handle_end_element;
553  saxHandler.characters = handle_characters;
554 
555  xmlSAXUserParseMemory(&saxHandler, &state, ast_str_buffer(response), ast_str_strlen(response));
556 
558 
559  ast_free(response);
560  ast_free(state.cdata);
561 
562  return 0;
563 }
struct ast_str * cdata
static void handle_start_element(void *data, const xmlChar *fullname, const xmlChar **atts)
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
int timeframe
Definition: calendar.h:131
static void handle_characters(void *data, const xmlChar *ch, int len)
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.
Definition: res_calendar.c:961
static void handle_end_element(void *data, const xmlChar *name)
struct ast_calendar * owner
static struct ast_str * caldav_get_events_between(struct caldav_pvt *pvt, time_t start_time, time_t end_time)
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
#define ast_free(a)
Definition: astmm.h:97
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:471
struct ao2_container * events
static int verify_cert ( void *  userdata,
int  failures,
const ne_ssl_certificate *  cert 
)
static

Definition at line 565 of file res_calendar_caldav.c.

Referenced by caldav_load_calendar().

566 {
567  /* Verify all certs */
568  return 0;
569 }

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Asterisk CalDAV Calendar Integration" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, }
static

Definition at line 719 of file res_calendar_caldav.c.

Definition at line 719 of file res_calendar_caldav.c.

struct ast_calendar_tech caldav_tech
static

Definition at line 53 of file res_calendar_caldav.c.