#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 "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 | icalendar_pvt |
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 icalcomponent * | fetch_icalendar (struct icalendar_pvt *pvt) |
static int | fetch_response_reader (void *data, const char *block, size_t len) |
static void * | ical_load_calendar (void *data) |
static void | icalendar_add_event (icalcomponent *comp, struct icaltime_span *span, void *data) |
static void | icalendar_destructor (void *obj) |
static void | icalendar_update_events (struct icalendar_pvt *pvt) |
static time_t | icalfloat_to_timet (icaltimetype time) |
static int | load_module (void) |
static int | unload_module (void) |
static void * | unref_icalendar (void *obj) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Asterisk iCalendar .ics file 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 | ical_tech |
Definition in file res_calendar_icalendar.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 499 of file res_calendar_icalendar.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 499 of file res_calendar_icalendar.c.
static int auth_credentials | ( | void * | userdata, | |
const char * | realm, | |||
int | attempts, | |||
char * | username, | |||
char * | secret | |||
) | [static] |
Definition at line 110 of file res_calendar_icalendar.c.
References ast_log(), LOG_WARNING, ast_calendar::name, icalendar_pvt::owner, icalendar_pvt::secret, and icalendar_pvt::user.
00111 { 00112 struct icalendar_pvt *pvt = userdata; 00113 00114 if (attempts > 1) { 00115 ast_log(LOG_WARNING, "Invalid username or password for iCalendar '%s'\n", pvt->owner->name); 00116 return -1; 00117 } 00118 00119 ne_strnzcpy(username, pvt->user, NE_ABUFSIZ); 00120 ne_strnzcpy(secret, pvt->secret, NE_ABUFSIZ); 00121 00122 return 0; 00123 }
static icalcomponent* fetch_icalendar | ( | struct icalendar_pvt * | pvt | ) | [static] |
Definition at line 125 of file res_calendar_icalendar.c.
References ast_free, ast_log(), ast_str_buffer(), ast_str_create(), ast_str_strlen(), ast_strlen_zero(), fetch_response_reader(), LOG_ERROR, LOG_WARNING, ast_calendar::name, icalendar_pvt::owner, icalendar_pvt::session, icalendar_pvt::uri, and icalendar_pvt::url.
Referenced by ical_load_calendar().
00126 { 00127 int ret; 00128 struct ast_str *response; 00129 ne_request *req; 00130 icalcomponent *comp = NULL; 00131 00132 if (!pvt) { 00133 ast_log(LOG_ERROR, "There is no private!\n"); 00134 } 00135 00136 if (!(response = ast_str_create(512))) { 00137 ast_log(LOG_ERROR, "Could not allocate memory for response.\n"); 00138 return NULL; 00139 } 00140 00141 req = ne_request_create(pvt->session, "GET", pvt->uri.path); 00142 ne_add_response_body_reader(req, ne_accept_2xx, fetch_response_reader, &response); 00143 00144 ret = ne_request_dispatch(req); 00145 ne_request_destroy(req); 00146 if (ret != NE_OK || !ast_str_strlen(response)) { 00147 ast_log(LOG_WARNING, "Unable to retrieve iCalendar '%s' from '%s': %s\n", pvt->owner->name, pvt->url, ne_get_error(pvt->session)); 00148 ast_free(response); 00149 return NULL; 00150 } 00151 00152 if (!ast_strlen_zero(ast_str_buffer(response))) { 00153 comp = icalparser_parse_string(ast_str_buffer(response)); 00154 } 00155 ast_free(response); 00156 00157 return comp; 00158 }
static int fetch_response_reader | ( | void * | data, | |
const char * | block, | |||
size_t | len | |||
) | [static] |
Definition at line 94 of file res_calendar_icalendar.c.
References ast_free, ast_malloc, and ast_str_append().
00095 { 00096 struct ast_str **response = data; 00097 unsigned char *tmp; 00098 00099 if (!(tmp = ast_malloc(len + 1))) { 00100 return -1; 00101 } 00102 memcpy(tmp, block, len); 00103 tmp[len] = '\0'; 00104 ast_str_append(response, 0, "%s", tmp); 00105 ast_free(tmp); 00106 00107 return 0; 00108 }
static void * ical_load_calendar | ( | void * | data | ) | [static] |
Definition at line 344 of file res_calendar_icalendar.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(), fetch_icalendar(), icalendar_destructor(), icalendar_update_events(), LOG_ERROR, LOG_WARNING, ast_variable::name, ast_calendar::name, ast_variable::next, refreshlock, secret, ast_calendar::tech_pvt, tv, ast_calendar::unloading, unref_icalendar(), url, and ast_variable::value.
00345 { 00346 struct icalendar_pvt *pvt; 00347 const struct ast_config *cfg; 00348 struct ast_variable *v; 00349 struct ast_calendar *cal = void_data; 00350 ast_mutex_t refreshlock; 00351 00352 if (!(cal && (cfg = ast_calendar_config_acquire()))) { 00353 ast_log(LOG_ERROR, "You must enable calendar support for res_icalendar to load\n"); 00354 return NULL; 00355 } 00356 if (ao2_trylock(cal)) { 00357 if (cal->unloading) { 00358 ast_log(LOG_WARNING, "Unloading module, load_calendar cancelled.\n"); 00359 } else { 00360 ast_log(LOG_WARNING, "Could not lock calendar, aborting!\n"); 00361 } 00362 ast_calendar_config_release(); 00363 return NULL; 00364 } 00365 00366 if (!(pvt = ao2_alloc(sizeof(*pvt), icalendar_destructor))) { 00367 ast_log(LOG_ERROR, "Could not allocate icalendar_pvt structure for calendar: %s\n", cal->name); 00368 ast_calendar_config_release(); 00369 return NULL; 00370 } 00371 00372 pvt->owner = cal; 00373 00374 if (!(pvt->events = ast_calendar_event_container_alloc())) { 00375 ast_log(LOG_ERROR, "Could not allocate space for fetching events for calendar: %s\n", cal->name); 00376 pvt = unref_icalendar(pvt); 00377 ao2_unlock(cal); 00378 ast_calendar_config_release(); 00379 return NULL; 00380 } 00381 00382 if (ast_string_field_init(pvt, 32)) { 00383 ast_log(LOG_ERROR, "Couldn't allocate string field space for calendar: %s\n", cal->name); 00384 pvt = unref_icalendar(pvt); 00385 ao2_unlock(cal); 00386 ast_calendar_config_release(); 00387 return NULL; 00388 } 00389 00390 for (v = ast_variable_browse(cfg, cal->name); v; v = v->next) { 00391 if (!strcasecmp(v->name, "url")) { 00392 ast_string_field_set(pvt, url, v->value); 00393 } else if (!strcasecmp(v->name, "user")) { 00394 ast_string_field_set(pvt, user, v->value); 00395 } else if (!strcasecmp(v->name, "secret")) { 00396 ast_string_field_set(pvt, secret, v->value); 00397 } 00398 } 00399 00400 ast_calendar_config_release(); 00401 00402 if (ast_strlen_zero(pvt->url)) { 00403 ast_log(LOG_WARNING, "No URL was specified for iCalendar '%s' - skipping.\n", cal->name); 00404 pvt = unref_icalendar(pvt); 00405 ao2_unlock(cal); 00406 return NULL; 00407 } 00408 00409 if (ne_uri_parse(pvt->url, &pvt->uri) || pvt->uri.host == NULL || pvt->uri.path == NULL) { 00410 ast_log(LOG_WARNING, "Could not parse url '%s' for iCalendar '%s' - skipping.\n", pvt->url, cal->name); 00411 pvt = unref_icalendar(pvt); 00412 ao2_unlock(cal); 00413 return NULL; 00414 } 00415 00416 if (pvt->uri.scheme == NULL) { 00417 pvt->uri.scheme = "http"; 00418 } 00419 00420 if (pvt->uri.port == 0) { 00421 pvt->uri.port = ne_uri_defaultport(pvt->uri.scheme); 00422 } 00423 00424 pvt->session = ne_session_create(pvt->uri.scheme, pvt->uri.host, pvt->uri.port); 00425 ne_redirect_register(pvt->session); 00426 ne_set_server_auth(pvt->session, auth_credentials, pvt); 00427 if (!strcasecmp(pvt->uri.scheme, "https")) { 00428 ne_ssl_trust_default_ca(pvt->session); 00429 } 00430 00431 cal->tech_pvt = pvt; 00432 00433 ast_mutex_init(&refreshlock); 00434 00435 /* Load it the first time */ 00436 if (!(pvt->data = fetch_icalendar(pvt))) { 00437 ast_log(LOG_WARNING, "Unable to parse iCalendar '%s'\n", cal->name); 00438 } 00439 00440 icalendar_update_events(pvt); 00441 00442 ao2_unlock(cal); 00443 00444 /* The only writing from another thread will be if unload is true */ 00445 for(;;) { 00446 struct timeval tv = ast_tvnow(); 00447 struct timespec ts = {0,}; 00448 00449 ts.tv_sec = tv.tv_sec + (60 * pvt->owner->refresh); 00450 00451 ast_mutex_lock(&refreshlock); 00452 while (!pvt->owner->unloading) { 00453 if (ast_cond_timedwait(&pvt->owner->unload, &refreshlock, &ts) == ETIMEDOUT) { 00454 break; 00455 } 00456 } 00457 ast_mutex_unlock(&refreshlock); 00458 00459 if (pvt->owner->unloading) { 00460 ast_debug(10, "Skipping refresh since we got a shutdown signal\n"); 00461 return NULL; 00462 } 00463 00464 ast_debug(10, "Refreshing after %d minute timeout\n", pvt->owner->refresh); 00465 00466 if (!(pvt->data = fetch_icalendar(pvt))) { 00467 ast_log(LOG_WARNING, "Unable to parse iCalendar '%s'\n", pvt->owner->name); 00468 continue; 00469 } 00470 00471 icalendar_update_events(pvt); 00472 } 00473 00474 return NULL; 00475 }
static void icalendar_add_event | ( | icalcomponent * | comp, | |
struct icaltime_span * | span, | |||
void * | data | |||
) | [static] |
Definition at line 186 of file res_calendar_icalendar.c.
References ast_calendar_event::alarm, ao2_link, AST_CALENDAR_BS_BUSY, AST_CALENDAR_BS_FREE, ast_calendar_event_alloc(), ast_calendar_unref_event(), ast_calloc, AST_LIST_INSERT_TAIL, ast_log(), ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_calendar_event::attendees, ast_calendar_event::busy_state, ast_calendar_event::end, icalendar_pvt::events, icalfloat_to_timet(), LOG_ERROR, LOG_WARNING, icalendar_pvt::owner, ast_calendar_event::priority, ast_calendar_event::start, and ast_calendar_event::summary.
Referenced by icalendar_update_events().
00187 { 00188 struct icalendar_pvt *pvt = data; 00189 struct ast_calendar_event *event; 00190 icaltimezone *utc = icaltimezone_get_utc_timezone(); 00191 icaltimetype start, end, tmp; 00192 icalcomponent *valarm; 00193 icalproperty *prop; 00194 struct icaltriggertype trigger; 00195 00196 if (!(pvt && pvt->owner)) { 00197 ast_log(LOG_ERROR, "Require a private structure with an ownenr\n"); 00198 return; 00199 } 00200 00201 if (!(event = ast_calendar_event_alloc(pvt->owner))) { 00202 ast_log(LOG_ERROR, "Could not allocate an event!\n"); 00203 return; 00204 } 00205 00206 start = icalcomponent_get_dtstart(comp); 00207 end = icalcomponent_get_dtend(comp); 00208 00209 event->start = icaltime_get_tzid(start) ? span->start : icalfloat_to_timet(start); 00210 event->end = icaltime_get_tzid(end) ? span->end : icalfloat_to_timet(end); 00211 event->busy_state = span->is_busy ? AST_CALENDAR_BS_BUSY : AST_CALENDAR_BS_FREE; 00212 00213 if ((prop = icalcomponent_get_first_property(comp, ICAL_SUMMARY_PROPERTY))) { 00214 ast_string_field_set(event, summary, icalproperty_get_value_as_string(prop)); 00215 } 00216 00217 if ((prop = icalcomponent_get_first_property(comp, ICAL_DESCRIPTION_PROPERTY))) { 00218 ast_string_field_set(event, description, icalproperty_get_value_as_string(prop)); 00219 } 00220 00221 if ((prop = icalcomponent_get_first_property(comp, ICAL_ORGANIZER_PROPERTY))) { 00222 ast_string_field_set(event, organizer, icalproperty_get_value_as_string(prop)); 00223 } 00224 00225 if ((prop = icalcomponent_get_first_property(comp, ICAL_LOCATION_PROPERTY))) { 00226 ast_string_field_set(event, location, icalproperty_get_value_as_string(prop)); 00227 } 00228 00229 if ((prop = icalcomponent_get_first_property(comp, ICAL_CATEGORIES_PROPERTY))) { 00230 ast_string_field_set(event, categories, icalproperty_get_value_as_string(prop)); 00231 } 00232 00233 if ((prop = icalcomponent_get_first_property(comp, ICAL_PRIORITY_PROPERTY))) { 00234 event->priority = icalvalue_get_integer(icalproperty_get_value(prop)); 00235 } 00236 00237 if ((prop = icalcomponent_get_first_property(comp, ICAL_UID_PROPERTY))) { 00238 ast_string_field_set(event, uid, icalproperty_get_value_as_string(prop)); 00239 } else { 00240 ast_log(LOG_WARNING, "No UID found, but one is required. Generating, but updates may not be acurate\n"); 00241 if (!ast_strlen_zero(event->summary)) { 00242 ast_string_field_set(event, uid, event->summary); 00243 } else { 00244 char tmp[100]; 00245 snprintf(tmp, sizeof(tmp), "%lu", event->start); 00246 ast_string_field_set(event, uid, tmp); 00247 } 00248 } 00249 00250 /* Get the attendees */ 00251 for (prop = icalcomponent_get_first_property(comp, ICAL_ATTENDEE_PROPERTY); 00252 prop; prop = icalcomponent_get_next_property(comp, ICAL_ATTENDEE_PROPERTY)) { 00253 struct ast_calendar_attendee *attendee; 00254 const char *data; 00255 00256 if (!(attendee = ast_calloc(1, sizeof(*attendee)))) { 00257 event = ast_calendar_unref_event(event); 00258 return; 00259 } 00260 data = icalproperty_get_attendee(prop); 00261 if (!ast_strlen_zero(data)) { 00262 attendee->data = ast_strdup(data);; 00263 AST_LIST_INSERT_TAIL(&event->attendees, attendee, next); 00264 } 00265 } 00266 00267 00268 /* Only set values for alarm based on VALARM. Can be overriden in main/calendar.c by autoreminder 00269 * therefore, go ahead and add events even if their is no VALARM or it is malformed 00270 * Currently we are only getting the first VALARM and are handling repitition in main/calendar.c from calendar.conf */ 00271 if (!(valarm = icalcomponent_get_first_component(comp, ICAL_VALARM_COMPONENT))) { 00272 ao2_link(pvt->events, event); 00273 event = ast_calendar_unref_event(event); 00274 return; 00275 } 00276 00277 if (!(prop = icalcomponent_get_first_property(valarm, ICAL_TRIGGER_PROPERTY))) { 00278 ast_log(LOG_WARNING, "VALARM has no TRIGGER, skipping!\n"); 00279 ao2_link(pvt->events, event); 00280 event = ast_calendar_unref_event(event); 00281 return; 00282 } 00283 00284 trigger = icalproperty_get_trigger(prop); 00285 00286 if (icaltriggertype_is_null_trigger(trigger)) { 00287 ast_log(LOG_WARNING, "Bad TRIGGER for VALARM, skipping!\n"); 00288 ao2_link(pvt->events, event); 00289 event = ast_calendar_unref_event(event); 00290 return; 00291 } 00292 00293 if (!icaltime_is_null_time(trigger.time)) { /* This is an absolute time */ 00294 tmp = icaltime_convert_to_zone(trigger.time, utc); 00295 event->alarm = icaltime_as_timet_with_zone(tmp, utc); 00296 } else { /* Offset from either dtstart or dtend */ 00297 /* XXX Technically you can check RELATED to see if the event fires from the END of the event 00298 * But, I'm not sure I've ever seen anyone implement it in calendaring software, so I'm ignoring for now */ 00299 tmp = icaltime_add(start, trigger.duration); 00300 event->alarm = icaltime_as_timet_with_zone(tmp, utc); 00301 } 00302 00303 ao2_link(pvt->events, event); 00304 event = ast_calendar_unref_event(event); 00305 00306 return; 00307 }
static void icalendar_destructor | ( | void * | obj | ) | [static] |
Definition at line 68 of file res_calendar_icalendar.c.
References ao2_callback, ao2_ref, ast_debug, ast_string_field_free_memory, icalendar_pvt::data, icalendar_pvt::events, ast_calendar::name, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, icalendar_pvt::owner, and icalendar_pvt::session.
Referenced by ical_load_calendar().
00069 { 00070 struct icalendar_pvt *pvt = obj; 00071 00072 ast_debug(1, "Destroying pvt for iCalendar %s\n", pvt->owner->name); 00073 if (pvt->session) { 00074 ne_session_destroy(pvt->session); 00075 } 00076 if (pvt->data) { 00077 icalcomponent_free(pvt->data); 00078 } 00079 ast_string_field_free_memory(pvt); 00080 00081 ao2_callback(pvt->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL); 00082 00083 ao2_ref(pvt->events, -1); 00084 }
static void icalendar_update_events | ( | struct icalendar_pvt * | pvt | ) | [static] |
Definition at line 309 of file res_calendar_icalendar.c.
References ast_calendar_merge_events(), ast_log(), icalendar_pvt::data, icalendar_pvt::events, icalendar_add_event(), LOG_ERROR, icalendar_pvt::owner, and ast_calendar::timeframe.
Referenced by ical_load_calendar().
00310 { 00311 struct icaltimetype start_time, end_time; 00312 icalcomponent *iter; 00313 00314 if (!pvt) { 00315 ast_log(LOG_ERROR, "iCalendar is NULL\n"); 00316 return; 00317 } 00318 00319 if (!pvt->owner) { 00320 ast_log(LOG_ERROR, "iCalendar is an orphan!\n"); 00321 return; 00322 } 00323 00324 if (!pvt->data) { 00325 ast_log(LOG_ERROR, "The iCalendar has not been parsed!\n"); 00326 return; 00327 } 00328 00329 start_time = icaltime_current_time_with_zone(icaltimezone_get_utc_timezone()); 00330 end_time = icaltime_current_time_with_zone(icaltimezone_get_utc_timezone()); 00331 end_time.second += pvt->owner->timeframe * 60; 00332 icaltime_normalize(end_time); 00333 00334 for (iter = icalcomponent_get_first_component(pvt->data, ICAL_VEVENT_COMPONENT); 00335 iter; 00336 iter = icalcomponent_get_next_component(pvt->data, ICAL_VEVENT_COMPONENT)) 00337 { 00338 icalcomponent_foreach_recurrence(iter, start_time, end_time, icalendar_add_event, pvt); 00339 } 00340 00341 ast_calendar_merge_events(pvt->owner, pvt->events); 00342 }
static time_t icalfloat_to_timet | ( | icaltimetype | time | ) | [static] |
Definition at line 160 of file res_calendar_icalendar.c.
References ast_mktime(), ast_tm::tm_hour, ast_tm::tm_isdst, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, ast_tm::tm_sec, and ast_tm::tm_year.
00161 { 00162 struct ast_tm tm = {0,}; 00163 struct timeval tv; 00164 00165 tm.tm_mday = time.day; 00166 tm.tm_mon = time.month - 1; 00167 tm.tm_year = time.year - 1900; 00168 tm.tm_hour = time.hour; 00169 tm.tm_min = time.minute; 00170 tm.tm_sec = time.second; 00171 tm.tm_isdst = -1; 00172 tv = ast_mktime(&tm, NULL); 00173 00174 return tv.tv_sec; 00175 }
static int load_module | ( | void | ) | [static] |
Definition at line 477 of file res_calendar_icalendar.c.
References ast_calendar_register(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and ical_tech.
00478 { 00479 ne_sock_init(); 00480 if (ast_calendar_register(&ical_tech)) { 00481 ne_sock_exit(); 00482 return AST_MODULE_LOAD_DECLINE; 00483 } 00484 00485 return AST_MODULE_LOAD_SUCCESS; 00486 }
static int unload_module | ( | void | ) | [static] |
Definition at line 488 of file res_calendar_icalendar.c.
References ast_calendar_unregister(), and ical_tech.
00489 { 00490 ast_calendar_unregister(&ical_tech); 00491 ne_sock_exit(); 00492 return 0; 00493 }
static void * unref_icalendar | ( | void * | obj | ) | [static] |
Definition at line 86 of file res_calendar_icalendar.c.
References ao2_ref.
Referenced by ical_load_calendar().
00087 { 00088 struct icalendar_pvt *pvt = obj; 00089 00090 ao2_ref(pvt, -1); 00091 return NULL; 00092 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Asterisk iCalendar .ics file 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 499 of file res_calendar_icalendar.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 499 of file res_calendar_icalendar.c.
struct ast_calendar_tech ical_tech [static] |
Definition at line 47 of file res_calendar_icalendar.c.
Referenced by load_module(), and unload_module().