Asterisk - The Open Source Telephony Project GIT-master-2de1a68
Data Structures | Functions | Variables
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/channel.h"
#include "asterisk/calendar.h"
#include "asterisk/lock.h"
#include "asterisk/config.h"
#include "asterisk/astobj2.h"
#include "asterisk/uuid.h"
Include dependency graph for res_calendar_exchange.c:

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)
 
struct ast_moduleAST_MODULE_SELF_SYM (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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, .requires = "res_calendar", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_calendar_tech exchangecal_tech
 

Detailed Description

Resource for handling MS Exchange calendars.

Definition in file res_calendar_exchange.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 749 of file res_calendar_exchange.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 749 of file res_calendar_exchange.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 749 of file res_calendar_exchange.c.

◆ auth_credentials()

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

Definition at line 357 of file res_calendar_exchange.c.

358{
359 struct exchangecal_pvt *pvt = userdata;
360
361 if (attempts > 1) {
362 ast_log(LOG_WARNING, "Invalid username or password for Exchange calendar '%s'\n", pvt->owner->name);
363 return -1;
364 }
365
366 ne_strnzcpy(username, pvt->user, NE_ABUFSIZ);
367 ne_strnzcpy(secret, pvt->secret, NE_ABUFSIZ);
368
369 return 0;
370}
#define ast_log
Definition: astobj2.c:42
#define LOG_WARNING
const ast_string_field name
Definition: calendar.h:129
struct ast_calendar * owner
const ast_string_field user
const ast_string_field secret

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

Referenced by exchangecal_load_calendar().

◆ bs_to_exchange_bs()

static struct ast_str * bs_to_exchange_bs ( struct ast_str dst,
enum ast_calendar_busy_state  bs 
)
static

Definition at line 323 of file res_calendar_exchange.c.

324{
325 switch (bs) {
327 ast_str_set(&dst, 0, "%s", "BUSY");
328 break;
329
331 ast_str_set(&dst, 0, "%s", "TENTATIVE");
332 break;
333
334 default:
335 ast_str_set(&dst, 0, "%s", "FREE");
336 }
337
338 return dst;
339}
@ AST_CALENDAR_BS_BUSY_TENTATIVE
Definition: calendar.h:85
@ AST_CALENDAR_BS_BUSY
Definition: calendar.h:86
char * bs
Definition: eagi_proxy.c:73
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113

References AST_CALENDAR_BS_BUSY, AST_CALENDAR_BS_BUSY_TENTATIVE, ast_str_set(), and bs.

Referenced by exchangecal_write_event().

◆ epoch_to_exchange_time()

static struct ast_str * epoch_to_exchange_time ( struct ast_str dst,
time_t  epoch 
)
static

Definition at line 302 of file res_calendar_exchange.c.

303{
304 icaltimezone *utc = icaltimezone_get_utc_timezone();
305 icaltimetype tt = icaltime_from_timet_with_zone(epoch, 0, utc);
306 char tmp[30];
307 int i;
308
309 ast_copy_string(tmp, icaltime_as_ical_string(tt), sizeof(tmp));
310 for (i = 0; tmp[i]; i++) {
311 ast_str_append(&dst, 0, "%c", tmp[i]);
312 if (i == 3 || i == 5)
313 ast_str_append(&dst, 0, "%c", '-');
314 if (i == 10 || i == 12)
315 ast_str_append(&dst, 0, "%c", ':');
316 if (i == 14)
317 ast_str_append(&dst, 0, "%s", ".000");
318 }
319
320 return dst;
321}
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:1139
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425

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

Referenced by exchangecal_write_event().

◆ exchangecal_destructor()

static void exchangecal_destructor ( void *  obj)
static

Definition at line 219 of file res_calendar_exchange.c.

220{
221 struct exchangecal_pvt *pvt = obj;
222
223 ast_debug(1, "Destroying pvt for Exchange calendar %s\n", pvt->owner->name);
224 if (pvt->session) {
225 ne_session_destroy(pvt->session);
226 }
227 ne_uri_free(&pvt->uri);
229
231
232 ao2_ref(pvt->events, -1);
233}
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ OBJ_UNLINK
Definition: astobj2.h:1039
#define ast_debug(level,...)
Log a DEBUG message.
#define NULL
Definition: resample.c:96
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
struct ao2_container * events

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

Referenced by exchangecal_load_calendar().

◆ exchangecal_get_events_between()

static struct ast_str * exchangecal_get_events_between ( struct exchangecal_pvt pvt,
time_t  start_time,
time_t  end_time 
)
static

Definition at line 532 of file res_calendar_exchange.c.

533{
534 struct ast_str *body, *response;
535 char start[80], end[80];
536 struct timeval tv = {0,};
537 struct ast_tm tm;
538
539 tv.tv_sec = start_time;
540 ast_localtime(&tv, &tm, "UTC");
541 ast_strftime(start, sizeof(start), "%Y/%m/%d %T", &tm);
542
543 tv.tv_sec = end_time;
544 ast_localtime(&tv, &tm, "UTC");
545 ast_strftime(end, sizeof(end), "%Y/%m/%d %T", &tm);
546
547 if (!(body = ast_str_create(512))) {
548 ast_log(LOG_ERROR, "Could not allocate memory for body of request!\n");
549 return NULL;
550 }
551
552 ast_str_append(&body, 0,
553 "<?xml version=\"1.0\"?>\n"
554 "<g:searchrequest xmlns:g=\"DAV:\">\n"
555 " <g:sql> SELECT \"urn:schemas:calendar:location\", \"urn:schemas:httpmail:subject\",\n"
556 " \"urn:schemas:calendar:dtstart\", \"urn:schemas:calendar:dtend\",\n"
557 " \"urn:schemas:calendar:busystatus\", \"urn:schemas:calendar:instancetype\",\n"
558 " \"urn:schemas:calendar:uid\", \"urn:schemas:httpmail:textdescription\",\n"
559 " \"urn:schemas:calendar:organizer\", \"urn:schemas:calendar:reminderoffset\"\n"
560 " FROM Scope('SHALLOW TRAVERSAL OF \"%s/Calendar\"')\n"
561 " WHERE NOT \"urn:schemas:calendar:instancetype\" = 1\n"
562 " AND \"DAV:contentclass\" = 'urn:content-classes:appointment'\n"
563 " AND NOT (\"urn:schemas:calendar:dtend\" &lt; '%s'\n"
564 " OR \"urn:schemas:calendar:dtstart\" &gt; '%s')\n"
565 " ORDER BY \"urn:schemas:calendar:dtstart\" ASC\n"
566 " </g:sql>\n"
567 "</g:searchrequest>\n", pvt->url, start, end);
568
569 ast_debug(5, "Request:\n%s\n", ast_str_buffer(body));
570 response = exchangecal_request(pvt, "SEARCH", body, NULL);
571 ast_debug(5, "Response:\n%s\n", ast_str_buffer(response));
572 ast_free(body);
573
574 return response;
575}
#define ast_free(a)
Definition: astmm.h:180
char * end
Definition: eagi_proxy.c:73
#define LOG_ERROR
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:1739
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:2524
static struct ast_str * exchangecal_request(struct exchangecal_pvt *pvt, const char *method, struct ast_str *req_body, struct ast_str *subdir)
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
Support for dynamic strings.
Definition: strings.h:623
const ast_string_field url

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

Referenced by update_exchangecal().

◆ exchangecal_load_calendar()

static void * exchangecal_load_calendar ( void *  data)
static

Definition at line 600 of file res_calendar_exchange.c.

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

References ao2_alloc, ao2_trylock, ao2_unlock, ast_calendar_config_acquire(), ast_calendar_config_release(), ast_calendar_event_container_alloc(), ast_cond_timedwait, ast_debug, ast_log, ast_mutex_init, ast_mutex_lock, ast_mutex_unlock, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ast_tvnow(), ast_variable_browse(), auth_credentials(), exchangecal_pvt::events, exchangecal_destructor(), LOG_ERROR, LOG_WARNING, ast_calendar::name, ast_variable::name, ast_variable::next, NULL, exchangecal_pvt::owner, ast_calendar::refresh, refreshlock, 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.

◆ exchangecal_request()

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 372 of file res_calendar_exchange.c.

373{
374 struct ast_str *response;
375 ne_request *req;
376 int ret;
377 char buf[1000];
378
379 if (!pvt) {
380 ast_log(LOG_ERROR, "There is no private!\n");
381 return NULL;
382 }
383
384 if (!(response = ast_str_create(512))) {
385 ast_log(LOG_ERROR, "Could not allocate memory for response.\n");
386 return NULL;
387 }
388
389 snprintf(buf, sizeof(buf), "%s%s", pvt->uri.path, subdir ? ast_str_buffer(subdir) : "");
390
391 req = ne_request_create(pvt->session, method, buf);
392 ne_add_response_body_reader(req, ne_accept_2xx, fetch_response_reader, &response);
393 ne_set_request_body_buffer(req, ast_str_buffer(req_body), ast_str_strlen(req_body));
394 ne_add_request_header(req, "Content-type", "text/xml");
395
396 ret = ne_request_dispatch(req);
397 ne_request_destroy(req);
398
399 if (ret != NE_OK || !ast_str_strlen(response)) {
400 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));
401 ast_free(response);
402 return NULL;
403 }
404
405 return response;
406}
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int fetch_response_reader(void *data, const char *block, size_t len)
const char * method
Definition: res_pjsip.c:1279
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730

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

