#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_id * | get_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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_calendar_tech | ewscal_tech |
Definition in file res_calendar_ews.c.
anonymous enum |
Definition at line 80 of file res_calendar_ews.c.
00080 { 00081 XML_EVENT_NAME = 10, 00082 XML_EVENT_START, 00083 XML_EVENT_END, 00084 XML_EVENT_BUSY, 00085 XML_EVENT_ORGANIZER, 00086 XML_EVENT_LOCATION, 00087 XML_EVENT_ATTENDEE_LIST, 00088 XML_EVENT_ATTENDEE, 00089 XML_EVENT_MAILBOX, 00090 XML_EVENT_EMAIL_ADDRESS, 00091 XML_EVENT_CATEGORIES, 00092 XML_EVENT_CATEGORY, 00093 XML_EVENT_IMPORTANCE, 00094 };
enum xml_op |
Definition at line 59 of file res_calendar_ews.c.
00059 { 00060 XML_OP_FIND = 100, 00061 XML_OP_GET, 00062 XML_OP_CREATE, 00063 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 916 of file res_calendar_ews.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 916 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 133 of file res_calendar_ews.c.
References ast_log(), LOG_WARNING, ast_calendar::name, ewscal_pvt::owner, ewscal_pvt::secret, and ewscal_pvt::user.
00134 { 00135 struct ewscal_pvt *pvt = userdata; 00136 00137 if (attempts > 1) { 00138 ast_log(LOG_WARNING, "Invalid username or password for Exchange Web Service calendar '%s'\n", pvt->owner->name); 00139 return -1; 00140 } 00141 00142 ne_strnzcpy(username, pvt->user, NE_ABUFSIZ); 00143 ne_strnzcpy(secret, pvt->secret, NE_ABUFSIZ); 00144 00145 return 0; 00146 }
static int cdata | ( | void * | userdata, | |
int | state, | |||
const char * | cdata, | |||
size_t | len | |||
) | [static] |
Definition at line 315 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().
00316 { 00317 struct xml_context *ctx = userdata; 00318 char data[len + 1]; 00319 00320 /* !!! DON'T USE AST_STRING_FIELD FUNCTIONS HERE, JUST COLLECT CTX->CDATA !!! */ 00321 if (state < XML_EVENT_NAME || ctx->op == XML_OP_CREATE) { 00322 return 0; 00323 } 00324 00325 if (!ctx->event) { 00326 ast_log(LOG_ERROR, "Parsing event data, but event object does not exist!\n"); 00327 return 1; 00328 } 00329 00330 if (!ctx->cdata) { 00331 ast_log(LOG_ERROR, "String for storing CDATA is unitialized!\n"); 00332 return 1; 00333 } 00334 00335 ast_copy_string(data, cdata, len + 1); 00336 00337 switch (state) { 00338 case XML_EVENT_START: 00339 ctx->event->start = mstime_to_time_t(data); 00340 break; 00341 case XML_EVENT_END: 00342 ctx->event->end = mstime_to_time_t(data); 00343 break; 00344 case XML_EVENT_BUSY: 00345 if (!strcmp(data, "Busy") || !strcmp(data, "OOF")) { 00346 ast_debug(3, "EWS: XML: Busy: yes\n"); 00347 ctx->event->busy_state = AST_CALENDAR_BS_BUSY; 00348 } 00349 else if (!strcmp(data, "Tentative")) { 00350 ast_debug(3, "EWS: XML: Busy: tentative\n"); 00351 ctx->event->busy_state = AST_CALENDAR_BS_BUSY_TENTATIVE; 00352 } 00353 else { 00354 ast_debug(3, "EWS: XML: Busy: no\n"); 00355 ctx->event->busy_state = AST_CALENDAR_BS_FREE; 00356 } 00357 break; 00358 case XML_EVENT_CATEGORY: 00359 if (ast_str_strlen(ctx->cdata) == 0) { 00360 ast_str_set(&ctx->cdata, 0, "%s", data); 00361 } else { 00362 ast_str_append(&ctx->cdata, 0, ",%s", data); 00363 } 00364 break; 00365 default: 00366 ast_str_append(&ctx->cdata, 0, "%s", data); 00367 } 00368 00369 ast_debug(5, "EWS: XML: CDATA: %s\n", ast_str_buffer(ctx->cdata)); 00370 00371 return 0; 00372 }
static int endelm | ( | void * | userdata, | |
int | state, | |||
const char * | nspace, | |||
const char * | name | |||
) | [static] |
Definition at line 374 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().
00375 { 00376 struct xml_context *ctx = userdata; 00377 00378 ast_debug(5, "EWS: XML: End: %s\n", name); 00379 if (ctx->op == XML_OP_FIND || ctx->op == XML_OP_CREATE) { 00380 return NE_XML_DECLINE; 00381 } 00382 00383 if (!strcmp(name, "Subject")) { 00384 /* Event name end*/ 00385 ast_string_field_set(ctx->event, summary, ast_str_buffer(ctx->cdata)); 00386 ast_debug(3, "EWS: XML: Summary: %s\n", ctx->event->summary); 00387 ast_str_reset(ctx->cdata); 00388 } else if (!strcmp(name, "Organizer")) { 00389 /* Event organizer end */ 00390 ast_string_field_set(ctx->event, organizer, ast_str_buffer(ctx->cdata)); 00391 ast_debug(3, "EWS: XML: Organizer: %s\n", ctx->event->organizer); 00392 ast_str_reset(ctx->cdata); 00393 } else if (!strcmp(name, "Location")) { 00394 /* Event location end */ 00395 ast_string_field_set(ctx->event, location, ast_str_buffer(ctx->cdata)); 00396 ast_debug(3, "EWS: XML: Location: %s\n", ctx->event->location); 00397 ast_str_reset(ctx->cdata); 00398 } else if (!strcmp(name, "Categories")) { 00399 /* Event categories end */ 00400 ast_string_field_set(ctx->event, categories, ast_str_buffer(ctx->cdata)); 00401 ast_debug(3, "EWS: XML: Categories: %s\n", ctx->event->categories); 00402 ast_str_reset(ctx->cdata); 00403 } else if (!strcmp(name, "Importance")) { 00404 /* Event importance end */ 00405 if (!strcmp(ast_str_buffer(ctx->cdata), "Low")) { 00406 ctx->event->priority = 9; 00407 } else if (!strcmp(ast_str_buffer(ctx->cdata), "Normal")) { 00408 ctx->event->priority = 5; 00409 } else if (!strcmp(ast_str_buffer(ctx->cdata), "High")) { 00410 ctx->event->priority = 1; 00411 } 00412 ast_debug(3, "EWS: XML: Importance: %s (%d)\n", ast_str_buffer(ctx->cdata), ctx->event->priority); 00413 ast_str_reset(ctx->cdata); 00414 } else if (state == XML_EVENT_EMAIL_ADDRESS) { 00415 struct ast_calendar_attendee *attendee; 00416 00417 if (!(attendee = ast_calloc(1, sizeof(*attendee)))) { 00418 ctx->event = ast_calendar_unref_event(ctx->event); 00419 return 1; 00420 } 00421 00422 if (ast_str_strlen(ctx->cdata)) { 00423 attendee->data = ast_strdup(ast_str_buffer(ctx->cdata)); 00424 AST_LIST_INSERT_TAIL(&ctx->event->attendees, attendee, next); 00425 } 00426 ast_debug(3, "EWS: XML: attendee address '%s'\n", ast_str_buffer(ctx->cdata)); 00427 ast_str_reset(ctx->cdata); 00428 } else if (!strcmp(name, "CalendarItem")) { 00429 /* Event end */ 00430 ast_debug(3, "EWS: XML: </CalendarItem>\n"); 00431 ast_free(ctx->cdata); 00432 if (ctx->event) { 00433 ao2_link(ctx->pvt->events, ctx->event); 00434 ctx->event = ast_calendar_unref_event(ctx->event); 00435 } else { 00436 ast_log(LOG_ERROR, "Event data ended in XML, but event object does not exist!\n"); 00437 return 1; 00438 } 00439 } else if (!strcmp(name, "Envelope")) { 00440 /* Events end */ 00441 ast_debug(3, "EWS: XML: %d of %d event(s) has been parsed…\n", ao2_container_count(ctx->pvt->events), ctx->pvt->items); 00442 if (ao2_container_count(ctx->pvt->events) >= ctx->pvt->items) { 00443 ast_debug(3, "EWS: XML: All events has been parsed, merging…\n"); 00444 ast_calendar_merge_events(ctx->pvt->owner, ctx->pvt->events); 00445 } 00446 } 00447 00448 return 0; 00449 }
static void ewscal_destructor | ( | void * | obj | ) | [static] |
Definition at line 109 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().
00110 { 00111 struct ewscal_pvt *pvt = obj; 00112 00113 ast_debug(1, "Destroying pvt for Exchange Web Service calendar %s\n", "pvt->owner->name"); 00114 if (pvt->session) { 00115 ne_session_destroy(pvt->session); 00116 } 00117 ast_string_field_free_memory(pvt); 00118 00119 ao2_callback(pvt->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL); 00120 00121 ao2_ref(pvt->events, -1); 00122 }
static void * ewscal_load_calendar | ( | void * | data | ) | [static] |
Definition at line 751 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.
00752 { 00753 struct ewscal_pvt *pvt; 00754 const struct ast_config *cfg; 00755 struct ast_variable *v; 00756 struct ast_calendar *cal = void_data; 00757 ast_mutex_t refreshlock; 00758 00759 ast_debug(5, "EWS: ewscal_load_calendar()\n"); 00760 00761 if (!(cal && (cfg = ast_calendar_config_acquire()))) { 00762 ast_log(LOG_ERROR, "You must enable calendar support for res_ewscal to load\n"); 00763 return NULL; 00764 } 00765 00766 if (ao2_trylock(cal)) { 00767 if (cal->unloading) { 00768 ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n"); 00769 } else { 00770 ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n"); 00771 } 00772 ast_calendar_config_release(); 00773 return NULL; 00774 } 00775 00776 if (!(pvt = ao2_alloc(sizeof(*pvt), ewscal_destructor))) { 00777 ast_log(LOG_ERROR, "Could not allocate ewscal_pvt structure for calendar: %s\n", cal->name); 00778 ast_calendar_config_release(); 00779 return NULL; 00780 } 00781 00782 pvt->owner = cal; 00783 00784 if (!(pvt->events = ast_calendar_event_container_alloc())) { 00785 ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name); 00786 pvt = unref_ewscal(pvt); 00787 ao2_unlock(cal); 00788 ast_calendar_config_release(); 00789 return NULL; 00790 } 00791 00792 if (ast_string_field_init(pvt, 32)) { 00793 ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name); 00794 pvt = unref_ewscal(pvt); 00795 ao2_unlock(cal); 00796 ast_calendar_config_release(); 00797 return NULL; 00798 } 00799 00800 for (v = ast_variable_browse(cfg, cal->name); v; v = v->next) { 00801 if (!strcasecmp(v->name, "url")) { 00802 ast_string_field_set(pvt, url, v->value); 00803 } else if (!strcasecmp(v->name, "user")) { 00804 ast_string_field_set(pvt, user, v->value); 00805 } else if (!strcasecmp(v->name, "secret")) { 00806 ast_string_field_set(pvt, secret, v->value); 00807 } 00808 } 00809 00810 ast_calendar_config_release(); 00811 00812 if (ast_strlen_zero(pvt->url)) { 00813 ast_log(LOG_WARNING, "No URL was specified for Exchange Web Service calendar '%s' - skipping.\n", cal->name); 00814 pvt = unref_ewscal(pvt); 00815 ao2_unlock(cal); 00816 return NULL; 00817 } 00818 00819 if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) { 00820 ast_log(LOG_WARNING, "Could not parse url '%s' for Exchange Web Service calendar '%s' - skipping.\n", pvt->url, cal->name); 00821 pvt = unref_ewscal(pvt); 00822 ao2_unlock(cal); 00823 return NULL; 00824 } 00825 00826 if (pvt->uri.scheme == NULL) { 00827 pvt->uri.scheme = "http"; 00828 } 00829 00830 if (pvt->uri.port == 0) { 00831 pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme); 00832 } 00833 00834 ast_debug(3, "ne_uri.scheme = %s\n", pvt->uri.scheme); 00835 ast_debug(3, "ne_uri.host = %s\n", pvt->uri.host); 00836 ast_debug(3, "ne_uri.port = %u\n", pvt->uri.port); 00837 ast_debug(3, "ne_uri.path = %s\n", pvt->uri.path); 00838 ast_debug(3, "user = %s\n", pvt->user); 00839 ast_debug(3, "secret = %s\n", pvt->secret); 00840 00841 pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port); 00842 ne_redirect_register(pvt->session); 00843 ne_set_server_auth(pvt->session, auth_credentials, pvt); 00844 ne_set_useragent(pvt->session, "Asterisk"); 00845 00846 if (!strcasecmp(pvt->uri.scheme, "https")) { 00847 ne_ssl_trust_default_ca(pvt->session); 00848 ne_ssl_set_verify(pvt->session, ssl_verify, pvt); 00849 } 00850 00851 cal->tech_pvt = pvt; 00852 00853 ast_mutex_init(&refreshlock); 00854 00855 /* Load it the first time */ 00856 update_ewscal(pvt); 00857 00858 ao2_unlock(cal); 00859 00860 /* The only writing from another thread will be if unload is true */ 00861 for (;;) { 00862 struct timeval tv = ast_tvnow(); 00863 struct timespec ts = {0,}; 00864 00865 ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh); 00866 00867 ast_mutex_lock(&refreshlock); 00868 while (!pvt->owner->unloading) { 00869 if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) { 00870 break; 00871 } 00872 } 00873 ast_mutex_unlock(&refreshlock); 00874 00875 if (pvt->owner->unloading) { 00876 ast_debug(10, "Skipping refresh since we got a shutdown signal\n"); 00877 return NULL; 00878 } 00879 00880 ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh); 00881 00882 update_ewscal(pvt); 00883 } 00884 00885 return NULL; 00886 }
static int ewscal_write_event | ( | struct ast_calendar_event * | event | ) | [static] |
Definition at line 543 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.
00544 { 00545 struct ast_str *request; 00546 struct ewscal_pvt *pvt = event->owner->tech_pvt; 00547 char start[21], end[21]; 00548 struct xml_context ctx = { 00549 .op = XML_OP_CREATE, 00550 .pvt = pvt, 00551 }; 00552 int ret; 00553 char *category, *categories; 00554 00555 if (!pvt) { 00556 return -1; 00557 } 00558 00559 if (!(request = ast_str_create(1024))) { 00560 return -1; 00561 } 00562 00563 ast_str_set(&request, 0, 00564 "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " 00565 "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " 00566 "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " 00567 "xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">" 00568 "<soap:Body>" 00569 "<CreateItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\" " 00570 "xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\" " 00571 "SendMeetingInvitations=\"SendToNone\" >" 00572 "<SavedItemFolderId>" 00573 "<t:DistinguishedFolderId Id=\"calendar\"/>" 00574 "</SavedItemFolderId>" 00575 "<Items>" 00576 "<t:CalendarItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/types\">" 00577 "<Subject>%s</Subject>" 00578 "<Body BodyType=\"Text\">%s</Body>" 00579 "<ReminderIsSet>false</ReminderIsSet>" 00580 "<Start>%s</Start>" 00581 "<End>%s</End>" 00582 "<IsAllDayEvent>false</IsAllDayEvent>" 00583 "<LegacyFreeBusyStatus>%s</LegacyFreeBusyStatus>" 00584 "<Location>%s</Location>", 00585 event->summary, 00586 event->description, 00587 mstime(event->start, start, sizeof(start)), 00588 mstime(event->end, end, sizeof(end)), 00589 msstatus(event->busy_state), 00590 event->location 00591 ); 00592 /* Event priority */ 00593 switch (event->priority) { 00594 case 1: 00595 case 2: 00596 case 3: 00597 case 4: 00598 ast_str_append(&request, 0, "<Importance>High</Importance>"); 00599 break; 00600 case 5: 00601 ast_str_append(&request, 0, "<Importance>Normal</Importance>"); 00602 break; 00603 case 6: 00604 case 7: 00605 case 8: 00606 case 9: 00607 ast_str_append(&request, 0, "<Importance>Low</Importance>"); 00608 break; 00609 } 00610 /* Event categories*/ 00611 if (strlen(event->categories) > 0) { 00612 ast_str_append(&request, 0, "<Categories>"); 00613 categories = ast_strdupa(event->categories); /* Duplicate string, since strsep() is destructive */ 00614 category = strsep(&categories, ","); 00615 while (category != NULL) { 00616 ast_str_append(&request, 0, "<String>%s</String>", category); 00617 category = strsep(&categories, ","); 00618 } 00619 ast_str_append(&request, 0, "</Categories>"); 00620 } 00621 /* Finish request */ 00622 ast_str_append(&request, 0, "</t:CalendarItem></Items></CreateItem></soap:Body></soap:Envelope>"); 00623 00624 ret = send_ews_request_and_parse(request, &ctx); 00625 00626 ast_free(request); 00627 00628 return ret; 00629 }
static struct calendar_id* get_ewscal_ids_for | ( | struct ewscal_pvt * | pvt | ) | [static] |
Definition at line 631 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().
00632 { 00633 char start[21], end[21]; 00634 struct ast_tm tm; 00635 struct timeval tv; 00636 struct ast_str *request; 00637 struct xml_context ctx = { 00638 .op = XML_OP_FIND, 00639 .pvt = pvt, 00640 }; 00641 00642 ast_debug(5, "EWS: get_ewscal_ids_for()\n"); 00643 00644 if (!pvt) { 00645 ast_log(LOG_ERROR, "There is no private!\n"); 00646 return NULL; 00647 } 00648 00649 /* Prepare timeframe strings */ 00650 tv = ast_tvnow(); 00651 ast_localtime(&tv, &tm, "UTC"); 00652 ast_strftime(start, sizeof(start), "%FT%TZ", &tm); 00653 tv.tv_sec += 60 * pvt->owner->timeframe; 00654 ast_localtime(&tv, &tm, "UTC"); 00655 ast_strftime(end, sizeof(end), "%FT%TZ", &tm); 00656 00657 /* Prepare SOAP request */ 00658 if (!(request = ast_str_create(512))) { 00659 return NULL; 00660 } 00661 00662 ast_str_set(&request, 0, 00663 "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" " 00664 "xmlns:ns1=\"http://schemas.microsoft.com/exchange/services/2006/types\" " 00665 "xmlns:ns2=\"http://schemas.microsoft.com/exchange/services/2006/messages\">" 00666 "<SOAP-ENV:Body>" 00667 "<ns2:FindItem Traversal=\"Shallow\">" 00668 "<ns2:ItemShape>" 00669 "<ns1:BaseShape>IdOnly</ns1:BaseShape>" 00670 "</ns2:ItemShape>" 00671 "<ns2:CalendarView StartDate=\"%s\" EndDate=\"%s\"/>" /* Timeframe */ 00672 "<ns2:ParentFolderIds>" 00673 "<ns1:DistinguishedFolderId Id=\"calendar\"/>" 00674 "</ns2:ParentFolderIds>" 00675 "</ns2:FindItem>" 00676 "</SOAP-ENV:Body>" 00677 "</SOAP-ENV:Envelope>", 00678 start, end /* Timeframe */ 00679 ); 00680 00681 AST_LIST_HEAD_INIT_NOLOCK(&ctx.ids); 00682 00683 /* Dispatch request and parse response as XML */ 00684 if (send_ews_request_and_parse(request, &ctx)) { 00685 ast_free(request); 00686 return NULL; 00687 } 00688 00689 /* Cleanup */ 00690 ast_free(request); 00691 00692 return AST_LIST_FIRST(&ctx.ids); 00693 }
static const char* get_soap_action | ( | enum xml_op | op | ) | [static] |
Definition at line 478 of file res_calendar_ews.c.
References XML_OP_CREATE, XML_OP_FIND, and XML_OP_GET.
Referenced by send_ews_request_and_parse().
00479 { 00480 switch (op) { 00481 case XML_OP_FIND: 00482 return "\"http://schemas.microsoft.com/exchange/services/2006/messages/FindItem\""; 00483 case XML_OP_GET: 00484 return "\"http://schemas.microsoft.com/exchange/services/2006/messages/GetItem\""; 00485 case XML_OP_CREATE: 00486 return "\"http://schemas.microsoft.com/exchange/services/2006/messages/CreateItem\""; 00487 } 00488 00489 return ""; 00490 }
static int load_module | ( | void | ) | [static] |
Definition at line 888 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.
00889 { 00890 /* Actualy, 0.29.1 is required (because of NTLM authentication), but this 00891 * function does not support matching patch version. */ 00892 if (ne_version_match(0, 29)) { 00893 ast_log(LOG_ERROR, "Exchange Web Service calendar module require neon >= 0.29.1, but %s is installed.\n", ne_version_string()); 00894 return AST_MODULE_LOAD_DECLINE; 00895 } 00896 00897 if (ast_calendar_register(&ewscal_tech) && (ne_sock_init() == 0)) { 00898 return AST_MODULE_LOAD_DECLINE; 00899 } 00900 00901 return AST_MODULE_LOAD_SUCCESS; 00902 }
static const char* msstatus | ( | enum ast_calendar_busy_state | state | ) | [static] |
Definition at line 464 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().
00465 { 00466 switch (state) { 00467 case AST_CALENDAR_BS_BUSY_TENTATIVE: 00468 return "Tentative"; 00469 case AST_CALENDAR_BS_BUSY: 00470 return "Busy"; 00471 case AST_CALENDAR_BS_FREE: 00472 return "Free"; 00473 default: 00474 return ""; 00475 } 00476 }
static const char* mstime | ( | time_t | t, | |
char * | buf, | |||
size_t | buflen | |||
) | [static] |
Definition at line 451 of file res_calendar_ews.c.
References ast_localtime(), ast_strftime(), and S_OR.
Referenced by ewscal_write_event().
00452 { 00453 struct timeval tv = { 00454 .tv_sec = t, 00455 }; 00456 struct ast_tm tm; 00457 00458 ast_localtime(&tv, &tm, "utc"); 00459 ast_strftime(buf, buflen, "%FT%TZ", &tm); 00460 00461 return S_OR(buf, ""); 00462 }
static time_t mstime_to_time_t | ( | char * | mstime | ) | [static] |
Definition at line 158 of file res_calendar_ews.c.
References ast_mktime(), and ast_strptime().
Referenced by cdata(), and parse_cdata().
00159 { 00160 struct ast_tm tm; 00161 struct timeval tv; 00162 00163 if (ast_strptime(mstime, "%FT%TZ", &tm)) { 00164 tv = ast_mktime(&tm, "UTC"); 00165 return tv.tv_sec; 00166 } 00167 return 0; 00168 }
static int parse_ewscal_id | ( | struct ewscal_pvt * | pvt, | |
const char * | id | |||
) | [static] |
Definition at line 695 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().
00695 { 00696 struct ast_str *request; 00697 struct xml_context ctx = { 00698 .pvt = pvt, 00699 .op = XML_OP_GET, 00700 }; 00701 00702 if (!(request = ast_str_create(512))) { 00703 return -1; 00704 } 00705 00706 ast_str_set(&request, 0, 00707 "<?xml version=\"1.0\" encoding=\"utf-8\"?>" 00708 "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " 00709 "xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">" 00710 "<soap:Body>" 00711 "<GetItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\">" 00712 "<ItemShape>" 00713 "<t:BaseShape>AllProperties</t:BaseShape>" 00714 "</ItemShape>" 00715 "<ItemIds>" 00716 "<t:ItemId Id=\"%s\"/>" 00717 "</ItemIds>" 00718 "</GetItem>" 00719 "</soap:Body>" 00720 "</soap:Envelope>", id 00721 ); 00722 00723 if (send_ews_request_and_parse(request, &ctx)) { 00724 ast_free(request); 00725 return -1; 00726 } 00727 00728 ast_free(request); 00729 00730 return 0; 00731 }
static int send_ews_request_and_parse | ( | struct ast_str * | request, | |
struct xml_context * | ctx | |||
) | [static] |
Definition at line 492 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().
00493 { 00494 int ret; 00495 ne_request *req; 00496 ne_xml_parser *parser; 00497 00498 ast_debug(3, "EWS: HTTP request...\n"); 00499 if (!(ctx && ctx->pvt)) { 00500 ast_log(LOG_ERROR, "There is no private!\n"); 00501 return -1; 00502 } 00503 00504 if (!ast_str_strlen(request)) { 00505 ast_log(LOG_ERROR, "No request to send!\n"); 00506 return -1; 00507 } 00508 00509 ast_debug(3, "%s\n", ast_str_buffer(request)); 00510 00511 /* Prepare HTTP POST request */ 00512 req = ne_request_create(ctx->pvt->session, "POST", ctx->pvt->uri.path); 00513 ne_set_request_flag(req, NE_REQFLAG_IDEMPOTENT, 0); 00514 00515 /* Set headers--should be application/soap+xml, but MS… :/ */ 00516 ne_add_request_header(req, "Content-Type", "text/xml; charset=utf-8"); 00517 ne_add_request_header(req, "SOAPAction", get_soap_action(ctx->op)); 00518 00519 /* Set body to SOAP request */ 00520 ne_set_request_body_buffer(req, ast_str_buffer(request), ast_str_strlen(request)); 00521 00522 /* Prepare XML parser */ 00523 parser = ne_xml_create(); 00524 ctx->parser = parser; 00525 ne_xml_push_handler(parser, startelm, cdata, endelm, ctx); /* Callbacks */ 00526 00527 /* Dispatch request and parse response as XML */ 00528 ret = ne_xml_dispatch_request(req, parser); 00529 if (ret != NE_OK) { /* Error handling */ 00530 ast_log(LOG_WARNING, "Unable to communicate with Exchange Web Service at '%s': %s\n", ctx->pvt->url, ne_get_error(ctx->pvt->session)); 00531 ne_request_destroy(req); 00532 ne_xml_destroy(parser); 00533 return -1; 00534 } 00535 00536 /* Cleanup */ 00537 ne_request_destroy(req); 00538 ne_xml_destroy(parser); 00539 00540 return 0; 00541 }
static int ssl_verify | ( | void * | userdata, | |
int | failures, | |||
const ne_ssl_certificate * | cert | |||
) | [static] |
Definition at line 148 of file res_calendar_ews.c.
References ast_log(), LOG_WARNING, ast_calendar::name, and ewscal_pvt::owner.
Referenced by ewscal_load_calendar().
00149 { 00150 struct ewscal_pvt *pvt = userdata; 00151 if (failures & NE_SSL_UNTRUSTED) { 00152 ast_log(LOG_WARNING, "Untrusted SSL certificate for calendar %s!\n", pvt->owner->name); 00153 return 0; 00154 } 00155 return 1; /* NE_SSL_NOTYETVALID, NE_SSL_EXPIRED, NE_SSL_IDMISMATCH */ 00156 }
static int startelm | ( | void * | userdata, | |
int | parent, | |||
const char * | nspace, | |||
const char * | name, | |||
const char ** | atts | |||
) | [static] |
Definition at line 170 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().
00171 { 00172 struct xml_context *ctx = userdata; 00173 00174 ast_debug(5, "EWS: XML: Start: %s\n", name); 00175 if (ctx->op == XML_OP_CREATE) { 00176 return NE_XML_DECLINE; 00177 } 00178 00179 /* Nodes needed for traversing until CalendarItem is found */ 00180 if (!strcmp(name, "Envelope") || 00181 !strcmp(name, "Body") || 00182 !strcmp(name, "FindItemResponse") || 00183 !strcmp(name, "GetItemResponse") || 00184 !strcmp(name, "CreateItemResponse") || 00185 !strcmp(name, "ResponseMessages") || 00186 !strcmp(name, "FindItemResponseMessage") || !strcmp(name, "GetItemResponseMessage") || 00187 !strcmp(name, "Items") 00188 ) { 00189 return 1; 00190 } else if (!strcmp(name, "RootFolder")) { 00191 /* Get number of events */ 00192 unsigned int items; 00193 00194 ast_debug(3, "EWS: XML: <RootFolder>\n"); 00195 if (sscanf(ne_xml_get_attr(ctx->parser, atts, NULL, "TotalItemsInView"), "%u", &items) != 1) { 00196 /* Couldn't read enything */ 00197 ne_xml_set_error(ctx->parser, "Could't read number of events."); 00198 return NE_XML_ABORT; 00199 } 00200 00201 ast_debug(3, "EWS: %u calendar items to load\n", items); 00202 ctx->pvt->items = items; 00203 if (items < 1) { 00204 /* Stop processing XML if there are no events */ 00205 ast_calendar_merge_events(ctx->pvt->owner, ctx->pvt->events); 00206 return NE_XML_DECLINE; 00207 } 00208 return 1; 00209 } else if (!strcmp(name, "CalendarItem")) { 00210 /* Event start */ 00211 ast_debug(3, "EWS: XML: <CalendarItem>\n"); 00212 if (!(ctx->pvt && ctx->pvt->owner)) { 00213 ast_log(LOG_ERROR, "Require a private structure with an owner\n"); 00214 return NE_XML_ABORT; 00215 } 00216 00217 ctx->event = ast_calendar_event_alloc(ctx->pvt->owner); 00218 if (!ctx->event) { 00219 ast_log(LOG_ERROR, "Could not allocate an event!\n"); 00220 return NE_XML_ABORT; 00221 } 00222 00223 ctx->cdata = ast_str_create(64); 00224 if (!ctx->cdata) { 00225 ast_log(LOG_ERROR, "Could not allocate CDATA!\n"); 00226 return NE_XML_ABORT; 00227 } 00228 00229 return 1; 00230 } else if (!strcmp(name, "ItemId")) { 00231 /* Event UID */ 00232 if (ctx->op == XML_OP_FIND) { 00233 struct calendar_id *id; 00234 if (!(id = ast_calloc(1, sizeof(id)))) { 00235 return NE_XML_ABORT; 00236 } 00237 if (!(id->id = ast_str_create(256))) { 00238 ast_free(id); 00239 return NE_XML_ABORT; 00240 } 00241 ast_str_set(&id->id, 0, "%s", ne_xml_get_attr(ctx->parser, atts, NULL, "Id")); 00242 AST_LIST_INSERT_TAIL(&ctx->ids, id, next); 00243 ast_debug(3, "EWS_FIND: XML: UID: %s\n", ast_str_buffer(id->id)); 00244 } else { 00245 ast_debug(3, "EWS_GET: XML: UID: %s\n", ne_xml_get_attr(ctx->parser, atts, NULL, "Id")); 00246 ast_string_field_set(ctx->event, uid, ne_xml_get_attr(ctx->parser, atts, NULL, "Id")); 00247 } 00248 return XML_EVENT_NAME; 00249 } else if (!strcmp(name, "Subject")) { 00250 /* Event name */ 00251 if (!ctx->cdata) { 00252 return NE_XML_ABORT; 00253 } 00254 ast_str_reset(ctx->cdata); 00255 return XML_EVENT_NAME; 00256 } else if (!strcmp(name, "Start")) { 00257 /* Event start time */ 00258 return XML_EVENT_START; 00259 } else if (!strcmp(name, "End")) { 00260 /* Event end time */ 00261 return XML_EVENT_END; 00262 } else if (!strcmp(name, "LegacyFreeBusyStatus")) { 00263 /* Event busy state */ 00264 return XML_EVENT_BUSY; 00265 } else if (!strcmp(name, "Organizer") || 00266 (parent == XML_EVENT_ORGANIZER && (!strcmp(name, "Mailbox") || 00267 !strcmp(name, "Name")))) { 00268 /* Event organizer */ 00269 if (!ctx->cdata) { 00270 return NE_XML_ABORT; 00271 } 00272 ast_str_reset(ctx->cdata); 00273 return XML_EVENT_ORGANIZER; 00274 } else if (!strcmp(name, "Location")) { 00275 /* Event location */ 00276 if (!ctx->cdata) { 00277 return NE_XML_ABORT; 00278 } 00279 ast_str_reset(ctx->cdata); 00280 return XML_EVENT_LOCATION; 00281 } else if (!strcmp(name, "Categories")) { 00282 /* Event categories */ 00283 if (!ctx->cdata) { 00284 return NE_XML_ABORT; 00285 } 00286 ast_str_reset(ctx->cdata); 00287 return XML_EVENT_CATEGORIES; 00288 } else if (parent == XML_EVENT_CATEGORIES && !strcmp(name, "String")) { 00289 /* Event category */ 00290 return XML_EVENT_CATEGORY; 00291 } else if (!strcmp(name, "Importance")) { 00292 /* Event importance (priority) */ 00293 if (!ctx->cdata) { 00294 return NE_XML_ABORT; 00295 } 00296 ast_str_reset(ctx->cdata); 00297 return XML_EVENT_IMPORTANCE; 00298 } else if (!strcmp(name, "RequiredAttendees") || !strcmp(name, "OptionalAttendees")) { 00299 return XML_EVENT_ATTENDEE_LIST; 00300 } else if (!strcmp(name, "Attendee") && parent == XML_EVENT_ATTENDEE_LIST) { 00301 return XML_EVENT_ATTENDEE; 00302 } else if (!strcmp(name, "Mailbox") && parent == XML_EVENT_ATTENDEE) { 00303 return XML_EVENT_MAILBOX; 00304 } else if (!strcmp(name, "EmailAddress") && parent == XML_EVENT_MAILBOX) { 00305 if (!ctx->cdata) { 00306 return NE_XML_ABORT; 00307 } 00308 ast_str_reset(ctx->cdata); 00309 return XML_EVENT_EMAIL_ADDRESS; 00310 } 00311 00312 return NE_XML_DECLINE; 00313 }
static int unload_module | ( | void | ) | [static] |
Definition at line 904 of file res_calendar_ews.c.
References ast_calendar_unregister(), and ewscal_tech.
00905 { 00906 ne_sock_exit(); 00907 ast_calendar_unregister(&ewscal_tech); 00908 00909 return 0; 00910 }
static void * unref_ewscal | ( | void * | obj | ) | [static] |
Definition at line 124 of file res_calendar_ews.c.
References ao2_ref, and ast_debug.
Referenced by ewscal_load_calendar().
00125 { 00126 struct ewscal_pvt *pvt = obj; 00127 00128 ast_debug(5, "EWS: unref_ewscal()\n"); 00129 ao2_ref(pvt, -1); 00130 return NULL; 00131 }
static int update_ewscal | ( | struct ewscal_pvt * | pvt | ) | [static] |
Definition at line 733 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().
00734 { 00735 struct calendar_id *id_head; 00736 struct calendar_id *iter; 00737 00738 if (!(id_head = get_ewscal_ids_for(pvt))) { 00739 return 0; 00740 } 00741 00742 for (iter = id_head; iter; iter = AST_LIST_NEXT(iter, next)) { 00743 parse_ewscal_id(pvt, ast_str_buffer(iter->id)); 00744 ast_free(iter->id); 00745 ast_free(iter); 00746 } 00747 00748 return 0; 00749 }
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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, } [static] |
Definition at line 916 of file res_calendar_ews.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 916 of file res_calendar_ews.c.
struct ast_calendar_tech ewscal_tech [static] |