Mon Oct 8 12:39:27 2012

Asterisk developer's documentation


res_calendar_ews.c File Reference

Resource for handling MS Exchange Web Service calendars. More...

#include "asterisk.h"
#include <ne_request.h>
#include <ne_session.h>
#include <ne_uri.h>
#include <ne_socket.h>
#include <ne_auth.h>
#include <ne_xml.h>
#include <ne_xmlreq.h>
#include <ne_utils.h>
#include <ne_redirect.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  calendar_id
struct  ewscal_pvt
struct  xml_context
struct  xml_context::ids

Enumerations

enum  {
  XML_EVENT_NAME = 10, XML_EVENT_START, XML_EVENT_END, XML_EVENT_BUSY,
  XML_EVENT_ORGANIZER, XML_EVENT_LOCATION, XML_EVENT_ATTENDEE_LIST, XML_EVENT_ATTENDEE,
  XML_EVENT_MAILBOX, XML_EVENT_EMAIL_ADDRESS, XML_EVENT_CATEGORIES, XML_EVENT_CATEGORY,
  XML_EVENT_IMPORTANCE
}
enum  xml_op { XML_OP_FIND = 100, XML_OP_GET, XML_OP_CREATE }

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 int cdata (void *userdata, int state, const char *cdata, size_t len)
static int endelm (void *userdata, int state, const char *nspace, const char *name)
static void ewscal_destructor (void *obj)
static void * ewscal_load_calendar (void *data)
static int ewscal_write_event (struct ast_calendar_event *event)
static struct calendar_idget_ewscal_ids_for (struct ewscal_pvt *pvt)
static const char * get_soap_action (enum xml_op op)
static int load_module (void)
static const char * msstatus (enum ast_calendar_busy_state state)
static const char * mstime (time_t t, char *buf, size_t buflen)
static time_t mstime_to_time_t (char *mstime)
static int parse_ewscal_id (struct ewscal_pvt *pvt, const char *id)
static int send_ews_request_and_parse (struct ast_str *request, struct xml_context *ctx)
static int ssl_verify (void *userdata, int failures, const ne_ssl_certificate *cert)
static int startelm (void *userdata, int parent, const char *nspace, const char *name, const char **atts)
static int unload_module (void)
static void * unref_ewscal (void *obj)
static int update_ewscal (struct ewscal_pvt *pvt)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Asterisk MS Exchange Web Service 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 ewscal_tech


Detailed Description

Resource for handling MS Exchange Web Service calendars.

Definition in file res_calendar_ews.c.


Enumeration Type Documentation

anonymous enum

Enumerator:
XML_EVENT_NAME 
XML_EVENT_START 
XML_EVENT_END 
XML_EVENT_BUSY 
XML_EVENT_ORGANIZER 
XML_EVENT_LOCATION 
XML_EVENT_ATTENDEE_LIST 
XML_EVENT_ATTENDEE 
XML_EVENT_MAILBOX 
XML_EVENT_EMAIL_ADDRESS 
XML_EVENT_CATEGORIES 
XML_EVENT_CATEGORY 
XML_EVENT_IMPORTANCE 

Definition at line 82 of file res_calendar_ews.c.

enum xml_op

Enumerator:
XML_OP_FIND 
XML_OP_GET 
XML_OP_CREATE 

Definition at line 61 of file res_calendar_ews.c.

