Mon Mar 19 11:30:53 2012

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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 765 of file res_calendar_exchange.c.

static void __unreg_module ( void   )  [static]

Definition at line 765 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, ast_calendar::name, exchangecal_pvt::owner, exchangecal_pvt::secret, and exchangecal_pvt::user.

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]

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]

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, ast_calendar::name, 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]

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

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

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

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

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

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

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

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

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

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]

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

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

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

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.

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

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(), events, LOG_ERROR, state, and ast_calendar_event::uid.

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

References ast_calendar_unregister(), and exchangecal_tech.

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

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

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

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

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

Definition at line 765 of file res_calendar_exchange.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 765 of file res_calendar_exchange.c.

struct ast_calendar_tech exchangecal_tech [static]

Definition at line 52 of file res_calendar_exchange.c.

Referenced by load_module(), and unload_module().


Generated on Mon Mar 19 11:30:53 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7