Wed Aug 7 17:16:10 2019

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, exchangecal_pvt::owner, exchangecal_pvt::secret, and exchangecal_pvt::user.

Referenced by exchangecal_load_calendar().

00371 {
00372    struct exchangecal_pvt *pvt = userdata;
00373 
00374    if (attempts > 1) {
00375       ast_log(LOG_WARNING, "Invalid username or password for Exchange calendar '%s'\n", pvt->owner->name);
00376       return -1;
00377    }
00378 
00379    ne_strnzcpy(username, pvt->user, NE_ABUFSIZ);
00380    ne_strnzcpy(secret, pvt->secret, NE_ABUFSIZ);
00381 
00382    return 0;
00383 }

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

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

00337 {
00338    switch (bs) {
00339    case AST_CALENDAR_BS_BUSY:
00340       ast_str_set(&dst, 0, "%s", "BUSY");
00341       break;
00342 
00343    case AST_CALENDAR_BS_BUSY_TENTATIVE:
00344       ast_str_set(&dst, 0, "%s", "TENTATIVE");
00345       break;
00346 
00347    default:
00348       ast_str_set(&dst, 0, "%s", "FREE");
00349    }
00350 
00351    return dst;
00352 }

static struct ast_str* epoch_to_exchange_time ( struct ast_str dst,
time_t  epoch 
) [static, read]

Definition at line 315 of file res_calendar_exchange.c.

References ast_copy_string(), and ast_str_append().

Referenced by exchangecal_write_event().

00316 {
00317    icaltimezone *utc = icaltimezone_get_utc_timezone();
00318    icaltimetype tt = icaltime_from_timet_with_zone(epoch, 0, utc);
00319    char tmp[30];
00320    int i;
00321 
00322    ast_copy_string(tmp, icaltime_as_ical_string(tt), sizeof(tmp));
00323    for (i = 0; tmp[i]; i++) {
00324       ast_str_append(&dst, 0, "%c", tmp[i]);
00325       if (i == 3 || i == 5)
00326          ast_str_append(&dst, 0, "%c", '-');
00327       if (i == 10 || i == 12)
00328          ast_str_append(&dst, 0, "%c", ':');
00329       if (i == 14)
00330          ast_str_append(&dst, 0, "%s", ".000");
00331    }
00332 
00333    return dst;
00334 }

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

Referenced by exchangecal_load_calendar().