00061             {
00062    XML_OP_FIND = 100,
00063    XML_OP_GET,
00064    XML_OP_CREATE,
00065 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 920 of file res_calendar_ews.c.

static void __unreg_module ( void   )  [static]

Definition at line 920 of file res_calendar_ews.c.

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

Definition at line 135 of file res_calendar_ews.c.

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

00136 {
00137    struct ewscal_pvt *pvt = userdata;
00138 
00139    if (attempts > 1) {
00140       ast_log(LOG_WARNING, "Invalid username or password for Exchange Web Service calendar '%s'\n", pvt->owner->name);
00141       return -1;
00142    }
00143 
00144    ne_strnzcpy(username, pvt->user, NE_ABUFSIZ);
00145    ne_strnzcpy(secret, pvt->secret, NE_ABUFSIZ);
00146 
00147    return 0;
00148 }

static int cdata ( void *  userdata,
int  state,
const char *  cdata,
size_t  len 
) [static]

Definition at line 317 of file res_calendar_ews.c.

References AST_CALENDAR_BS_BUSY, AST_CALENDAR_BS_BUSY_TENTATIVE, AST_CALENDAR_BS_FREE, ast_copy_string(), ast_debug, ast_log(), ast_str_append(), ast_str_buffer(), ast_str_set(), ast_str_strlen(), ast_calendar_event::busy_state, xml_context::cdata, ast_calendar_event::end, xml_context::event, LOG_ERROR, mstime_to_time_t(), ast_calendar_event::start, XML_EVENT_BUSY, XML_EVENT_CATEGORY, XML_EVENT_END, XML_EVENT_START, and XML_OP_CREATE.

Referenced by send_ews_request_and_parse().

00318 {
00319    struct xml_context *ctx = userdata;
00320    char data[len + 1];
00321 
00322    /* !!! DON'T USE AST_STRING_FIELD FUNCTIONS HERE, JUST COLLECT CTX->CDATA !!! */
00323    if (state < XML_EVENT_NAME || ctx->op == XML_OP_CREATE) {
00324       return 0;
00325    }
00326 
00327    if (!ctx->event) {
00328       ast_log(LOG_ERROR, "Parsing event data, but event object does not exist!\n");
00329       return 1;
00330    }
00331 
00332    if (!ctx->cdata) {
00333       ast_log(LOG_ERROR, "String for storing CDATA is unitialized!\n");
00334       return 1;
00335    }
00336 
00337    ast_copy_string(data, cdata, len + 1);
00338 
00339    switch (state) {
00340    case XML_EVENT_START:
00341       ctx->event->start = mstime_to_time_t(data);
00342       break;
00343    case XML_EVENT_END:
00344       ctx->event->end = mstime_to_time_t(data);
00345       break;
00346    case XML_EVENT_BUSY:
00347       if (!strcmp(data, "Busy") || !strcmp(data, "OOF")) {
00348          ast_debug(3, "EWS: XML: Busy: yes\n");
00349          ctx->event->busy_state = AST_CALENDAR_BS_BUSY;
00350       }
00351       else if (!strcmp(data, "Tentative")) {
00352          ast_debug(3, "EWS: XML: Busy: tentative\n");
00353          ctx->event->busy_state = AST_CALENDAR_BS_BUSY_TENTATIVE;
00354       }
00355       else {
00356          ast_debug(3, "EWS: XML: Busy: no\n");
00357          ctx->event->busy_state = AST_CALENDAR_BS_FREE;
00358       }
00359       break;
00360    case XML_EVENT_CATEGORY:
00361       if (ast_str_strlen(ctx->cdata) == 0) {
00362          ast_str_set(&ctx->cdata, 0, "%s", data);
00363       } else {
00364          ast_str_append(&ctx->cdata, 0, ",%s", data);
00365       }
00366       break;
00367    default:
00368       ast_str_append(&ctx->cdata, 0, "%s", data);
00369    }
00370 
00371    ast_debug(5, "EWS: XML: CDATA: %s\n", ast_str_buffer(ctx->cdata));
00372 
00373    return 0;
00374 }

static int endelm ( void *  userdata,
int  state,
const char *  nspace,
const char *  name 
) [static]

Definition at line 376 of file res_calendar_ews.c.

References ao2_container_count(), ao2_link, ast_calendar_merge_events(), ast_calendar_unref_event(), ast_calloc, ast_debug, ast_free, AST_LIST_INSERT_TAIL, ast_log(), ast_str_buffer(), ast_str_reset(), ast_str_strlen(), ast_strdup, ast_string_field_set, ast_calendar_event::attendees, ast_calendar_event::categories, xml_context::cdata, xml_context::event, ewscal_pvt::events, ewscal_pvt::items, ast_calendar_event::location, LOG_ERROR, calendar_id::next, xml_context::op, ast_calendar_event::organizer, ewscal_pvt::owner, ast_calendar_event::priority, xml_context::pvt, ast_calendar_event::summary, XML_EVENT_EMAIL_ADDRESS, XML_OP_CREATE, and XML_OP_FIND.

Referenced by send_ews_request_and_parse().

00377 {
00378    struct xml_context *ctx = userdata;
00379 
00380    ast_debug(5, "EWS: XML: End:   %s\n", name);
00381    if (ctx->op == XML_OP_FIND || ctx->op == XML_OP_CREATE) {
00382       return NE_XML_DECLINE;
00383    }
00384 
00385    if (!strcmp(name, "Subject")) {
00386       /* Event name end*/
00387       ast_string_field_set(ctx->event, summary, ast_str_buffer(ctx->cdata));
00388       ast_debug(3, "EWS: XML: Summary: %s\n", ctx->event->summary);
00389       ast_str_reset(ctx->cdata);
00390    } else if (!strcmp(name, "Organizer")) {
00391       /* Event organizer end */
00392       ast_string_field_set(ctx->event, organizer, ast_str_buffer(ctx->cdata));
00393       ast_debug(3, "EWS: XML: Organizer: %s\n", ctx->event->organizer);
00394       ast_str_reset(ctx->cdata);
00395    } else if (!strcmp(name, "Location")) {
00396       /* Event location end */
00397       ast_string_field_set(ctx->event, location, ast_str_buffer(ctx->cdata));
00398       ast_debug(3, "EWS: XML: Location: %s\n", ctx->event->location);
00399       ast_str_reset(ctx->cdata);
00400    } else if (!strcmp(name, "Categories")) {
00401       /* Event categories end */
00402       ast_string_field_set(ctx->event, categories, ast_str_buffer(ctx->cdata));
00403       ast_debug(3, "EWS: XML: Categories: %s\n", ctx->event->categories);
00404       ast_str_reset(ctx->cdata);
00405    } else if (!strcmp(name, "Importance")) {
00406       /* Event importance end */
00407       if (!strcmp(ast_str_buffer(ctx->cdata), "Low")) {
00408          ctx->event->priority = 9;
00409       } else if (!strcmp(ast_str_buffer(ctx->cdata), "Normal")) {
00410          ctx->event->priority = 5;
00411       } else if (!strcmp(ast_str_buffer(ctx->cdata), "High")) {
00412          ctx->event->priority = 1;
00413       }
00414       ast_debug(3, "EWS: XML: Importance: %s (%d)\n", ast_str_buffer(ctx->cdata), ctx->event->priority);
00415       ast_str_reset(ctx->cdata);
00416    } else if (state == XML_EVENT_EMAIL_ADDRESS) {
00417       struct ast_calendar_attendee *attendee;
00418 
00419       if (!(attendee = ast_calloc(1, sizeof(*attendee)))) {
00420          ctx->event = ast_calendar_unref_event(ctx->event);
00421          return  1;
00422       }
00423 
00424       if (ast_str_strlen(ctx->cdata)) {
00425          attendee->data = ast_strdup(ast_str_buffer(ctx->cdata));
00426          AST_LIST_INSERT_TAIL(&ctx->event->attendees, attendee, next);
00427       } else {
00428          ast_free(attendee);
00429       }
00430       ast_debug(3, "EWS: XML: attendee address '%s'\n", ast_str_buffer(ctx->cdata));
00431       ast_str_reset(ctx->cdata);
00432    } else if (!strcmp(name, "CalendarItem")) {
00433       /* Event end */
00434       ast_debug(3, "EWS: XML: </CalendarItem>\n");
00435       ast_free(ctx->cdata);
00436       if (ctx->event) {
00437          ao2_link(ctx->pvt->events, ctx->event);
00438          ctx->event = ast_calendar_unref_event(ctx->event);
00439       } else {
00440          ast_log(LOG_ERROR, "Event data ended in XML, but event object does not exist!\n");
00441          return 1;
00442       }
00443    } else if (!strcmp(name, "Envelope")) {
00444       /* Events end */
00445       ast_debug(3, "EWS: XML: %d of %d event(s) has been parsed…\n", ao2_container_count(ctx->pvt->events), ctx->pvt->items);
00446       if (ao2_container_count(ctx->pvt->events) >= ctx->pvt->items) {
00447          ast_debug(3, "EWS: XML: All events has been parsed, merging…\n");
00448          ast_calendar_merge_events(ctx->pvt->owner, ctx->pvt->events);
00449       }
00450    }
00451 
00452    return 0;
00453 }

static void ewscal_destructor ( void *  obj  )  [static]

Definition at line 111 of file res_calendar_ews.c.

References ao2_callback, ao2_ref, ast_debug, ast_string_field_free_memory, ewscal_pvt::events, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, and ewscal_pvt::session.

Referenced by ewscal_load_calendar().

00112 {
00113    struct ewscal_pvt *pvt = obj;
00114 
00115    ast_debug(1, "Destroying pvt for Exchange Web Service calendar %s\n", "pvt->owner->name");
00116    if (pvt->session) {
00117       ne_session_destroy(pvt->session);
00118    }
00119    ast_string_field_free_memory(pvt);
00120 
00121    ao2_callback(pvt->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
00122 
00123    ao2_ref(pvt->events, -1);
00124 }

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

Definition at line 755 of file res_calendar_ews.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(), ewscal_destructor(), LOG_ERROR, LOG_WARNING, ast_variable::name, ast_calendar::name, ast_variable::next, refreshlock, secret, ssl_verify(), ast_calendar::tech_pvt, tv, ast_calendar::unloading, unref_ewscal(), update_ewscal(), url, and ast_variable::value.

00756 {
00757    struct ewscal_pvt *pvt;
00758    const struct ast_config *cfg;
00759    struct ast_variable *v;
00760    struct ast_calendar *cal = void_data;
00761    ast_mutex_t refreshlock;
00762 
00763    ast_debug(5, "EWS: ewscal_load_calendar()\n");
00764 
00765    if (!(cal && (cfg = ast_calendar_config_acquire()))) {
00766       ast_log(LOG_ERROR, "You must enable calendar support for res_ewscal to load\n");
00767       return NULL;
00768    }
00769 
00770    if (ao2_trylock(cal)) {
00771       if (cal->unloading) {
00772          ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n");
00773       } else {
00774          ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n");
00775       }
00776       ast_calendar_config_release();
00777       return NULL;
00778    }
00779 
00780    if (!(pvt = ao2_alloc(sizeof(*pvt), ewscal_destructor))) {
00781       ast_log(LOG_ERROR, "Could not allocate ewscal_pvt structure for calendar: %s\n", cal->name);
00782       ast_calendar_config_release();
00783       return NULL;
00784    }
00785 
00786    pvt->owner = cal;
00787 
00788    if (!(pvt->events = ast_calendar_event_container_alloc())) {
00789       ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name);
00790       pvt = unref_ewscal(pvt);
00791       ao2_unlock(cal);
00792       ast_calendar_config_release();
00793       return NULL;
00794    }
00795 
00796    if (ast_string_field_init(pvt, 32)) {
00797       ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name);
00798       pvt = unref_ewscal(pvt);
00799       ao2_unlock(cal);
00800       ast_calendar_config_release();
00801       return NULL;
00802    }
00803 
00804    for (v = ast_variable_browse(cfg, cal->name); v; v = v->next) {
00805       if (!strcasecmp(v->name, "url")) {
00806          ast_string_field_set(pvt, url, v->value);
00807       } else if (!strcasecmp(v->name, "user")) {
00808          ast_string_field_set(pvt, user, v->value);
00809       } else if (!strcasecmp(v->name, "secret")) {
00810          ast_string_field_set(pvt, secret, v->value);
00811       }
00812    }
00813 
00814    ast_calendar_config_release();
00815 
00816    if (ast_strlen_zero(pvt->url)) {
00817       ast_log(LOG_WARNING, "No URL was specified for Exchange Web Service calendar '%s' - skipping.\n", cal->name);
00818       pvt = unref_ewscal(pvt);
00819       ao2_unlock(cal);
00820       return NULL;
00821    }
00822 
00823    if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) {
00824       ast_log(LOG_WARNING, "Could not parse url '%s' for Exchange Web Service calendar '%s' - skipping.\n", pvt->url, cal->name);
00825       pvt = unref_ewscal(pvt);
00826       ao2_unlock(cal);
00827       return NULL;
00828    }
00829 
00830    if (pvt->uri.scheme == NULL) {
00831       pvt->uri.scheme = "http";
00832    }
00833 
00834    if (pvt->uri.port == 0) {
00835       pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme);
00836    }
00837 
00838    ast_debug(3, "ne_uri.scheme   = %s\n", pvt->uri.scheme);
00839    ast_debug(3, "ne_uri.host  = %s\n", pvt->uri.host);
00840    ast_debug(3, "ne_uri.port  = %u\n", pvt->uri.port);
00841    ast_debug(3, "ne_uri.path  = %s\n", pvt->uri.path);
00842    ast_debug(3, "user      = %s\n", pvt->user);
00843    ast_debug(3, "secret    = %s\n", pvt->secret);
00844 
00845    pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port);
00846    ne_redirect_register(pvt->session);
00847    ne_set_server_auth(pvt->session, auth_credentials, pvt);
00848    ne_set_useragent(pvt->session, "Asterisk");
00849 
00850    if (!strcasecmp(pvt->uri.scheme, "https")) {
00851       ne_ssl_trust_default_ca(pvt->session);
00852       ne_ssl_set_verify(pvt->session, ssl_verify, pvt);
00853    }
00854 
00855    cal->tech_pvt = pvt;
00856 
00857    ast_mutex_init(&refreshlock);
00858 
00859    /* Load it the first time */
00860    update_ewscal(pvt);
00861 
00862    ao2_unlock(cal);
00863 
00864    /* The only writing from another thread will be if unload is true */
00865    for (;;) {
00866       struct timeval tv = ast_tvnow();
00867       struct timespec ts = {0,};
00868 
00869       ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh);
00870 
00871       ast_mutex_lock(&refreshlock);
00872       while (!pvt->owner->unloading) {
00873          if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) {
00874             break;
00875          }
00876       }
00877       ast_mutex_unlock(&refreshlock);
00878 
00879       if (pvt->owner->unloading) {
00880          ast_debug(10, "Skipping refresh since we got a shutdown signal\n");
00881          return NULL;
00882       }
00883 
00884       ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh);
00885 
00886       update_ewscal(pvt);
00887    }
00888 
00889    return NULL;
00890 }