Referenced by exchangecal_get_events_between(), and exchangecal_write_event().

◆ exchangecal_write_event()

static int exchangecal_write_event ( struct ast_calendar_event event)
static

Definition at line 408 of file res_calendar_exchange.c.

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

References ast_free, ast_log, ast_str_append(), ast_str_buffer(), ast_str_create, ast_str_set(), ast_strlen_zero(), AST_UUID_STR_LEN, ast_verb, bs_to_exchange_bs(), end, epoch_to_exchange_time(), exchangecal_request(), generate_exchange_uuid(), is_valid_uuid(), LOG_ERROR, LOG_WARNING, NULL, and xml_encode_str().

◆ fetch_response_reader()

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

Definition at line 341 of file res_calendar_exchange.c.

342{
343 struct ast_str **response = data;
344 unsigned char *tmp;
345
346 if (!(tmp = ast_malloc(len + 1))) {
347 return -1;
348 }
349 memcpy(tmp, block, len);
350 tmp[len] = '\0';
351 ast_str_append(response, 0, "%s", tmp);
352 ast_free(tmp);
353
354 return 0;
355}
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)

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

Referenced by exchangecal_request().

◆ generate_exchange_uuid()

static struct ast_str * generate_exchange_uuid ( struct ast_str uid)
static

