#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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_calendar_tech | exchangecal_tech |
Definition in file res_calendar_exchange.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 765 of file res_calendar_exchange.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 765 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 368 of file res_calendar_exchange.c.
References ast_log(), LOG_WARNING, ast_calendar::name, exchangecal_pvt::owner, exchangecal_pvt::secret, and exchangecal_pvt::user.
00369 { 00370 struct exchangecal_pvt *pvt = userdata; 00371 00372 if (attempts > 1) { 00373 ast_log(LOG_WARNING, "Invalid username or password for Exchange calendar '%s'\n", pvt->owner->name); 00374 return -1; 00375 } 00376 00377 ne_strnzcpy(username, pvt->user, NE_ABUFSIZ); 00378 ne_strnzcpy(secret, pvt->secret, NE_ABUFSIZ); 00379 00380 return 0; 00381 }
static struct ast_str* bs_to_exchange_bs | ( | struct ast_str * | dst, | |
enum ast_calendar_busy_state | bs | |||
) | [static] |
Definition at line 334 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().
00335 { 00336 switch (bs) { 00337 case AST_CALENDAR_BS_BUSY: 00338 ast_str_set(&dst, 0, "%s", "BUSY"); 00339 break; 00340 00341 case AST_CALENDAR_BS_BUSY_TENTATIVE: 00342 ast_str_set(&dst, 0, "%s", "TENTATIVE"); 00343 break; 00344 00345 default: 00346 ast_str_set(&dst, 0, "%s", "FREE"); 00347 } 00348 00349 return dst; 00350 }
Definition at line 313 of file res_calendar_exchange.c.
References ast_copy_string(), and ast_str_append().
Referenced by exchangecal_write_event().
00314 { 00315 icaltimezone *utc = icaltimezone_get_utc_timezone(); 00316 icaltimetype tt = icaltime_from_timet_with_zone(epoch, 0, utc); 00317 char tmp[30]; 00318 int i; 00319 00320 ast_copy_string(tmp, icaltime_as_ical_string(tt), sizeof(tmp)); 00321 for (i = 0; tmp[i]; i++) { 00322 ast_str_append(&dst, 0, "%c", tmp[i]); 00323 if (i == 3 || i == 5) 00324 ast_str_append(&dst, 0, "%c", '-'); 00325 if (i == 10 || i == 12) 00326 ast_str_append(&dst, 0, "%c", ':'); 00327 if (i == 14) 00328 ast_str_append(&dst, 0, "%s", ".000"); 00329 } 00330 00331 return dst; 00332 }
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, ast_calendar::name, 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] |
Definition at line 550 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().
00551 { 00552 struct ast_str *body, *response; 00553 char start[80], end[80]; 00554 struct timeval tv = {0,}; 00555 struct ast_tm tm; 00556 00557 tv.tv_sec = start_time; 00558 ast_localtime(&tv, &tm, "UTC"); 00559 ast_strftime(start, sizeof(start), "%Y/%m/%d %T", &tm); 00560 00561 tv.tv_sec = end_time; 00562 ast_localtime(&tv, &tm, "UTC"); 00563 ast_strftime(end, sizeof(end), "%Y/%m/%d %T", &tm); 00564 00565 if (!(body = ast_str_create(512))) { 00566 ast_log(LOG_ERROR, "Could not allocate memory for body of request!\n"); 00567 return NULL; 00568 } 00569 00570 ast_str_append(&body, 0, 00571 "<?xml version=\"1.0\"?>\n" 00572 "<g:searchrequest xmlns:g=\"DAV:\">\n" 00573 " <g:sql> SELECT \"urn:schemas:calendar:location\", \"urn:schemas:httpmail:subject\",\n" 00574 " \"urn:schemas:calendar:dtstart\", \"urn:schemas:calendar:dtend\",\n" 00575 " \"urn:schemas:calendar:busystatus\", \"urn:schemas:calendar:instancetype\",\n" 00576 " \"urn:schemas:calendar:uid\", \"urn:schemas:httpmail:textdescription\",\n" 00577 " \"urn:schemas:calendar:organizer\", \"urn:schemas:calendar:reminderoffset\"\n" 00578 " FROM Scope('SHALLOW TRAVERSAL OF \"%s/Calendar\"')\n" 00579 " WHERE NOT \"urn:schemas:calendar:instancetype\" = 1\n" 00580 " AND \"DAV:contentclass\" = 'urn:content-classes:appointment'\n" 00581 " AND NOT (\"urn:schemas:calendar:dtend\" < '%s'\n" 00582 " OR \"urn:schemas:calendar:dtstart\" > '%s')\n" 00583 " ORDER BY \"urn:schemas:calendar:dtstart\" ASC\n" 00584 " </g:sql>\n" 00585 "</g:searchrequest>\n", pvt->url, start, end); 00586 00587 ast_debug(5, "Request:\n%s\n", ast_str_buffer(body)); 00588 response = exchangecal_request(pvt, "SEARCH", body, NULL); 00589 ast_debug(5, "Response:\n%s\n", ast_str_buffer(response)); 00590 ast_free(body); 00591 00592 return response; 00593 }
static void * exchangecal_load_calendar | ( | void * | data | ) | [static] |
Definition at line 618 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.
00619 { 00620 struct exchangecal_pvt *pvt; 00621 const struct ast_config *cfg; 00622 struct ast_variable *v; 00623 struct ast_calendar *cal = void_data; 00624 ast_mutex_t refreshlock; 00625 00626 if (!(cal && (cfg = ast_calendar_config_acquire()))) { 00627 ast_log(LOG_ERROR, "You must enable calendar support for res_exchangecal to load\n"); 00628 return NULL; 00629 } 00630 00631 if (ao2_trylock(cal)) { 00632 if (cal->unloading) { 00633 ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n"); 00634 } else { 00635 ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n"); 00636 } 00637 ast_calendar_config_release(); 00638 return NULL; 00639 } 00640 00641 if (!(pvt = ao2_alloc(sizeof(*pvt), exchangecal_destructor))) { 00642 ast_log(LOG_ERROR, "Could not allocate exchangecal_pvt structure for calendar: %s\n", cal->name); 00643 ast_calendar_config_release(); 00644 return NULL; 00645 } 00646 00647 pvt->owner = cal; 00648 00649 if (!(pvt->events = ast_calendar_event_container_alloc())) { 00650 ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name); 00651 pvt = unref_exchangecal(pvt); 00652 ao2_unlock(cal); 00653 ast_calendar_config_release(); 00654 return NULL; 00655 } 00656 00657 if (ast_string_field_init(pvt, 32)) { 00658 ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name); 00659 pvt = unref_exchangecal(pvt); 00660 ao2_unlock(cal); 00661 ast_calendar_config_release(); 00662 return NULL; 00663 } 00664 00665 for (v = ast_variable_browse(cfg, cal->name); v; v = v->next) { 00666 if (!strcasecmp(v->name, "url")) { 00667 ast_string_field_set(pvt, url, v->value); 00668 } else if (!strcasecmp(v->name, "user")) { 00669 ast_string_field_set(pvt, user, v->value); 00670 } else if (!strcasecmp(v->name, "secret")) { 00671 ast_string_field_set(pvt, secret, v->value); 00672 } 00673 } 00674 00675 ast_calendar_config_release(); 00676 00677 if (ast_strlen_zero(pvt->url)) { 00678 ast_log(LOG_WARNING, "No URL was specified for Exchange calendar '%s' - skipping.\n", cal->name); 00679 pvt = unref_exchangecal(pvt); 00680 ao2_unlock(cal); 00681 return NULL; 00682 } 00683 00684 if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) { 00685 ast_log(LOG_WARNING, "Could not parse url '%s' for Exchange calendar '%s' - skipping.\n", pvt->url, cal->name); 00686 pvt = unref_exchangecal(pvt); 00687 ao2_unlock(cal); 00688 return NULL; 00689 } 00690 00691 if (pvt->uri.scheme == NULL) { 00692 pvt->uri.scheme = "http"; 00693 } 00694 00695 if (pvt->uri.port == 0) { 00696 pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme); 00697 } 00698 00699 pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port); 00700 ne_redirect_register(pvt->session); 00701 ne_set_server_auth(pvt->session, auth_credentials, pvt); 00702 if (!strcasecmp(pvt->uri.scheme, "https")) { 00703 ne_ssl_trust_default_ca(pvt->session); 00704 } 00705 00706 cal->tech_pvt = pvt; 00707 00708 ast_mutex_init(&refreshlock); 00709 00710 /* Load it the first time */ 00711 update_exchangecal(pvt); 00712 00713 ao2_unlock(cal); 00714 00715 /* The only writing from another thread will be if unload is true */ 00716 for (;;) { 00717 struct timeval tv = ast_tvnow(); 00718 struct timespec ts = {0,}; 00719 00720 ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh); 00721 00722 ast_mutex_lock(&refreshlock); 00723 while (!pvt->owner->unloading) { 00724 if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) { 00725 break; 00726 } 00727 } 00728 ast_mutex_unlock(&refreshlock); 00729 00730 if (pvt->owner->unloading) { 00731 ast_debug(10, "Skipping refresh since we got a shutdown signal\n"); 00732 return NULL; 00733 } 00734 00735 ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh); 00736 00737 update_exchangecal(pvt); 00738 } 00739 00740 return NULL; 00741 }
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 383 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().
00384 { 00385 struct ast_str *response; 00386 ne_request *req; 00387 int ret; 00388 char buf[1000]; 00389 00390 if (!pvt) { 00391 ast_log(LOG_ERROR, "There is no private!\n"); 00392 return NULL; 00393 } 00394 00395 if (!(response = ast_str_create(512))) { 00396 ast_log(LOG_ERROR, "Could not allocate memory for response.\n"); 00397 return NULL; 00398 } 00399 00400 snprintf(buf, sizeof(buf), "%s%s", pvt->uri.path, subdir ? ast_str_buffer(subdir) : ""); 00401 00402 req = ne_request_create(pvt->session, method, buf); 00403 ne_add_response_body_reader(req, ne_accept_2xx, fetch_response_reader, &response); 00404 ne_set_request_body_buffer(req, ast_str_buffer(req_body), ast_str_strlen(req_body)); 00405 ne_add_request_header(req, "Content-type", "text/xml"); 00406 00407 ret = ne_request_dispatch(req); 00408 ne_request_destroy(req); 00409 00410 if (ret != NE_OK || !ast_str_strlen(response)) { 00411 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)); 00412 ast_free(response); 00413 return NULL; 00414 } 00415 00416 return response; 00417 }
static int exchangecal_write_event | ( | struct ast_calendar_event * | event | ) | [static] |
Definition at line 419 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().
00420 { 00421 struct ast_str *body = NULL, *response = NULL, *subdir = NULL; 00422 struct ast_str *uid = NULL, *summary = NULL, *description = NULL, *organizer = NULL, 00423 *location = NULL, *start = NULL, *end = NULL, *busystate = NULL; 00424 int ret = -1; 00425 00426 if (!event) { 00427 ast_log(LOG_WARNING, "No event passed!\n"); 00428 return -1; 00429 } 00430 00431 if (!(event->start && event->end)) { 00432 ast_log(LOG_WARNING, "The event must contain a start and an end\n"); 00433 return -1; 00434 } 00435 if (!(body = ast_str_create(512)) || 00436 !(subdir = ast_str_create(32)) || 00437 !(response = ast_str_create(512))) { 00438 ast_log(LOG_ERROR, "Could not allocate memory for request and response!\n"); 00439 goto write_cleanup; 00440 } 00441 00442 if (!(uid = ast_str_create(32)) || 00443 !(summary = ast_str_create(32)) || 00444 !(description = ast_str_create(32)) || 00445 !(organizer = ast_str_create(32)) || 00446 !(location = ast_str_create(32)) || 00447 !(start = ast_str_create(32)) || 00448 !(end = ast_str_create(32)) || 00449 !(busystate = ast_str_create(32))) { 00450 ast_log(LOG_ERROR, "Unable to allocate memory for request values\n"); 00451 goto write_cleanup; 00452 } 00453 00454 if (ast_strlen_zero(event->uid)) { 00455 uid = generate_exchange_uuid(uid); 00456 } else { 00457 ast_str_set(&uid, 36, "%s", event->uid); 00458 } 00459 00460 if (!is_valid_uuid(uid)) { 00461 ast_log(LOG_WARNING, "An invalid uid was provided, you may leave this field blank to have one generated for you\n"); 00462 goto write_cleanup; 00463 } 00464 00465 summary = xml_encode_str(summary, event->summary); 00466 description = xml_encode_str(description, event->description); 00467 organizer = xml_encode_str(organizer, event->organizer); 00468 location = xml_encode_str(location, event->location); 00469 start = epoch_to_exchange_time(start, event->start); 00470 end = epoch_to_exchange_time(end, event->end); 00471 busystate = bs_to_exchange_bs(busystate, event->busy_state); 00472 00473 ast_str_append(&body, 0, 00474 "<?xml version=\"1.0\"?>\n" 00475 "<a:propertyupdate\n" 00476 " xmlns:a=\"DAV:\"\n" 00477 " xmlns:e=\"http://schemas.microsoft.com/exchange/\"\n" 00478 " xmlns:mapi=\"http://schemas.microsoft.com/mapi/\"\n" 00479 " xmlns:mapit=\"http://schemas.microsoft.com/mapi/proptag/\"\n" 00480 " xmlns:x=\"xml:\" xmlns:cal=\"urn:schemas:calendar:\"\n" 00481 " xmlns:dt=\"uuid:%s/\"\n" /* uid */ 00482 " xmlns:header=\"urn:schemas:mailheader:\"\n" 00483 " xmlns:mail=\"urn:schemas:httpmail:\"\n" 00484 ">\n" 00485 " <a:set>\n" 00486 " <a:prop>\n" 00487 " <a:contentclass>urn:content-classes:appointment</a:contentclass>\n" 00488 " <e:outlookmessageclass>IPM.Appointment</e:outlookmessageclass>\n" 00489 " <mail:subject>%s</mail:subject>\n" /* summary */ 00490 " <mail:description>%s</mail:description>\n" /* description */ 00491 " <header:to>%s</header:to>\n" /* organizer */ 00492 " <cal:location>%s</cal:location>\n" /* location */ 00493 " <cal:dtstart dt:dt=\"dateTime.tz\">%s</cal:dtstart>\n" /* start */ 00494 " <cal:dtend dt:dt=\"dateTime.tz\">%s</cal:dtend>\n" /* end */ 00495 " <cal:instancetype dt:dt=\"int\">0</cal:instancetype>\n" 00496 " <cal:busystatus>%s</cal:busystatus>\n" /* busy_state (BUSY, FREE, BUSY_TENTATIVE) */ 00497 " <cal:meetingstatus>CONFIRMED</cal:meetingstatus>\n" 00498 " <cal:alldayevent dt:dt=\"boolean\">0</cal:alldayevent>\n" /* XXX need to add event support for all day events */ 00499 " <cal:responserequested dt:dt=\"boolean\">0</cal:responserequested>\n" 00500 " <mapi:finvited dt:dt=\"boolean\">1</mapi:finvited>\n" 00501 " </a:prop>\n" 00502 " </a:set>\n" 00503 "</a:propertyupdate>\n", 00504 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)); 00505 ast_verb(0, "\n\n%s\n\n", ast_str_buffer(body)); 00506 ast_str_set(&subdir, 0, "/Calendar/%s.eml", ast_str_buffer(uid)); 00507 00508 response = exchangecal_request(event->owner->tech_pvt, "PROPPATCH", body, subdir); 00509 00510 ret = 0; 00511 write_cleanup: 00512 if (uid) { 00513 ast_free(uid); 00514 } 00515 if (summary) { 00516 ast_free(summary); 00517 } 00518 if (description) { 00519 ast_free(description); 00520 } 00521 if (organizer) { 00522 ast_free(organizer); 00523 } 00524 if (location) { 00525 ast_free(location); 00526 } 00527 if (start) { 00528 ast_free(start); 00529 } 00530 if (end) { 00531 ast_free(end); 00532 } 00533 if (busystate) { 00534 ast_free(busystate); 00535 } 00536 if (body) { 00537 ast_free(body); 00538 } 00539 if (response) { 00540 ast_free(response); 00541 } 00542 if (subdir) { 00543 ast_free(subdir); 00544 } 00545 00546 return ret; 00547 }
static int fetch_response_reader | ( | void * | data, | |
const char * | block, | |||
size_t | len | |||
) | [static] |
Definition at line 352 of file res_calendar_exchange.c.
References ast_free, ast_malloc, and ast_str_append().
00353 { 00354 struct ast_str **response = data; 00355 unsigned char *tmp; 00356 00357 if (!(tmp = ast_malloc(len + 1))) { 00358 return -1; 00359 } 00360 memcpy(tmp, block, len); 00361 tmp[len] = '\0'; 00362 ast_str_append(response, 0, "%s", tmp); 00363 ast_free(tmp); 00364 00365 return 0; 00366 }
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", val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]); 00251 00252 return uid; 00253 }
static int is_valid_uuid | ( | struct ast_str * | uid | ) | [static] |
Definition at line 255 of file res_calendar_exchange.c.
References ast_str_buffer(), and ast_str_strlen().
Referenced by exchangecal_write_event().
00256 { 00257 int i; 00258 00259 if (ast_str_strlen(uid) != 36) { 00260 return 0; 00261 } 00262 00263 for (i = 0; i < ast_str_strlen(uid); i++) { 00264 if (i == 8 || i == 13 || i == 18 || i == 23) { 00265 if (ast_str_buffer(uid)[i] != '-') { 00266 return 0; 00267 } 00268 } 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))) { 00269 return 0; 00270 } 00271 } 00272 00273 return 1; 00274 }
static int load_module | ( | void | ) | [static] |
Definition at line 743 of file res_calendar_exchange.c.
References ast_calendar_register(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and exchangecal_tech.
00744 { 00745 ne_sock_init(); 00746 if (ast_calendar_register(&exchangecal_tech)) { 00747 ne_sock_exit(); 00748 return AST_MODULE_LOAD_DECLINE; 00749 } 00750 00751 return AST_MODULE_LOAD_SUCCESS; 00752 }
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.
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_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().
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(), events, LOG_ERROR, state, and ast_calendar_event::uid.
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 754 of file res_calendar_exchange.c.
References ast_calendar_unregister(), and exchangecal_tech.
00755 { 00756 ast_calendar_unregister(&exchangecal_tech); 00757 ne_sock_exit(); 00758 return 0; 00759 }
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 595 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().
00596 { 00597 struct xmlstate state; 00598 struct timeval now = ast_tvnow(); 00599 time_t start, end; 00600 struct ast_str *response; 00601 iksparser *p; 00602 00603 state.pvt = pvt; 00604 start = now.tv_sec; 00605 end = now.tv_sec + 60 * pvt->owner->timeframe; 00606 if (!(response = exchangecal_get_events_between(pvt, start, end))) { 00607 return -1; 00608 } 00609 00610 p = iks_sax_new(&state, parse_tag, parse_cdata); 00611 iks_parse(p, ast_str_buffer(response), ast_str_strlen(response), 1); 00612 ast_calendar_merge_events(pvt->owner, pvt->events); 00613 ast_free(response); 00614 00615 return 0; 00616 }
Definition at line 276 of file res_calendar_exchange.c.
References ast_str_append().
Referenced by exchangecal_write_event().
00277 { 00278 const char *tmp; 00279 char buf[7]; 00280 00281 for (tmp = src; *tmp; tmp++) { 00282 switch (*tmp) { 00283 case '\"': 00284 strcpy(buf, """); 00285 break; 00286 00287 case '\'': 00288 strcpy(buf, "'"); 00289 break; 00290 00291 case '&': 00292 strcpy(buf, "&"); 00293 break; 00294 00295 case '<': 00296 strcpy(buf, "<"); 00297 break; 00298 00299 case '>': 00300 strcpy(buf, ">"); 00301 break; 00302 00303 default: 00304 sprintf(buf, "%c", *tmp); 00305 } 00306 00307 ast_str_append(&dst, 0, "%s", buf); 00308 } 00309 00310 return dst; 00311 }
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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, } [static] |
Definition at line 765 of file res_calendar_exchange.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 765 of file res_calendar_exchange.c.
struct ast_calendar_tech exchangecal_tech [static] |
Definition at line 52 of file res_calendar_exchange.c.
Referenced by load_module(), and unload_module().