00219 {
00220    struct exchangecal_pvt *pvt = obj;
00221 
00222    ast_debug(1, "Destroying pvt for Exchange calendar %s\n", pvt->owner->name);
00223    if (pvt->session) {
00224       ne_session_destroy(pvt->session);
00225    }
00226    ast_string_field_free_memory(pvt);
00227 
00228    ao2_callback(pvt->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
00229 
00230    ao2_ref(pvt->events, -1);
00231 }

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

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

00552 {
00553    struct ast_str *body, *response;
00554    char start[80], end[80];
00555    struct timeval tv = {0,};
00556    struct ast_tm tm;
00557 
00558    tv.tv_sec = start_time;
00559    ast_localtime(&tv, &tm, "UTC");
00560    ast_strftime(start, sizeof(start), "%Y/%m/%d %T", &tm);
00561 
00562    tv.tv_sec = end_time;
00563    ast_localtime(&tv, &tm, "UTC");
00564    ast_strftime(end, sizeof(end), "%Y/%m/%d %T", &tm);
00565 
00566    if (!(body = ast_str_create(512))) {
00567       ast_log(LOG_ERROR, "Could not allocate memory for body of request!\n");
00568       return NULL;
00569    }
00570 
00571    ast_str_append(&body, 0,
00572       "<?xml version=\"1.0\"?>\n"
00573       "<g:searchrequest xmlns:g=\"DAV:\">\n"
00574       "        <g:sql> SELECT \"urn:schemas:calendar:location\", \"urn:schemas:httpmail:subject\",\n"
00575       "                \"urn:schemas:calendar:dtstart\", \"urn:schemas:calendar:dtend\",\n"
00576       "                \"urn:schemas:calendar:busystatus\", \"urn:schemas:calendar:instancetype\",\n"
00577       "                \"urn:schemas:calendar:uid\", \"urn:schemas:httpmail:textdescription\",\n"
00578       "                \"urn:schemas:calendar:organizer\", \"urn:schemas:calendar:reminderoffset\"\n"
00579       "                FROM Scope('SHALLOW TRAVERSAL OF \"%s/Calendar\"')\n"
00580       "                WHERE NOT \"urn:schemas:calendar:instancetype\" = 1\n"
00581       "                AND \"DAV:contentclass\" = 'urn:content-classes:appointment'\n"
00582       "                AND NOT (\"urn:schemas:calendar:dtend\" &lt; '%s'\n"
00583       "                OR \"urn:schemas:calendar:dtstart\" &gt; '%s')\n"
00584       "                ORDER BY \"urn:schemas:calendar:dtstart\" ASC\n"
00585       "         </g:sql>\n"
00586       "</g:searchrequest>\n", pvt->url, start, end);
00587 
00588    ast_debug(5, "Request:\n%s\n", ast_str_buffer(body));
00589    response = exchangecal_request(pvt, "SEARCH", body, NULL);
00590    ast_debug(5, "Response:\n%s\n", ast_str_buffer(response));
00591    ast_free(body);
00592 
00593    return response;
00594 }

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

00620 {
00621    struct exchangecal_pvt *pvt;
00622    const struct ast_config *cfg;
00623    struct ast_variable *v;
00624    struct ast_calendar *cal = void_data;
00625    ast_mutex_t refreshlock;
00626 
00627    if (!(cal && (cfg = ast_calendar_config_acquire()))) {
00628       ast_log(LOG_ERROR, "You must enable calendar support for res_exchangecal to load\n");
00629       return NULL;
00630    }
00631 
00632    if (ao2_trylock(cal)) {
00633       if (cal->unloading) {
00634          ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n");
00635       } else {
00636          ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n");
00637       }
00638       ast_calendar_config_release();
00639       return NULL;
00640    }
00641 
00642    if (!(pvt = ao2_alloc(sizeof(*pvt), exchangecal_destructor))) {
00643       ast_log(LOG_ERROR, "Could not allocate exchangecal_pvt structure for calendar: %s\n", cal->name);
00644       ast_calendar_config_release();
00645       return NULL;
00646    }
00647 
00648    pvt->owner = cal;
00649 
00650    if (!(pvt->events = ast_calendar_event_container_alloc())) {
00651       ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name);
00652       pvt = unref_exchangecal(pvt);
00653       ao2_unlock(cal);
00654       ast_calendar_config_release();
00655       return NULL;
00656    }
00657 
00658    if (ast_string_field_init(pvt, 32)) {
00659       ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name);
00660       pvt = unref_exchangecal(pvt);
00661       ao2_unlock(cal);
00662       ast_calendar_config_release();
00663       return NULL;
00664    }
00665 
00666    for (v = ast_variable_browse(cfg, cal->name); v; v = v->next) {
00667       if (!strcasecmp(v->name, "url")) {
00668          ast_string_field_set(pvt, url, v->value);
00669       } else if (!strcasecmp(v->name, "user")) {
00670          ast_string_field_set(pvt, user, v->value);
00671       } else if (!strcasecmp(v->name, "secret")) {
00672          ast_string_field_set(pvt, secret, v->value);
00673       }
00674    }
00675 
00676    ast_calendar_config_release();
00677 
00678    if (ast_strlen_zero(pvt->url)) {
00679       ast_log(LOG_WARNING, "No URL was specified for Exchange calendar '%s' - skipping.\n", cal->name);
00680       pvt = unref_exchangecal(pvt);
00681       ao2_unlock(cal);
00682       return NULL;
00683    }
00684 
00685    if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) {
00686       ast_log(LOG_WARNING, "Could not parse url '%s' for Exchange calendar '%s' - skipping.\n", pvt->url, cal->name);
00687       pvt = unref_exchangecal(pvt);
00688       ao2_unlock(cal);
00689       return NULL;
00690    }
00691 
00692    if (pvt->uri.scheme == NULL) {
00693       pvt->uri.scheme = "http";
00694    }
00695 
00696    if (pvt->uri.port == 0) {
00697       pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme);
00698    }
00699 
00700    pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port);
00701    ne_redirect_register(pvt->session);
00702    ne_set_server_auth(pvt->session, auth_credentials, pvt);
00703    if (!strcasecmp(pvt->uri.scheme, "https")) {
00704       ne_ssl_trust_default_ca(pvt->session);
00705    }
00706 
00707    cal->tech_pvt = pvt;
00708 
00709    ast_mutex_init(&refreshlock);
00710 
00711    /* Load it the first time */
00712    update_exchangecal(pvt);
00713 
00714    ao2_unlock(cal);
00715 
00716    /* The only writing from another thread will be if unload is true */
00717    for (;;) {
00718       struct timeval tv = ast_tvnow();
00719       struct timespec ts = {0,};
00720 
00721       ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh);
00722 
00723       ast_mutex_lock(&refreshlock);
00724       while (!pvt->owner->unloading) {
00725          if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) {
00726             break;
00727          }
00728       }
00729       ast_mutex_unlock(&refreshlock);
00730 
00731       if (pvt->owner->unloading) {
00732          ast_debug(10, "Skipping refresh since we got a shutdown signal\n");
00733          return NULL;
00734       }
00735 
00736       ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh);
00737 
00738       update_exchangecal(pvt);
00739    }
00740 
00741    return NULL;
00742 }

