Wed Jan 8 2020 09:50:18

Asterisk developer's documentation


res_calendar_exchange.c File Reference

Resource for handling MS Exchange 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 <iksemel.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  exchangecal_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 struct ast_strbs_to_exchange_bs (struct ast_str *dst, enum ast_calendar_busy_state bs)
 
static struct ast_strepoch_to_exchange_time (struct ast_str *dst, time_t epoch)
 
static void exchangecal_destructor (void *obj)
 
static struct ast_strexchangecal_get_events_between (struct exchangecal_pvt *pvt, time_t start_time, time_t end_time)
 
static void * exchangecal_load_calendar (void *data)
 
static struct ast_strexchangecal_request (struct exchangecal_pvt *pvt, const char *method, struct ast_str *req_body, struct ast_str *subdir)
 
static int exchangecal_write_event (struct ast_calendar_event *event)
 
static int fetch_response_reader (void *data, const char *block, size_t len)
 
static struct ast_strgenerate_exchange_uuid (struct ast_str *uid)
 
static int is_valid_uuid (struct ast_str *uid)
 
static int load_module (void)
 
static enum ast_calendar_busy_state msbusy_to_bs (const char *msbusy)
 
static time_t mstime_to_time_t (char *mstime)
 
static int parse_cdata (void *data, char *value, size_t len)
 
static int parse_tag (void *data, char *name, char **atts, int type)
 
static int unload_module (void)
 
static void * unref_exchangecal (void *obj)
 
static int update_exchangecal (struct exchangecal_pvt *pvt)
 
static struct ast_strxml_encode_str (struct ast_str *dst, const char *src)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Asterisk MS Exchange 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 exchangecal_tech
 

Detailed Description

Resource for handling MS Exchange calendars.

Definition in file res_calendar_exchange.c.

Function Documentation

static void __reg_module ( void  )
static

Definition at line 766 of file res_calendar_exchange.c.

static void __unreg_module ( void  )
static

Definition at line 766 of file res_calendar_exchange.c.

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

Definition at line 370 of file res_calendar_exchange.c.

References ast_log(), LOG_WARNING, ast_calendar::name, exchangecal_pvt::owner, exchangecal_pvt::secret, and exchangecal_pvt::user.

Referenced by exchangecal_load_calendar().

371 {
372  struct exchangecal_pvt *pvt = userdata;
373 
374  if (attempts > 1) {
375  ast_log(LOG_WARNING, "Invalid username or password for Exchange calendar '%s'\n", pvt->owner->name);
376  return -1;
377  }
378 
379  ne_strnzcpy(username, pvt->user, NE_ABUFSIZ);
380  ne_strnzcpy(secret, pvt->secret, NE_ABUFSIZ);
381 
382  return 0;
383 }
#define LOG_WARNING
Definition: logger.h:144
const ast_string_field secret
struct ast_calendar * owner
const ast_string_field user
const ast_string_field name
Definition: calendar.h:127
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
static struct ast_str* bs_to_exchange_bs ( struct ast_str dst,
enum ast_calendar_busy_state  bs 
)
static

Definition at line 336 of file res_calendar_exchange.c.

References AST_CALENDAR_BS_BUSY, AST_CALENDAR_BS_BUSY_TENTATIVE, and ast_str_set().

Referenced by exchangecal_write_event().

337 {
338  switch (bs) {
340  ast_str_set(&dst, 0, "%s", "BUSY");
341  break;
342 
344  ast_str_set(&dst, 0, "%s", "TENTATIVE");
345  break;
346 
347  default:
348  ast_str_set(&dst, 0, "%s", "FREE");
349  }
350 
351  return dst;
352 }
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* epoch_to_exchange_time ( struct ast_str dst,
time_t  epoch 
)
static

Definition at line 315 of file res_calendar_exchange.c.

References ast_copy_string(), and ast_str_append().

Referenced by exchangecal_write_event().

316 {
317  icaltimezone *utc = icaltimezone_get_utc_timezone();
318  icaltimetype tt = icaltime_from_timet_with_zone(epoch, 0, utc);
319  char tmp[30];
320  int i;
321 
322  ast_copy_string(tmp, icaltime_as_ical_string(tt), sizeof(tmp));
323  for (i = 0; tmp[i]; i++) {
324  ast_str_append(&dst, 0, "%c", tmp[i]);
325  if (i == 3 || i == 5)
326  ast_str_append(&dst, 0, "%c", '-');
327  if (i == 10 || i == 12)
328  ast_str_append(&dst, 0, "%c", ':');
329  if (i == 14)
330  ast_str_append(&dst, 0, "%s", ".000");
331  }
332 
333  return dst;
334 }
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
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
static void exchangecal_destructor ( void *  obj)
static

