Resource for handling MS Exchange calendars. More...
#include "asterisk.h"
#include <libical/ical.h>
#include <ne_session.h>
#include <ne_uri.h>
#include <ne_request.h>
#include <ne_auth.h>
#include <ne_redirect.h>
#include <iksemel.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 | exchangecal_pvt |
struct | xmlstate |
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 struct ast_str * | bs_to_exchange_bs (struct ast_str *dst, enum ast_calendar_busy_state bs) |
static struct ast_str * | epoch_to_exchange_time (struct ast_str *dst, time_t epoch) |
static void | exchangecal_destructor (void *obj) |
static struct ast_str * | exchangecal_get_events_between (struct exchangecal_pvt *pvt, time_t start_time, time_t end_time) |
static void * | exchangecal_load_calendar (void *data) |
static struct ast_str * | exchangecal_request (struct exchangecal_pvt *pvt, const char *method, struct ast_str *req_body, struct ast_str *subdir) |
static int | exchangecal_write_event (struct ast_calendar_event *event) |
static int | fetch_response_reader (void *data, const char *block, size_t len) |
static struct ast_str * | generate_exchange_uuid (struct ast_str *uid) |
static int | is_valid_uuid (struct ast_str *uid) |
static int | load_module (void) |
static enum ast_calendar_busy_state | msbusy_to_bs (const char *msbusy) |
static time_t | mstime_to_time_t (char *mstime) |
static int | parse_cdata (void *data, char *value, size_t len) |
static int | parse_tag (void *data, char *name, char **atts, int type) |
static int | unload_module (void) |
static void * | unref_exchangecal (void *obj) |
static int | update_exchangecal (struct exchangecal_pvt *pvt) |
static struct ast_str * | xml_encode_str (struct ast_str *dst, const char *src) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Asterisk MS Exchange 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 | exchangecal_tech |
Resource for handling MS Exchange calendars.
Definition in file res_calendar_exchange.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 766 of file res_calendar_exchange.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 766 of file res_calendar_exchange.c.
static int auth_credentials | ( | void * | userdata, | |
const char * | realm, | |||
int | attempts, | |||
char * | username, | |||
char * | secret | |||
) | [static] |
Definition at line 370 of file res_calendar_exchange.c.
References ast_log(), LOG_WARNING, exchangecal_pvt::owner, exchangecal_pvt::secret, and exchangecal_pvt::user.
Referenced by exchangecal_load_calendar().
00371 { 00372 struct exchangecal_pvt *pvt = userdata; 00373 00374 if (attempts > 1) { 00375 ast_log(LOG_WARNING, "Invalid username or password for Exchange calendar '%s'\n", pvt->owner->name); 00376 return -1; 00377 } 00378 00379 ne_strnzcpy(username, pvt->user, NE_ABUFSIZ); 00380 ne_strnzcpy(secret, pvt->secret, NE_ABUFSIZ); 00381 00382 return 0; 00383 }
static struct ast_str* bs_to_exchange_bs | ( | struct ast_str * | dst, | |
enum ast_calendar_busy_state | bs | |||
) | [static, read] |
Definition at line 336 of file res_calendar_exchange.c.
References AST_CALENDAR_BS_BUSY, AST_CALENDAR_BS_BUSY_TENTATIVE, and ast_str_set().
Referenced by exchangecal_write_event().
00337 { 00338 switch (bs) { 00339 case AST_CALENDAR_BS_BUSY: 00340 ast_str_set(&dst, 0, "%s", "BUSY"); 00341 break; 00342 00343 case AST_CALENDAR_BS_BUSY_TENTATIVE: 00344 ast_str_set(&dst, 0, "%s", "TENTATIVE"); 00345 break; 00346 00347 default: 00348 ast_str_set(&dst, 0, "%s", "FREE"); 00349 } 00350 00351 return dst; 00352 }
Definition at line 315 of file res_calendar_exchange.c.
References ast_copy_string(), and ast_str_append().
Referenced by exchangecal_write_event().
00316 { 00317 icaltimezone *utc = icaltimezone_get_utc_timezone(); 00318 icaltimetype tt = icaltime_from_timet_with_zone(epoch, 0, utc); 00319 char tmp[30]; 00320 int i; 00321 00322 ast_copy_string(tmp, icaltime_as_ical_string(tt), sizeof(tmp)); 00323 for (i = 0; tmp[i]; i++) { 00324 ast_str_append(&dst, 0, "%c", tmp[i]); 00325 if (i == 3 || i == 5) 00326 ast_str_append(&dst, 0, "%c", '-'); 00327 if (i == 10 || i == 12) 00328 ast_str_append(&dst, 0, "%c", ':'); 00329 if (i == 14) 00330 ast_str_append(&dst, 0, "%s", ".000"); 00331 } 00332 00333 return dst; 00334 }
static void exchangecal_destructor | ( | void * | obj | ) | [static] |
Definition at line 218 of file res_calendar_exchange.c.
References ao2_callback, ao2_ref, ast_debug, ast_string_field_free_memory, exchangecal_pvt::events, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, exchangecal_pvt::owner, and exchangecal_pvt::session.
Referenced by exchangecal_load_calendar().
00219 { 00220 struct exchangecal_pvt *pvt = obj; 00221 00222 ast_debug(1, "Destroying pvt for Exchange calendar %s\n", pvt->owner->name); 00223 if (pvt->session) { 00224 ne_session_destroy(pvt->session); 00225 } 00226 ast_string_field_free_memory(pvt); 00227 00228 ao2_callback(pvt->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL); 00229 00230 ao2_ref(pvt->events, -1); 00231 }
static struct ast_str* exchangecal_get_events_between | ( | struct exchangecal_pvt * | pvt, | |
time_t | start_time, | |||
time_t | end_time | |||
) | [static, read] |
Definition at line 551 of file res_calendar_exchange.c.
References ast_debug, ast_free, ast_localtime(), ast_log(), ast_str_append(), ast_str_buffer(), ast_str_create(), ast_strftime(), exchangecal_request(), LOG_ERROR, and exchangecal_pvt::url.
Referenced by update_exchangecal().
00552 { 00553 struct ast_str *body, *response; 00554 char start[80], end[80]; 00555 struct timeval tv = {0,}; 00556 struct ast_tm tm; 00557 00558 tv.tv_sec = start_time; 00559 ast_localtime(&tv, &tm, "UTC"); 00560 ast_strftime(start, sizeof(start), "%Y/%m/%d %T", &tm); 00561 00562 tv.tv_sec = end_time; 00563 ast_localtime(&tv, &tm, "UTC"); 00564 ast_strftime(end, sizeof(end), "%Y/%m/%d %T", &tm); 00565 00566 if (!(body = ast_str_create(512))) { 00567 ast_log(LOG_ERROR, "Could not allocate memory for body of request!\n"); 00568 return NULL; 00569 } 00570 00571 ast_str_append(&body, 0, 00572 "<?xml version=\"1.0\"?>\n" 00573 "<g:searchrequest xmlns:g=\"DAV:\">\n" 00574 " <g:sql> SELECT \"urn:schemas:calendar:location\", \"urn:schemas:httpmail:subject\",\n" 00575 " \"urn:schemas:calendar:dtstart\", \"urn:schemas:calendar:dtend\",\n" 00576 " \"urn:schemas:calendar:busystatus\", \"urn:schemas:calendar:instancetype\",\n" 00577 " \"urn:schemas:calendar:uid\", \"urn:schemas:httpmail:textdescription\",\n" 00578 " \"urn:schemas:calendar:organizer\", \"urn:schemas:calendar:reminderoffset\"\n" 00579 " FROM Scope('SHALLOW TRAVERSAL OF \"%s/Calendar\"')\n" 00580 " WHERE NOT \"urn:schemas:calendar:instancetype\" = 1\n" 00581 " AND \"DAV:contentclass\" = 'urn:content-classes:appointment'\n" 00582 " AND NOT (\"urn:schemas:calendar:dtend\" < '%s'\n" 00583 " OR \"urn:schemas:calendar:dtstart\" > '%s')\n" 00584 " ORDER BY \"urn:schemas:calendar:dtstart\" ASC\n" 00585 " </g:sql>\n" 00586 "</g:searchrequest>\n", pvt->url, start, end); 00587 00588 ast_debug(5, "Request:\n%s\n", ast_str_buffer(body)); 00589 response = exchangecal_request(pvt, "SEARCH", body, NULL); 00590 ast_debug(5, "Response:\n%s\n", ast_str_buffer(response)); 00591 ast_free(body); 00592 00593 return response; 00594 }
static void * exchangecal_load_calendar | ( | void * | data | ) | [static] |
Definition at line 619 of file res_calendar_exchange.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(), exchangecal_pvt::events, exchangecal_destructor(), LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, exchangecal_pvt::owner, ast_calendar::refresh, refreshlock, secret, exchangecal_pvt::session, ast_calendar::tech_pvt, ast_calendar::unload, ast_calendar::unloading, unref_exchangecal(), update_exchangecal(), exchangecal_pvt::uri, exchangecal_pvt::url, url, and ast_variable::value.
00620 { 00621 struct exchangecal_pvt *pvt; 00622 const struct ast_config *cfg; 00623 struct ast_variable *v; 00624 struct ast_calendar *cal = void_data; 00625 ast_mutex_t refreshlock; 00626 00627 if (!(cal && (cfg = ast_calendar_config_acquire()))) { 00628 ast_log(LOG_ERROR, "You must enable calendar support for res_exchangecal to load\n"); 00629 return NULL; 00630 } 00631 00632 if (ao2_trylock(cal)) { 00633 if (cal->unloading) { 00634 ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n"); 00635 } else { 00636 ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n"); 00637 } 00638 ast_calendar_config_release(); 00639 return NULL; 00640 } 00641 00642 if (!(pvt = ao2_alloc(sizeof(*pvt), exchangecal_destructor))) { 00643 ast_log(LOG_ERROR, "Could not allocate exchangecal_pvt structure for calendar: %s\n", cal->name); 00644 ast_calendar_config_release(); 00645 return NULL; 00646 } 00647 00648 pvt->owner = cal; 00649 00650 if (!(pvt->events = ast_calendar_event_container_alloc())) { 00651 ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name); 00652 pvt = unref_exchangecal(pvt); 00653 ao2_unlock(cal); 00654 ast_calendar_config_release(); 00655 return NULL; 00656 } 00657 00658 if (ast_string_field_init(pvt, 32)) { 00659 ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name); 00660 pvt = unref_exchangecal(pvt); 00661 ao2_unlock(cal); 00662 ast_calendar_config_release(); 00663 return NULL; 00664 } 00665 00666 for (v = ast_variable_browse(cfg, cal->name); v; v = v->next) { 00667 if (!strcasecmp(v->name, "url")) { 00668 ast_string_field_set(pvt, url, v->value); 00669 } else if (!strcasecmp(v->name, "user")) { 00670 ast_string_field_set(pvt, user, v->value); 00671 } else if (!strcasecmp(v->name, "secret")) { 00672 ast_string_field_set(pvt, secret, v->value); 00673 } 00674 } 00675 00676 ast_calendar_config_release(); 00677 00678 if (ast_strlen_zero(pvt->url)) { 00679 ast_log(LOG_WARNING, "No URL was specified for Exchange calendar '%s' - skipping.\n", cal->name); 00680 pvt = unref_exchangecal(pvt); 00681 ao2_unlock(cal); 00682 return NULL; 00683 } 00684 00685 if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) { 00686 ast_log(LOG_WARNING, "Could not parse url '%s' for Exchange calendar '%s' - skipping.\n", pvt->url, cal->name); 00687 pvt = unref_exchangecal(pvt); 00688 ao2_unlock(cal); 00689 return NULL; 00690 } 00691 00692 if (pvt->uri.scheme == NULL) { 00693 pvt->uri.scheme = "http"; 00694 } 00695 00696 if (pvt->uri.port == 0) { 00697 pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme); 00698 } 00699 00700 pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port); 00701 ne_redirect_register(pvt->session); 00702 ne_set_server_auth(pvt->session, auth_credentials, pvt); 00703 if (!strcasecmp(pvt->uri.scheme, "https")) { 00704 ne_ssl_trust_default_ca(pvt->session); 00705 } 00706 00707 cal->tech_pvt = pvt; 00708 00709 ast_mutex_init(&refreshlock); 00710 00711 /* Load it the first time */ 00712 update_exchangecal(pvt); 00713 00714 ao2_unlock(cal); 00715 00716 /* The only writing from another thread will be if unload is true */ 00717 for (;;) { 00718 struct timeval tv = ast_tvnow(); 00719 struct timespec ts = {0,}; 00720 00721 ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh); 00722 00723 ast_mutex_lock(&refreshlock); 00724 while (!pvt->owner->unloading) { 00725 if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) { 00726 break; 00727 } 00728 } 00729 ast_mutex_unlock(&refreshlock); 00730 00731 if (pvt->owner->unloading) { 00732 ast_debug(10, "Skipping refresh since we got a shutdown signal\n"); 00733 return NULL; 00734 } 00735 00736 ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh); 00737 00738 update_exchangecal(pvt); 00739 } 00740 00741 return NULL; 00742 }
static struct ast_str* exchangecal_request | ( | struct exchangecal_pvt * | pvt, | |
const char * | method, | |||
struct ast_str * | req_body, | |||
struct ast_str * | subdir | |||
) | [static, read] |
Definition at line 385 of file res_calendar_exchange.c.
References ast_free, ast_log(), ast_str_buffer(), ast_str_create(), ast_str_strlen(), fetch_response_reader(), LOG_ERROR, LOG_WARNING, exchangecal_pvt::owner, exchangecal_pvt::session, exchangecal_pvt::uri, and exchangecal_pvt::url.
Referenced by exchangecal_get_events_between(), and exchangecal_write_event().
00386 { 00387 struct ast_str *response; 00388 ne_request *req; 00389 int ret; 00390 char buf[1000]; 00391 00392 if (!pvt) { 00393 ast_log(LOG_ERROR, "There is no private!\n"); 00394 return NULL; 00395 } 00396 00397 if (!(response = ast_str_create(512))) { 00398 ast_log(LOG_ERROR, "Could not allocate memory for response.\n"); 00399 return NULL; 00400 } 00401 00402 snprintf(buf, sizeof(buf), "%s%s", pvt->uri.path, subdir ? ast_str_buffer(subdir) : ""); 00403 00404 req = ne_request_create(pvt->session, method, buf); 00405 ne_add_response_body_reader(req, ne_accept_2xx, fetch_response_reader, &response); 00406 ne_set_request_body_buffer(req, ast_str_buffer(req_body), ast_str_strlen(req_body)); 00407 ne_add_request_header(req, "Content-type", "text/xml"); 00408 00409 ret = ne_request_dispatch(req); 00410 ne_request_destroy(req); 00411 00412 if (ret != NE_OK || !ast_str_strlen(response)) { 00413 ast_log(LOG_WARNING, "Unknown response to CalDAV calendar %s, request %s to %s: %s\n", pvt->owner->name, method, pvt->url, ne_get_error(pvt->session)); 00414 ast_free(response); 00415 return NULL; 00416 } 00417 00418 return response; 00419 }
static int exchangecal_write_event | ( | struct ast_calendar_event * | event | ) | [static] |
Definition at line 421 of file res_calendar_exchange.c.
References ast_free, ast_log(), ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_set(), ast_strlen_zero(), ast_verb, bs_to_exchange_bs(), ast_calendar_event::busy_state, ast_calendar_event::end, epoch_to_exchange_time(), exchangecal_request(), generate_exchange_uuid(), is_valid_uuid(), LOG_ERROR, LOG_WARNING, ast_calendar_event::owner, ast_calendar_event::start, ast_calendar::tech_pvt, and xml_encode_str().
00422 { 00423 struct ast_str *body = NULL, *response = NULL, *subdir = NULL; 00424 struct ast_str *uid = NULL, *summary = NULL, *description = NULL, *organizer = NULL, 00425 *location = NULL, *start = NULL, *end = NULL, *busystate = NULL; 00426 int ret = -1; 00427 00428 if (!event) { 00429 ast_log(LOG_WARNING, "No event passed!\n"); 00430 return -1; 00431 } 00432 00433 if (!(event->start && event->end)) { 00434 ast_log(LOG_WARNING, "The event must contain a start and an end\n"); 00435 return -1; 00436 } 00437 if (!(body = ast_str_create(512)) || 00438 !(subdir = ast_str_create(32))) { 00439 ast_log(LOG_ERROR, "Could not allocate memory for request!\n"); 00440 goto write_cleanup; 00441 } 00442 00443 if (!(uid = ast_str_create(32)) || 00444 !(summary = ast_str_create(32)) || 00445 !(description = ast_str_create(32)) || 00446 !(organizer = ast_str_create(32)) || 00447 !(location = ast_str_create(32)) || 00448 !(start = ast_str_create(32)) || 00449 !(end = ast_str_create(32)) || 00450 !(busystate = ast_str_create(32))) { 00451 ast_log(LOG_ERROR, "Unable to allocate memory for request values\n"); 00452 goto write_cleanup; 00453 } 00454 00455 if (ast_strlen_zero(event->uid)) { 00456 uid = generate_exchange_uuid(uid); 00457 } else { 00458 ast_str_set(&uid, 36, "%s", event->uid); 00459 } 00460 00461 if (!is_valid_uuid(uid)) { 00462 ast_log(LOG_WARNING, "An invalid uid was provided, you may leave this field blank to have one generated for you\n"); 00463 goto write_cleanup; 00464 } 00465 00466 summary = xml_encode_str(summary, event->summary); 00467 description = xml_encode_str(description, event->description); 00468 organizer = xml_encode_str(organizer, event->organizer); 00469 location = xml_encode_str(location, event->location); 00470 start = epoch_to_exchange_time(start, event->start); 00471 end = epoch_to_exchange_time(end, event->end); 00472 busystate = bs_to_exchange_bs(busystate, event->busy_state); 00473 00474 ast_str_append(&body, 0, 00475 "<?xml version=\"1.0\"?>\n" 00476 "<a:propertyupdate\n" 00477 " xmlns:a=\"DAV:\"\n" 00478 " xmlns:e=\"http://schemas.microsoft.com/exchange/\"\n" 00479 " xmlns:mapi=\"http://schemas.microsoft.com/mapi/\"\n" 00480 " xmlns:mapit=\"http://schemas.microsoft.com/mapi/proptag/\"\n" 00481 " xmlns:x=\"xml:\" xmlns:cal=\"urn:schemas:calendar:\"\n" 00482 " xmlns:dt=\"uuid:%s/\"\n" /* uid */ 00483 " xmlns:header=\"urn:schemas:mailheader:\"\n" 00484 " xmlns:mail=\"urn:schemas:httpmail:\"\n" 00485 ">\n" 00486 " <a:set>\n" 00487 " <a:prop>\n" 00488 " <a:contentclass>urn:content-classes:appointment</a:contentclass>\n" 00489 " <e:outlookmessageclass>IPM.Appointment</e:outlookmessageclass>\n" 00490 " <mail:subject>%s</mail:subject>\n" /* summary */ 00491 " <mail:description>%s</mail:description>\n" /* description */ 00492 " <header:to>%s</header:to>\n" /* organizer */ 00493 " <cal:location>%s</cal:location>\n" /* location */ 00494 " <cal:dtstart dt:dt=\"dateTime.tz\">%s</cal:dtstart>\n" /* start */ 00495 " <cal:dtend dt:dt=\"dateTime.tz\">%s</cal:dtend>\n" /* end */ 00496 " <cal:instancetype dt:dt=\"int\">0</cal:instancetype>\n" 00497 " <cal:busystatus>%s</cal:busystatus>\n" /* busy_state (BUSY, FREE, BUSY_TENTATIVE) */ 00498 " <cal:meetingstatus>CONFIRMED</cal:meetingstatus>\n" 00499 " <cal:alldayevent dt:dt=\"boolean\">0</cal:alldayevent>\n" /* XXX need to add event support for all day events */ 00500 " <cal:responserequested dt:dt=\"boolean\">0</cal:responserequested>\n" 00501 " <mapi:finvited dt:dt=\"boolean\">1</mapi:finvited>\n" 00502 " </a:prop>\n" 00503 " </a:set>\n" 00504 "</a:propertyupdate>\n", 00505 ast_str_buffer(uid), ast_str_buffer(summary), ast_str_buffer(description), ast_str_buffer(organizer), ast_str_buffer(location), ast_str_buffer(start), ast_str_buffer(end), ast_str_buffer(busystate)); 00506 ast_verb(0, "\n\n%s\n\n", ast_str_buffer(body)); 00507 ast_str_set(&subdir, 0, "/Calendar/%s.eml", ast_str_buffer(uid)); 00508 00509 response = exchangecal_request(event->owner->tech_pvt, "PROPPATCH", body, subdir); 00510 00511 ret = 0; 00512 write_cleanup: 00513 if (uid) { 00514 ast_free(uid); 00515 } 00516 if (summary) { 00517 ast_free(summary); 00518 } 00519 if (description) { 00520 ast_free(description); 00521 } 00522 if (organizer) { 00523 ast_free(organizer); 00524 } 00525 if (location) { 00526 ast_free(location); 00527 } 00528 if (start) { 00529 ast_free(start); 00530 } 00531 if (end) { 00532 ast_free(end); 00533 } 00534 if (busystate) { 00535 ast_free(busystate); 00536 } 00537 if (body) { 00538 ast_free(body); 00539 } 00540 if (response) { 00541 ast_free(response); 00542 } 00543 if (subdir) { 00544 ast_free(subdir); 00545 } 00546 00547 return ret; 00548 }
static int fetch_response_reader | ( | void * | data, | |
const char * | block, | |||
size_t | len | |||
) | [static] |
Definition at line 354 of file res_calendar_exchange.c.
References ast_free, ast_malloc, and ast_str_append().
Referenced by exchangecal_request().
00355 { 00356 struct ast_str **response = data; 00357 unsigned char *tmp; 00358 00359 if (!(tmp = ast_malloc(len + 1))) { 00360 return -1; 00361 } 00362 memcpy(tmp, block, len); 00363 tmp[len] = '\0'; 00364 ast_str_append(response, 0, "%s", tmp); 00365 ast_free(tmp); 00366 00367 return 0; 00368 }
Definition at line 242 of file res_calendar_exchange.c.
References ast_random(), and ast_str_set().
Referenced by exchangecal_write_event().
00243 { 00244 unsigned short val[8]; 00245 int x; 00246 00247 for (x = 0; x < 8; x++) { 00248 val[x] = ast_random(); 00249 } 00250 ast_str_set(&uid, 0, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", (unsigned)val[0], 00251 (unsigned)val[1], (unsigned)val[2], (unsigned)val[3], (unsigned)val[4], 00252 (unsigned)val[5], (unsigned)val[6], (unsigned)val[7]); 00253 00254 return uid; 00255 }
static int is_valid_uuid | ( | struct ast_str * | uid | ) | [static] |
Definition at line 257 of file res_calendar_exchange.c.
References ast_str_buffer(), and ast_str_strlen().
Referenced by exchangecal_write_event().
00258 { 00259 int i; 00260 00261 if (ast_str_strlen(uid) != 36) { 00262 return 0; 00263 } 00264 00265 for (i = 0; i < ast_str_strlen(uid); i++) { 00266 if (i == 8 || i == 13 || i == 18 || i == 23) { 00267 if (ast_str_buffer(uid)[i] != '-') { 00268 return 0; 00269 } 00270 } else if (!((ast_str_buffer(uid)[i] > 47 && ast_str_buffer(uid)[i] < 58) || (ast_str_buffer(uid)[i] > 96 && ast_str_buffer(uid)[i] < 103))) { 00271 return 0; 00272 } 00273 } 00274 00275 return 1; 00276 }
static int load_module | ( | void | ) | [static] |
Definition at line 744 of file res_calendar_exchange.c.
References ast_calendar_register(), AST_MODULE_LOAD_DECLINE, and AST_MODULE_LOAD_SUCCESS.
00745 { 00746 ne_sock_init(); 00747 if (ast_calendar_register(&exchangecal_tech)) { 00748 ne_sock_exit(); 00749 return AST_MODULE_LOAD_DECLINE; 00750 } 00751 00752 return AST_MODULE_LOAD_SUCCESS; 00753 }
static enum ast_calendar_busy_state msbusy_to_bs | ( | const char * | msbusy | ) | [static] |
Definition at line 159 of file res_calendar_exchange.c.
References AST_CALENDAR_BS_BUSY, AST_CALENDAR_BS_BUSY_TENTATIVE, and AST_CALENDAR_BS_FREE.
Referenced by parse_cdata().
00160 { 00161 if (!strcasecmp(msbusy, "FREE")) { 00162 return AST_CALENDAR_BS_FREE; 00163 } else if (!strcasecmp(msbusy, "TENTATIVE")) { 00164 return AST_CALENDAR_BS_BUSY_TENTATIVE; 00165 } else { 00166 return AST_CALENDAR_BS_BUSY; 00167 } 00168 }
static time_t mstime_to_time_t | ( | char * | mstime | ) | [static] |
Definition at line 139 of file res_calendar_exchange.c.
Referenced by parse_cdata().
00140 { 00141 char *read, *write; 00142 icaltimetype tt; 00143 for (read = write = mstime; *read; read++) { 00144 if (*read == '.') { 00145 *write++ = 'Z'; 00146 *write = '\0'; 00147 break; 00148 } 00149 if (*read == '-' || *read == ':') 00150 continue; 00151 *write = *read; 00152 write++; 00153 } 00154 00155 tt = icaltime_from_string(mstime); 00156 return icaltime_as_timet(tt); 00157 }
static int parse_cdata | ( | void * | data, | |
char * | value, | |||
size_t | len | |||
) | [static] |
Definition at line 170 of file res_calendar_exchange.c.
References ast_calloc, ast_free, ast_skip_blanks(), ast_string_field_build, xmlstate::in_prop, xmlstate::in_propstat, xmlstate::in_response, msbusy_to_bs(), mstime_to_time_t(), xmlstate::ptr, str, and xmlstate::tag.
Referenced by update_exchangecal().
00171 { 00172 char *str; 00173 struct xmlstate *state = data; 00174 struct ast_calendar_event *event = state->ptr; 00175 00176 00177 str = ast_skip_blanks(value); 00178 00179 if (str == value + len) 00180 return IKS_OK; 00181 00182 if (!(str = ast_calloc(1, len + 1))) { 00183 return IKS_NOMEM; 00184 } 00185 memcpy(str, value, len); 00186 if (!(state->in_response && state->in_propstat && state->in_prop)) { 00187 ast_free(str); 00188 return IKS_OK; 00189 } 00190 /* We use ast_string_field_build here because libiksemel is parsing CDATA with < as 00191 * new elements which is a bit odd and shouldn't happen */ 00192 if (!strcasecmp(state->tag, "subject")) { 00193 ast_string_field_build(event, summary, "%s%s", event->summary, str); 00194 } else if (!strcasecmp(state->tag, "location")) { 00195 ast_string_field_build(event, location, "%s%s", event->location, str); 00196 } else if (!strcasecmp(state->tag, "uid")) { 00197 ast_string_field_build(event, uid, "%s%s", event->location, str); 00198 } else if (!strcasecmp(state->tag, "organizer")) { 00199 ast_string_field_build(event, organizer, "%s%s", event->organizer, str); 00200 } else if (!strcasecmp(state->tag, "textdescription")) { 00201 ast_string_field_build(event, description, "%s%s", event->description, str); 00202 } else if (!strcasecmp(state->tag, "dtstart")) { 00203 event->start = mstime_to_time_t(str); 00204 } else if (!strcasecmp(state->tag, "dtend")) { 00205 event->end = mstime_to_time_t(str); 00206 } else if (!strcasecmp(state->tag, "busystatus")) { 00207 event->busy_state = msbusy_to_bs(str); 00208 } else if (!strcasecmp(state->tag, "reminderoffset")) { 00209 /*XXX Currently we rely on event->start being set first which means we rely on the response order 00210 * which technically should be fine since the query returns in the order we ask for, but ... */ 00211 event->alarm = event->start - atoi(str); 00212 } 00213 00214 ast_free(str); 00215 return IKS_OK; 00216 }
static int parse_tag | ( | void * | data, | |
char * | name, | |||
char ** | atts, | |||
int | type | |||
) | [static] |
Definition at line 82 of file res_calendar_exchange.c.
References ao2_link, ast_calendar_event_alloc(), ast_calendar_unref_event(), ast_copy_string(), ast_log(), ast_strlen_zero(), caldav_pvt::events, events, xmlstate::in_prop, xmlstate::in_propstat, xmlstate::in_response, LOG_ERROR, caldav_pvt::owner, xmlstate::ptr, xmlstate::pvt, and xmlstate::tag.
Referenced by update_exchangecal().
00083 { 00084 struct xmlstate *state = data; 00085 char *tmp; 00086 00087 if ((tmp = strchr(name, ':'))) { 00088 tmp++; 00089 } else { 00090 return IKS_HOOK; 00091 } 00092 00093 ast_copy_string(state->tag, tmp, sizeof(state->tag)); 00094 00095 switch (type) { 00096 case IKS_OPEN: 00097 if (!strcasecmp(state->tag, "response")) { 00098 struct ast_calendar_event *event; 00099 00100 state->in_response = 1; 00101 if (!(event = ast_calendar_event_alloc(state->pvt->owner))) { 00102 return IKS_NOMEM; 00103 } 00104 state->ptr = event; 00105 } else if (!strcasecmp(state->tag, "propstat")) { 00106 state->in_propstat = 1; 00107 } else if (!strcasecmp(state->tag, "prop")) { 00108 state->in_prop = 1; 00109 } 00110 break; 00111 00112 case IKS_CLOSE: 00113 if (!strcasecmp(state->tag, "response")) { 00114 struct ao2_container *events = state->pvt->events; 00115 struct ast_calendar_event *event = state->ptr; 00116 00117 state->in_response = 0; 00118 if (ast_strlen_zero(event->uid)) { 00119 ast_log(LOG_ERROR, "This event has no UID, something has gone wrong\n"); 00120 event = ast_calendar_unref_event(event); 00121 return IKS_HOOK; 00122 } 00123 ao2_link(events, event); 00124 event = ast_calendar_unref_event(event); 00125 } else if (!strcasecmp(state->tag, "propstat")) { 00126 state->in_propstat = 0; 00127 } else if (!strcasecmp(state->tag, "prop")) { 00128 state->in_prop = 0; 00129 } 00130 break; 00131 00132 default: 00133 return IKS_OK; 00134 } 00135 00136 return IKS_OK; 00137 }
static int unload_module | ( | void | ) | [static] |
Definition at line 755 of file res_calendar_exchange.c.
References ast_calendar_unregister().
00756 { 00757 ast_calendar_unregister(&exchangecal_tech); 00758 ne_sock_exit(); 00759 return 0; 00760 }
static void * unref_exchangecal | ( | void * | obj | ) | [static] |
Definition at line 233 of file res_calendar_exchange.c.
References ao2_ref.
Referenced by exchangecal_load_calendar().
00234 { 00235 struct exchangecal_pvt *pvt = obj; 00236 00237 ao2_ref(pvt, -1); 00238 return NULL; 00239 }
static int update_exchangecal | ( | struct exchangecal_pvt * | pvt | ) | [static] |
Definition at line 596 of file res_calendar_exchange.c.
References ast_calendar_merge_events(), ast_free, ast_str_buffer(), ast_str_strlen(), ast_tvnow(), exchangecal_pvt::events, exchangecal_get_events_between(), exchangecal_pvt::owner, parse_cdata(), parse_tag(), xmlstate::pvt, and ast_calendar::timeframe.
Referenced by exchangecal_load_calendar().
00597 { 00598 struct xmlstate state; 00599 struct timeval now = ast_tvnow(); 00600 time_t start, end; 00601 struct ast_str *response; 00602 iksparser *p; 00603 00604 state.pvt = pvt; 00605 start = now.tv_sec; 00606 end = now.tv_sec + 60 * pvt->owner->timeframe; 00607 if (!(response = exchangecal_get_events_between(pvt, start, end))) { 00608 return -1; 00609 } 00610 00611 p = iks_sax_new(&state, parse_tag, parse_cdata); 00612 iks_parse(p, ast_str_buffer(response), ast_str_strlen(response), 1); 00613 ast_calendar_merge_events(pvt->owner, pvt->events); 00614 ast_free(response); 00615 00616 return 0; 00617 }
Definition at line 278 of file res_calendar_exchange.c.
References ast_str_append().
Referenced by exchangecal_write_event().
00279 { 00280 const char *tmp; 00281 char buf[7]; 00282 00283 for (tmp = src; *tmp; tmp++) { 00284 switch (*tmp) { 00285 case '\"': 00286 strcpy(buf, """); 00287 break; 00288 00289 case '\'': 00290 strcpy(buf, "'"); 00291 break; 00292 00293 case '&': 00294 strcpy(buf, "&"); 00295 break; 00296 00297 case '<': 00298 strcpy(buf, "<"); 00299 break; 00300 00301 case '>': 00302 strcpy(buf, ">"); 00303 break; 00304 00305 default: 00306 sprintf(buf, "%c", *tmp); 00307 } 00308 00309 ast_str_append(&dst, 0, "%s", buf); 00310 } 00311 00312 return dst; 00313 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Asterisk MS Exchange 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 766 of file res_calendar_exchange.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 766 of file res_calendar_exchange.c.
struct ast_calendar_tech exchangecal_tech [static] |
Definition at line 52 of file res_calendar_exchange.c.