static struct ast_str* exchangecal_request ( struct exchangecal_pvt pvt,
const char *  method,
struct ast_str req_body,
struct ast_str subdir 
) [static, read]

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, exchangecal_pvt::owner, exchangecal_pvt::session, exchangecal_pvt::uri, and exchangecal_pvt::url.

Referenced by exchangecal_get_events_between(), and exchangecal_write_event().

00386 {
00387    struct ast_str *response;
00388    ne_request *req;
00389    int ret;
00390    char buf[1000];
00391 
00392    if (!pvt) {
00393       ast_log(LOG_ERROR, "There is no private!\n");
00394       return NULL;
00395    }
00396 
00397    if (!(response = ast_str_create(512))) {
00398       ast_log(LOG_ERROR, "Could not allocate memory for response.\n");
00399       return NULL;
00400    }
00401 
00402    snprintf(buf, sizeof(buf), "%s%s", pvt->uri.path, subdir ? ast_str_buffer(subdir) : "");
00403 
00404    req = ne_request_create(pvt->session, method, buf);
00405    ne_add_response_body_reader(req, ne_accept_2xx, fetch_response_reader, &response);
00406    ne_set_request_body_buffer(req, ast_str_buffer(req_body), ast_str_strlen(req_body));
00407    ne_add_request_header(req, "Content-type", "text/xml");
00408 
00409    ret = ne_request_dispatch(req);
00410    ne_request_destroy(req);
00411 
00412    if (ret != NE_OK || !ast_str_strlen(response)) {
00413       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));
00414       ast_free(response);
00415       return NULL;
00416    }
00417 
00418    return response;
00419 }

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::end, epoch_to_exchange_time(), exchangecal_request(), generate_exchange_uuid(), is_valid_uuid(), LOG_ERROR, LOG_WARNING, ast_calendar_event::owner, ast_calendar_event::start, ast_calendar::tech_pvt, and xml_encode_str().