Definition at line 218 of file res_calendar_exchange.c.

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

Referenced by exchangecal_load_calendar().

219 {
220  struct exchangecal_pvt *pvt = obj;
221 
222  ast_debug(1, "Destroying pvt for Exchange calendar %s\n", pvt->owner->name);
223  if (pvt->session) {
224  ne_session_destroy(pvt->session);
225  }
227 
228  ao2_callback(pvt->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
229 
230  ao2_ref(pvt->events, -1);
231 }
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:910
struct ast_calendar * owner
#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 ao2_container * events
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:253
static struct ast_str* exchangecal_get_events_between ( struct exchangecal_pvt pvt,
time_t  start_time,
time_t  end_time 
)
static

Definition at line 551 of file res_calendar_exchange.c.

References ast_debug, ast_free, ast_localtime(), ast_log(), ast_str_append(), ast_str_buffer(), ast_str_create(), ast_strftime(), exchangecal_request(), LOG_ERROR, and exchangecal_pvt::url.

Referenced by update_exchangecal().

552 {
553  struct ast_str *body, *response;
554  char start[80], end[80];
555  struct timeval tv = {0,};
556  struct ast_tm tm;
557 
558  tv.tv_sec = start_time;
559  ast_localtime(&tv, &tm, "UTC");
560  ast_strftime(start, sizeof(start), "%Y/%m/%d %T", &tm);
561 
562  tv.tv_sec = end_time;
563  ast_localtime(&tv, &tm, "UTC");
564  ast_strftime(end, sizeof(end), "%Y/%m/%d %T", &tm);
565 
566  if (!(body = ast_str_create(512))) {
567  ast_log(LOG_ERROR, "Could not allocate memory for body of request!\n");
568  return NULL;
569  }
570 
571  ast_str_append(&body, 0,
572  "<?xml version=\"1.0\"?>\n"
573  "<g:searchrequest xmlns:g=\"DAV:\">\n"
574  " <g:sql> SELECT \"urn:schemas:calendar:location\", \"urn:schemas:httpmail:subject\",\n"
575  " \"urn:schemas:calendar:dtstart\", \"urn:schemas:calendar:dtend\",\n"
576  " \"urn:schemas:calendar:busystatus\", \"urn:schemas:calendar:instancetype\",\n"
577  " \"urn:schemas:calendar:uid\", \"urn:schemas:httpmail:textdescription\",\n"
578  " \"urn:schemas:calendar:organizer\", \"urn:schemas:calendar:reminderoffset\"\n"
579  " FROM Scope('SHALLOW TRAVERSAL OF \"%s/Calendar\"')\n"
580  " WHERE NOT \"urn:schemas:calendar:instancetype\" = 1\n"
581  " AND \"DAV:contentclass\" = 'urn:content-classes:appointment'\n"
582  " AND NOT (\"urn:schemas:calendar:dtend\" &lt; '%s'\n"
583  " OR \"urn:schemas:calendar:dtstart\" &gt; '%s')\n"
584  " ORDER BY \"urn:schemas:calendar:dtstart\" ASC\n"
585  " </g:sql>\n"
586  "</g:searchrequest>\n", pvt->url, start, end);
587 
588  ast_debug(5, "Request:\n%s\n", ast_str_buffer(body));
589  response = exchangecal_request(pvt, "SEARCH", body, NULL);
590  ast_debug(5, "Response:\n%s\n", ast_str_buffer(response));
591  ast_free(body);
592 
593  return response;
594 }
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1570
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
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#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
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2351
static struct ast_str * exchangecal_request(struct exchangecal_pvt *pvt, const char *method, struct ast_str *req_body, struct ast_str *subdir)
struct timeval tv
const ast_string_field url
static void * exchangecal_load_calendar ( void *  data)
static

Definition at line 619 of file res_calendar_exchange.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(), exchangecal_pvt::events, exchangecal_destructor(), LOG_ERROR, LOG_WARNING, ast_variable::name, ast_calendar::name, ast_variable::next, exchangecal_pvt::owner, ast_calendar::refresh, refreshlock, secret, exchangecal_pvt::session, ast_calendar::tech_pvt, ast_calendar::unload, ast_calendar::unloading, unref_exchangecal(), update_exchangecal(), exchangecal_pvt::uri, exchangecal_pvt::url, url, and ast_variable::value.

620 {
621  struct exchangecal_pvt *pvt;
622  const struct ast_config *cfg;
623  struct ast_variable *v;
624  struct ast_calendar *cal = void_data;
626 
627  if (!(cal && (cfg = ast_calendar_config_acquire()))) {
628  ast_log(LOG_ERROR, "You must enable calendar support for res_exchangecal to load\n");
629  return NULL;
630  }
631 
632  if (ao2_trylock(cal)) {
633  if (cal->unloading) {
634  ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n");
635  } else {
636  ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n");
637  }
639  return NULL;
640  }
641 
642  if (!(pvt = ao2_alloc(sizeof(*pvt), exchangecal_destructor))) {
643  ast_log(LOG_ERROR, "Could not allocate exchangecal_pvt structure for calendar: %s\n", cal->name);
645  return NULL;
646  }
647 
648  pvt->owner = cal;
649 
650  if (!(pvt->events = ast_calendar_event_container_alloc())) {
651  ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name);
652  pvt = unref_exchangecal(pvt);
653  ao2_unlock(cal);
655  return NULL;
656  }
657 
658  if (ast_string_field_init(pvt, 32)) {
659  ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name);
660  pvt = unref_exchangecal(pvt);
661  ao2_unlock(cal);
663  return NULL;
664  }
665 
666  for (v = ast_variable_browse(cfg, cal->name); v; v = v->next) {
667  if (!strcasecmp(v->name, "url")) {
668  ast_string_field_set(pvt, url, v->value);
669  } else if (!strcasecmp(v->name, "user")) {
670  ast_string_field_set(pvt, user, v->value);
671  } else if (!strcasecmp(v->name, "secret")) {
673  }
674  }
675 
677 
678  if (ast_strlen_zero(pvt->url)) {
679  ast_log(LOG_WARNING, "No URL was specified for Exchange calendar '%s' - skipping.\n", cal->name);
680  pvt = unref_exchangecal(pvt);
681  ao2_unlock(cal);
682  return NULL;
683  }
684 
685  if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) {
686  ast_log(LOG_WARNING, "Could not parse url '%s' for Exchange calendar '%s' - skipping.\n", pvt->url, cal->name);
687  pvt = unref_exchangecal(pvt);
688  ao2_unlock(cal);
689  return NULL;
690  }
691 
692  if (pvt->uri.scheme == NULL) {
693  pvt->uri.scheme = "http";
694  }
695 
696  if (pvt->uri.port == 0) {
697  pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme);
698  }
699 
700  pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port);
701  ne_redirect_register(pvt->session);
702  ne_set_server_auth(pvt->session, auth_credentials, pvt);
703  if (!strcasecmp(pvt->uri.scheme, "https")) {
704  ne_ssl_trust_default_ca(pvt->session);
705  }
706 
707  cal->tech_pvt = pvt;
708 
709  ast_mutex_init(&refreshlock);
710 
711  /* Load it the first time */
712  update_exchangecal(pvt);
713 
714  ao2_unlock(cal);
715 
716  /* The only writing from another thread will be if unload is true */
717  for (;;) {
718  struct timeval tv = ast_tvnow();
719  struct timespec ts = {0,};
720 
721  ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh);
722 
723  ast_mutex_lock(&refreshlock);
724  while (!pvt->owner->unloading) {
725  if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) {
726  break;
727  }
728  }
729  ast_mutex_unlock(&refreshlock);
730 
731  if (pvt->owner->unloading) {
732  ast_debug(10, "Skipping refresh since we got a shutdown signal\n");
733  return NULL;
734  }
735 
736  ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh);
737 
738  update_exchangecal(pvt);
739  }
740 
741  return NULL;
742 }
ast_cond_t unload
Definition: calendar.h:133
int unloading
Definition: calendar.h:134
static int update_exchangecal(struct exchangecal_pvt *pvt)
#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 ast_calendar * owner
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
static void * unref_exchangecal(void *obj)
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
#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
static int auth_credentials(void *userdata, const char *realm, int attempts, char *username, char *secret)
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
#define LOG_ERROR
Definition: logger.h:155
#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
struct ao2_container * events
structure to hold users read from users.conf
static char secret[50]
Definition: chan_h323.c:148
struct timeval tv
const ast_string_field url
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
static void exchangecal_destructor(void *obj)
static struct ast_str* exchangecal_request ( struct exchangecal_pvt pvt,
const char *  method,
struct ast_str req_body,
struct ast_str subdir 
)
static