Definition at line 244 of file res_calendar_exchange.c.

245{
246 char buffer[AST_UUID_STR_LEN];
247
248 ast_uuid_generate_str(buffer, sizeof(buffer));
249 ast_str_set(&uid, 0, "%s", buffer);
250 return uid;
251}
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
Definition: uuid.c:141

References ast_str_set(), ast_uuid_generate_str(), and AST_UUID_STR_LEN.

Referenced by exchangecal_write_event().

◆ is_valid_uuid()

static int is_valid_uuid ( struct ast_str uid)
static

Definition at line 253 of file res_calendar_exchange.c.

254{
255 struct ast_uuid *uuid = ast_str_to_uuid(ast_str_buffer(uid));
256
257 if (uuid) {
258 ast_free(uuid);
259 return 1;
260 }
261
262 return 0;
263}
Definition: uuid.c:39
struct ast_uuid * ast_str_to_uuid(char *str)
Convert a string to a UUID.
Definition: uuid.c:149

References ast_free, ast_str_buffer(), and ast_str_to_uuid().

Referenced by exchangecal_write_event().

◆ load_module()

static int load_module ( void  )
static

Definition at line 725 of file res_calendar_exchange.c.

726{
727 ne_sock_init();
729 ne_sock_exit();
731 }
732
734}
int ast_calendar_register(struct ast_calendar_tech *tech)
Register a new calendar technology.
Definition: res_calendar.c:551
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static struct ast_calendar_tech exchangecal_tech

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

◆ msbusy_to_bs()

static enum ast_calendar_busy_state msbusy_to_bs ( const char *  msbusy)
static

Definition at line 160 of file res_calendar_exchange.c.

161{
162 if (!strcasecmp(msbusy, "FREE")) {
164 } else if (!strcasecmp(msbusy, "TENTATIVE")) {
166 } else {
168 }
169}
@ AST_CALENDAR_BS_FREE
Definition: calendar.h:84

References AST_CALENDAR_BS_BUSY, AST_CALENDAR_BS_BUSY_TENTATIVE, and AST_CALENDAR_BS_FREE.

Referenced by parse_cdata().

◆ mstime_to_time_t()

static time_t mstime_to_time_t ( char *  mstime)
static

Definition at line 140 of file res_calendar_exchange.c.

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

References mstime().

Referenced by parse_cdata().

◆ parse_cdata()