00422 {
00423    struct ast_str *body = NULL, *response = NULL, *subdir = NULL;
00424    struct ast_str *uid = NULL, *summary = NULL, *description = NULL, *organizer = NULL,
00425                   *location = NULL, *start = NULL, *end = NULL, *busystate = NULL;
00426    int ret = -1;
00427 
00428    if (!event) {
00429       ast_log(LOG_WARNING, "No event passed!\n");
00430       return -1;
00431    }
00432 
00433    if (!(event->start && event->end)) {
00434       ast_log(LOG_WARNING, "The event must contain a start and an end\n");
00435       return -1;
00436    }
00437    if (!(body = ast_str_create(512)) ||
00438       !(subdir = ast_str_create(32))) {
00439       ast_log(LOG_ERROR, "Could not allocate memory for request!\n");
00440       goto write_cleanup;
00441    }
00442 
00443    if (!(uid = ast_str_create(32)) ||
00444       !(summary = ast_str_create(32)) ||
00445       !(description = ast_str_create(32)) ||
00446       !(organizer = ast_str_create(32)) ||
00447       !(location = ast_str_create(32)) ||
00448       !(start = ast_str_create(32)) ||
00449       !(end = ast_str_create(32)) ||
00450       !(busystate = ast_str_create(32))) {
00451       ast_log(LOG_ERROR, "Unable to allocate memory for request values\n");
00452       goto write_cleanup;
00453    }
00454 
00455    if (ast_strlen_zero(event->uid)) {
00456       uid = generate_exchange_uuid(uid);
00457    } else {
00458       ast_str_set(&uid, 36, "%s", event->uid);
00459    }
00460 
00461    if (!is_valid_uuid(uid)) {
00462       ast_log(LOG_WARNING, "An invalid uid was provided, you may leave this field blank to have one generated for you\n");
00463       goto write_cleanup;
00464    }
00465 
00466    summary = xml_encode_str(summary, event->summary);
00467    description = xml_encode_str(description, event->description);
00468    organizer = xml_encode_str(organizer, event->organizer);
00469    location = xml_encode_str(location, event->location);
00470    start = epoch_to_exchange_time(start, event->start);
00471    end = epoch_to_exchange_time(end, event->end);
00472    busystate = bs_to_exchange_bs(busystate, event->busy_state);
00473 
00474    ast_str_append(&body, 0,
00475       "<?xml version=\"1.0\"?>\n"
00476       "<a:propertyupdate\n"
00477       "  xmlns:a=\"DAV:\"\n"
00478       "  xmlns:e=\"http://schemas.microsoft.com/exchange/\"\n"
00479       "  xmlns:mapi=\"http://schemas.microsoft.com/mapi/\"\n"
00480       "  xmlns:mapit=\"http://schemas.microsoft.com/mapi/proptag/\"\n"
00481       "  xmlns:x=\"xml:\" xmlns:cal=\"urn:schemas:calendar:\"\n"
00482       "  xmlns:dt=\"uuid:%s/\"\n" /* uid */
00483       "  xmlns:header=\"urn:schemas:mailheader:\"\n"
00484       "  xmlns:mail=\"urn:schemas:httpmail:\"\n"
00485       ">\n"
00486       "    <a:set>\n"
00487       "      <a:prop>\n"
00488       "        <a:contentclass>urn:content-classes:appointment</a:contentclass>\n"
00489       "        <e:outlookmessageclass>IPM.Appointment</e:outlookmessageclass>\n"
00490       "        <mail:subject>%s</mail:subject>\n" /* summary */
00491       "        <mail:description>%s</mail:description>\n" /* description */
00492       "        <header:to>%s</header:to>\n" /* organizer */
00493       "        <cal:location>%s</cal:location>\n" /* location */
00494       "        <cal:dtstart dt:dt=\"dateTime.tz\">%s</cal:dtstart>\n" /* start */
00495       "        <cal:dtend dt:dt=\"dateTime.tz\">%s</cal:dtend>\n" /* end */
00496       "        <cal:instancetype dt:dt=\"int\">0</cal:instancetype>\n"
00497       "        <cal:busystatus>%s</cal:busystatus>\n" /* busy_state (BUSY, FREE, BUSY_TENTATIVE) */
00498       "        <cal:meetingstatus>CONFIRMED</cal:meetingstatus>\n"
00499       "        <cal:alldayevent dt:dt=\"boolean\">0</cal:alldayevent>\n" /* XXX need to add event support for all day events */
00500       "        <cal:responserequested dt:dt=\"boolean\">0</cal:responserequested>\n"
00501       "        <mapi:finvited dt:dt=\"boolean\">1</mapi:finvited>\n"
00502       "      </a:prop>\n"
00503       "    </a:set>\n"
00504       "</a:propertyupdate>\n",
00505       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));
00506    ast_verb(0, "\n\n%s\n\n", ast_str_buffer(body));
00507    ast_str_set(&subdir, 0, "/Calendar/%s.eml", ast_str_buffer(uid));
00508 
00509    response = exchangecal_request(event->owner->tech_pvt, "PROPPATCH", body, subdir);
00510 
00511    ret = 0;
00512 write_cleanup:
00513    if (uid) {
00514       ast_free(uid);
00515    }
00516    if (summary) {
00517       ast_free(summary);
00518    }
00519    if (description) {
00520       ast_free(description);
00521    }
00522    if (organizer) {
00523       ast_free(organizer);
00524    }
00525    if (location) {
00526       ast_free(location);
00527    }
00528    if (start) {
00529       ast_free(start);
00530    }
00531    if (end) {
00532       ast_free(end);
00533    }
00534    if (busystate) {
00535       ast_free(busystate);
00536    }
00537    if (body) {
00538       ast_free(body);
00539    }
00540    if (response) {
00541       ast_free(response);
00542    }
00543    if (subdir) {
00544       ast_free(subdir);
00545    }
00546 
00547    return ret;
00548 }

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, and ast_str_append().

