Tue Aug 20 16:35:13 2013

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

static void __unreg_module ( void   )  [static]

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

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

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

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

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

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

Definition at line 313 of file res_calendar_exchange.c.

References ast_copy_string(), and ast_str_append().

Referenced by exchangecal_write_event().

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

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

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

static void * exchangecal_load_calendar ( void *  data  )  [static]

Definition at line 617 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.

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

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

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

static int exchangecal_write_event ( struct ast_calendar_event event  )  [static]

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

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

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

Definition at line 352 of file res_calendar_exchange.c.

References ast_free, ast_malloc, and ast_str_append().

Referenced by exchangecal_request().

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

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", val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]);
00251 
00252    return uid;
00253 }

static int is_valid_uuid ( struct ast_str uid  )  [static]

Definition at line 255 of file res_calendar_exchange.c.

References ast_str_buffer(), and ast_str_strlen().

Referenced by exchangecal_write_event().

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

static int load_module ( void   )  [static]

Definition at line 742 of file res_calendar_exchange.c.

References ast_calendar_register(), AST_MODULE_LOAD_DECLINE, and AST_MODULE_LOAD_SUCCESS.

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

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

References ast_calendar_unregister().

00754 {
00755    ast_calendar_unregister(&exchangecal_tech);
00756    ne_sock_exit();
00757    return 0;
00758 }

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

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

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

Definition at line 276 of file res_calendar_exchange.c.

References ast_str_append().

Referenced by exchangecal_write_event().

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


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

Definition at line 764 of file res_calendar_exchange.c.

Definition at line 52 of file res_calendar_exchange.c.


Generated on 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1