static int parse_cdata ( void *  data,
char *  value,
size_t  len 
)
static

Definition at line 171 of file res_calendar_exchange.c.

172{
173 char *str;
174 struct xmlstate *state = data;
175 struct ast_calendar_event *event = state->ptr;
176
177
179
180 if (str == value + len)
181 return IKS_OK;
182
183 if (!(str = ast_calloc(1, len + 1))) {
184 return IKS_NOMEM;
185 }
186 memcpy(str, value, len);
187 if (!(state->in_response && state->in_propstat && state->in_prop)) {
188 ast_free(str);
189 return IKS_OK;
190 }
191 /* We use ast_string_field_build here because libiksemel is parsing CDATA with &lt; as
192 * new elements which is a bit odd and shouldn't happen */
193 if (!strcasecmp(state->tag, "subject")) {
194 ast_string_field_build(event, summary, "%s%s", event->summary, str);
195 } else if (!strcasecmp(state->tag, "location")) {
196 ast_string_field_build(event, location, "%s%s", event->location, str);
197 } else if (!strcasecmp(state->tag, "uid")) {
198 ast_string_field_build(event, uid, "%s%s", event->location, str);
199 } else if (!strcasecmp(state->tag, "organizer")) {
200 ast_string_field_build(event, organizer, "%s%s", event->organizer, str);
201 } else if (!strcasecmp(state->tag, "textdescription")) {
202 ast_string_field_build(event, description, "%s%s", event->description, str);
203 } else if (!strcasecmp(state->tag, "dtstart")) {
204 event->start = mstime_to_time_t(str);
205 } else if (!strcasecmp(state->tag, "dtend")) {
206 event->end = mstime_to_time_t(str);
207 } else if (!strcasecmp(state->tag, "busystatus")) {
208 event->busy_state = msbusy_to_bs(str);
209 } else if (!strcasecmp(state->tag, "reminderoffset")) {
210 /*XXX Currently we rely on event->start being set first which means we rely on the response order
211 * which technically should be fine since the query returns in the order we ask for, but ... */
212 event->alarm = event->start - atoi(str);
213 }
214
215 ast_free(str);
216 return IKS_OK;
217}
const char * str
Definition: app_jack.c:147
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
static enum ast_calendar_busy_state msbusy_to_bs(const char *msbusy)
static time_t mstime_to_time_t(char *mstime)
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Definition: stringfields.h:555
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:161
Calendar events.
Definition: calendar.h:95
const ast_string_field uid
Definition: calendar.h:103
const ast_string_field location
Definition: calendar.h:103
const ast_string_field description
Definition: calendar.h:103
const ast_string_field organizer
Definition: calendar.h:103
const ast_string_field summary
Definition: calendar.h:103
int value
Definition: syslog.c:37

References ast_calloc, ast_free, ast_skip_blanks(), ast_string_field_build, ast_calendar_event::description, len(), ast_calendar_event::location, msbusy_to_bs(), mstime_to_time_t(), ast_calendar_event::organizer, str, ast_calendar_event::summary, ast_calendar_event::uid, and value.

Referenced by update_exchangecal().

◆ parse_tag()

static int parse_tag ( void *  data,
char *  name,
char **  atts,
int  type 
)
static

Definition at line 83 of file res_calendar_exchange.c.

84{
85 struct xmlstate *state = data;
86 char *tmp;
87
88 if ((tmp = strchr(name, ':'))) {
89 tmp++;
90 } else {
91 return IKS_HOOK;
92 }
93
94 ast_copy_string(state->tag, tmp, sizeof(state->tag));
95
96 switch (type) {
97 case IKS_OPEN:
98 if (!strcasecmp(state->tag, "response")) {
100
101 state->in_response = 1;
102 if (!(event = ast_calendar_event_alloc(state->pvt->owner))) {
103 return IKS_NOMEM;
104 }
105 state->ptr = event;
106 } else if (!strcasecmp(state->tag, "propstat")) {
107 state->in_propstat = 1;
108 } else if (!strcasecmp(state->tag, "prop")) {
109 state->in_prop = 1;
110 }
111 break;
112
113 case IKS_CLOSE:
114 if (!strcasecmp(state->tag, "response")) {
115 struct ao2_container *events = state->pvt->events;
116 struct ast_calendar_event *event = state->ptr;
117
118 state->in_response = 0;
119 if (ast_strlen_zero(event->uid)) {
120 ast_log(LOG_ERROR, "This event has no UID, something has gone wrong\n");
122 return IKS_HOOK;
123 }
126 } else if (!strcasecmp(state->tag, "propstat")) {
127 state->in_propstat = 0;
128 } else if (!strcasecmp(state->tag, "prop")) {
129 state->in_prop = 0;
130 }
131 break;
132
133 default:
134 return IKS_OK;
135 }
136
137 return IKS_OK;
138}
static const struct adsi_event events[]
Definition: app_adsiprog.c:85
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
struct ast_calendar_event * ast_calendar_event_alloc(struct ast_calendar *cal)
Allocate an astobj2 ast_calendar_event object.
Definition: res_calendar.c:669
struct ast_calendar_event * ast_calendar_unref_event(struct ast_calendar_event *event)
Unreference an ast_calendar_event.
Definition: res_calendar.c:323
static const char type[]
Definition: chan_ooh323.c:109
static const char name[]
Definition: format_mp3.c:68
Generic container type.