Referenced by exchangecal_request().

00355 {
00356    struct ast_str **response = data;
00357    unsigned char *tmp;
00358 
00359    if (!(tmp = ast_malloc(len + 1))) {
00360       return -1;
00361    }
00362    memcpy(tmp, block, len);
00363    tmp[len] = '\0';
00364    ast_str_append(response, 0, "%s", tmp);
00365    ast_free(tmp);
00366 
00367    return 0;
00368 }

static struct ast_str* generate_exchange_uuid ( struct ast_str uid  )  [static, read]

Definition at line 242 of file res_calendar_exchange.c.

References ast_random(), and ast_str_set().

Referenced by exchangecal_write_event().

00243 {
00244    unsigned short val[8];
00245    int x;
00246 
00247    for (x = 0; x < 8; x++) {
00248       val[x] = ast_random();
00249    }
00250    ast_str_set(&uid, 0, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", (unsigned)val[0],
00251       (unsigned)val[1], (unsigned)val[2], (unsigned)val[3], (unsigned)val[4],
00252       (unsigned)val[5], (unsigned)val[6], (unsigned)val[7]);
00253 
00254    return uid;
00255 }

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

00258 {
00259    int i;
00260 
00261    if (ast_str_strlen(uid) != 36) {
00262       return 0;
00263    }
00264 
00265    for (i = 0; i < ast_str_strlen(uid); i++) {
00266       if (i == 8 || i == 13 || i == 18 || i == 23) {
00267          if (ast_str_buffer(uid)[i] != '-') {
00268             return 0;
00269          }
00270       } 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))) {
00271          return 0;
00272       }
00273    }
00274 
00275    return 1;
00276 }

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.

00745 {
00746    ne_sock_init();
00747    if (ast_calendar_register(&exchangecal_tech)) {
00748       ne_sock_exit();
00749       return AST_MODULE_LOAD_DECLINE;
00750    }
00751 
00752    return AST_MODULE_LOAD_SUCCESS;
00753 }

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

