Asterisk - The Open Source Telephony Project  18.5.0
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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .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.

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

Referenced by caldav_load_calendar().

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 LOG_WARNING
Definition: logger.h:274
#define ast_log
Definition: astobj2.c:42
const ast_string_field name
Definition: calendar.h:127
const ast_string_field secret
struct ast_calendar * owner
const ast_string_field user

◆ 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.

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, 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, ast_calendar_event::summary, and tmp().

Referenced by handle_end_element().

350 {
351  struct caldav_pvt *pvt = data;
352  struct ast_calendar_event *event;
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 acurate\n");
404  if (!ast_strlen_zero(event->summary)) {
405  ast_string_field_set(event, uid, event->summary);
406  } else {
407  char tmp[100];
408  snprintf(tmp, sizeof(tmp), "%ld", event->start);
409  ast_string_field_set(event, uid, 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)))) {
420  event = ast_calendar_unref_event(event);
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);
438  event = ast_calendar_unref_event(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);
445  event = ast_calendar_unref_event(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);
454  event = ast_calendar_unref_event(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);
469  event = ast_calendar_unref_event(event);
470 
471  return;
472 }
static time_t icalfloat_to_timet(icaltimetype time)
#define LOG_WARNING
Definition: logger.h:274
static int tmp()
Definition: bt_open.c:389
struct ast_calendar_attendee * next
Definition: calendar.h:89
Definition: astman.c:222
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
char * end
Definition: eagi_proxy.c:73
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
struct ast_calendar_event * ast_calendar_event_alloc(struct ast_calendar *cal)
Allocate an astobj2 ast_calendar_event object.
Definition: res_calendar.c:667
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
struct ast_calendar * owner
struct association categories[]
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
struct ast_calendar_event * ast_calendar_unref_event(struct ast_calendar_event *event)
Unreference an ast_calendar_event.
Definition: res_calendar.c:321
struct ast_calendar_event::attendees attendees
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:514
struct ao2_container * events
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ caldav_destructor()

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, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, caldav_pvt::owner, caldav_pvt::session, and caldav_pvt::uri.

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  }
82  ne_uri_free(&pvt->uri);
84 
86 
87  ao2_ref(pvt->events, -1);
88 }
ne_session * session
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ao2_ref(o, delta)
Definition: astobj2.h:464
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:368
struct ao2_container * events

◆ 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.

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().

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 }
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:1091
#define NULL
Definition: resample.c:96
char * end
Definition: eagi_proxy.c:73
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 ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define ast_free(a)
Definition: astmm.h:182
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620

◆ caldav_load_calendar()

static void * caldav_load_calendar ( void *  data)
static

Definition at line 607 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, NULL, caldav_pvt::owner, ast_calendar::refresh, refreshlock, caldav_pvt::secret, caldav_pvt::session, ast_calendar::tech_pvt, ast_calendar::unload, ast_calendar::unloading, unref_caldav(), update_caldav(), caldav_pvt::uri, caldav_pvt::url, ast_variable::value, and verify_cert().

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 
638  if (!(pvt->events = ast_calendar_event_container_alloc())) {
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")) {
656  ast_string_field_set(pvt, url, v->value);
657  } else if (!strcasecmp(v->name, "user")) {
658  ast_string_field_set(pvt, user, v->value);
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 
698  ast_mutex_init(&refreshlock);
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 
712  ast_mutex_lock(&refreshlock);
713  while (!pvt->owner->unloading) {
714  if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) {
715  break;
716  }
717  }
718  ast_mutex_unlock(&refreshlock);
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 }
struct ast_variable * next
ast_cond_t unload
Definition: calendar.h:135
unsigned int unloading
Definition: calendar.h:136
static int auth_credentials(void *userdata, const char *realm, int attempts, char *username, char *secret)
ne_session * session
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
#define LOG_WARNING
Definition: logger.h:274
Structure for variables, used for configurations and for channel variables.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define ast_mutex_lock(a)
Definition: lock.h:187
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
void * tech_pvt
Definition: calendar.h:119
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static void caldav_destructor(void *obj)
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
struct ao2_container * ast_calendar_event_container_alloc(void)
Allocate an astobj2 container for ast_calendar_event objects.
Definition: res_calendar.c:689
const ast_string_field name
Definition: calendar.h:127
static int update_caldav(struct caldav_pvt *pvt)
#define LOG_ERROR
Definition: logger.h:285
struct ast_calendar * owner
#define ao2_trylock(a)
Definition: astobj2.h:740
static ast_mutex_t refreshlock
Definition: res_calendar.c:225
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
static void * unref_caldav(void *obj)
const struct ast_config * ast_calendar_config_acquire(void)
Grab and lock pointer to the calendar config (read only)
Definition: res_calendar.c:258
structure to hold users read from users.conf
static int verify_cert(void *userdata, int failures, const ne_ssl_certificate *cert)
const ast_string_field url
#define ast_mutex_init(pmutex)
Definition: lock.h:184
Asterisk calendar structure.
Definition: calendar.h:117
void ast_calendar_config_release(void)
Release the calendar config.
Definition: res_calendar.c:270
static char url[512]
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:204
Structure for mutex and tracking information.
Definition: lock.h:135
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
struct ao2_container * events