static int ewscal_write_event ( struct ast_calendar_event event  )  [static]

Definition at line 547 of file res_calendar_ews.c.

References ast_free, ast_str_append(), ast_str_create(), ast_str_set(), ast_strdupa, ast_calendar_event::busy_state, ast_calendar_event::categories, ast_calendar_event::description, ast_calendar_event::end, xml_context::event, ast_calendar_event::location, msstatus(), mstime(), xml_context::op, ast_calendar_event::owner, ast_calendar_event::priority, xml_context::pvt, send_ews_request_and_parse(), ast_calendar_event::start, strsep(), ast_calendar_event::summary, ast_calendar::tech_pvt, and XML_OP_CREATE.

00548 {
00549    struct ast_str *request;
00550    struct ewscal_pvt *pvt = event->owner->tech_pvt;
00551    char start[21], end[21];
00552    struct xml_context ctx = {
00553       .op = XML_OP_CREATE,
00554       .pvt = pvt,
00555    };
00556    int ret;
00557    char *category, *categories;
00558 
00559    if (!pvt) {
00560       return -1;
00561    }
00562 
00563    if (!(request = ast_str_create(1024))) {
00564       return -1;
00565    }
00566 
00567    ast_str_set(&request, 0,
00568       "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
00569          "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "
00570          "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" "
00571          "xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">"
00572          "<soap:Body>"
00573          "<CreateItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\" "
00574             "xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\" "
00575             "SendMeetingInvitations=\"SendToNone\" >"
00576             "<SavedItemFolderId>"
00577                "<t:DistinguishedFolderId Id=\"calendar\"/>"
00578             "</SavedItemFolderId>"
00579             "<Items>"
00580                "<t:CalendarItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/types\">"
00581                   "<Subject>%s</Subject>"
00582                   "<Body BodyType=\"Text\">%s</Body>"
00583                   "<ReminderIsSet>false</ReminderIsSet>"
00584                   "<Start>%s</Start>"
00585                   "<End>%s</End>"
00586                   "<IsAllDayEvent>false</IsAllDayEvent>"
00587                   "<LegacyFreeBusyStatus>%s</LegacyFreeBusyStatus>"
00588                   "<Location>%s</Location>",
00589       event->summary,
00590       event->description,
00591       mstime(event->start, start, sizeof(start)),
00592       mstime(event->end, end, sizeof(end)),
00593       msstatus(event->busy_state),
00594       event->location
00595    );
00596    /* Event priority */
00597    switch (event->priority) {
00598    case 1:
00599    case 2:
00600    case 3:
00601    case 4:
00602       ast_str_append(&request, 0, "<Importance>High</Importance>");
00603       break;
00604    case 5:
00605       ast_str_append(&request, 0, "<Importance>Normal</Importance>");
00606       break;
00607    case 6:
00608    case 7:
00609    case 8:
00610    case 9:
00611       ast_str_append(&request, 0, "<Importance>Low</Importance>");
00612       break;
00613    }
00614    /* Event categories*/
00615    if (strlen(event->categories) > 0) {
00616       ast_str_append(&request, 0, "<Categories>");
00617       categories = ast_strdupa(event->categories); /* Duplicate string, since strsep() is destructive */
00618       category = strsep(&categories, ",");
00619       while (category != NULL) {
00620          ast_str_append(&request, 0, "<String>%s</String>", category);
00621          category = strsep(&categories, ",");
00622       }
00623       ast_str_append(&request, 0, "</Categories>");
00624    }
00625    /* Finish request */
00626    ast_str_append(&request, 0, "</t:CalendarItem></Items></CreateItem></soap:Body></soap:Envelope>");
00627 
00628    ret = send_ews_request_and_parse(request, &ctx);
00629 
00630    ast_free(request);
00631 
00632    return ret;
00633 }