00160 {
00161    if (!strcasecmp(msbusy, "FREE")) {
00162       return AST_CALENDAR_BS_FREE;
00163    } else if (!strcasecmp(msbusy, "TENTATIVE")) {
00164       return AST_CALENDAR_BS_BUSY_TENTATIVE;
00165    } else {
00166       return AST_CALENDAR_BS_BUSY;
00167    }
00168 }

static time_t mstime_to_time_t ( char *  mstime  )  [static]

Definition at line 139 of file res_calendar_exchange.c.

Referenced by parse_cdata().

00140 {
00141    char *read, *write;
00142    icaltimetype tt;
00143    for (read = write = mstime; *read; read++) {
00144       if (*read == '.') {
00145          *write++ = 'Z';
00146          *write = '\0';
00147          break;
00148       }
00149       if (*read == '-' || *read == ':')
00150          continue;
00151       *write = *read;
00152       write++;
00153    }
00154 
00155    tt = icaltime_from_string(mstime);
00156    return icaltime_as_timet(tt);
00157 }

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, xmlstate::in_prop, xmlstate::in_propstat, xmlstate::in_response, msbusy_to_bs(), mstime_to_time_t(), xmlstate::ptr, str, and xmlstate::tag.

Referenced by update_exchangecal().

00171 {
00172    char *str;
00173    struct xmlstate *state = data;
00174    struct ast_calendar_event *event = state->ptr;
00175 
00176 
00177    str = ast_skip_blanks(value);
00178 
00179    if (str == value + len)
00180       return IKS_OK;
00181 
00182    if (!(str = ast_calloc(1, len + 1))) {
00183       return IKS_NOMEM;
00184    }
00185    memcpy(str, value, len);
00186    if (!(state->in_response && state->in_propstat && state->in_prop)) {
00187       ast_free(str);
00188       return IKS_OK;
00189    }
00190    /* We use ast_string_field_build here because libiksemel is parsing CDATA with &lt; as
00191     * new elements which is a bit odd and shouldn't happen */
00192    if (!strcasecmp(state->tag, "subject")) {
00193       ast_string_field_build(event, summary, "%s%s", event->summary, str);
00194    } else if (!strcasecmp(state->tag, "location")) {
00195       ast_string_field_build(event, location, "%s%s", event->location, str);
00196    } else if (!strcasecmp(state->tag, "uid")) {
00197       ast_string_field_build(event, uid, "%s%s", event->location, str);
00198    } else if (!strcasecmp(state->tag, "organizer")) {
00199       ast_string_field_build(event, organizer, "%s%s", event->organizer, str);
00200    } else if (!strcasecmp(state->tag, "textdescription")) {
00201       ast_string_field_build(event, description, "%s%s", event->description, str);
00202    } else if (!strcasecmp(state->tag, "dtstart")) {
00203       event->start = mstime_to_time_t(str);
00204    } else if (!strcasecmp(state->tag, "dtend")) {
00205       event->end = mstime_to_time_t(str);
00206    } else if (!strcasecmp(state->tag, "busystatus")) {
00207       event->busy_state = msbusy_to_bs(str);
00208    } else if (!strcasecmp(state->tag, "reminderoffset")) {
00209       /*XXX Currently we rely on event->start being set first which means we rely on the response order
00210        * which technically should be fine since the query returns in the order we ask for, but ... */
00211       event->alarm = event->start - atoi(str);
00212    }
00213 
00214    ast_free(str);
00215    return IKS_OK;
00216 }

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(), caldav_pvt::events, 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().

