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_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 = "ac1f6a56484a8820659555499174e588" , .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 |
Resource for handling MS Exchange Web Service calendars.
Definition in file res_calendar_ews.c.
anonymous enum |
Definition at line 82 of file res_calendar_ews.c.
00082 { 00083 XML_EVENT_CALENDAR_ITEM = 9, 00084 XML_EVENT_NAME = 10, 00085 XML_EVENT_DESCRIPTION, 00086 XML_EVENT_START, 00087 XML_EVENT_END, 00088 XML_EVENT_BUSY, 00089 XML_EVENT_ORGANIZER, 00090 XML_EVENT_LOCATION, 00091 XML_EVENT_ATTENDEE_LIST, 00092 XML_EVENT_ATTENDEE, 00093 XML_EVENT_MAILBOX, 00094 XML_EVENT_EMAIL_ADDRESS, 00095 XML_EVENT_CATEGORIES, 00096 XML_EVENT_CATEGORY, 00097 XML_EVENT_IMPORTANCE, 00098 };
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 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 }
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.
struct ast_module_info* ast_module_info = &__mod_info [static] |
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.