static struct calendar_id* get_ewscal_ids_for ( struct ewscal_pvt pvt  )  [static]

Definition at line 635 of file res_calendar_ews.c.

References ast_debug, ast_free, AST_LIST_FIRST, AST_LIST_HEAD_INIT_NOLOCK, ast_localtime(), ast_log(), ast_str_create(), ast_str_set(), ast_strftime(), ast_tvnow(), xml_context::ids, LOG_ERROR, xml_context::op, ewscal_pvt::owner, xml_context::pvt, send_ews_request_and_parse(), ast_calendar::timeframe, and XML_OP_FIND.

Referenced by update_ewscal().

00636 {
00637    char start[21], end[21];
00638    struct ast_tm tm;
00639    struct timeval tv;
00640    struct ast_str *request;
00641    struct xml_context ctx = {
00642       .op = XML_OP_FIND,
00643       .pvt = pvt,
00644    };
00645 
00646    ast_debug(5, "EWS: get_ewscal_ids_for()\n");
00647 
00648    if (!pvt) {
00649       ast_log(LOG_ERROR, "There is no private!\n");
00650       return NULL;
00651    }
00652 
00653    /* Prepare timeframe strings */
00654    tv = ast_tvnow();
00655    ast_localtime(&tv, &tm, "UTC");
00656    ast_strftime(start, sizeof(start), "%FT%TZ", &tm);
00657    tv.tv_sec += 60 * pvt->owner->timeframe;
00658    ast_localtime(&tv, &tm, "UTC");
00659    ast_strftime(end, sizeof(end), "%FT%TZ", &tm);
00660 
00661    /* Prepare SOAP request */
00662    if (!(request = ast_str_create(512))) {
00663       return NULL;
00664    }
00665 
00666    ast_str_set(&request, 0,
00667       "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "
00668       "xmlns:ns1=\"http://schemas.microsoft.com/exchange/services/2006/types\" "
00669       "xmlns:ns2=\"http://schemas.microsoft.com/exchange/services/2006/messages\">"
00670          "<SOAP-ENV:Body>"
00671             "<ns2:FindItem Traversal=\"Shallow\">"
00672                "<ns2:ItemShape>"
00673                   "<ns1:BaseShape>IdOnly</ns1:BaseShape>"
00674                "</ns2:ItemShape>"
00675                "<ns2:CalendarView StartDate=\"%s\" EndDate=\"%s\"/>" /* Timeframe */
00676                "<ns2:ParentFolderIds>"
00677                   "<ns1:DistinguishedFolderId Id=\"calendar\"/>"
00678                "</ns2:ParentFolderIds>"
00679             "</ns2:FindItem>"
00680          "</SOAP-ENV:Body>"
00681       "</SOAP-ENV:Envelope>",
00682       start, end  /* Timeframe */
00683    );
00684 
00685    AST_LIST_HEAD_INIT_NOLOCK(&ctx.ids);
00686 
00687    /* Dispatch request and parse response as XML */
00688    if (send_ews_request_and_parse(request, &ctx)) {
00689       ast_free(request);
00690       return NULL;
00691    }
00692 
00693    /* Cleanup */
00694    ast_free(request);
00695 
00696    return AST_LIST_FIRST(&ctx.ids);
00697 }

