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