Definition at line 385 of file res_calendar_exchange.c.

References ast_free, ast_log(), ast_str_buffer(), ast_str_create(), ast_str_strlen(), fetch_response_reader(), LOG_ERROR, LOG_WARNING, ast_calendar::name, exchangecal_pvt::owner, exchangecal_pvt::session, exchangecal_pvt::uri, and exchangecal_pvt::url.

Referenced by exchangecal_get_events_between(), and exchangecal_write_event().

386 {
387  struct ast_str *response;
388  ne_request *req;
389  int ret;
390  char buf[1000];
391 
392  if (!pvt) {
393  ast_log(LOG_ERROR, "There is no private!\n");
394  return NULL;
395  }
396 
397  if (!(response = ast_str_create(512))) {
398  ast_log(LOG_ERROR, "Could not allocate memory for response.\n");
399  return NULL;
400  }
401 
402  snprintf(buf, sizeof(buf), "%s%s", pvt->uri.path, subdir ? ast_str_buffer(subdir) : "");
403 
404  req = ne_request_create(pvt->session, method, buf);
405  ne_add_response_body_reader(req, ne_accept_2xx, fetch_response_reader, &response);
406  ne_set_request_body_buffer(req, ast_str_buffer(req_body), ast_str_strlen(req_body));
407  ne_add_request_header(req, "Content-type", "text/xml");
408 
409  ret = ne_request_dispatch(req);
410  ne_request_destroy(req);
411 
412  if (ret != NE_OK || !ast_str_strlen(response)) {
413  ast_log(LOG_WARNING, "Unknown response to CalDAV calendar %s, request %s to %s: %s\n", pvt->owner->name, method, pvt->url, ne_get_error(pvt->session));
414  ast_free(response);
415  return NULL;
416  }
417 
418  return response;
419 }
static int fetch_response_reader(void *data, const char *block, size_t len)
#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_calendar * owner
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 name
Definition: calendar.h:127
#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
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:471
const ast_string_field url
static int exchangecal_write_event ( struct ast_calendar_event event)
static