References ao2_link, ast_calendar_event_alloc(), ast_calendar_unref_event(), ast_copy_string(), ast_log, ast_strlen_zero(), events, LOG_ERROR, name, tmp(), and type.

Referenced by update_exchangecal().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 736 of file res_calendar_exchange.c.

737{
739 ne_sock_exit();
740 return 0;
741}
void ast_calendar_unregister(struct ast_calendar_tech *tech)
Unregister a new calendar technology.
Definition: res_calendar.c:589

References ast_calendar_unregister(), and exchangecal_tech.

◆ unref_exchangecal()

static void * unref_exchangecal ( void *  obj)
static

Definition at line 235 of file res_calendar_exchange.c.

236{
237 struct exchangecal_pvt *pvt = obj;
238
239 ao2_ref(pvt, -1);
240 return NULL;
241}

References ao2_ref, and NULL.

Referenced by exchangecal_load_calendar().

◆ update_exchangecal()

static int update_exchangecal ( struct exchangecal_pvt pvt)
static

Definition at line 577 of file res_calendar_exchange.c.

578{
579 struct xmlstate state;
580 struct timeval now = ast_tvnow();
581 time_t start, end;
582 struct ast_str *response;
583 iksparser *p;
584
585 state.pvt = pvt;
586 start = now.tv_sec;
587 end = now.tv_sec + 60 * pvt->owner->timeframe;
588 if (!(response = exchangecal_get_events_between(pvt, start, end))) {
589 return -1;
590 }
591
592 p = iks_sax_new(&state, parse_tag, parse_cdata);
593 iks_parse(p, ast_str_buffer(response), ast_str_strlen(response), 1);
595 ast_free(response);
596
597 return 0;
598}
void ast_calendar_merge_events(struct ast_calendar *cal, struct ao2_container *new_events)
Add an event to the list of events for a calendar.
static int parse_tag(void *data, char *name, char **atts, int type)
static int parse_cdata(void *data, char *value, size_t len)
static struct ast_str * exchangecal_get_events_between(struct exchangecal_pvt *pvt, time_t start_time, time_t end_time)
int timeframe
Definition: calendar.h:135

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

Referenced by exchangecal_load_calendar().

◆ xml_encode_str()

static struct ast_str * xml_encode_str ( struct ast_str dst,
const char *  src 
)
static

Definition at line 265 of file res_calendar_exchange.c.

266{
267 const char *tmp;
268 char buf[7];
269
270 for (tmp = src; *tmp; tmp++) {
271 switch (*tmp) {
272 case '\"':
273 strcpy(buf, "&quot;");
274 break;
275
276 case '\'':
277 strcpy(buf, "&apos;");
278 break;
279
280 case '&':
281 strcpy(buf, "&amp;");
282 break;
283
284 case '<':
285 strcpy(buf, "&lt;");
286 break;
287
288 case '>':
289 strcpy(buf, "&gt;");
290 break;
291
292 default:
293 sprintf(buf, "%c", *tmp);
294 }
295
296 ast_str_append(&dst, 0, "%s", buf);
297 }
298
299 return dst;
300}

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

Referenced by exchangecal_write_event().

Variable Documentation

◆ __mod_info

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

Definition at line 749 of file res_calendar_exchange.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 749 of file res_calendar_exchange.c.

◆ exchangecal_tech

struct ast_calendar_tech exchangecal_tech
static

Definition at line 53 of file res_calendar_exchange.c.

Referenced by load_module(), and unload_module().