#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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 82 of file res_calendar_ews.c.
00082 { 00083 XML_EVENT_NAME = 10, 00084 XML_EVENT_START, 00085 XML_EVENT_END, 00086 XML_EVENT_BUSY, 00087 XML_EVENT_ORGANIZER, 00088 XML_EVENT_LOCATION, 00089 XML_EVENT_ATTENDEE_LIST, 00090 XML_EVENT_ATTENDEE, 00091 XML_EVENT_MAILBOX, 00092 XML_EVENT_EMAIL_ADDRESS, 00093 XML_EVENT_CATEGORIES, 00094 XML_EVENT_CATEGORY, 00095 XML_EVENT_IMPORTANCE, 00096 };
enum xml_op |
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 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 918 of file res_calendar_ews.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 918 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 } 00428 ast_debug(3, "EWS: XML: attendee address '%s'\n", ast_str_buffer(ctx->cdata)); 00429 ast_str_reset(ctx->cdata); 00430 } else if (!strcmp(name, "CalendarItem")) { 00431 /* Event end */ 00432 ast_debug(3, "EWS: XML: </CalendarItem>\n"); 00433 ast_free(ctx->cdata); 00434 if (ctx->event) { 00435 ao2_link(ctx->pvt->events, ctx->event); 00436 ctx->event = ast_calendar_unref_event(ctx->event); 00437 } else { 00438 ast_log(LOG_ERROR, "Event data ended in XML, but event object does not exist!\n"); 00439 return 1; 00440 } 00441 } else if (!strcmp(name, "Envelope")) { 00442 /* Events end */ 00443 ast_debug(3, "EWS: XML: %d of %d event(s) has been parsed…\n", ao2_container_count(ctx->pvt->events), ctx->pvt->items); 00444 if (ao2_container_count(ctx->pvt->events) >= ctx->pvt->items) { 00445 ast_debug(3, "EWS: XML: All events has been parsed, merging…\n"); 00446 ast_calendar_merge_events(ctx->pvt->owner, ctx->pvt->events); 00447 } 00448 } 00449 00450 return 0; 00451 }
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 753 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.
00754 { 00755 struct ewscal_pvt *pvt; 00756 const struct ast_config *cfg; 00757 struct ast_variable *v; 00758 struct ast_calendar *cal = void_data; 00759 ast_mutex_t refreshlock; 00760 00761 ast_debug(5, "EWS: ewscal_load_calendar()\n"); 00762 00763 if (!(cal && (cfg = ast_calendar_config_acquire()))) { 00764 ast_log(LOG_ERROR, "You must enable calendar support for res_ewscal to load\n"); 00765 return NULL; 00766 } 00767 00768 if (ao2_trylock(cal)) { 00769 if (cal->unloading) { 00770 ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n"); 00771 } else { 00772 ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n"); 00773 } 00774 ast_calendar_config_release(); 00775 return NULL; 00776 } 00777 00778 if (!(pvt = ao2_alloc(sizeof(*pvt), ewscal_destructor))) { 00779 ast_log(LOG_ERROR, "Could not allocate ewscal_pvt structure for calendar: %s\n", cal->name); 00780 ast_calendar_config_release(); 00781 return NULL; 00782 } 00783 00784 pvt->owner = cal; 00785 00786 if (!(pvt->events = ast_calendar_event_container_alloc())) { 00787 ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name); 00788 pvt = unref_ewscal(pvt); 00789 ao2_unlock(cal); 00790 ast_calendar_config_release(); 00791 return NULL; 00792 } 00793 00794 if (ast_string_field_init(pvt, 32)) { 00795 ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name); 00796 pvt = unref_ewscal(pvt); 00797 ao2_unlock(cal); 00798 ast_calendar_config_release(); 00799 return NULL; 00800 } 00801 00802 for (v = ast_variable_browse(cfg, cal->name); v; v = v->next) { 00803 if (!strcasecmp(v->name, "url")) { 00804 ast_string_field_set(pvt, url, v->value); 00805 } else if (!strcasecmp(v->name, "user")) { 00806 ast_string_field_set(pvt, user, v->value); 00807 } else if (!strcasecmp(v->name, "secret")) { 00808 ast_string_field_set(pvt, secret, v->value); 00809 } 00810 } 00811 00812 ast_calendar_config_release(); 00813 00814 if (ast_strlen_zero(pvt->url)) { 00815 ast_log(LOG_WARNING, "No URL was specified for Exchange Web Service calendar '%s' - skipping.\n", cal->name); 00816 pvt = unref_ewscal(pvt); 00817 ao2_unlock(cal); 00818 return NULL; 00819 } 00820 00821 if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) { 00822 ast_log(LOG_WARNING, "Could not parse url '%s' for Exchange Web Service calendar '%s' - skipping.\n", pvt->url, cal->name); 00823 pvt = unref_ewscal(pvt); 00824 ao2_unlock(cal); 00825 return NULL; 00826 } 00827 00828 if (pvt->uri.scheme == NULL) { 00829 pvt->uri.scheme = "http"; 00830 } 00831 00832 if (pvt->uri.port == 0) { 00833 pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme); 00834 } 00835 00836 ast_debug(3, "ne_uri.scheme = %s\n", pvt->uri.scheme); 00837 ast_debug(3, "ne_uri.host = %s\n", pvt->uri.host); 00838 ast_debug(3, "ne_uri.port = %u\n", pvt->uri.port); 00839 ast_debug(3, "ne_uri.path = %s\n", pvt->uri.path); 00840 ast_debug(3, "user = %s\n", pvt->user); 00841 ast_debug(3, "secret = %s\n", pvt->secret); 00842 00843 pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port); 00844 ne_redirect_register(pvt->session); 00845 ne_set_server_auth(pvt->session, auth_credentials, pvt); 00846 ne_set_useragent(pvt->session, "Asterisk"); 00847 00848 if (!strcasecmp(pvt->uri.scheme, "https")) { 00849 ne_ssl_trust_default_ca(pvt->session); 00850 ne_ssl_set_verify(pvt->session, ssl_verify, pvt); 00851 } 00852 00853 cal->tech_pvt = pvt; 00854 00855 ast_mutex_init(&refreshlock); 00856 00857 /* Load it the first time */ 00858 update_ewscal(pvt); 00859 00860 ao2_unlock(cal); 00861 00862 /* The only writing from another thread will be if unload is true */ 00863 for (;;) { 00864 struct timeval tv = ast_tvnow(); 00865 struct timespec ts = {0,}; 00866 00867 ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh); 00868 00869 ast_mutex_lock(&refreshlock); 00870 while (!pvt->owner->unloading) { 00871 if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) { 00872 break; 00873 } 00874 } 00875 ast_mutex_unlock(&refreshlock); 00876 00877 if (pvt->owner->unloading) { 00878 ast_debug(10, "Skipping refresh since we got a shutdown signal\n"); 00879 return NULL; 00880 } 00881 00882 ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh); 00883 00884 update_ewscal(pvt); 00885 } 00886 00887 return NULL; 00888 }
static int ewscal_write_event | ( | struct ast_calendar_event * | event | ) | [static] |
Definition at line 545 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.
00546 { 00547 struct ast_str *request; 00548 struct ewscal_pvt *pvt = event->owner->tech_pvt; 00549 char start[21], end[21]; 00550 struct xml_context ctx = { 00551 .op = XML_OP_CREATE, 00552 .pvt = pvt, 00553 }; 00554 int ret; 00555 char *category, *categories; 00556 00557 if (!pvt) { 00558 return -1; 00559 } 00560 00561 if (!(request = ast_str_create(1024))) { 00562 return -1; 00563 } 00564 00565 ast_str_set(&request, 0, 00566 "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " 00567 "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " 00568 "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " 00569 "xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">" 00570 "<soap:Body>" 00571 "<CreateItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\" " 00572 "xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\" " 00573 "SendMeetingInvitations=\"SendToNone\" >" 00574 "<SavedItemFolderId>" 00575 "<t:DistinguishedFolderId Id=\"calendar\"/>" 00576 "</SavedItemFolderId>" 00577 "<Items>" 00578 "<t:CalendarItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/types\">" 00579 "<Subject>%s</Subject>" 00580 "<Body BodyType=\"Text\">%s</Body>" 00581 "<ReminderIsSet>false</ReminderIsSet>" 00582 "<Start>%s</Start>" 00583 "<End>%s</End>" 00584 "<IsAllDayEvent>false</IsAllDayEvent>" 00585 "<LegacyFreeBusyStatus>%s</LegacyFreeBusyStatus>" 00586 "<Location>%s</Location>", 00587 event->summary, 00588 event->description, 00589 mstime(event->start, start, sizeof(start)), 00590 mstime(event->end, end, sizeof(end)), 00591 msstatus(event->busy_state), 00592 event->location 00593 ); 00594 /* Event priority */ 00595 switch (event->priority) { 00596 case 1: 00597 case 2: 00598 case 3: 00599 case 4: 00600 ast_str_append(&request, 0, "<Importance>High</Importance>"); 00601 break; 00602 case 5: 00603 ast_str_append(&request, 0, "<Importance>Normal</Importance>"); 00604 break; 00605 case 6: 00606 case 7: 00607 case 8: 00608 case 9: 00609 ast_str_append(&request, 0, "<Importance>Low</Importance>"); 00610 break; 00611 } 00612 /* Event categories*/ 00613 if (strlen(event->categories) > 0) { 00614 ast_str_append(&request, 0, "<Categories>"); 00615 categories = ast_strdupa(event->categories); /* Duplicate string, since strsep() is destructive */ 00616 category = strsep(&categories, ","); 00617 while (category != NULL) { 00618 ast_str_append(&request, 0, "<String>%s</String>", category); 00619 category = strsep(&categories, ","); 00620 } 00621 ast_str_append(&request, 0, "</Categories>"); 00622 } 00623 /* Finish request */ 00624 ast_str_append(&request, 0, "</t:CalendarItem></Items></CreateItem></soap:Body></soap:Envelope>"); 00625 00626 ret = send_ews_request_and_parse(request, &ctx); 00627 00628 ast_free(request); 00629 00630 return ret; 00631 }
static struct calendar_id* get_ewscal_ids_for | ( | struct ewscal_pvt * | pvt | ) | [static] |
Definition at line 633 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().
00634 { 00635 char start[21], end[21]; 00636 struct ast_tm tm; 00637 struct timeval tv; 00638 struct ast_str *request; 00639 struct xml_context ctx = { 00640 .op = XML_OP_FIND, 00641 .pvt = pvt, 00642 }; 00643 00644 ast_debug(5, "EWS: get_ewscal_ids_for()\n"); 00645 00646 if (!pvt) { 00647 ast_log(LOG_ERROR, "There is no private!\n"); 00648 return NULL; 00649 } 00650 00651 /* Prepare timeframe strings */ 00652 tv = ast_tvnow(); 00653 ast_localtime(&tv, &tm, "UTC"); 00654 ast_strftime(start, sizeof(start), "%FT%TZ", &tm); 00655 tv.tv_sec += 60 * pvt->owner->timeframe; 00656 ast_localtime(&tv, &tm, "UTC"); 00657 ast_strftime(end, sizeof(end), "%FT%TZ", &tm); 00658 00659 /* Prepare SOAP request */ 00660 if (!(request = ast_str_create(512))) { 00661 return NULL; 00662 } 00663 00664 ast_str_set(&request, 0, 00665 "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" " 00666 "xmlns:ns1=\"http://schemas.microsoft.com/exchange/services/2006/types\" " 00667 "xmlns:ns2=\"http://schemas.microsoft.com/exchange/services/2006/messages\">" 00668 "<SOAP-ENV:Body>" 00669 "<ns2:FindItem Traversal=\"Shallow\">" 00670 "<ns2:ItemShape>" 00671 "<ns1:BaseShape>IdOnly</ns1:BaseShape>" 00672 "</ns2:ItemShape>" 00673 "<ns2:CalendarView StartDate=\"%s\" EndDate=\"%s\"/>" /* Timeframe */ 00674 "<ns2:ParentFolderIds>" 00675 "<ns1:DistinguishedFolderId Id=\"calendar\"/>" 00676 "</ns2:ParentFolderIds>" 00677 "</ns2:FindItem>" 00678 "</SOAP-ENV:Body>" 00679 "</SOAP-ENV:Envelope>", 00680 start, end /* Timeframe */ 00681 ); 00682 00683 AST_LIST_HEAD_INIT_NOLOCK(&ctx.ids); 00684 00685 /* Dispatch request and parse response as XML */ 00686 if (send_ews_request_and_parse(request, &ctx)) { 00687 ast_free(request); 00688 return NULL; 00689 } 00690 00691 /* Cleanup */ 00692 ast_free(request); 00693 00694 return AST_LIST_FIRST(&ctx.ids); 00695 }
static const char* get_soap_action | ( | enum xml_op | op | ) | [static] |
Definition at line 480 of file res_calendar_ews.c.
References XML_OP_CREATE, XML_OP_FIND, and XML_OP_GET.
Referenced by send_ews_request_and_parse().
00481 { 00482 switch (op) { 00483 case XML_OP_FIND: 00484 return "\"http://schemas.microsoft.com/exchange/services/2006/messages/FindItem\""; 00485 case XML_OP_GET: 00486 return "\"http://schemas.microsoft.com/exchange/services/2006/messages/GetItem\""; 00487 case XML_OP_CREATE: 00488 return "\"http://schemas.microsoft.com/exchange/services/2006/messages/CreateItem\""; 00489 } 00490 00491 return ""; 00492 }
static int load_module | ( | void | ) | [static] |
Definition at line 890 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.
00891 { 00892 /* Actualy, 0.29.1 is required (because of NTLM authentication), but this 00893 * function does not support matching patch version. */ 00894 if (ne_version_match(0, 29)) { 00895 ast_log(LOG_ERROR, "Exchange Web Service calendar module require neon >= 0.29.1, but %s is installed.\n", ne_version_string()); 00896 return AST_MODULE_LOAD_DECLINE; 00897 } 00898 00899 if (ast_calendar_register(&ewscal_tech) && (ne_sock_init() == 0)) { 00900 return AST_MODULE_LOAD_DECLINE; 00901 } 00902 00903 return AST_MODULE_LOAD_SUCCESS; 00904 }
static const char* msstatus | ( | enum ast_calendar_busy_state | state | ) | [static] |
Definition at line 466 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().
00467 { 00468 switch (state) { 00469 case AST_CALENDAR_BS_BUSY_TENTATIVE: 00470 return "Tentative"; 00471 case AST_CALENDAR_BS_BUSY: 00472 return "Busy"; 00473 case AST_CALENDAR_BS_FREE: 00474 return "Free"; 00475 default: 00476 return ""; 00477 } 00478 }
static const char* mstime | ( | time_t | t, | |
char * | buf, | |||
size_t | buflen | |||
) | [static] |
Definition at line 453 of file res_calendar_ews.c.
References ast_localtime(), ast_strftime(), and S_OR.
Referenced by ewscal_write_event().
00454 { 00455 struct timeval tv = { 00456 .tv_sec = t, 00457 }; 00458 struct ast_tm tm; 00459 00460 ast_localtime(&tv, &tm, "utc"); 00461 ast_strftime(buf, buflen, "%FT%TZ", &tm); 00462 00463 return S_OR(buf, ""); 00464 }
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 697 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().
00697 { 00698 struct ast_str *request; 00699 struct xml_context ctx = { 00700 .pvt = pvt, 00701 .op = XML_OP_GET, 00702 }; 00703 00704 if (!(request = ast_str_create(512))) { 00705 return -1; 00706 } 00707 00708 ast_str_set(&request, 0, 00709 "<?xml version=\"1.0\" encoding=\"utf-8\"?>" 00710 "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " 00711 "xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">" 00712 "<soap:Body>" 00713 "<GetItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\">" 00714 "<ItemShape>" 00715 "<t:BaseShape>AllProperties</t:BaseShape>" 00716 "</ItemShape>" 00717 "<ItemIds>" 00718 "<t:ItemId Id=\"%s\"/>" 00719 "</ItemIds>" 00720 "</GetItem>" 00721 "</soap:Body>" 00722 "</soap:Envelope>", id 00723 ); 00724 00725 if (send_ews_request_and_parse(request, &ctx)) { 00726 ast_free(request); 00727 return -1; 00728 } 00729 00730 ast_free(request); 00731 00732 return 0; 00733 }
static int send_ews_request_and_parse | ( | struct ast_str * | request, | |
struct xml_context * | ctx | |||
) | [static] |
Definition at line 494 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().
00495 { 00496 int ret; 00497 ne_request *req; 00498 ne_xml_parser *parser; 00499 00500 ast_debug(3, "EWS: HTTP request...\n"); 00501 if (!(ctx && ctx->pvt)) { 00502 ast_log(LOG_ERROR, "There is no private!\n"); 00503 return -1; 00504 } 00505 00506 if (!ast_str_strlen(request)) { 00507 ast_log(LOG_ERROR, "No request to send!\n"); 00508 return -1; 00509 } 00510 00511 ast_debug(3, "%s\n", ast_str_buffer(request)); 00512 00513 /* Prepare HTTP POST request */ 00514 req = ne_request_create(ctx->pvt->session, "POST", ctx->pvt->uri.path); 00515 ne_set_request_flag(req, NE_REQFLAG_IDEMPOTENT, 0); 00516 00517 /* Set headers--should be application/soap+xml, but MS… :/ */ 00518 ne_add_request_header(req, "Content-Type", "text/xml; charset=utf-8"); 00519 ne_add_request_header(req, "SOAPAction", get_soap_action(ctx->op)); 00520 00521 /* Set body to SOAP request */ 00522 ne_set_request_body_buffer(req, ast_str_buffer(request), ast_str_strlen(request)); 00523 00524 /* Prepare XML parser */ 00525 parser = ne_xml_create(); 00526 ctx->parser = parser; 00527 ne_xml_push_handler(parser, startelm, cdata, endelm, ctx); /* Callbacks */ 00528 00529 /* Dispatch request and parse response as XML */ 00530 ret = ne_xml_dispatch_request(req, parser); 00531 if (ret != NE_OK) { /* Error handling */ 00532 ast_log(LOG_WARNING, "Unable to communicate with Exchange Web Service at '%s': %s\n", ctx->pvt->url, ne_get_error(ctx->pvt->session)); 00533 ne_request_destroy(req); 00534 ne_xml_destroy(parser); 00535 return -1; 00536 } 00537 00538 /* Cleanup */ 00539 ne_request_destroy(req); 00540 ne_xml_destroy(parser); 00541 00542 return 0; 00543 }
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 906 of file res_calendar_ews.c.
References ast_calendar_unregister(), and ewscal_tech.
00907 { 00908 ne_sock_exit(); 00909 ast_calendar_unregister(&ewscal_tech); 00910 00911 return 0; 00912 }
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 735 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().
00736 { 00737 struct calendar_id *id_head; 00738 struct calendar_id *iter; 00739 00740 if (!(id_head = get_ewscal_ids_for(pvt))) { 00741 return 0; 00742 } 00743 00744 for (iter = id_head; iter; iter = AST_LIST_NEXT(iter, next)) { 00745 parse_ewscal_id(pvt, ast_str_buffer(iter->id)); 00746 ast_free(iter->id); 00747 ast_free(iter); 00748 } 00749 00750 return 0; 00751 }
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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, } [static] |
Definition at line 918 of file res_calendar_ews.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 918 of file res_calendar_ews.c.
struct ast_calendar_tech ewscal_tech [static] |