Definition at line 421 of file res_calendar_exchange.c.

References ast_free, ast_log(), ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), ast_strlen_zero(), ast_verb, bs_to_exchange_bs(), ast_calendar_event::busy_state, ast_calendar_event::description, ast_calendar_event::end, epoch_to_exchange_time(), exchangecal_request(), generate_exchange_uuid(), is_valid_uuid(), ast_calendar_event::location, LOG_ERROR, LOG_WARNING, ast_calendar_event::organizer, ast_calendar_event::owner, ast_calendar_event::start, ast_calendar_event::summary, ast_calendar::tech_pvt, ast_calendar_event::uid, and xml_encode_str().

422 {
423  struct ast_str *body = NULL, *response = NULL, *subdir = NULL;
424  struct ast_str *uid = NULL, *summary = NULL, *description = NULL, *organizer = NULL,
425  *location = NULL, *start = NULL, *end = NULL, *busystate = NULL;
426  int ret = -1;
427 
428  if (!event) {
429  ast_log(LOG_WARNING, "No event passed!\n");
430  return -1;
431  }
432 
433  if (!(event->start && event->end)) {
434  ast_log(LOG_WARNING, "The event must contain a start and an end\n");
435  return -1;
436  }
437  if (!(body = ast_str_create(512)) ||
438  !(subdir = ast_str_create(32))) {
439  ast_log(LOG_ERROR, "Could not allocate memory for request!\n");
440  goto write_cleanup;
441  }
442 
443  if (!(uid = ast_str_create(32)) ||
444  !(summary = ast_str_create(32)) ||
445  !(description = ast_str_create(32)) ||
446  !(organizer = ast_str_create(32)) ||
447  !(location = ast_str_create(32)) ||
448  !(start = ast_str_create(32)) ||
449  !(end = ast_str_create(32)) ||
450  !(busystate = ast_str_create(32))) {
451  ast_log(LOG_ERROR, "Unable to allocate memory for request values\n");
452  goto write_cleanup;
453  }
454 
455  if (ast_strlen_zero(event->uid)) {
456  uid = generate_exchange_uuid(uid);
457  } else {
458  ast_str_set(&uid, 36, "%s", event->uid);
459  }
460 
461  if (!is_valid_uuid(uid)) {
462  ast_log(LOG_WARNING, "An invalid uid was provided, you may leave this field blank to have one generated for you\n");
463  goto write_cleanup;
464  }
465 
466  summary = xml_encode_str(summary, event->summary);
467  description = xml_encode_str(description, event->description);
468  organizer = xml_encode_str(organizer, event->organizer);
469  location = xml_encode_str(location, event->location);
470  start = epoch_to_exchange_time(start, event->start);
471  end = epoch_to_exchange_time(end, event->end);
472  busystate = bs_to_exchange_bs(busystate, event->busy_state);
473 
474  ast_str_append(&body, 0,
475  "<?xml version=\"1.0\"?>\n"
476  "<a:propertyupdate\n"
477  " xmlns:a=\"DAV:\"\n"
478  " xmlns:e=\"http://schemas.microsoft.com/exchange/\"\n"
479  " xmlns:mapi=\"http://schemas.microsoft.com/mapi/\"\n"
480  " xmlns:mapit=\"http://schemas.microsoft.com/mapi/proptag/\"\n"
481  " xmlns:x=\"xml:\" xmlns:cal=\"urn:schemas:calendar:\"\n"
482  " xmlns:dt=\"uuid:%s/\"\n" /* uid */
483  " xmlns:header=\"urn:schemas:mailheader:\"\n"
484  " xmlns:mail=\"urn:schemas:httpmail:\"\n"
485  ">\n"
486  " <a:set>\n"
487  " <a:prop>\n"
488  " <a:contentclass>urn:content-classes:appointment</a:contentclass>\n"
489  " <e:outlookmessageclass>IPM.Appointment</e:outlookmessageclass>\n"
490  " <mail:subject>%s</mail:subject>\n" /* summary */
491  " <mail:description>%s</mail:description>\n" /* description */
492  " <header:to>%s</header:to>\n" /* organizer */
493  " <cal:location>%s</cal:location>\n" /* location */
494  " <cal:dtstart dt:dt=\"dateTime.tz\">%s</cal:dtstart>\n" /* start */
495  " <cal:dtend dt:dt=\"dateTime.tz\">%s</cal:dtend>\n" /* end */
496  " <cal:instancetype dt:dt=\"int\">0</cal:instancetype>\n"
497  " <cal:busystatus>%s</cal:busystatus>\n" /* busy_state (BUSY, FREE, BUSY_TENTATIVE) */
498  " <cal:meetingstatus>CONFIRMED</cal:meetingstatus>\n"
499  " <cal:alldayevent dt:dt=\"boolean\">0</cal:alldayevent>\n" /* XXX need to add event support for all day events */
500  " <cal:responserequested dt:dt=\"boolean\">0</cal:responserequested>\n"
501  " <mapi:finvited dt:dt=\"boolean\">1</mapi:finvited>\n"
502  " </a:prop>\n"
503  " </a:set>\n"
504  "</a:propertyupdate>\n",
505  ast_str_buffer(uid), ast_str_buffer(summary), ast_str_buffer(description), ast_str_buffer(organizer), ast_str_buffer(location), ast_str_buffer(start), ast_str_buffer(end), ast_str_buffer(busystate));
506  ast_verb(0, "\n\n%s\n\n", ast_str_buffer(body));
507  ast_str_set(&subdir, 0, "/Calendar/%s.eml", ast_str_buffer(uid));
508 
509  response = exchangecal_request(event->owner->tech_pvt, "PROPPATCH", body, subdir);
510 
511  ret = 0;
512 write_cleanup:
513  if (uid) {
514  ast_free(uid);
515  }
516  if (summary) {
517  ast_free(summary);
518  }
519  if (description) {
520  ast_free(description);
521  }
522  if (organizer) {
523  ast_free(organizer);
524  }
525  if (location) {
526  ast_free(location);
527  }
528  if (start) {
529  ast_free(start);
530  }
531  if (end) {
532  ast_free(end);
533  }
534  if (busystate) {
535  ast_free(busystate);
536  }
537  if (body) {
538  ast_free(body);
539  }
540  if (response) {
541  ast_free(response);
542  }
543  if (subdir) {
544  ast_free(subdir);
545  }
546 
547  return ret;
548 }
static struct ast_str * xml_encode_str(struct ast_str *dst, const char *src)
#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
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
#define ast_verb(level,...)
Definition: logger.h:243
const ast_string_field organizer
Definition: calendar.h:101
static struct ast_str * bs_to_exchange_bs(struct ast_str *dst, enum ast_calendar_busy_state bs)
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
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
#define LOG_ERROR
Definition: logger.h:155
static int is_valid_uuid(struct ast_str *uid)
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
static struct ast_str * generate_exchange_uuid(struct ast_str *uid)
#define ast_free(a)
Definition: astmm.h:97
struct ast_calendar * owner
Definition: calendar.h:103
static struct ast_str * exchangecal_request(struct exchangecal_pvt *pvt, const char *method, struct ast_str *req_body, struct ast_str *subdir)
const ast_string_field summary
Definition: calendar.h:101
static struct ast_str * epoch_to_exchange_time(struct ast_str *dst, time_t epoch)
static int fetch_response_reader ( void *  data,
const char *  block,
size_t  len 
)
static