00083 {
00084    struct xmlstate *state = data;
00085    char *tmp;
00086 
00087    if ((tmp = strchr(name, ':'))) {
00088       tmp++;
00089    } else {
00090       return IKS_HOOK;
00091    }
00092 
00093    ast_copy_string(state->tag, tmp, sizeof(state->tag));
00094 
00095    switch (type) {
00096    case IKS_OPEN:
00097       if (!strcasecmp(state->tag, "response")) {
00098          struct ast_calendar_event *event;
00099 
00100          state->in_response = 1;
00101          if (!(event = ast_calendar_event_alloc(state->pvt->owner))) {
00102             return IKS_NOMEM;
00103          }
00104          state->ptr = event;
00105       } else if (!strcasecmp(state->tag, "propstat")) {
00106          state->in_propstat = 1;
00107       } else if (!strcasecmp(state->tag, "prop")) {
00108          state->in_prop = 1;
00109       }
00110       break;
00111 
00112    case IKS_CLOSE:
00113       if (!strcasecmp(state->tag, "response")) {
00114          struct ao2_container *events = state->pvt->events;
00115          struct ast_calendar_event *event = state->ptr;
00116 
00117          state->in_response = 0;
00118          if (ast_strlen_zero(event->uid)) {
00119             ast_log(LOG_ERROR, "This event has no UID, something has gone wrong\n");
00120             event = ast_calendar_unref_event(event);
00121             return IKS_HOOK;
00122          }
00123          ao2_link(events, event);
00124          event = ast_calendar_unref_event(event);
00125       } else if (!strcasecmp(state->tag, "propstat")) {
00126          state->in_propstat = 0;
00127       } else if (!strcasecmp(state->tag, "prop")) {
00128          state->in_prop = 0;
00129       }
00130       break;
00131 
00132    default:
00133       return IKS_OK;
00134    }
00135 
00136    return IKS_OK;
00137 }

static int unload_module ( void   )  [static]

Definition at line 755 of file res_calendar_exchange.c.

References ast_calendar_unregister().

00756 {
00757    ast_calendar_unregister(&exchangecal_tech);
00758    ne_sock_exit();
00759    return 0;
00760 }

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

00234 {
00235    struct exchangecal_pvt *pvt = obj;
00236 
00237    ao2_ref(pvt, -1);
00238    return NULL;
00239 }

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

00597 {
00598    struct xmlstate state;
00599    struct timeval now = ast_tvnow();
00600    time_t start, end;
00601    struct ast_str *response;
00602    iksparser *p;
00603 
00604    state.pvt = pvt;
00605    start = now.tv_sec;
00606    end = now.tv_sec + 60 * pvt->owner->timeframe;
00607    if (!(response = exchangecal_get_events_between(pvt, start, end))) {
00608       return -1;
00609    }
00610 
00611    p = iks_sax_new(&state, parse_tag, parse_cdata);
00612    iks_parse(p, ast_str_buffer(response), ast_str_strlen(response), 1);
00613    ast_calendar_merge_events(pvt->owner, pvt->events);
00614    ast_free(response);
00615 
00616    return 0;
00617 }

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

Definition at line 278 of file res_calendar_exchange.c.

References ast_str_append().

Referenced by exchangecal_write_event().

00279 {
00280    const char *tmp;
00281    char buf[7];
00282 
00283    for (tmp = src; *tmp; tmp++) {
00284       switch (*tmp) {
00285       case '\"':
00286          strcpy(buf, "&quot;");
00287          break;
00288 
00289       case '\'':
00290          strcpy(buf, "&apos;");
00291          break;
00292 
00293       case '&':
00294          strcpy(buf, "&amp;");
00295          break;
00296 
00297       case '<':
00298          strcpy(buf, "&lt;");
00299          break;
00300 
00301       case '>':
00302          strcpy(buf, "&gt;");
00303          break;
00304 
00305       default:
00306          sprintf(buf, "%c", *tmp);
00307       }
00308 
00309       ast_str_append(&dst, 0, "%s", buf);
00310    }
00311 
00312    return dst;
00313 }


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.

Definition at line 52 of file res_calendar_exchange.c.


Generated on 7 Aug 2019 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1