static const char* get_soap_action ( enum xml_op  op  )  [static]

Definition at line 482 of file res_calendar_ews.c.

References XML_OP_CREATE, XML_OP_FIND, and XML_OP_GET.

Referenced by send_ews_request_and_parse().

00483 {
00484    switch (op) {
00485    case XML_OP_FIND:
00486       return "\"http://schemas.microsoft.com/exchange/services/2006/messages/FindItem\"";
00487    case XML_OP_GET:
00488       return "\"http://schemas.microsoft.com/exchange/services/2006/messages/GetItem\"";
00489    case XML_OP_CREATE:
00490       return "\"http://schemas.microsoft.com/exchange/services/2006/messages/CreateItem\"";
00491    }
00492 
00493    return "";
00494 }

static int load_module ( void   )  [static]

Definition at line 892 of file res_calendar_ews.c.

References ast_calendar_register(), ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ewscal_tech, and LOG_ERROR.

00893 {
00894    /* Actualy, 0.29.1 is required (because of NTLM authentication), but this
00895     * function does not support matching patch version. */
00896    if (ne_version_match(0, 29)) {
00897       ast_log(LOG_ERROR, "Exchange Web Service calendar module require neon >= 0.29.1, but %s is installed.\n", ne_version_string());
00898       return AST_MODULE_LOAD_DECLINE;
00899    }
00900 
00901    if (ast_calendar_register(&ewscal_tech) && (ne_sock_init() == 0)) {
00902       return AST_MODULE_LOAD_DECLINE;
00903    }
00904 
00905    return AST_MODULE_LOAD_SUCCESS;
00906 }

static const char* msstatus ( enum ast_calendar_busy_state  state  )  [static]