Definition at line 354 of file res_calendar_exchange.c.

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

Referenced by exchangecal_request().

355 {
356  struct ast_str **response = data;
357  unsigned char *tmp;
358 
359  if (!(tmp = ast_malloc(len + 1))) {
360  return -1;
361  }
362  memcpy(tmp, block, len);
363  tmp[len] = '\0';
364  ast_str_append(response, 0, "%s", tmp);
365  ast_free(tmp);
366 
367  return 0;
368 }
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 struct ast_str* generate_exchange_uuid ( struct ast_str uid)
static

Definition at line 242 of file res_calendar_exchange.c.

References ast_random(), and ast_str_set().

Referenced by exchangecal_write_event().

243 {
244  unsigned short val[8];
245  int x;
246 
247  for (x = 0; x < 8; x++) {
248  val[x] = ast_random();
249  }
250  ast_str_set(&uid, 0, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", (unsigned)val[0],
251  (unsigned)val[1], (unsigned)val[2], (unsigned)val[3], (unsigned)val[4],
252  (unsigned)val[5], (unsigned)val[6], (unsigned)val[7]);
253 
254  return uid;
255 }
Definition: ast_expr2.c:325
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
long int ast_random(void)
Definition: utils.c:1640
static int is_valid_uuid ( struct ast_str uid)
static