◆ 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.

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, ast_calendar::name, NULL, caldav_pvt::owner, caldav_pvt::session, and caldav_pvt::uri.

Referenced by caldav_get_events_between(), and caldav_write_event().

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 }
ne_session * session
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
const char * method
Definition: res_pjsip.c:4335
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 ast_string_field name
Definition: calendar.h:127
#define LOG_ERROR
Definition: logger.h:285
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:584
#define ast_free(a)
Definition: astmm.h:182
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620

◆ caldav_write_event()

static int caldav_write_event ( struct ast_calendar_event event)
static

Definition at line 175 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, NULL, 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.

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 
262 write_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 }
Definition: ast_expr2.c:325
#define LOG_WARNING
Definition: logger.h:274
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:1091
const ast_string_field uid
Definition: calendar.h:101
enum ast_calendar_busy_state busy_state
Definition: calendar.h:107
#define NULL
Definition: resample.c:96
const ast_string_field description
Definition: calendar.h:101
const ast_string_field organizer
Definition: calendar.h:101
#define ast_strlen_zero(foo)
Definition: strings.h:52
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:1065
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
#define ast_log
Definition: astobj2.c:42
const ast_string_field location
Definition: calendar.h:101
long int ast_random(void)
Definition: main/utils.c:2064
#define LOG_ERROR
Definition: logger.h:285
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:584
#define ast_free(a)
Definition: astmm.h:182
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:550
const ast_string_field categories
Definition: calendar.h:101
const ast_string_field url
const ast_string_field summary
Definition: calendar.h:101
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620

◆ 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.

References ast_debug.

Referenced by caldav_request().

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 }
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452

◆ 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.

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

Referenced by caldav_request().

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 }
static int tmp()
Definition: bt_open.c:389
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:1091
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define ast_free(a)
Definition: astmm.h:182

◆ handle_characters()

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

Definition at line 533 of file res_calendar_caldav.c.

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

Referenced by update_caldav().

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 }
struct ast_str * cdata
static int tmp()
Definition: bt_open.c:389
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:1091
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)

◆ 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.

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

Referenced by update_caldav().

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 }
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:714
struct caldav_pvt * pvt
char * end
Definition: eagi_proxy.c:73
static const xmlChar * caldav_node_nsuri
static const xmlChar * caldav_node_localname
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
static void caldav_add_event(icalcomponent *comp, struct icaltime_span *span, void *data)

◆ 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.

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

Referenced by update_caldav().

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 }
struct ast_str * cdata
static const xmlChar * caldav_node_nsuri
static const xmlChar * caldav_node_localname
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:653

◆ icalfloat_to_timet()

static time_t icalfloat_to_timet ( icaltimetype  time)
static

Definition at line 324 of file res_calendar_caldav.c.

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().

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 }
#define NULL
Definition: resample.c:96
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:2357
int tm_isdst
Definition: localtime.h:44
int tm_min
Definition: localtime.h:37

◆ load_module()

static int load_module ( void  )
static

Definition at line 733 of file res_calendar_caldav.c.

References ast_calendar_register(), AST_MODULE_LOAD_DECLINE, and AST_MODULE_LOAD_SUCCESS.

Referenced by unload_module().

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:549
static struct ast_calendar_tech caldav_tech
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 744 of file res_calendar_caldav.c.

References ast_calendar_unregister(), AST_MODFLAG_LOAD_ORDER, AST_MODPRI_DEVSTATE_PLUGIN, AST_MODULE_INFO(), AST_MODULE_SUPPORT_EXTENDED, ASTERISK_GPL_KEY, and load_module().

745 {
747  ne_sock_exit();
748  return 0;
749 }
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:587

◆ unref_caldav()

static void * unref_caldav ( void *  obj)
static

Definition at line 90 of file res_calendar_caldav.c.

References ao2_ref, and NULL.

Referenced by caldav_load_calendar().

91 {
92  struct caldav_pvt *pvt = obj;
93 
94  ao2_ref(pvt, -1);
95  return NULL;
96 }
#define NULL
Definition: resample.c:96
#define ao2_ref(o, delta)
Definition: astobj2.h:464

◆ update_caldav()

static int update_caldav ( struct caldav_pvt pvt)
static

Definition at line 547 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, end, 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().

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 }
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:714
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
int timeframe
Definition: calendar.h:133
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 void handle_end_element(void *data, const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri)
char * end
Definition: eagi_proxy.c:73
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.
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:584
#define ast_free(a)
Definition: astmm.h:182
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
struct ao2_container * events

◆ 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.

Referenced by caldav_load_calendar().

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

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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .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.