Definition at line 468 of file res_calendar_ews.c.

References AST_CALENDAR_BS_BUSY, AST_CALENDAR_BS_BUSY_TENTATIVE, and AST_CALENDAR_BS_FREE.

Referenced by ewscal_write_event().

00469 {
00470    switch (state) {
00471    case AST_CALENDAR_BS_BUSY_TENTATIVE:
00472       return "Tentative";
00473    case AST_CALENDAR_BS_BUSY:
00474       return "Busy";
00475    case AST_CALENDAR_BS_FREE:
00476       return "Free";
00477    default:
00478       return "";
00479    }
00480 }

static const char* mstime ( time_t  t,
char *  buf,
size_t  buflen 
) [static]

Definition at line 455 of file res_calendar_ews.c.

References ast_localtime(), ast_strftime(), and S_OR.

Referenced by ewscal_write_event().

00456 {
00457    struct timeval tv = {
00458       .tv_sec = t,
00459    };
00460    struct ast_tm tm;
00461 
00462    ast_localtime(&tv, &tm, "utc");
00463    ast_strftime(buf, buflen, "%FT%TZ", &tm);
00464 
00465    return S_OR(buf, "");
00466 }

static time_t mstime_to_time_t ( char *  mstime  )  [static]

Definition at line 160 of file res_calendar_ews.c.

References ast_mktime(), and ast_strptime().

Referenced by cdata(), and parse_cdata().

00161 {
00162    struct ast_tm tm;
00163    struct timeval tv;
00164 
00165    if (ast_strptime(mstime, "%FT%TZ", &tm)) {
00166       tv = ast_mktime(&tm, "UTC");
00167       return tv.tv_sec;
00168    }
00169    return 0;
00170 }

static int parse_ewscal_id ( struct ewscal_pvt pvt,
const char *  id 
) [static]

Definition at line 699 of file res_calendar_ews.c.

References ast_free, ast_str_create(), ast_str_set(), xml_context::pvt, send_ews_request_and_parse(), and XML_OP_GET.

Referenced by update_ewscal().

00699                                                                    {
00700    struct ast_str *request;
00701    struct xml_context ctx = {
00702       .pvt = pvt,
00703       .op = XML_OP_GET,
00704    };
00705 
00706    if (!(request = ast_str_create(512))) {
00707       return -1;
00708    }
00709 
00710    ast_str_set(&request, 0,
00711       "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
00712       "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" "
00713       "xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">"
00714       "<soap:Body>"
00715          "<GetItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\">"
00716             "<ItemShape>"
00717                "<t:BaseShape>AllProperties</t:BaseShape>"
00718             "</ItemShape>"
00719             "<ItemIds>"
00720                "<t:ItemId Id=\"%s\"/>"
00721             "</ItemIds>"
00722          "</GetItem>"
00723       "</soap:Body>"
00724       "</soap:Envelope>", id
00725    );
00726 
00727    if (send_ews_request_and_parse(request, &ctx)) {
00728       ast_free(request);
00729       return -1;
00730    }
00731 
00732    ast_free(request);
00733 
00734    return 0;
00735 }

static int send_ews_request_and_parse ( struct ast_str request,
struct xml_context ctx 
) [static]

Definition at line 496 of file res_calendar_ews.c.

References ast_debug, ast_log(), ast_str_buffer(), ast_str_strlen(), cdata(), endelm(), get_soap_action(), LOG_ERROR, LOG_WARNING, xml_context::op, xml_context::parser, xml_context::pvt, ewscal_pvt::session, startelm(), ewscal_pvt::uri, and ewscal_pvt::url.

Referenced by ewscal_write_event(), get_ewscal_ids_for(), and parse_ewscal_id().

00497 {
00498    int ret;
00499    ne_request *req;
00500    ne_xml_parser *parser;
00501 
00502    ast_debug(3, "EWS: HTTP request...\n");
00503    if (!(ctx && ctx->pvt)) {
00504       ast_log(LOG_ERROR, "There is no private!\n");
00505       return -1;
00506    }
00507 
00508    if (!ast_str_strlen(request)) {
00509       ast_log(LOG_ERROR, "No request to send!\n");
00510       return -1;
00511    }
00512 
00513    ast_debug(3, "%s\n", ast_str_buffer(request));
00514 
00515    /* Prepare HTTP POST request */
00516    req = ne_request_create(ctx->pvt->session, "POST", ctx->pvt->uri.path);
00517    ne_set_request_flag(req, NE_REQFLAG_IDEMPOTENT, 0);
00518 
00519    /* Set headers--should be application/soap+xml, but MS… :/ */
00520    ne_add_request_header(req, "Content-Type", "text/xml; charset=utf-8");
00521    ne_add_request_header(req, "SOAPAction", get_soap_action(ctx->op));
00522 
00523    /* Set body to SOAP request */
00524    ne_set_request_body_buffer(req, ast_str_buffer(request), ast_str_strlen(request));
00525 
00526    /* Prepare XML parser */
00527    parser = ne_xml_create();
00528    ctx->parser = parser;
00529    ne_xml_push_handler(parser, startelm, cdata, endelm, ctx);  /* Callbacks */
00530 
00531    /* Dispatch request and parse response as XML */
00532    ret = ne_xml_dispatch_request(req, parser);
00533    if (ret != NE_OK) { /* Error handling */
00534       ast_log(LOG_WARNING, "Unable to communicate with Exchange Web Service at '%s': %s\n", ctx->pvt->url, ne_get_error(ctx->pvt->session));
00535       ne_request_destroy(req);
00536       ne_xml_destroy(parser);
00537       return -1;
00538    }
00539 
00540    /* Cleanup */
00541    ne_request_destroy(req);
00542    ne_xml_destroy(parser);
00543 
00544    return 0;
00545 }