Definition at line 257 of file res_calendar_exchange.c.

References ast_str_buffer(), and ast_str_strlen().

Referenced by exchangecal_write_event().

258 {
259  int i;
260 
261  if (ast_str_strlen(uid) != 36) {
262  return 0;
263  }
264 
265  for (i = 0; i < ast_str_strlen(uid); i++) {
266  if (i == 8 || i == 13 || i == 18 || i == 23) {
267  if (ast_str_buffer(uid)[i] != '-') {
268  return 0;
269  }
270  } else if (!((ast_str_buffer(uid)[i] > 47 && ast_str_buffer(uid)[i] < 58) || (ast_str_buffer(uid)[i] > 96 && ast_str_buffer(uid)[i] < 103))) {
271  return 0;
272  }
273  }
274 
275  return 1;
276 }
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
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 load_module ( void  )
static

Definition at line 744 of file res_calendar_exchange.c.

References ast_calendar_register(), AST_MODULE_LOAD_DECLINE, and AST_MODULE_LOAD_SUCCESS.

745 {
746  ne_sock_init();
748  ne_sock_exit();
750  }
751 
753 }
int ast_calendar_register(struct ast_calendar_tech *tech)
Register a new calendar technology.
Definition: res_calendar.c:490
static struct ast_calendar_tech exchangecal_tech
static enum ast_calendar_busy_state msbusy_to_bs ( const char *  msbusy)
static

Definition at line 159 of file res_calendar_exchange.c.

References AST_CALENDAR_BS_BUSY, AST_CALENDAR_BS_BUSY_TENTATIVE, and AST_CALENDAR_BS_FREE.

Referenced by parse_cdata().

160 {
161  if (!strcasecmp(msbusy, "FREE")) {
162  return AST_CALENDAR_BS_FREE;
163  } else if (!strcasecmp(msbusy, "TENTATIVE")) {
165  } else {
166  return AST_CALENDAR_BS_BUSY;
167  }
168 }
static time_t mstime_to_time_t ( char *  mstime)
static

Definition at line 139 of file res_calendar_exchange.c.

Referenced by parse_cdata().

140 {
141  char *read, *write;
142  icaltimetype tt;
143  for (read = write = mstime; *read; read++) {
144  if (*read == '.') {
145  *write++ = 'Z';
146  *write = '\0';
147  break;
148  }
149  if (*read == '-' || *read == ':')
150  continue;
151  *write = *read;
152  write++;
153  }
154 
155  tt = icaltime_from_string(mstime);
156  return icaltime_as_timet(tt);
157 }
static const char * mstime(time_t t, char *buf, size_t buflen)
static int parse_cdata ( void *  data,
char *  value,
size_t  len 
)
static

Definition at line 170 of file res_calendar_exchange.c.

References ast_calloc, ast_free, ast_skip_blanks(), ast_string_field_build, ast_calendar_event::description, xmlstate::in_prop, xmlstate::in_propstat, xmlstate::in_response, ast_calendar_event::location, msbusy_to_bs(), mstime_to_time_t(), ast_calendar_event::organizer, xmlstate::ptr, str, ast_calendar_event::summary, xmlstate::tag, and ast_calendar_event::uid.

