Fri Aug 17 00:17:47 2018

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  ids
struct  xml_context

Enumerations

enum  {
  XML_EVENT_CALENDAR_ITEM = 9, XML_EVENT_NAME = 10, XML_EVENT_DESCRIPTION, 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_CALENDAR_ITEM 
XML_EVENT_NAME 
XML_EVENT_DESCRIPTION 
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 943 of file res_calendar_ews.c.

static void __unreg_module ( void   )  [static]

Definition at line 943 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 137 of file res_calendar_ews.c.

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

Referenced by ewscal_load_calendar().

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

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

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

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

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

Definition at line 385 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, xml_context::cdata, ast_calendar_attendee::data, xml_context::event, ewscal_pvt::events, ewscal_pvt::items, LOG_ERROR, xml_context::op, ewscal_pvt::owner, ast_calendar_event::priority, xml_context::pvt, XML_EVENT_DESCRIPTION, XML_EVENT_EMAIL_ADDRESS, XML_OP_CREATE, and XML_OP_FIND.

Referenced by send_ews_request_and_parse().

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

static void ewscal_destructor ( void *  obj  )  [static]

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

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

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

Definition at line 769 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_pvt::events, ewscal_destructor(), LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, ewscal_pvt::owner, ast_calendar::refresh, refreshlock, ewscal_pvt::secret, secret, ewscal_pvt::session, ssl_verify(), ast_calendar::tech_pvt, ast_calendar::unload, ast_calendar::unloading, unref_ewscal(), update_ewscal(), ewscal_pvt::uri, ewscal_pvt::url, url, ewscal_pvt::user, and ast_variable::value.

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

static int ewscal_write_event ( struct ast_calendar_event event  )  [static]

Definition at line 561 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::end, msstatus(), mstime(), xml_context::op, ewscal_pvt::owner, ast_calendar_event::priority, send_ews_request_and_parse(), ast_calendar_event::start, ast_calendar::tech_pvt, and XML_OP_CREATE.

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

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

Definition at line 649 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, send_ews_request_and_parse(), ast_calendar::timeframe, and XML_OP_FIND.

Referenced by update_ewscal().

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

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

Definition at line 496 of file res_calendar_ews.c.

References XML_OP_CREATE, XML_OP_FIND, and XML_OP_GET.

Referenced by send_ews_request_and_parse().

00497 {
00498    switch (op) {
00499    case XML_OP_FIND:
00500       return "\"http://schemas.microsoft.com/exchange/services/2006/messages/FindItem\"";
00501    case XML_OP_GET:
00502       return "\"http://schemas.microsoft.com/exchange/services/2006/messages/GetItem\"";
00503    case XML_OP_CREATE:
00504       return "\"http://schemas.microsoft.com/exchange/services/2006/messages/CreateItem\"";
00505    }
00506 
00507    return "";
00508 }

static int load_module ( void   )  [static]

Definition at line 906 of file res_calendar_ews.c.

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

00907 {
00908    /* Actualy, 0.29.1 is required (because of NTLM authentication), but this
00909     * function does not support matching patch version.
00910     *
00911     * The ne_version_match function returns non-zero if the library
00912     * version is not of major version major, or the minor version
00913     * is less than minor. For neon versions 0.x, every minor
00914     * version is assumed to be incompatible with every other minor
00915     * version.
00916     *
00917     * I.e. for version 1.2..1.9 we would do ne_version_match(1, 2)
00918     * but for version 0.29 and 0.30 we need two checks. */
00919    if (ne_version_match(0, 29) && ne_version_match(0, 30)) {
00920       ast_log(LOG_ERROR, "Exchange Web Service calendar module require neon >= 0.29.1, but %s is installed.\n", ne_version_string());
00921       return AST_MODULE_LOAD_DECLINE;
00922    }
00923 
00924    if (ast_calendar_register(&ewscal_tech) && (ne_sock_init() == 0)) {
00925       return AST_MODULE_LOAD_DECLINE;
00926    }
00927 
00928    return AST_MODULE_LOAD_SUCCESS;
00929 }

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

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

00483 {
00484    switch (state) {
00485    case AST_CALENDAR_BS_BUSY_TENTATIVE:
00486       return "Tentative";
00487    case AST_CALENDAR_BS_BUSY:
00488       return "Busy";
00489    case AST_CALENDAR_BS_FREE:
00490       return "Free";
00491    default:
00492       return "";
00493    }
00494 }

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

Definition at line 469 of file res_calendar_ews.c.

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

Referenced by ewscal_write_event().

00470 {
00471    struct timeval tv = {
00472       .tv_sec = t,
00473    };
00474    struct ast_tm tm;
00475 
00476    ast_localtime(&tv, &tm, "utc");
00477    ast_strftime(buf, buflen, "%FT%TZ", &tm);
00478 
00479    return S_OR(buf, "");
00480 }

static time_t mstime_to_time_t ( char *  mstime  )  [static]

Definition at line 162 of file res_calendar_ews.c.

References ast_mktime(), and ast_strptime().

Referenced by cdata().

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

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

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

00713                                                                    {
00714    struct ast_str *request;
00715    struct xml_context ctx = {
00716       .pvt = pvt,
00717       .op = XML_OP_GET,
00718    };
00719 
00720    if (!(request = ast_str_create(512))) {
00721       return -1;
00722    }
00723 
00724    ast_str_set(&request, 0,
00725       "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
00726       "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" "
00727       "xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">"
00728       "<soap:Body>"
00729          "<GetItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\">"
00730             "<ItemShape>"
00731                "<t:BaseShape>AllProperties</t:BaseShape>"
00732             "</ItemShape>"
00733             "<ItemIds>"
00734                "<t:ItemId Id=\"%s\"/>"
00735             "</ItemIds>"
00736          "</GetItem>"
00737       "</soap:Body>"
00738       "</soap:Envelope>", id
00739    );
00740 
00741    if (send_ews_request_and_parse(request, &ctx)) {
00742       ast_free(request);
00743       return -1;
00744    }
00745 
00746    ast_free(request);
00747 
00748    return 0;
00749 }

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

Definition at line 510 of file res_calendar_ews.c.

References ast_debug, ast_log(), ast_str_buffer(), ast_str_strlen(), 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().

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

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

Definition at line 152 of file res_calendar_ews.c.

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

Referenced by ewscal_load_calendar().

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

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

Definition at line 174 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, xml_context::op, ewscal_pvt::owner, xml_context::parser, xml_context::pvt, XML_EVENT_ATTENDEE, XML_EVENT_ATTENDEE_LIST, XML_EVENT_BUSY, XML_EVENT_CALENDAR_ITEM, XML_EVENT_CATEGORIES, XML_EVENT_CATEGORY, XML_EVENT_DESCRIPTION, 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().

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

static int unload_module ( void   )  [static]

Definition at line 931 of file res_calendar_ews.c.

References ast_calendar_unregister().

00932 {
00933    ne_sock_exit();
00934    ast_calendar_unregister(&ewscal_tech);
00935 
00936    return 0;
00937 }

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

Definition at line 128 of file res_calendar_ews.c.

References ao2_ref, and ast_debug.

Referenced by ewscal_load_calendar().

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

static int update_ewscal ( struct ewscal_pvt pvt  )  [static]

Definition at line 751 of file res_calendar_ews.c.

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

Referenced by ewscal_load_calendar().

00752 {
00753    struct calendar_id *id_head;
00754    struct calendar_id *iter;
00755 
00756    if (!(id_head = get_ewscal_ids_for(pvt))) {
00757       return 0;
00758    }
00759 
00760    for (iter = id_head; iter; iter = AST_LIST_NEXT(iter, next)) {
00761       parse_ewscal_id(pvt, ast_str_buffer(iter->id));
00762       ast_free(iter->id);
00763       ast_free(iter);
00764    }
00765 
00766    return 0;
00767 }


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 943 of file res_calendar_ews.c.

Definition at line 943 of file res_calendar_ews.c.

struct ast_calendar_tech ewscal_tech [static]

Definition at line 52 of file res_calendar_ews.c.


Generated on 17 Aug 2018 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1