static int ssl_verify ( void *  userdata,
int  failures,
const ne_ssl_certificate *  cert 
) [static]

Definition at line 150 of file res_calendar_ews.c.

References ast_log(), LOG_WARNING, ast_calendar::name, and ewscal_pvt::owner.

Referenced by ewscal_load_calendar().

00151 {
00152    struct ewscal_pvt *pvt = userdata;
00153    if (failures & NE_SSL_UNTRUSTED) {
00154       ast_log(LOG_WARNING, "Untrusted SSL certificate for calendar %s!\n", pvt->owner->name);
00155       return 0;
00156    }
00157    return 1;   /* NE_SSL_NOTYETVALID, NE_SSL_EXPIRED, NE_SSL_IDMISMATCH */
00158 }

static int startelm ( void *  userdata,
int  parent,
const char *  nspace,
const char *  name,
const char **  atts 
) [static]

Definition at line 172 of file res_calendar_ews.c.

References ast_calendar_event_alloc(), ast_calendar_merge_events(), ast_calloc, ast_debug, ast_free, AST_LIST_INSERT_TAIL, ast_log(), ast_str_buffer(), ast_str_create(), ast_str_reset(), ast_str_set(), ast_string_field_set, xml_context::cdata, xml_context::event, ewscal_pvt::events, calendar_id::id, xml_context::ids, ewscal_pvt::items, LOG_ERROR, calendar_id::next, xml_context::op, ewscal_pvt::owner, xml_context::parser, xml_context::pvt, XML_EVENT_ATTENDEE, XML_EVENT_ATTENDEE_LIST, XML_EVENT_BUSY, XML_EVENT_CATEGORIES, XML_EVENT_CATEGORY, XML_EVENT_EMAIL_ADDRESS, XML_EVENT_END, XML_EVENT_IMPORTANCE, XML_EVENT_LOCATION, XML_EVENT_MAILBOX, XML_EVENT_NAME, XML_EVENT_ORGANIZER, XML_EVENT_START, XML_OP_CREATE, and XML_OP_FIND.

Referenced by send_ews_request_and_parse().