Referenced by update_exchangecal().

171 {
172  char *str;
173  struct xmlstate *state = data;
174  struct ast_calendar_event *event = state->ptr;
175 
176 
177  str = ast_skip_blanks(value);
178 
179  if (str == value + len)
180  return IKS_OK;
181 
182  if (!(str = ast_calloc(1, len + 1))) {
183  return IKS_NOMEM;
184  }
185  memcpy(str, value, len);
186  if (!(state->in_response && state->in_propstat && state->in_prop)) {
187  ast_free(str);
188  return IKS_OK;
189  }
190  /* We use ast_string_field_build here because libiksemel is parsing CDATA with &lt; as
191  * new elements which is a bit odd and shouldn't happen */
192  if (!strcasecmp(state->tag, "subject")) {
193  ast_string_field_build(event, summary, "%s%s", event->summary, str);
194  } else if (!strcasecmp(state->tag, "location")) {
195  ast_string_field_build(event, location, "%s%s", event->location, str);
196  } else if (!strcasecmp(state->tag, "uid")) {
197  ast_string_field_build(event, uid, "%s%s", event->location, str);
198  } else if (!strcasecmp(state->tag, "organizer")) {
199  ast_string_field_build(event, organizer, "%s%s", event->organizer, str);
200  } else if (!strcasecmp(state->tag, "textdescription")) {
201  ast_string_field_build(event, description, "%s%s", event->description, str);
202  } else if (!strcasecmp(state->tag, "dtstart")) {
203  event->start = mstime_to_time_t(str);
204  } else if (!strcasecmp(state->tag, "dtend")) {
205  event->end = mstime_to_time_t(str);
206  } else if (!strcasecmp(state->tag, "busystatus")) {
207  event->busy_state = msbusy_to_bs(str);
208  } else if (!strcasecmp(state->tag, "reminderoffset")) {
209  /*XXX Currently we rely on event->start being set first which means we rely on the response order
210  * which technically should be fine since the query returns in the order we ask for, but ... */
211  event->alarm = event->start - atoi(str);
212  }
213 
214  ast_free(str);
215  return IKS_OK;
216 }
static time_t mstime_to_time_t(char *mstime)
const ast_string_field uid
Definition: calendar.h:101
const char * str
Definition: app_jack.c:144
int value
Definition: syslog.c:39
const ast_string_field description
Definition: calendar.h:101
const ast_string_field organizer
Definition: calendar.h:101
const ast_string_field location
Definition: calendar.h:101
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:97
#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
#define ast_calloc(a, b)
Definition: astmm.h:82
const ast_string_field summary
Definition: calendar.h:101
static enum ast_calendar_busy_state msbusy_to_bs(const char *msbusy)
static int parse_tag ( void *  data,
char *  name,
char **  atts,
int  type 
)
static

Definition at line 82 of file res_calendar_exchange.c.

References ao2_link, ast_calendar_event_alloc(), ast_calendar_unref_event(), ast_copy_string(), ast_log(), ast_strlen_zero(), events, caldav_pvt::events, xmlstate::in_prop, xmlstate::in_propstat, xmlstate::in_response, LOG_ERROR, caldav_pvt::owner, xmlstate::ptr, xmlstate::pvt, and xmlstate::tag.

Referenced by update_exchangecal().

83 {
84  struct xmlstate *state = data;
85  char *tmp;
86 
87  if ((tmp = strchr(name, ':'))) {
88  tmp++;
89  } else {
90  return IKS_HOOK;
91  }
92 
93  ast_copy_string(state->tag, tmp, sizeof(state->tag));
94 
95  switch (type) {
96  case IKS_OPEN:
97  if (!strcasecmp(state->tag, "response")) {
98  struct ast_calendar_event *event;
99 
100  state->in_response = 1;
101  if (!(event = ast_calendar_event_alloc(state->pvt->owner))) {
102  return IKS_NOMEM;
103  }
104  state->ptr = event;
105  } else if (!strcasecmp(state->tag, "propstat")) {
106  state->in_propstat = 1;
107  } else if (!strcasecmp(state->tag, "prop")) {
108  state->in_prop = 1;
109  }
110  break;
111 
112  case IKS_CLOSE:
113  if (!strcasecmp(state->tag, "response")) {
114  struct ao2_container *events = state->pvt->events;
115  struct ast_calendar_event *event = state->ptr;
116 
117  state->in_response = 0;
118  if (ast_strlen_zero(event->uid)) {
119  ast_log(LOG_ERROR, "This event has no UID, something has gone wrong\n");
120  event = ast_calendar_unref_event(event);
121  return IKS_HOOK;
122  }
123  ao2_link(events, event);
124  event = ast_calendar_unref_event(event);
125  } else if (!strcasecmp(state->tag, "propstat")) {
126  state->in_propstat = 0;
127  } else if (!strcasecmp(state->tag, "prop")) {
128  state->in_prop = 0;
129  }
130  break;
131 
132  default:
133  return IKS_OK;
134  }
135 
136  return IKS_OK;
137 }
#define ao2_link(arg1, arg2)
Definition: astobj2.h:785
struct caldav_pvt * pvt
const ast_string_field uid
Definition: calendar.h:101
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
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 const char name[]
struct ast_calendar_event * ast_calendar_unref_event(struct ast_calendar_event *event)
Unreference an ast_calendar_event.
Definition: res_calendar.c:300
static const char type[]
Definition: chan_nbs.c:57
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
static struct adsi_event events[]
Definition: app_adsiprog.c:78
struct ao2_container * events
static int unload_module ( void  )
static

