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