00173 {
00174    struct xml_context *ctx = userdata;
00175 
00176    ast_debug(5, "EWS: XML: Start: %s\n", name);
00177    if (ctx->op == XML_OP_CREATE) {
00178       return NE_XML_DECLINE;
00179    }
00180 
00181    /* Nodes needed for traversing until CalendarItem is found */
00182    if (!strcmp(name, "Envelope") ||
00183       !strcmp(name, "Body") ||
00184       !strcmp(name, "FindItemResponse") ||
00185       !strcmp(name, "GetItemResponse") ||
00186       !strcmp(name, "CreateItemResponse") ||
00187       !strcmp(name, "ResponseMessages") ||
00188       !strcmp(name, "FindItemResponseMessage") || !strcmp(name, "GetItemResponseMessage") ||
00189       !strcmp(name, "Items")
00190    ) {
00191       return 1;
00192    } else if (!strcmp(name, "RootFolder")) {
00193       /* Get number of events */
00194       unsigned int items;
00195 
00196       ast_debug(3, "EWS: XML: <RootFolder>\n");
00197       if (sscanf(ne_xml_get_attr(ctx->parser, atts, NULL, "TotalItemsInView"), "%u", &items) != 1) {
00198          /* Couldn't read enything */
00199          ne_xml_set_error(ctx->parser, "Could't read number of events.");
00200          return NE_XML_ABORT;
00201       }
00202 
00203       ast_debug(3, "EWS: %u calendar items to load\n", items);
00204       ctx->pvt->items = items;
00205       if (items < 1) {
00206          /* Stop processing XML if there are no events */
00207          ast_calendar_merge_events(ctx->pvt->owner, ctx->pvt->events);
00208          return NE_XML_DECLINE;
00209       }
00210       return 1;
00211    } else if (!strcmp(name, "CalendarItem")) {
00212       /* Event start */
00213       ast_debug(3, "EWS: XML: <CalendarItem>\n");
00214       if (!(ctx->pvt && ctx->pvt->owner)) {
00215          ast_log(LOG_ERROR, "Require a private structure with an owner\n");
00216          return NE_XML_ABORT;
00217       }
00218 
00219       ctx->event = ast_calendar_event_alloc(ctx->pvt->owner);
00220       if (!ctx->event) {
00221          ast_log(LOG_ERROR, "Could not allocate an event!\n");
00222          return NE_XML_ABORT;
00223       }
00224 
00225       ctx->cdata = ast_str_create(64);
00226       if (!ctx->cdata) {
00227          ast_log(LOG_ERROR, "Could not allocate CDATA!\n");
00228          return NE_XML_ABORT;
00229       }
00230 
00231       return 1;
00232    } else if (!strcmp(name, "ItemId")) {
00233       /* Event UID */
00234       if (ctx->op == XML_OP_FIND) {
00235          struct calendar_id *id;
00236          if (!(id = ast_calloc(1, sizeof(*id)))) {
00237             return NE_XML_ABORT;
00238          }
00239          if (!(id->id = ast_str_create(256))) {
00240             ast_free(id);
00241             return NE_XML_ABORT;
00242          }
00243          ast_str_set(&id->id, 0, "%s", ne_xml_get_attr(ctx->parser, atts, NULL, "Id"));
00244          AST_LIST_INSERT_TAIL(&ctx->ids, id, next);
00245          ast_debug(3, "EWS_FIND: XML: UID: %s\n", ast_str_buffer(id->id));
00246       } else {
00247          ast_debug(3, "EWS_GET: XML: UID: %s\n", ne_xml_get_attr(ctx->parser, atts, NULL, "Id"));
00248          ast_string_field_set(ctx->event, uid, ne_xml_get_attr(ctx->parser, atts, NULL, "Id"));
00249       }
00250       return XML_EVENT_NAME;
00251    } else if (!strcmp(name, "Subject")) {
00252       /* Event name */
00253       if (!ctx->cdata) {
00254          return NE_XML_ABORT;
00255       }
00256       ast_str_reset(ctx->cdata);
00257       return XML_EVENT_NAME;
00258    } else if (!strcmp(name, "Start")) {
00259       /* Event start time */
00260       return XML_EVENT_START;
00261    } else if (!strcmp(name, "End")) {
00262       /* Event end time */
00263       return XML_EVENT_END;
00264    } else if (!strcmp(name, "LegacyFreeBusyStatus")) {
00265       /* Event busy state */
00266       return XML_EVENT_BUSY;
00267    } else if (!strcmp(name, "Organizer") ||
00268          (parent == XML_EVENT_ORGANIZER && (!strcmp(name, "Mailbox") ||
00269          !strcmp(name, "Name")))) {
00270       /* Event organizer */
00271       if (!ctx->cdata) {
00272          return NE_XML_ABORT;
00273       }
00274       ast_str_reset(ctx->cdata);
00275       return XML_EVENT_ORGANIZER;
00276    } else if (!strcmp(name, "Location")) {
00277       /* Event location */
00278       if (!ctx->cdata) {
00279          return NE_XML_ABORT;
00280       }
00281       ast_str_reset(ctx->cdata);
00282       return XML_EVENT_LOCATION;
00283    } else if (!strcmp(name, "Categories")) {
00284       /* Event categories */
00285       if (!ctx->cdata) {
00286          return NE_XML_ABORT;
00287       }
00288       ast_str_reset(ctx->cdata);
00289       return XML_EVENT_CATEGORIES;
00290    } else if (parent == XML_EVENT_CATEGORIES && !strcmp(name, "String")) {
00291       /* Event category */
00292       return XML_EVENT_CATEGORY;
00293    } else if (!strcmp(name, "Importance")) {
00294       /* Event importance (priority) */
00295       if (!ctx->cdata) {
00296          return NE_XML_ABORT;
00297       }
00298       ast_str_reset(ctx->cdata);
00299       return XML_EVENT_IMPORTANCE;
00300    } else if (!strcmp(name, "RequiredAttendees") || !strcmp(name, "OptionalAttendees")) {
00301       return XML_EVENT_ATTENDEE_LIST;
00302    } else if (!strcmp(name, "Attendee") && parent == XML_EVENT_ATTENDEE_LIST) {
00303       return XML_EVENT_ATTENDEE;
00304    } else if (!strcmp(name, "Mailbox") && parent == XML_EVENT_ATTENDEE) {
00305       return XML_EVENT_MAILBOX;
00306    } else if (!strcmp(name, "EmailAddress") && parent == XML_EVENT_MAILBOX) {
00307       if (!ctx->cdata) {
00308          return NE_XML_ABORT;
00309       }
00310       ast_str_reset(ctx->cdata);
00311       return XML_EVENT_EMAIL_ADDRESS;
00312    }
00313 
00314    return NE_XML_DECLINE;
00315 }

static int unload_module ( void   )  [static]

Definition at line 908 of file res_calendar_ews.c.

References ast_calendar_unregister(), and ewscal_tech.

00909 {
00910    ne_sock_exit();
00911    ast_calendar_unregister(&ewscal_tech);
00912 
00913    return 0;
00914 }

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

Definition at line 126 of file res_calendar_ews.c.

References ao2_ref, and ast_debug.

Referenced by ewscal_load_calendar().

00127 {
00128    struct ewscal_pvt *pvt = obj;
00129 
00130    ast_debug(5, "EWS: unref_ewscal()\n");
00131    ao2_ref(pvt, -1);
00132    return NULL;
00133 }

static int update_ewscal ( struct ewscal_pvt pvt  )  [static]

Definition at line 737 of file res_calendar_ews.c.

References ast_free, AST_LIST_NEXT, ast_str_buffer(), get_ewscal_ids_for(), calendar_id::id, calendar_id::next, and parse_ewscal_id().

Referenced by ewscal_load_calendar().

00738 {
00739    struct calendar_id *id_head;
00740    struct calendar_id *iter;
00741 
00742    if (!(id_head = get_ewscal_ids_for(pvt))) {
00743       return 0;
00744    }
00745 
00746    for (iter = id_head; iter; iter = AST_LIST_NEXT(iter, next)) {
00747       parse_ewscal_id(pvt, ast_str_buffer(iter->id));
00748       ast_free(iter->id);
00749       ast_free(iter);
00750    }
00751 
00752    return 0;
00753 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Asterisk MS Exchange Web Service 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 920 of file res_calendar_ews.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 920 of file res_calendar_ews.c.

struct ast_calendar_tech ewscal_tech [static]

Definition at line 52 of file res_calendar_ews.c.

Referenced by load_module(), and unload_module().


Generated on Mon Oct 8 12:39:27 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7