Definition at line 755 of file res_calendar_exchange.c.

References ast_calendar_unregister().

756 {
758  ne_sock_exit();
759  return 0;
760 }
static struct ast_calendar_tech exchangecal_tech
void ast_calendar_unregister(struct ast_calendar_tech *tech)
Unregister a new calendar technology.
Definition: res_calendar.c:523
static void * unref_exchangecal ( void *  obj)
static

Definition at line 233 of file res_calendar_exchange.c.

References ao2_ref.

Referenced by exchangecal_load_calendar().

234 {
235  struct exchangecal_pvt *pvt = obj;
236 
237  ao2_ref(pvt, -1);
238  return NULL;
239 }
#define ao2_ref(o, delta)
Definition: astobj2.h:472
static int update_exchangecal ( struct exchangecal_pvt pvt)
static

Definition at line 596 of file res_calendar_exchange.c.

References ast_calendar_merge_events(), ast_free, ast_str_buffer(), ast_str_strlen(), ast_tvnow(), exchangecal_pvt::events, exchangecal_get_events_between(), exchangecal_pvt::owner, parse_cdata(), parse_tag(), xmlstate::pvt, and ast_calendar::timeframe.

Referenced by exchangecal_load_calendar().

597 {
598  struct xmlstate state;
599  struct timeval now = ast_tvnow();
600  time_t start, end;
601  struct ast_str *response;
602  iksparser *p;
603 
604  state.pvt = pvt;
605  start = now.tv_sec;
606  end = now.tv_sec + 60 * pvt->owner->timeframe;
607  if (!(response = exchangecal_get_events_between(pvt, start, end))) {
608  return -1;
609  }
610 
611  p = iks_sax_new(&state, parse_tag, parse_cdata);
612  iks_parse(p, ast_str_buffer(response), ast_str_strlen(response), 1);
614  ast_free(response);
615 
616  return 0;
617 }
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
struct ast_calendar * owner
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
int timeframe
Definition: calendar.h:131
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
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
static int parse_tag(void *data, char *name, char **atts, int type)
static struct ast_str * exchangecal_get_events_between(struct exchangecal_pvt *pvt, time_t start_time, time_t end_time)
struct ao2_container * events
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 parse_cdata(void *data, char *value, size_t len)
static struct ast_str* xml_encode_str ( struct ast_str dst,
const char *  src 
)
static

Definition at line 278 of file res_calendar_exchange.c.

References ast_str_append().

Referenced by exchangecal_write_event().

279 {
280  const char *tmp;
281  char buf[7];
282 
283  for (tmp = src; *tmp; tmp++) {
284  switch (*tmp) {
285  case '\"':
286  strcpy(buf, "&quot;");
287  break;
288 
289  case '\'':
290  strcpy(buf, "&apos;");
291  break;
292 
293  case '&':
294  strcpy(buf, "&amp;");
295  break;
296 
297  case '<':
298  strcpy(buf, "&lt;");
299  break;
300 
301  case '>':
302  strcpy(buf, "&gt;");
303  break;
304 
305  default:
306  sprintf(buf, "%c", *tmp);
307  }
308 
309  ast_str_append(&dst, 0, "%s", buf);
310  }
311 
312  return dst;
313 }
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

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Asterisk MS Exchange 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 766 of file res_calendar_exchange.c.

Definition at line 766 of file res_calendar_exchange.c.

struct ast_calendar_tech exchangecal_tech
static

Definition at line 52 of file res_calendar_exchange.c.