#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 |
Definition in file res_calendar_exchange.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 764 of file res_calendar_exchange.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 764 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 549 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().
00550 { 00551 struct ast_str *body, *response; 00552 char start[80], end[80]; 00553 struct timeval tv = {0,}; 00554 struct ast_tm tm; 00555 00556 tv.tv_sec = start_time; 00557 ast_localtime(&tv, &tm, "UTC"); 00558 ast_strftime(start, sizeof(start), "%Y/%m/%d %T", &tm); 00559 00560 tv.tv_sec = end_time; 00561 ast_localtime(&tv, &tm, "UTC"); 00562 ast_strftime(end, sizeof(end), "%Y/%m/%d %T", &tm); 00563 00564 if (!(body = ast_str_create(512))) { 00565 ast_log(LOG_ERROR, "Could not allocate memory for body of request!\n"); 00566 return NULL; 00567 } 00568 00569 ast_str_append(&body, 0, 00570 "<?xml version=\"1.0\"?>\n" 00571 "<g:searchrequest xmlns:g=\"DAV:\">\n" 00572 " <g:sql> SELECT \"urn:schemas:calendar:location\", \"urn:schemas:httpmail:subject\",\n" 00573 " \"urn:schemas:calendar:dtstart\", \"urn:schemas:calendar:dtend\",\n" 00574 " \"urn:schemas:calendar:busystatus\", \"urn:schemas:calendar:instancetype\",\n" 00575 " \"urn:schemas:calendar:uid\", \"urn:schemas:httpmail:textdescription\",\n" 00576 " \"urn:schemas:calendar:organizer\", \"urn:schemas:calendar:reminderoffset\"\n" 00577 " FROM Scope('SHALLOW TRAVERSAL OF \"%s/Calendar\"')\n" 00578 " WHERE NOT \"urn:schemas:calendar:instancetype\" = 1\n" 00579 " AND \"DAV:contentclass\" = 'urn:content-classes:appointment'\n" 00580 " AND NOT (\"urn:schemas:calendar:dtend\" < '%s'\n" 00581 " OR \"urn:schemas:calendar:dtstart\" > '%s')\n" 00582 " ORDER BY \"urn:schemas:calendar:dtstart\" ASC\n" 00583 " </g:sql>\n" 00584 "</g:searchrequest>\n", pvt->url, start, end); 00585 00586 ast_debug(5, "Request:\n%s\n", ast_str_buffer(body)); 00587 response = exchangecal_request(pvt, "SEARCH", body, NULL); 00588 ast_debug(5, "Response:\n%s\n", ast_str_buffer(response)); 00589 ast_free(body); 00590 00591 return response; 00592 }
static void * exchangecal_load_calendar | ( | void * | data | ) | [static] |
Definition at line 617 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.
00618 { 00619 struct exchangecal_pvt *pvt; 00620 const struct ast_config *cfg; 00621 struct ast_variable *v; 00622 struct ast_calendar *cal = void_data; 00623 ast_mutex_t refreshlock; 00624 00625 if (!(cal && (cfg = ast_calendar_config_acquire()))) { 00626 ast_log(LOG_ERROR, "You must enable calendar support for res_exchangecal to load\n"); 00627 return NULL; 00628 } 00629 00630 if (ao2_trylock(cal)) { 00631 if (cal->unloading) { 00632 ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n"); 00633 } else { 00634 ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n"); 00635 } 00636 ast_calendar_config_release(); 00637 return NULL; 00638 } 00639 00640 if (!(pvt = ao2_alloc(sizeof(*pvt), exchangecal_destructor))) { 00641 ast_log(LOG_ERROR, "Could not allocate exchangecal_pvt structure for calendar: %s\n", cal->name); 00642 ast_calendar_config_release(); 00643 return NULL; 00644 } 00645 00646 pvt->owner = cal; 00647 00648 if (!(pvt->events = ast_calendar_event_container_alloc())) { 00649 ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name); 00650 pvt = unref_exchangecal(pvt); 00651 ao2_unlock(cal); 00652 ast_calendar_config_release(); 00653 return NULL; 00654 } 00655 00656 if (ast_string_field_init(pvt, 32)) { 00657 ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name); 00658 pvt = unref_exchangecal(pvt); 00659 ao2_unlock(cal); 00660 ast_calendar_config_release(); 00661 return NULL; 00662 } 00663 00664 for (v = ast_variable_browse(cfg, cal->name); v; v = v->next) { 00665 if (!strcasecmp(v->name, "url")) { 00666 ast_string_field_set(pvt, url, v->value); 00667 } else if (!strcasecmp(v->name, "user")) { 00668 ast_string_field_set(pvt, user, v->value); 00669 } else if (!strcasecmp(v->name, "secret")) { 00670 ast_string_field_set(pvt, secret, v->value); 00671 } 00672 } 00673 00674 ast_calendar_config_release(); 00675 00676 if (ast_strlen_zero(pvt->url)) { 00677 ast_log(LOG_WARNING, "No URL was specified for Exchange calendar '%s' - skipping.\n", cal->name); 00678 pvt = unref_exchangecal(pvt); 00679 ao2_unlock(cal); 00680 return NULL; 00681 } 00682 00683 if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) { 00684 ast_log(LOG_WARNING, "Could not parse url '%s' for Exchange calendar '%s' - skipping.\n", pvt->url, cal->name); 00685 pvt = unref_exchangecal(pvt); 00686 ao2_unlock(cal); 00687 return NULL; 00688 } 00689 00690 if (pvt->uri.scheme == NULL) { 00691 pvt->uri.scheme = "http"; 00692 } 00693 00694 if (pvt->uri.port == 0) { 00695 pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme); 00696 } 00697 00698 pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port); 00699 ne_redirect_register(pvt->session); 00700 ne_set_server_auth(pvt->session, auth_credentials, pvt); 00701 if (!strcasecmp(pvt->uri.scheme, "https")) { 00702 ne_ssl_trust_default_ca(pvt->session); 00703 } 00704 00705 cal->tech_pvt = pvt; 00706 00707 ast_mutex_init(&refreshlock); 00708 00709 /* Load it the first time */ 00710 update_exchangecal(pvt); 00711 00712 ao2_unlock(cal); 00713 00714 /* The only writing from another thread will be if unload is true */ 00715 for (;;) { 00716 struct timeval tv = ast_tvnow(); 00717 struct timespec ts = {0,}; 00718 00719 ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh); 00720 00721 ast_mutex_lock(&refreshlock); 00722 while (!pvt->owner->unloading) { 00723 if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) { 00724 break; 00725 } 00726 } 00727 ast_mutex_unlock(&refreshlock); 00728 00729 if (pvt->owner->unloading) { 00730 ast_debug(10, "Skipping refresh since we got a shutdown signal\n"); 00731 return NULL; 00732 } 00733 00734 ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh); 00735 00736 update_exchangecal(pvt); 00737 } 00738 00739 return NULL; 00740 }
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 ast_log(LOG_ERROR, "Could not allocate memory for request!\n"); 00438 goto write_cleanup; 00439 } 00440 00441 if (!(uid = ast_str_create(32)) || 00442 !(summary = ast_str_create(32)) || 00443 !(description = ast_str_create(32)) || 00444 !(organizer = ast_str_create(32)) || 00445 !(location = ast_str_create(32)) || 00446 !(start = ast_str_create(32)) || 00447 !(end = ast_str_create(32)) || 00448 !(busystate = ast_str_create(32))) { 00449 ast_log(LOG_ERROR, "Unable to allocate memory for request values\n"); 00450 goto write_cleanup; 00451 } 00452 00453 if (ast_strlen_zero(event->uid)) { 00454 uid = generate_exchange_uuid(uid); 00455 } else { 00456 ast_str_set(&uid, 36, "%s", event->uid); 00457 } 00458 00459 if (!is_valid_uuid(uid)) { 00460 ast_log(LOG_WARNING, "An invalid uid was provided, you may leave this field blank to have one generated for you\n"); 00461 goto write_cleanup; 00462 } 00463 00464 summary = xml_encode_str(summary, event->summary); 00465 description = xml_encode_str(description, event->description); 00466 organizer = xml_encode_str(organizer, event->organizer); 00467 location = xml_encode_str(location, event->location); 00468 start = epoch_to_exchange_time(start, event->start); 00469 end = epoch_to_exchange_time(end, event->end); 00470 busystate = bs_to_exchange_bs(busystate, event->busy_state); 00471 00472 ast_str_append(&body, 0, 00473 "<?xml version=\"1.0\"?>\n" 00474 "<a:propertyupdate\n" 00475 " xmlns:a=\"DAV:\"\n" 00476 " xmlns:e=\"http://schemas.microsoft.com/exchange/\"\n" 00477 " xmlns:mapi=\"http://schemas.microsoft.com/mapi/\"\n" 00478 " xmlns:mapit=\"http://schemas.microsoft.com/mapi/proptag/\"\n" 00479 " xmlns:x=\"xml:\" xmlns:cal=\"urn:schemas:calendar:\"\n" 00480 " xmlns:dt=\"uuid:%s/\"\n" /* uid */ 00481 " xmlns:header=\"urn:schemas:mailheader:\"\n" 00482 " xmlns:mail=\"urn:schemas:httpmail:\"\n" 00483 ">\n" 00484 " <a:set>\n" 00485 " <a:prop>\n" 00486 " <a:contentclass>urn:content-classes:appointment</a:contentclass>\n" 00487 " <e:outlookmessageclass>IPM.Appointment</e:outlookmessageclass>\n" 00488 " <mail:subject>%s</mail:subject>\n" /* summary */ 00489 " <mail:description>%s</mail:description>\n" /* description */ 00490 " <header:to>%s</header:to>\n" /* organizer */ 00491 " <cal:location>%s</cal:location>\n" /* location */ 00492 " <cal:dtstart dt:dt=\"dateTime.tz\">%s</cal:dtstart>\n" /* start */ 00493 " <cal:dtend dt:dt=\"dateTime.tz\">%s</cal:dtend>\n" /* end */ 00494 " <cal:instancetype dt:dt=\"int\">0</cal:instancetype>\n" 00495 " <cal:busystatus>%s</cal:busystatus>\n" /* busy_state (BUSY, FREE, BUSY_TENTATIVE) */ 00496 " <cal:meetingstatus>CONFIRMED</cal:meetingstatus>\n" 00497 " <cal:alldayevent dt:dt=\"boolean\">0</cal:alldayevent>\n" /* XXX need to add event support for all day events */ 00498 " <cal:responserequested dt:dt=\"boolean\">0</cal:responserequested>\n" 00499 " <mapi:finvited dt:dt=\"boolean\">1</mapi:finvited>\n" 00500 " </a:prop>\n" 00501 " </a:set>\n" 00502 "</a:propertyupdate>\n", 00503 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)); 00504 ast_verb(0, "\n\n%s\n\n", ast_str_buffer(body)); 00505 ast_str_set(&subdir, 0, "/Calendar/%s.eml", ast_str_buffer(uid)); 00506 00507 response = exchangecal_request(event->owner->tech_pvt, "PROPPATCH", body, subdir); 00508 00509 ret = 0; 00510 write_cleanup: 00511 if (uid) { 00512 ast_free(uid); 00513 } 00514 if (summary) { 00515 ast_free(summary); 00516 } 00517 if (description) { 00518 ast_free(description); 00519 } 00520 if (organizer) { 00521 ast_free(organizer); 00522 } 00523 if (location) { 00524 ast_free(location); 00525 } 00526 if (start) { 00527 ast_free(start); 00528 } 00529 if (end) { 00530 ast_free(end); 00531 } 00532 if (busystate) { 00533 ast_free(busystate); 00534 } 00535 if (body) { 00536 ast_free(body); 00537 } 00538 if (response) { 00539 ast_free(response); 00540 } 00541 if (subdir) { 00542 ast_free(subdir); 00543 } 00544 00545 return ret; 00546 }
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 742 of file res_calendar_exchange.c.
References ast_calendar_register(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and exchangecal_tech.
00743 { 00744 ne_sock_init(); 00745 if (ast_calendar_register(&exchangecal_tech)) { 00746 ne_sock_exit(); 00747 return AST_MODULE_LOAD_DECLINE; 00748 } 00749 00750 return AST_MODULE_LOAD_SUCCESS; 00751 }
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 753 of file res_calendar_exchange.c.
References ast_calendar_unregister(), and exchangecal_tech.
00754 { 00755 ast_calendar_unregister(&exchangecal_tech); 00756 ne_sock_exit(); 00757 return 0; 00758 }
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 594 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().
00595 { 00596 struct xmlstate state; 00597 struct timeval now = ast_tvnow(); 00598 time_t start, end; 00599 struct ast_str *response; 00600 iksparser *p; 00601 00602 state.pvt = pvt; 00603 start = now.tv_sec; 00604 end = now.tv_sec + 60 * pvt->owner->timeframe; 00605 if (!(response = exchangecal_get_events_between(pvt, start, end))) { 00606 return -1; 00607 } 00608 00609 p = iks_sax_new(&state, parse_tag, parse_cdata); 00610 iks_parse(p, ast_str_buffer(response), ast_str_strlen(response), 1); 00611 ast_calendar_merge_events(pvt->owner, pvt->events); 00612 ast_free(response); 00613 00614 return 0; 00615 }
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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEVSTATE_PLUGIN, } [static] |
Definition at line 764 of file res_calendar_exchange.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 764 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().