Wed Apr 6 11:30:08 2011

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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .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 763 of file res_calendar_exchange.c.

static void __unreg_module ( void   )  [static]

Definition at line 763 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 366 of file res_calendar_exchange.c.

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

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

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

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

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

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

Definition at line 311 of file res_calendar_exchange.c.

References ast_copy_string(), and ast_str_append().

Referenced by exchangecal_write_event().

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

static void exchangecal_destructor ( void *  obj  )  [static]

Definition at line 216 of file res_calendar_exchange.c.

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

Referenced by exchangecal_load_calendar().

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

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

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

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

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

Definition at line 616 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_destructor(), LOG_ERROR, LOG_WARNING, ast_variable::name, ast_calendar::name, ast_variable::next, refreshlock, secret, ast_calendar::tech_pvt, tv, ast_calendar::unloading, unref_exchangecal(), update_exchangecal(), url, and ast_variable::value.

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

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

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

Referenced by exchangecal_get_events_between(), and exchangecal_write_event().

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

static int exchangecal_write_event ( struct ast_calendar_event event  )  [static]

Definition at line 417 of file res_calendar_exchange.c.

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

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

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

Definition at line 350 of file res_calendar_exchange.c.

References ast_free, ast_malloc, and ast_str_append().

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

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

Definition at line 240 of file res_calendar_exchange.c.

References ast_random(), and ast_str_set().

Referenced by exchangecal_write_event().

00241 {
00242    unsigned short val[8];
00243    int x;
00244 
00245    for (x = 0; x < 8; x++) {
00246       val[x] = ast_random();
00247    }
00248    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]);
00249 
00250    return uid;
00251 }

static int is_valid_uuid ( struct ast_str uid  )  [static]

Definition at line 253 of file res_calendar_exchange.c.

References ast_str_buffer(), and ast_str_strlen().

Referenced by exchangecal_write_event().

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

static int load_module ( void   )  [static]

Definition at line 741 of file res_calendar_exchange.c.

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

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

static enum ast_calendar_busy_state msbusy_to_bs ( const char *  msbusy  )  [static]

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

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

static time_t mstime_to_time_t ( char *  mstime  )  [static]

Definition at line 137 of file res_calendar_exchange.c.

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

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

Definition at line 168 of file res_calendar_exchange.c.

References ast_calendar_event::alarm, ast_calloc, ast_free, ast_skip_blanks(), ast_string_field_build, ast_calendar_event::busy_state, ast_calendar_event::description, ast_calendar_event::end, ast_calendar_event::location, msbusy_to_bs(), mstime_to_time_t(), ast_calendar_event::organizer, ast_calendar_event::start, state, str, ast_calendar_event::summary, and ast_calendar_event::uid.

Referenced by update_exchangecal().

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

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

Definition at line 80 of file res_calendar_exchange.c.

References ao2_link, ast_calendar_event_alloc(), ast_calendar_unref_event(), ast_copy_string(), ast_log(), ast_strlen_zero(), events, LOG_ERROR, state, and ast_calendar_event::uid.

Referenced by update_exchangecal().

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

static int unload_module ( void   )  [static]

Definition at line 752 of file res_calendar_exchange.c.

References ast_calendar_unregister(), and exchangecal_tech.

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

static void * unref_exchangecal ( void *  obj  )  [static]

Definition at line 231 of file res_calendar_exchange.c.

References ao2_ref.

Referenced by exchangecal_load_calendar().

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

static int update_exchangecal ( struct exchangecal_pvt pvt  )  [static]

Definition at line 593 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(), state, and ast_calendar::timeframe.

Referenced by exchangecal_load_calendar().

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

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

Definition at line 274 of file res_calendar_exchange.c.

References ast_str_append().

Referenced by exchangecal_write_event().

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


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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, } [static]

Definition at line 763 of file res_calendar_exchange.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 763 of file res_calendar_exchange.c.

struct ast_calendar_tech exchangecal_tech [static]

Definition at line 50 of file res_calendar_exchange.c.

Referenced by load_module(), and unload_module().


Generated on Wed Apr 6 11:30:08 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7