res_calendar.c File Reference

Calendaring API. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/channel.h"
#include "asterisk/calendar.h"
#include "asterisk/utils.h"
#include "asterisk/astobj2.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/devicestate.h"
#include "asterisk/linkedlists.h"
#include "asterisk/sched.h"
#include "asterisk/dial.h"
#include "asterisk/cli.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/format_cache.h"

Include dependency graph for res_calendar.c:

Go to the source code of this file.

Data Structures

struct  evententry
struct  eventlist
struct  techs

Defines

#define CALENDAR_BUCKETS   19
#define FORMAT   "%-17.17s : %-20.20s\n"
#define FORMAT   "%-10.10s %-30.30s\n"
#define FORMAT   "%-20.20s %-10.10s %-6.6s\n"
#define FORMAT2   "%-12.12s: %-40.60s\n"

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int add_event_to_list (struct eventlist *events, struct ast_calendar_event *event, time_t start, time_t end)
static int add_new_event_cb (void *obj, void *arg, int flags)
void ast_calendar_clear_events (struct ast_calendar *cal)
 Remove all events from calendar.
struct ast_configast_calendar_config_acquire (void)
 Grab and lock pointer to the calendar config (read only).
void ast_calendar_config_release (void)
 Release the calendar config.
struct ast_calendar_eventast_calendar_event_alloc (struct ast_calendar *cal)
 Allocate an astobj2 ast_calendar_event object.
struct ao2_containerast_calendar_event_container_alloc (void)
 Allocate an astobj2 container for ast_calendar_event objects.
void ast_calendar_merge_events (struct ast_calendar *cal, struct ao2_container *new_events)
 Add an event to the list of events for a calendar.
int ast_calendar_register (struct ast_calendar_tech *tech)
 Register a new calendar technology.
struct ast_calendar_eventast_calendar_unref_event (struct ast_calendar_event *event)
 Unreference an ast_calendar_event.
void ast_calendar_unregister (struct ast_calendar_tech *tech)
 Unregister a new calendar technology.
static struct ast_calendarbuild_calendar (struct ast_config *cfg, const char *cat, const struct ast_calendar_tech *tech)
static int calendar_busy_callback (void *obj, void *arg, int flags)
static int calendar_busy_exec (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 A dialplan function that can be used to determine the busy status of a calendar.
static int calendar_cmp_fn (void *obj, void *arg, int flags)
static void calendar_destructor (void *obj)
static int calendar_devstate_change (const void *data)
static void calendar_event_destructor (void *obj)
static int calendar_event_notify (const void *data)
static int calendar_event_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int calendar_hash_fn (const void *obj, const int flags)
static int calendar_is_busy (struct ast_calendar *cal)
static void calendar_join_attendees (struct ast_calendar_event *event, char *buf, size_t len)
static int calendar_query_exec (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int calendar_query_result_exec (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int calendar_write_exec (struct ast_channel *chan, const char *cmd, char *data, const char *value)
static enum ast_device_state calendarstate (const char *data)
static int cb_pending_deletion (void *user_data, void *arg, int flags)
static int cb_rm_pending_deletion (void *user_data, void *arg, int flags)
static int clear_events_cb (void *user_data, void *arg, int flags)
static void copy_event_data (struct ast_calendar_event *dst, struct ast_calendar_event *src)
static struct ast_calendar_eventdestroy_event (struct ast_calendar_event *event)
static void * do_notify (void *data)
static void * do_refresh (void *data)
static char * epoch_to_string (char *buf, size_t buflen, time_t epoch)
static int event_cmp_fn (void *obj, void *arg, int flags)
static int event_hash_fn (const void *obj, const int flags)
static void event_notification_destroy (void *data)
static void * event_notification_duplicate (void *data)
static void eventlist_destroy (void *data)
static void eventlist_destructor (void *obj)
static void * eventlist_duplicate (void *data)
static struct ast_calendarfind_calendar (const char *name)
static struct ast_calendar_eventfind_event (struct ao2_container *events, const char *uid)
static char * generate_random_string (char *buf, size_t size)
 Generate 32 byte random string (stolen from chan_sip.c).
static char * handle_dump_sched (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_calendar (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_calendars (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to list available calendars.
static char * handle_show_calendars_types (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to list of all calendars types currently loaded on the backend.
static int load_config (int reload)
static int load_module (void)
 Load the module.
static int load_tech_calendars (struct ast_calendar_tech *tech)
static int match_caltech_cb (void *user_data, void *arg, int flags)
static int merge_events_cb (void *obj, void *arg, int flags)
static int null_chan_write (struct ast_channel *chan, struct ast_frame *frame)
static int reload (void)
static int schedule_calendar_event (struct ast_calendar *cal, struct ast_calendar_event *old_event, struct ast_calendar_event *cmp_event)
static int unload_module (void)
static struct ast_calendarunref_calendar (struct ast_calendar *cal)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Asterisk 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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, }
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_custom_function calendar_busy_function
static struct ast_cli_entry calendar_cli []
static struct ast_configcalendar_config
static struct ast_custom_function calendar_event_function
static struct ast_custom_function calendar_query_function
static struct ast_custom_function calendar_query_result_function
static struct ast_custom_function calendar_write_function
static struct ao2_containercalendars
static ast_rwlock_t config_lock = { {0} , NULL, 1 }
static struct ast_datastore_info event_notification_datastore
static struct ast_datastore_info eventlist_datastore_info
static int module_unloading
static struct ast_channel_tech null_tech
static ast_cond_t refresh_condition
static pthread_t refresh_thread = AST_PTHREADT_NULL
static ast_mutex_t refreshlock
static ast_mutex_t reloadlock
static struct ast_sched_contextsched


Detailed Description

Calendaring API.

Todo:
Support responding to a meeting invite
Todo:
Support writing attendees

Definition in file res_calendar.c.


Define Documentation

#define CALENDAR_BUCKETS   19

Definition at line 222 of file res_calendar.c.

Referenced by ast_calendar_event_container_alloc(), build_calendar(), and load_module().

#define FORMAT   "%-17.17s : %-20.20s\n"

#define FORMAT   "%-10.10s %-30.30s\n"

#define FORMAT   "%-20.20s %-10.10s %-6.6s\n"

#define FORMAT2   "%-12.12s: %-40.60s\n"


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1921 of file res_calendar.c.

static void __unreg_module ( void   )  [static]

Definition at line 1921 of file res_calendar.c.

static int add_event_to_list ( struct eventlist events,
struct ast_calendar_event event,
time_t  start,
time_t  end 
) [static]

Definition at line 1106 of file res_calendar.c.

References ao2_ref, ast_calloc, ast_debug, AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log, ast_calendar_event::end, evententry::event, evententry::list, LOG_ERROR, ast_calendar_event::start, ast_calendar_event::summary, and ast_calendar_event::uid.

Referenced by calendar_query_exec().

01107 {
01108    struct evententry *entry, *iter;
01109    long event_startdiff = labs(start - event->start);
01110    long event_enddiff = labs(end - event->end);
01111    int i = 0;
01112 
01113    if (!(entry = ast_calloc(1, sizeof(*entry)))) {
01114       ast_log(LOG_ERROR, "Unable to allocate memory for event list\n");
01115       return -1;
01116    }
01117 
01118    entry->event = event;
01119    ao2_ref(event, +1);
01120 
01121    if (start == end) {
01122       AST_LIST_TRAVERSE_SAFE_BEGIN(events, iter, list) {
01123          long startdiff = labs(iter->event->start - start);
01124 
01125          ast_debug(10, "Comparing %s with startdiff %ld to %s with startdiff %ld\n", event->summary, event_startdiff, iter->event->summary, startdiff);
01126          ++i;
01127          if (startdiff > event_startdiff) {
01128             AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01129             return i;
01130          }
01131          if (startdiff == event_startdiff) {
01132             long enddiff = labs(iter->event->end - end);
01133 
01134             if (enddiff > event_enddiff) {
01135                AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01136                return i;
01137             }
01138             if (event_startdiff == enddiff) {
01139                if (strcmp(event->uid, iter->event->uid) < 0) {
01140                   AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01141                   return i;
01142                }
01143             }
01144          }
01145       }
01146       AST_LIST_TRAVERSE_SAFE_END;
01147 
01148       AST_LIST_INSERT_TAIL(events, entry, list);
01149 
01150       return i;
01151    }
01152 
01153    AST_LIST_TRAVERSE_SAFE_BEGIN(events, iter, list) {
01154       ++i;
01155       if (iter->event->start > event->start) {
01156          AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01157          return i;
01158       }
01159 
01160       if (iter->event->start == event->start) {
01161          if ((iter->event->end - iter->event->start) == (event->end - event->start)) {
01162             if (strcmp(event->uid, iter->event->uid) < 0) {
01163                AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01164                return i;
01165             }
01166          }
01167          if ((iter->event->end - iter->event->start) < (event->end - event->start)) {
01168             AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01169             return i;
01170          }
01171       }
01172    }
01173    AST_LIST_TRAVERSE_SAFE_END;
01174 
01175    AST_LIST_INSERT_TAIL(events, entry, list);
01176 
01177    return i;
01178 }

static int add_new_event_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1030 of file res_calendar.c.

References ao2_link, CMP_MATCH, events, NULL, ast_calendar_event::owner, and schedule_calendar_event().

Referenced by ast_calendar_merge_events().

01031 {
01032    struct ast_calendar_event *new_event = obj;
01033    struct ao2_container *events = arg;
01034 
01035    ao2_link(events, new_event);
01036    schedule_calendar_event(new_event->owner, new_event, NULL);
01037    return CMP_MATCH;
01038 }

void ast_calendar_clear_events ( struct ast_calendar cal  ) 

Remove all events from calendar.

Parameters:
cal calendar whose events need to be cleared

Definition at line 648 of file res_calendar.c.

References ao2_callback, ast_debug, clear_events_cb(), ast_calendar::events, ast_calendar::name, NULL, OBJ_MULTIPLE, OBJ_NODATA, and OBJ_UNLINK.

Referenced by calendar_destructor().

00649 {
00650    ast_debug(3, "Clearing all events for calendar %s\n", cal->name);
00651 
00652    ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, clear_events_cb, NULL);
00653 }

struct ast_config* ast_calendar_config_acquire ( void   )  [read]

Grab and lock pointer to the calendar config (read only).

Note:
ast_calendar_config_release must be called when finished with the pointer
Returns:
the parsed calendar config

Definition at line 260 of file res_calendar.c.

References ast_rwlock_rdlock, ast_rwlock_unlock, and NULL.

Referenced by caldav_load_calendar(), ewscal_load_calendar(), exchangecal_load_calendar(), and ical_load_calendar().

00261 {
00262    ast_rwlock_rdlock(&config_lock);
00263 
00264    if (!calendar_config) {
00265       ast_rwlock_unlock(&config_lock);
00266       return NULL;
00267    }
00268 
00269    return calendar_config;
00270 }

void ast_calendar_config_release ( void   ) 

Release the calendar config.

Definition at line 272 of file res_calendar.c.

References ast_rwlock_unlock, and config_lock.

Referenced by caldav_load_calendar(), ewscal_load_calendar(), exchangecal_load_calendar(), and ical_load_calendar().

00273 {
00274    ast_rwlock_unlock(&config_lock);
00275 }

struct ast_calendar_event* ast_calendar_event_alloc ( struct ast_calendar cal  )  [read]

Allocate an astobj2 ast_calendar_event object.

Parameters:
cal calendar to allocate an event for
Returns:
a new, initialized calendar event

Definition at line 655 of file res_calendar.c.

References ao2_alloc, ast_calendar_unref_event(), AST_LIST_HEAD_INIT_NOLOCK, ast_string_field_init, ast_calendar_event::attendees, calendar_event_destructor(), and NULL.

Referenced by caldav_add_event(), calendar_write_exec(), icalendar_add_event(), parse_tag(), and startelm().

00656 {
00657    struct ast_calendar_event *event;
00658    if (!(event = ao2_alloc(sizeof(*event), calendar_event_destructor))) {
00659       return NULL;
00660    }
00661 
00662    if (ast_string_field_init(event, 32)) {
00663       event = ast_calendar_unref_event(event);
00664       return NULL;
00665    }
00666 
00667    event->owner = cal;
00668    event->notify_sched = -1;
00669    event->bs_start_sched = -1;
00670    event->bs_end_sched = -1;
00671 
00672    AST_LIST_HEAD_INIT_NOLOCK(&event->attendees);
00673 
00674    return event;
00675 }

struct ao2_container* ast_calendar_event_container_alloc ( void   )  [read]

Allocate an astobj2 container for ast_calendar_event objects.

Returns:
a new event container

Definition at line 677 of file res_calendar.c.

References ao2_container_alloc, CALENDAR_BUCKETS, event_cmp_fn(), and event_hash_fn().

Referenced by caldav_load_calendar(), ewscal_load_calendar(), exchangecal_load_calendar(), and ical_load_calendar().

void ast_calendar_merge_events ( struct ast_calendar cal,
struct ao2_container new_events 
)

Add an event to the list of events for a calendar.

Parameters:
cal calendar containing the events to be merged
new_events an oa2 container of events to be merged into cal->events

Definition at line 1040 of file res_calendar.c.

References add_new_event_cb(), ao2_callback, ast_calendar::events, merge_events_cb(), OBJ_MULTIPLE, OBJ_NODATA, and OBJ_UNLINK.

Referenced by endelm(), icalendar_update_events(), startelm(), update_caldav(), and update_exchangecal().

01041 {
01042    /* Loop through all events attached to the calendar.  If there is a matching new event
01043     * merge its data over and handle any schedule changes that need to be made.  Then remove
01044     * the new_event from new_events so that we are left with only new_events that we can add later. */
01045    ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, merge_events_cb, new_events);
01046 
01047    /* Now, we should only have completely new events in new_events.  Loop through and add them */
01048    ao2_callback(new_events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, add_new_event_cb, cal->events);
01049 }

int ast_calendar_register ( struct ast_calendar_tech tech  ) 

Register a new calendar technology.

Parameters:
tech calendar technology to register
Return values:
0 success
-1 failure

Definition at line 537 of file res_calendar.c.

References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_module_user_add, ast_verb, calendar_config, ast_calendar_tech::description, evententry::list, load_tech_calendars(), LOG_WARNING, NULL, ast_calendar_tech::type, and ast_calendar_tech::user.

Referenced by load_module().

00538 {
00539    struct ast_calendar_tech *iter;
00540 
00541    if (!calendar_config) {
00542       ast_log(LOG_WARNING, "Calendar support disabled, not loading %s calendar module\n", tech->type);
00543       return -1;
00544    }
00545 
00546    AST_LIST_LOCK(&techs);
00547    AST_LIST_TRAVERSE(&techs, iter, list) {
00548       if(!strcasecmp(tech->type, iter->type)) {
00549          ast_log(LOG_WARNING, "Already have a handler for calendar type '%s'\n", tech->type);
00550          AST_LIST_UNLOCK(&techs);
00551          return -1;
00552       }
00553    }
00554    AST_LIST_INSERT_HEAD(&techs, tech, list);
00555    tech->user = ast_module_user_add(NULL);
00556    AST_LIST_UNLOCK(&techs);
00557 
00558    ast_verb(2, "Registered calendar type '%s' (%s)\n", tech->type, tech->description);
00559 
00560    return load_tech_calendars(tech);
00561 }

struct ast_calendar_event* ast_calendar_unref_event ( struct ast_calendar_event event  )  [read]

void ast_calendar_unregister ( struct ast_calendar_tech tech  ) 

Unregister a new calendar technology.

Parameters:
tech calendar technology to unregister
Return values:
0 success
-1 failure

Definition at line 575 of file res_calendar.c.

References ao2_callback, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_module_user_remove, ast_verb, evententry::list, match_caltech_cb(), OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, ast_calendar_tech::type, and ast_calendar_tech::user.

Referenced by load_tech_calendars(), and unload_module().

00576 {
00577    struct ast_calendar_tech *iter;
00578 
00579    AST_LIST_LOCK(&techs);
00580    AST_LIST_TRAVERSE_SAFE_BEGIN(&techs, iter, list) {
00581       if (iter != tech) {
00582          continue;
00583       }
00584 
00585       ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, match_caltech_cb, tech);
00586 
00587       AST_LIST_REMOVE_CURRENT(list);
00588       ast_module_user_remove(iter->user);
00589       ast_verb(2, "Unregistered calendar type '%s'\n", tech->type);
00590       break;
00591    }
00592    AST_LIST_TRAVERSE_SAFE_END;
00593    AST_LIST_UNLOCK(&techs);
00594 
00595 }

static struct ast_calendar* build_calendar ( struct ast_config cfg,
const char *  cat,
const struct ast_calendar_tech tech 
) [static, read]

Definition at line 405 of file res_calendar.c.

References ao2_alloc, ao2_container_alloc, ao2_link, ao2_unlink, ast_cond_init, ast_free, ast_log, ast_pthread_create, AST_PTHREADT_NULL, ast_strdup, ast_string_field_init, ast_string_field_set, ast_strip(), ast_variable_browse(), ast_variable_new(), ast_calendar::autoreminder, CALENDAR_BUCKETS, calendar_destructor(), event_cmp_fn(), event_hash_fn(), ast_calendar::events, find_calendar(), last, ast_calendar_tech::load_calendar, LOG_ERROR, LOG_WARNING, ast_variable::name, name, ast_variable::next, ast_calendar::notify_waittime, NULL, ast_calendar::pending_deletion, ast_calendar::refresh, strsep(), ast_calendar::tech, ast_calendar::thread, ast_calendar::timeframe, ast_calendar::unload, unref_calendar(), value, ast_variable::value, var, and ast_calendar::vars.

Referenced by load_tech_calendars().

00406 {
00407    struct ast_calendar *cal;
00408    struct ast_variable *v, *last = NULL;
00409    int new_calendar = 0;
00410 
00411    if (!(cal = find_calendar(cat))) {
00412       new_calendar = 1;
00413       if (!(cal = ao2_alloc(sizeof(*cal), calendar_destructor))) {
00414          ast_log(LOG_ERROR, "Could not allocate calendar structure. Stopping.\n");
00415          return NULL;
00416       }
00417 
00418       if (!(cal->events = ao2_container_alloc(CALENDAR_BUCKETS, event_hash_fn, event_cmp_fn))) {
00419          ast_log(LOG_ERROR, "Could not allocate events container for %s\n", cat);
00420          cal = unref_calendar(cal);
00421          return NULL;
00422       }
00423 
00424       if (ast_string_field_init(cal, 32)) {
00425          ast_log(LOG_ERROR, "Couldn't create string fields for %s\n", cat);
00426          cal = unref_calendar(cal);
00427          return NULL;
00428       }
00429    } else {
00430       cal->pending_deletion = 0;
00431    }
00432 
00433    ast_string_field_set(cal, name, cat);
00434    cal->tech = tech;
00435 
00436    cal->refresh = 3600;
00437    cal->timeframe = 60;
00438    cal->notify_waittime = 30000;
00439 
00440    for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
00441       if (!strcasecmp(v->name, "autoreminder")) {
00442          cal->autoreminder = atoi(v->value);
00443       } else if (!strcasecmp(v->name, "channel")) {
00444          ast_string_field_set(cal, notify_channel, v->value);
00445       } else if (!strcasecmp(v->name, "context")) {
00446          ast_string_field_set(cal, notify_context, v->value);
00447       } else if (!strcasecmp(v->name, "extension")) {
00448          ast_string_field_set(cal, notify_extension, v->value);
00449       } else if (!strcasecmp(v->name, "waittime")) {
00450          int i = atoi(v->value);
00451          if (i > 0) {
00452             cal->notify_waittime = 1000 * i;
00453          }
00454       } else if (!strcasecmp(v->name, "app")) {
00455          ast_string_field_set(cal, notify_app, v->value);
00456       } else if (!strcasecmp(v->name, "appdata")) {
00457          ast_string_field_set(cal, notify_appdata, v->value);
00458       } else if (!strcasecmp(v->name, "refresh")) {
00459          cal->refresh = atoi(v->value);
00460       } else if (!strcasecmp(v->name, "timeframe")) {
00461          cal->timeframe = atoi(v->value);
00462       } else if (!strcasecmp(v->name, "setvar")) {
00463          char *name, *value;
00464          struct ast_variable *var;
00465 
00466          if ((name = (value = ast_strdup(v->value)))) {
00467             strsep(&value, "=");
00468             if (value) {
00469                if ((var = ast_variable_new(ast_strip(name), ast_strip(value), ""))) {
00470                   if (last) {
00471                      last->next = var;
00472                   } else {
00473                      cal->vars = var;
00474                   }
00475                   last = var;
00476                }
00477             } else {
00478                ast_log(LOG_WARNING, "Malformed argument. Should be '%s: variable=value'\n", v->name);
00479             }
00480             ast_free(name);
00481          }
00482       }
00483    }
00484 
00485    if (new_calendar) {
00486       cal->thread = AST_PTHREADT_NULL;
00487       ast_cond_init(&cal->unload, NULL);
00488       ao2_link(calendars, cal);
00489       if (ast_pthread_create(&cal->thread, NULL, cal->tech->load_calendar, cal)) {
00490          /* If we start failing to create threads, go ahead and return NULL
00491           * and the tech module will be unregistered
00492           */ 
00493          ao2_unlink(calendars, cal);
00494          cal = unref_calendar(cal);
00495       }
00496    }
00497 
00498    return cal;
00499 }

static int calendar_busy_callback ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 363 of file res_calendar.c.

References AST_CALENDAR_BS_FREE, ast_tvnow(), and CMP_STOP.

Referenced by calendar_is_busy().

00364 {
00365    struct ast_calendar_event *event = obj;
00366    int *is_busy = arg;
00367    struct timeval tv = ast_tvnow();
00368 
00369    if (tv.tv_sec >= event->start && tv.tv_sec <= event->end && event->busy_state > AST_CALENDAR_BS_FREE) {
00370       *is_busy = 1;
00371       return CMP_STOP;
00372    }
00373 
00374    return 0;
00375 }

static int calendar_busy_exec ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

A dialplan function that can be used to determine the busy status of a calendar.

Definition at line 1079 of file res_calendar.c.

References ast_log, ast_strlen_zero, calendar_is_busy(), find_calendar(), LOG_WARNING, and unref_calendar().

01080 {
01081    struct ast_calendar *cal;
01082 
01083    if (ast_strlen_zero(data)) {
01084       ast_log(LOG_WARNING, "CALENDAR_BUSY requires an argument: CALENDAR_BUSY(<calendar_name>)\n");
01085       return -1;
01086    }
01087 
01088    cal = find_calendar(data);
01089 
01090    if (!cal) {
01091       ast_log(LOG_WARNING, "Could not find calendar '%s'\n", data);
01092       return -1;
01093    }
01094 
01095    strcpy(buf, calendar_is_busy(cal) ? "1" : "0");
01096    cal = unref_calendar(cal);
01097 
01098    return 0;
01099 }

static int calendar_cmp_fn ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 289 of file res_calendar.c.

References CMP_MATCH, CMP_STOP, and ast_calendar::name.

Referenced by load_module().

00290 {
00291    const struct ast_calendar *one = obj, *two = arg;
00292    return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP: 0;
00293 }

static void calendar_destructor ( void *  obj  )  [static]

Definition at line 329 of file res_calendar.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_calendar_clear_events(), ast_cond_signal, ast_debug, ast_string_field_free_memory, ast_variables_destroy(), ast_calendar::events, ast_calendar::name, NULL, ast_calendar::tech, ast_calendar::tech_pvt, ast_calendar::thread, ast_calendar::unload, ast_calendar::unloading, ast_calendar_tech::unref_calendar, and ast_calendar::vars.

Referenced by build_calendar().

00330 {
00331    struct ast_calendar *cal = obj;
00332 
00333    ast_debug(3, "Destroying calendar %s\n", cal->name);
00334 
00335    ao2_lock(cal);
00336    cal->unloading = 1;
00337    ast_cond_signal(&cal->unload);
00338    pthread_join(cal->thread, NULL);
00339    if (cal->tech_pvt) {
00340       cal->tech_pvt = cal->tech->unref_calendar(cal->tech_pvt);
00341    }
00342    ast_calendar_clear_events(cal);
00343    ast_string_field_free_memory(cal);
00344    if (cal->vars) {
00345       ast_variables_destroy(cal->vars);
00346       cal->vars = NULL;
00347    }
00348    ao2_ref(cal->events, -1);
00349    ao2_unlock(cal);
00350 }

static int calendar_devstate_change ( const void *  data  )  [static]

Definition at line 879 of file res_calendar.c.

References ao2_ref, ast_calendar_unref_event(), AST_DEVICE_BUSY, AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_log, ast_tvnow(), calendar_is_busy(), and LOG_WARNING.

Referenced by schedule_calendar_event().

00880 {
00881    struct ast_calendar_event *event = (struct ast_calendar_event *)data;
00882    struct timeval now = ast_tvnow();
00883    int is_end_event;
00884 
00885    if (!event) {
00886       ast_log(LOG_WARNING, "Event was NULL!\n");
00887       return 0;
00888    }
00889 
00890    ao2_ref(event, +1);
00891 
00892    is_end_event = event->end <= now.tv_sec;
00893 
00894    if (is_end_event) {
00895       event->bs_end_sched = -1;
00896    } else {
00897       event->bs_start_sched = -1;
00898    }
00899 
00900    /* We can have overlapping events, so ignore the event->busy_state and check busy state
00901     * based on all events in the calendar */
00902    if (!calendar_is_busy(event->owner)) {
00903       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
00904    } else {
00905       ast_devstate_changed(AST_DEVICE_BUSY, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
00906    }
00907 
00908    event = ast_calendar_unref_event(event);
00909 
00910    return 0;
00911 }

static void calendar_event_destructor ( void *  obj  )  [static]

Definition at line 597 of file res_calendar.c.

References ast_debug, ast_free, AST_LIST_REMOVE_HEAD, ast_string_field_free_memory, ast_calendar_attendee::data, and evententry::next.

Referenced by ast_calendar_event_alloc().

00598 {
00599    struct ast_calendar_event *event = obj;
00600    struct ast_calendar_attendee *attendee;
00601 
00602    ast_debug(3, "Destroying event for calendar '%s'\n", event->owner->name);
00603    ast_string_field_free_memory(event);
00604    while ((attendee = AST_LIST_REMOVE_HEAD(&event->attendees, next))) {
00605       if (attendee->data) {
00606          ast_free(attendee->data);
00607       }
00608       ast_free(attendee);
00609    }
00610 }

static int calendar_event_notify ( const void *  data  )  [static]

Definition at line 855 of file res_calendar.c.

References ao2_ref, ast_log, ast_pthread_create_background, AST_PTHREADT_NULL, do_notify(), LOG_ERROR, and NULL.

Referenced by schedule_calendar_event().

00856 {
00857    struct ast_calendar_event *event = (void *)data;
00858    int res = -1;
00859    pthread_t notify_thread = AST_PTHREADT_NULL;
00860 
00861    if (!(event && event->owner)) {
00862       ast_log(LOG_ERROR, "Extremely low-cal...in fact cal is NULL!\n");
00863       return res;
00864    }
00865 
00866    ao2_ref(event, +1);
00867    event->notify_sched = -1;
00868 
00869    if (ast_pthread_create_background(&notify_thread, NULL, do_notify, event) < 0) {
00870       ast_log(LOG_ERROR, "Could not create notification thread\n");
00871       return res;
00872    }
00873 
00874    res = 0;
00875 
00876    return res;
00877 }

static int calendar_event_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 1697 of file res_calendar.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_copy_string(), ast_log, ast_strlen_zero, ast_calendar_event::busy_state, calendar_join_attendees(), ast_calendar_event::categories, ast_datastore::data, ast_calendar_event::description, ast_calendar_event::end, ast_calendar_event::location, LOG_WARNING, ast_calendar::name, NULL, ast_calendar_event::organizer, ast_calendar_event::owner, ast_calendar_event::priority, ast_calendar_event::start, ast_calendar_event::summary, and ast_calendar_event::uid.

01698 {
01699    struct ast_datastore *datastore;
01700    struct ast_calendar_event *event;
01701 
01702    if (!chan) {
01703       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
01704       return -1;
01705    }
01706 
01707    if (ast_strlen_zero(data)) {
01708       ast_log(LOG_WARNING, "%s requires an argument\n", cmd);
01709       return -1;
01710    }
01711 
01712    ast_channel_lock(chan);
01713    if (!(datastore = ast_channel_datastore_find(chan, &event_notification_datastore, NULL))) {
01714       ast_log(LOG_WARNING, "There is no event notification datastore on '%s'!\n", ast_channel_name(chan));
01715       ast_channel_unlock(chan);
01716       return -1;
01717    }
01718    ast_channel_unlock(chan);
01719 
01720    if (!(event = datastore->data)) {
01721       ast_log(LOG_WARNING, "The datastore contains no data!\n");
01722       return -1;
01723    }
01724 
01725    if (!strcasecmp(data, "summary")) {
01726       ast_copy_string(buf, event->summary, len);
01727    } else if (!strcasecmp(data, "description")) {
01728       ast_copy_string(buf, event->description, len);
01729    } else if (!strcasecmp(data, "organizer")) {
01730       ast_copy_string(buf, event->organizer, len);
01731    } else if (!strcasecmp(data, "location")) {
01732       ast_copy_string(buf, event->location, len);
01733    } else if (!strcasecmp(data, "categories")) {
01734       ast_copy_string(buf, event->categories, len);
01735    } else if (!strcasecmp(data, "priority")) {
01736       snprintf(buf, len, "%d", event->priority);
01737    } else if (!strcasecmp(data, "calendar")) {
01738       ast_copy_string(buf, event->owner->name, len);
01739    } else if (!strcasecmp(data, "uid")) {
01740       ast_copy_string(buf, event->uid, len);
01741    } else if (!strcasecmp(data, "start")) {
01742       snprintf(buf, len, "%ld", (long)event->start);
01743    } else if (!strcasecmp(data, "end")) {
01744       snprintf(buf, len, "%ld", (long)event->end);
01745    } else if (!strcasecmp(data, "busystate")) {
01746       snprintf(buf, len, "%u", event->busy_state);
01747    } else if (!strcasecmp(data, "attendees")) {
01748       calendar_join_attendees(event, buf, len);
01749    }
01750 
01751 
01752    return 0;
01753 }

static int calendar_hash_fn ( const void *  obj,
const int  flags 
) [static]

Definition at line 283 of file res_calendar.c.

References ast_str_case_hash(), and ast_calendar::name.

Referenced by load_module().

00284 {
00285    const struct ast_calendar *cal = obj;
00286    return ast_str_case_hash(cal->name);
00287 }

static int calendar_is_busy ( struct ast_calendar cal  )  [static]

Definition at line 377 of file res_calendar.c.

References ao2_callback, calendar_busy_callback(), ast_calendar::events, and OBJ_NODATA.

Referenced by calendar_busy_exec(), calendar_devstate_change(), calendarstate(), destroy_event(), and handle_show_calendars().

00378 {
00379    int is_busy = 0;
00380 
00381    ao2_callback(cal->events, OBJ_NODATA, calendar_busy_callback, &is_busy);
00382 
00383    return is_busy;
00384 }

static void calendar_join_attendees ( struct ast_calendar_event event,
char *  buf,
size_t  len 
) [static]

Definition at line 1291 of file res_calendar.c.

References ast_copy_string(), ast_free, AST_LIST_FIRST, AST_LIST_TRAVERSE, ast_log, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_calendar_event::attendees, ast_calendar_attendee::data, LOG_ERROR, evententry::next, and tmp().

Referenced by calendar_event_read(), and calendar_query_result_exec().

01292 {
01293    struct ast_str *tmp;
01294    struct ast_calendar_attendee *attendee;
01295 
01296    if (!(tmp = ast_str_create(32))) {
01297       ast_log(LOG_ERROR, "Could not allocate memory for attendees!\n");
01298       return;
01299    }
01300 
01301    AST_LIST_TRAVERSE(&event->attendees, attendee, next) {
01302       ast_str_append(&tmp, 0, "%s%s", attendee == AST_LIST_FIRST(&event->attendees) ? "" : ",", attendee->data);
01303    }
01304 
01305    ast_copy_string(buf, ast_str_buffer(tmp), len);
01306    ast_free(tmp);
01307 }

static int calendar_query_exec ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 1200 of file res_calendar.c.

References add_event_to_list(), ao2_alloc, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, args, AST_APP_ARG, ast_calendar_unref_event(), ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_debug, AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strlen_zero, ast_datastore::data, DATASTORE_INHERIT_FOREVER, ast_calendar_event::end, end, eventlist_destructor(), ast_calendar::events, events, find_calendar(), generate_random_string(), ast_datastore::inheritance, LOG_ERROR, LOG_WARNING, ast_calendar_event::start, ast_calendar_event::summary, and unref_calendar().

01201 {
01202    struct ast_calendar *cal;
01203    struct ao2_iterator i;
01204    struct ast_calendar_event *event;
01205    struct eventlist *events;
01206    time_t start = INT_MIN, end = INT_MAX;
01207    struct ast_datastore *eventlist_datastore;
01208    AST_DECLARE_APP_ARGS(args,
01209       AST_APP_ARG(calendar);
01210       AST_APP_ARG(start);
01211       AST_APP_ARG(end);
01212    );
01213 
01214    if (!chan) {
01215       ast_log(LOG_WARNING, "%s requires a channel to store the data on\n", cmd);
01216       return -1;
01217    }
01218 
01219    AST_STANDARD_APP_ARGS(args, data);
01220 
01221    if (ast_strlen_zero(args.calendar)) {
01222       ast_log(LOG_WARNING, "%s requires a calendar argument\n", cmd);
01223       return -1;
01224    }
01225 
01226    if (!(cal = find_calendar(args.calendar))) {
01227       ast_log(LOG_WARNING, "Unknown calendar '%s'\n", args.calendar);
01228       return -1;
01229    }
01230 
01231    if (!(events = ao2_alloc(sizeof(*events), eventlist_destructor))) {
01232       ast_log(LOG_ERROR, "Unable to allocate memory for event list\n");
01233       cal = unref_calendar(cal);
01234       return -1;
01235    }
01236 
01237    if (!ast_strlen_zero(args.start)) {
01238       start = atoi(args.start);
01239    }
01240 
01241    if (!ast_strlen_zero(args.end)) {
01242       end = atoi(args.end);
01243    }
01244 
01245    i = ao2_iterator_init(cal->events, 0);
01246    while ((event = ao2_iterator_next(&i))) {
01247       if (!(start > event->end || end < event->start)) {
01248          ast_debug(10, "%s (%ld - %ld) overlapped with (%ld - %ld)\n", event->summary, (long) event->start, (long) event->end, (long) start, (long) end);
01249          if (add_event_to_list(events, event, start, end) < 0) {
01250             event = ast_calendar_unref_event(event);
01251             cal = unref_calendar(cal);
01252             ao2_ref(events, -1);
01253             ao2_iterator_destroy(&i);
01254             return -1;
01255          }
01256       }
01257 
01258       event = ast_calendar_unref_event(event);
01259    }
01260    ao2_iterator_destroy(&i);
01261 
01262    ast_channel_lock(chan);
01263    do {
01264       generate_random_string(buf, len);
01265    } while (ast_channel_datastore_find(chan, &eventlist_datastore_info, buf));
01266    ast_channel_unlock(chan);
01267 
01268    if (!(eventlist_datastore = ast_datastore_alloc(&eventlist_datastore_info, buf))) {
01269       ast_log(LOG_ERROR, "Could not allocate datastore!\n");
01270       cal = unref_calendar(cal);
01271       ao2_ref(events, -1);
01272       return -1;
01273    }
01274 
01275    eventlist_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
01276    eventlist_datastore->data = events;
01277 
01278    ast_channel_lock(chan);
01279    ast_channel_datastore_add(chan, eventlist_datastore);
01280    ast_channel_unlock(chan);
01281 
01282    cal = unref_calendar(cal);
01283    return 0;
01284 }

static int calendar_query_result_exec ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 1309 of file res_calendar.c.

References args, AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_TRAVERSE, ast_log, AST_STANDARD_APP_ARGS, ast_strlen_zero, ast_calendar_event::busy_state, calendar_join_attendees(), ast_calendar_event::categories, ast_datastore::data, ast_calendar_event::description, ast_calendar_event::end, evententry::event, events, evententry::list, ast_calendar_event::location, LOG_WARNING, ast_calendar::name, ast_calendar_event::organizer, ast_calendar_event::owner, ast_calendar_event::priority, ast_calendar_event::start, ast_calendar_event::summary, and ast_calendar_event::uid.

01310 {
01311    struct ast_datastore *datastore;
01312    struct eventlist *events;
01313    struct evententry *entry;
01314    int row = 1;
01315    size_t listlen = 0;
01316    AST_DECLARE_APP_ARGS(args,
01317       AST_APP_ARG(id);
01318       AST_APP_ARG(field);
01319       AST_APP_ARG(row);
01320    );
01321 
01322    if (!chan) {
01323       ast_log(LOG_WARNING, "%s requires a channel\n", cmd);
01324       return -1;
01325    }
01326 
01327    AST_STANDARD_APP_ARGS(args, data);
01328 
01329    if (ast_strlen_zero(args.id) || ast_strlen_zero(args.field)) {
01330       ast_log(LOG_WARNING, "%s requires an id and a field", cmd);
01331       return -1;
01332    }
01333 
01334    ast_channel_lock(chan);
01335    if (!(datastore = ast_channel_datastore_find(chan, &eventlist_datastore_info, args.id))) {
01336       ast_log(LOG_WARNING, "There is no event notification datastore with id '%s' on '%s'!\n", args.id, ast_channel_name(chan));
01337       ast_channel_unlock(chan);
01338       return -1;
01339    }
01340    ast_channel_unlock(chan);
01341 
01342    if (!(events = datastore->data)) {
01343       ast_log(LOG_WARNING, "The datastore contains no data!\n");
01344       return -1;
01345    }
01346 
01347    if (!ast_strlen_zero(args.row)) {
01348       row = atoi(args.row);
01349    }
01350 
01351    AST_LIST_TRAVERSE(events, entry, list) {
01352       listlen++;
01353    }
01354 
01355    if (!strcasecmp(args.field, "getnum")) {
01356       snprintf(buf, len, "%zu", listlen);
01357       return 0;
01358    }
01359 
01360    AST_LIST_TRAVERSE(events, entry, list) {
01361       if (--row) {
01362          continue;
01363       }
01364       if (!strcasecmp(args.field, "summary")) {
01365          ast_copy_string(buf, entry->event->summary, len);
01366       } else if (!strcasecmp(args.field, "description")) {
01367          ast_copy_string(buf, entry->event->description, len);
01368       } else if (!strcasecmp(args.field, "organizer")) {
01369          ast_copy_string(buf, entry->event->organizer, len);
01370       } else if (!strcasecmp(args.field, "location")) {
01371          ast_copy_string(buf, entry->event->location, len);
01372       } else if (!strcasecmp(args.field, "categories")) {
01373          ast_copy_string(buf, entry->event->categories, len);
01374       } else if (!strcasecmp(args.field, "priority")) {
01375          snprintf(buf, len, "%d", entry->event->priority);
01376       } else if (!strcasecmp(args.field, "calendar")) {
01377          ast_copy_string(buf, entry->event->owner->name, len);
01378       } else if (!strcasecmp(args.field, "uid")) {
01379          ast_copy_string(buf, entry->event->uid, len);
01380       } else if (!strcasecmp(args.field, "start")) {
01381          snprintf(buf, len, "%ld", (long) entry->event->start);
01382       } else if (!strcasecmp(args.field, "end")) {
01383          snprintf(buf, len, "%ld", (long) entry->event->end);
01384       } else if (!strcasecmp(args.field, "busystate")) {
01385          snprintf(buf, len, "%u", entry->event->busy_state);
01386       } else if (!strcasecmp(args.field, "attendees")) {
01387          calendar_join_attendees(entry->event, buf, len);
01388       } else {
01389          ast_log(LOG_WARNING, "Unknown field '%s'\n", args.field);
01390       }
01391       break;
01392    }
01393 
01394    return 0;
01395 }

static int calendar_write_exec ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
) [static]

Definition at line 1402 of file res_calendar.c.

References AST_APP_ARG, ast_calendar_event_alloc(), ast_calendar_unref_event(), AST_DECLARE_APP_ARGS, ast_free, ast_log, AST_STANDARD_APP_ARGS, ast_strdup, ast_string_field_set, ast_strlen_zero, ast_tvnow(), categories, find_calendar(), LOG_ERROR, LOG_WARNING, ast_calendar::name, NULL, pbx_builtin_setvar_helper(), ast_calendar::tech, unref_calendar(), and ast_calendar_tech::write_event.

01403 {
01404    int i, j, ret = -1;
01405    char *val_dup = NULL;
01406    struct ast_calendar *cal = NULL;
01407    struct ast_calendar_event *event = NULL;
01408    struct timeval tv = ast_tvnow();
01409    AST_DECLARE_APP_ARGS(fields,
01410       AST_APP_ARG(field)[10];
01411    );
01412    AST_DECLARE_APP_ARGS(values,
01413       AST_APP_ARG(value)[10];
01414    );
01415 
01416    if (!(val_dup = ast_strdup(value))) {
01417       ast_log(LOG_ERROR, "Could not allocate memory for values\n");
01418       goto write_cleanup;
01419    }
01420 
01421    AST_STANDARD_APP_ARGS(fields, data);
01422    AST_STANDARD_APP_ARGS(values, val_dup);
01423 
01424    /* XXX Eventually we will support unnamed calendars, so if we don't find one, we parse
01425     * for a calendar type and create it */
01426    if (!(cal = find_calendar(fields.field[0]))) {
01427       ast_log(LOG_WARNING, "Couldn't find calendar '%s'\n", fields.field[0]);
01428       goto write_cleanup;
01429    }
01430 
01431    if (!(cal->tech->write_event)) {
01432       ast_log(LOG_WARNING, "Calendar '%s' has no write function!\n", cal->name);
01433       goto write_cleanup;
01434    }
01435 
01436    if (!(event = ast_calendar_event_alloc(cal))) {
01437       goto write_cleanup;
01438    }
01439 
01440    if (ast_strlen_zero(fields.field[0])) {
01441       ast_log(LOG_WARNING, "CALENDAR_WRITE requires a calendar name!\n");
01442       goto write_cleanup;
01443    }
01444 
01445    if (fields.argc - 1 != values.argc) {
01446       ast_log(LOG_WARNING, "CALENDAR_WRITE should have the same number of fields (%u) and values (%u)!\n", fields.argc - 1, values.argc);
01447       goto write_cleanup;
01448    }
01449 
01450    event->owner = cal;
01451 
01452    for (i = 1, j = 0; i < fields.argc; i++, j++) {
01453       if (!strcasecmp(fields.field[i], "summary")) {
01454          ast_string_field_set(event, summary, values.value[j]);
01455       } else if (!strcasecmp(fields.field[i], "description")) {
01456          ast_string_field_set(event, description, values.value[j]);
01457       } else if (!strcasecmp(fields.field[i], "organizer")) {
01458          ast_string_field_set(event, organizer, values.value[j]);
01459       } else if (!strcasecmp(fields.field[i], "location")) {
01460          ast_string_field_set(event, location, values.value[j]);
01461       } else if (!strcasecmp(fields.field[i], "categories")) {
01462          ast_string_field_set(event, categories, values.value[j]);
01463       } else if (!strcasecmp(fields.field[i], "priority")) {
01464          event->priority = atoi(values.value[j]);
01465       } else if (!strcasecmp(fields.field[i], "uid")) {
01466          ast_string_field_set(event, uid, values.value[j]);
01467       } else if (!strcasecmp(fields.field[i], "start")) {
01468          event->start = atoi(values.value[j]);
01469       } else if (!strcasecmp(fields.field[i], "end")) {
01470          event->end = atoi(values.value[j]);
01471       } else if (!strcasecmp(fields.field[i], "busystate")) {
01472          event->busy_state = atoi(values.value[j]);
01473       } else {
01474          ast_log(LOG_WARNING, "Unknown calendar event field '%s'\n", fields.field[i]);
01475       }
01476    }
01477 
01478    if (!event->start) {
01479       event->start = tv.tv_sec;
01480    }
01481 
01482    if (!event->end) {
01483       event->end = tv.tv_sec;
01484    }
01485 
01486    if((ret = cal->tech->write_event(event))) {
01487       ast_log(LOG_WARNING, "Writing event to calendar '%s' failed!\n", cal->name);
01488    }
01489 
01490 write_cleanup:
01491    if (ret) {
01492       pbx_builtin_setvar_helper(chan, "CALENDAR_SUCCESS", "0");
01493    } else {
01494       pbx_builtin_setvar_helper(chan, "CALENDAR_SUCCESS", "1");
01495    }
01496    if (cal) {
01497       cal = unref_calendar(cal);
01498    }
01499    if (event) {
01500       event = ast_calendar_unref_event(event);
01501    }
01502    if (val_dup) {
01503       ast_free(val_dup);
01504    }
01505 
01506    return ret;
01507 }

static enum ast_device_state calendarstate ( const char *  data  )  [static]

Definition at line 386 of file res_calendar.c.

References AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_strlen_zero, calendar_is_busy(), find_calendar(), ast_calendar_tech::is_busy, ast_calendar::tech, and unref_calendar().

Referenced by load_module().

00387 {
00388    enum ast_device_state state;
00389    struct ast_calendar *cal;
00390 
00391    if (ast_strlen_zero(data) || (!(cal = find_calendar(data)))) {
00392       return AST_DEVICE_INVALID;
00393    }
00394 
00395    if (cal->tech->is_busy) {
00396       state = cal->tech->is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
00397    } else {
00398       state = calendar_is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
00399    }
00400 
00401    cal = unref_calendar(cal);
00402    return state;
00403 }

static int cb_pending_deletion ( void *  user_data,
void *  arg,
int  flags 
) [static]

Definition at line 1760 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::pending_deletion.

Referenced by reload().

01761 {
01762    struct ast_calendar *cal = user_data;
01763 
01764    cal->pending_deletion = 1;
01765 
01766    return CMP_MATCH;
01767 }

static int cb_rm_pending_deletion ( void *  user_data,
void *  arg,
int  flags 
) [static]

Definition at line 1769 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::pending_deletion.

Referenced by reload().

01770 {
01771    struct ast_calendar *cal = user_data;
01772 
01773    return cal->pending_deletion ? CMP_MATCH : 0;
01774 }

static int clear_events_cb ( void *  user_data,
void *  arg,
int  flags 
) [static]

Definition at line 639 of file res_calendar.c.

References CMP_MATCH, and destroy_event().

Referenced by ast_calendar_clear_events().

00640 {
00641    struct ast_calendar_event *event = user_data;
00642 
00643    event = destroy_event(event);
00644 
00645    return CMP_MATCH;
00646 }

static void copy_event_data ( struct ast_calendar_event dst,
struct ast_calendar_event src 
) [static]

Definition at line 913 of file res_calendar.c.

References ast_calendar_event::alarm, ast_free, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_HEAD, ast_string_field_set, ast_calendar_event::attendees, ast_calendar_event::busy_state, ast_calendar_event::categories, categories, ast_calendar_event::description, ast_calendar_event::end, ast_calendar_event::location, evententry::next, ast_calendar_event::organizer, ast_calendar_event::owner, ast_calendar_event::priority, ast_calendar_event::start, ast_calendar_event::summary, and ast_calendar_event::uid.

Referenced by merge_events_cb().

00914 {
00915    struct ast_calendar_attendee *attendee;
00916 
00917    ast_string_field_set(dst, summary, src->summary);
00918    ast_string_field_set(dst, description, src->description);
00919    ast_string_field_set(dst, organizer, src->organizer);
00920    ast_string_field_set(dst, location, src->location);
00921    ast_string_field_set(dst, uid, src->uid);
00922    ast_string_field_set(dst, categories, src->categories);
00923    dst->priority = src->priority;
00924    dst->owner = src->owner;
00925    dst->start = src->start;
00926    dst->end = src->end;
00927    dst->alarm = src->alarm;
00928    dst->busy_state = src->busy_state;
00929 
00930    /* Delete any existing attendees */
00931    while ((attendee = AST_LIST_REMOVE_HEAD(&dst->attendees, next))) {
00932       ast_free(attendee);
00933    }
00934 
00935    /* Copy over the new attendees */
00936    while ((attendee = AST_LIST_REMOVE_HEAD(&src->attendees, next))) {
00937       AST_LIST_INSERT_TAIL(&dst->attendees, attendee, next);
00938    }
00939 }

static struct ast_calendar_event* destroy_event ( struct ast_calendar_event event  )  [static, read]

Definition at line 614 of file res_calendar.c.

References ast_debug, AST_DEVICE_BUSY, AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_sched_del(), ast_calendar_event::bs_end_sched, ast_calendar_event::bs_start_sched, calendar_is_busy(), ast_calendar::name, ast_calendar_event::notify_sched, NULL, and ast_calendar_event::owner.

Referenced by clear_events_cb(), and merge_events_cb().

00615 {
00616    if (event->notify_sched > -1 && ast_sched_del(sched, event->notify_sched)) {
00617       ast_debug(3, "Notification running, can't delete sched entry\n");
00618    }
00619    if (event->bs_start_sched > -1 && ast_sched_del(sched, event->bs_start_sched)) {
00620       ast_debug(3, "Devicestate update (start) running, can't delete sched entry\n");
00621    }
00622    if (event->bs_end_sched > -1 && ast_sched_del(sched, event->bs_end_sched)) {
00623       ast_debug(3, "Devicestate update (end) running, can't delete sched entry\n");
00624    }
00625 
00626    /* If an event is being deleted and we've fired an event changing the status at the beginning,
00627     * but haven't hit the end event yet, go ahead and set the devicestate to the current busy status */
00628    if (event->bs_start_sched < 0 && event->bs_end_sched >= 0) {
00629       if (!calendar_is_busy(event->owner)) {
00630          ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
00631       } else {
00632          ast_devstate_changed(AST_DEVICE_BUSY, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
00633       }
00634    }
00635 
00636    return NULL;
00637 }

static void* do_notify ( void *  data  )  [static]

Definition at line 728 of file res_calendar.c.

References ao2_ref, ast_calendar_unref_event(), ast_channel_alloc, ast_channel_context_set(), ast_channel_datastore_add(), ast_channel_exten_set(), ast_channel_lock, ast_channel_nativeformats_set(), ast_channel_priority_set(), ast_channel_release(), ast_channel_set_rawreadformat(), ast_channel_set_rawwriteformat(), ast_channel_set_readformat(), ast_channel_set_writeformat(), ast_channel_tech_set(), ast_channel_unlock, ast_datastore_alloc, ast_dial_answered_steal(), ast_dial_append(), ast_dial_create(), ast_dial_destroy(), AST_DIAL_OPTION_ANSWER_EXEC, ast_dial_option_global_enable(), AST_DIAL_RESULT_ANSWERED, ast_dial_run(), ast_dial_set_global_timeout(), ast_format_cap_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_slin, ast_free, ast_log, ast_pbx_run(), AST_STATE_DOWN, ast_str_buffer(), ast_str_create(), ast_str_set(), ast_str_substitute_variables(), ast_strdupa, ast_strlen_zero, ast_verb, buf, ast_datastore::data, DATASTORE_INHERIT_FOREVER, generate_random_string(), ast_datastore::inheritance, LOG_ERROR, LOG_WARNING, ast_variable::name, ast_variable::next, NULL, null_tech, pbx_builtin_setvar_helper(), and ast_variable::value.

Referenced by calendar_event_notify().

00729 {
00730    struct ast_calendar_event *event = data;
00731    struct ast_dial *dial = NULL;
00732    struct ast_str *apptext = NULL, *tmpstr = NULL;
00733    struct ast_datastore *datastore;
00734    enum ast_dial_result res;
00735    struct ast_channel *chan = NULL;
00736    struct ast_variable *itervar;
00737    char *tech, *dest;
00738    char buf[8];
00739    struct ast_format_cap *caps;
00740 
00741    tech = ast_strdupa(event->owner->notify_channel);
00742 
00743    if ((dest = strchr(tech, '/'))) {
00744       *dest = '\0';
00745       dest++;
00746    } else {
00747       ast_log(LOG_WARNING, "Channel should be in form Tech/Dest (was '%s')\n", tech);
00748       goto notify_cleanup;
00749    }
00750 
00751    if (!(dial = ast_dial_create())) {
00752       ast_log(LOG_ERROR, "Could not create dial structure\n");
00753       goto notify_cleanup;
00754    }
00755 
00756    if (ast_dial_append(dial, tech, dest, NULL) < 0) {
00757       ast_log(LOG_ERROR, "Could not append channel\n");
00758       goto notify_cleanup;
00759    }
00760 
00761    ast_dial_set_global_timeout(dial, event->owner->notify_waittime);
00762    generate_random_string(buf, sizeof(buf));
00763 
00764    if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, 0, 0, 0, 0, 0, NULL, NULL, 0, "Calendar/%s-%s", event->owner->name, buf))) {
00765       ast_log(LOG_ERROR, "Could not allocate notification channel\n");
00766       goto notify_cleanup;
00767    }
00768 
00769    ast_channel_tech_set(chan, &null_tech);
00770    ast_channel_set_writeformat(chan, ast_format_slin);
00771    ast_channel_set_readformat(chan, ast_format_slin);
00772    ast_channel_set_rawwriteformat(chan, ast_format_slin);
00773    ast_channel_set_rawreadformat(chan, ast_format_slin);
00774 
00775    caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
00776    if (!caps) {
00777       ast_log(LOG_ERROR, "Could not allocate capabilities, notification not being sent!\n");
00778       goto notify_cleanup;
00779    }
00780    ast_format_cap_append(caps, ast_format_slin, 0);
00781    ast_channel_nativeformats_set(chan, caps);
00782    ao2_ref(caps, -1);
00783 
00784    ast_channel_unlock(chan);
00785 
00786    if (!(datastore = ast_datastore_alloc(&event_notification_datastore, NULL))) {
00787       ast_log(LOG_ERROR, "Could not allocate datastore, notification not being sent!\n");
00788       goto notify_cleanup;
00789    }
00790 
00791    datastore->data = event;
00792    datastore->inheritance = DATASTORE_INHERIT_FOREVER;
00793 
00794    ao2_ref(event, +1);
00795 
00796    ast_channel_lock(chan);
00797    res = ast_channel_datastore_add(chan, datastore);
00798    ast_channel_unlock(chan);
00799 
00800    if (!(tmpstr = ast_str_create(32))) {
00801       goto notify_cleanup;
00802    }
00803 
00804    for (itervar = event->owner->vars; itervar; itervar = itervar->next) {
00805       ast_str_substitute_variables(&tmpstr, 0, chan, itervar->value);
00806       pbx_builtin_setvar_helper(chan, itervar->name, ast_str_buffer(tmpstr));
00807    }
00808 
00809    if (!(apptext = ast_str_create(32))) {
00810       goto notify_cleanup;
00811    }
00812 
00813    if (!ast_strlen_zero(event->owner->notify_app)) {
00814       ast_str_set(&apptext, 0, "%s,%s", event->owner->notify_app, event->owner->notify_appdata);
00815       ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, ast_str_buffer(apptext));
00816    } else {
00817    }
00818 
00819    ast_verb(3, "Dialing %s for notification on calendar %s\n", event->owner->notify_channel, event->owner->name);
00820    res = ast_dial_run(dial, chan, 0);
00821 
00822    if (res != AST_DIAL_RESULT_ANSWERED) {
00823       ast_verb(3, "Notification call for %s was not completed\n", event->owner->name);
00824    } else {
00825       struct ast_channel *answered;
00826 
00827       answered = ast_dial_answered_steal(dial);
00828       if (ast_strlen_zero(event->owner->notify_app)) {
00829          ast_channel_context_set(answered, event->owner->notify_context);
00830          ast_channel_exten_set(answered, event->owner->notify_extension);
00831          ast_channel_priority_set(answered, 1);
00832          ast_pbx_run(answered);
00833       }
00834    }
00835 
00836 notify_cleanup:
00837    if (apptext) {
00838       ast_free(apptext);
00839    }
00840    if (tmpstr) {
00841       ast_free(tmpstr);
00842    }
00843    if (dial) {
00844       ast_dial_destroy(dial);
00845    }
00846    if (chan) {
00847       ast_channel_release(chan);
00848    }
00849 
00850    event = ast_calendar_unref_event(event);
00851 
00852    return NULL;
00853 }

static void* do_refresh ( void *  data  )  [static]

Definition at line 1802 of file res_calendar.c.

References ast_cond_timedwait, ast_mutex_lock, ast_mutex_unlock, ast_sched_runq(), ast_sched_wait(), ast_tvnow(), and NULL.

01803 {
01804    for (;;) {
01805       struct timeval now = ast_tvnow();
01806       struct timespec ts = {0,};
01807       int wait;
01808 
01809       ast_mutex_lock(&refreshlock);
01810 
01811       while (!module_unloading) {
01812          if ((wait = ast_sched_wait(sched)) < 0) {
01813             wait = 1000;
01814          }
01815 
01816          ts.tv_sec = (now.tv_sec + wait / 1000) + 1;
01817          if (ast_cond_timedwait(&refresh_condition, &refreshlock, &ts) == ETIMEDOUT) {
01818             break;
01819          }
01820       }
01821       ast_mutex_unlock(&refreshlock);
01822 
01823       if (module_unloading) {
01824          break;
01825       }
01826       ast_sched_runq(sched);
01827    }
01828 
01829    return NULL;
01830 }

static char* epoch_to_string ( char *  buf,
size_t  buflen,
time_t  epoch 
) [static]

Definition at line 1574 of file res_calendar.c.

References ast_localtime(), ast_strftime(), and NULL.

Referenced by handle_show_calendar().

01575 {
01576    struct ast_tm tm;
01577    struct timeval tv = {
01578       .tv_sec = epoch,
01579    };
01580 
01581    if (!epoch) {
01582       *buf = '\0';
01583       return buf;
01584    }
01585    ast_localtime(&tv, &tm, NULL);
01586    ast_strftime(buf, buflen, "%F %r %z", &tm);
01587 
01588    return buf;
01589 }

static int event_cmp_fn ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 309 of file res_calendar.c.

References CMP_MATCH, CMP_STOP, and ast_calendar_event::uid.

Referenced by ast_calendar_event_container_alloc(), and build_calendar().

00310 {
00311    const struct ast_calendar_event *one = obj, *two = arg;
00312    return !strcmp(one->uid, two->uid) ? CMP_MATCH | CMP_STOP : 0;
00313 }

static int event_hash_fn ( const void *  obj,
const int  flags 
) [static]

Definition at line 303 of file res_calendar.c.

References ast_str_hash().

Referenced by ast_calendar_event_container_alloc(), and build_calendar().

00304 {
00305    const struct ast_calendar_event *event = obj;
00306    return ast_str_hash(event->uid);
00307 }

static void event_notification_destroy ( void *  data  )  [static]

Definition at line 682 of file res_calendar.c.

References ast_calendar_unref_event().

00683 {
00684    struct ast_calendar_event *event = data;
00685 
00686    event = ast_calendar_unref_event(event);
00687 
00688 }

static void * event_notification_duplicate ( void *  data  )  [static]

Definition at line 690 of file res_calendar.c.

References ao2_ref, and NULL.

00691 {
00692    struct ast_calendar_event *event = data;
00693 
00694    if (!event) {
00695       return NULL;
00696    }
00697 
00698    ao2_ref(event, +1);
00699 
00700    return event;
00701 }

static void eventlist_destroy ( void *  data  )  [static]

Definition at line 1180 of file res_calendar.c.

References ao2_ref, and events.

01181 {
01182    struct eventlist *events = data;
01183 
01184    ao2_ref(events, -1);
01185 }

static void eventlist_destructor ( void *  obj  )  [static]

Definition at line 352 of file res_calendar.c.

References ao2_ref, ast_free, AST_LIST_REMOVE_HEAD, evententry::event, events, and evententry::list.

Referenced by calendar_query_exec().

00353 {
00354    struct eventlist *events = obj;
00355    struct evententry *entry;
00356 
00357    while ((entry = AST_LIST_REMOVE_HEAD(events, list))) {
00358       ao2_ref(entry->event, -1);
00359       ast_free(entry);
00360    }
00361 }

static void * eventlist_duplicate ( void *  data  )  [static]

Definition at line 1187 of file res_calendar.c.

References ao2_ref, events, and NULL.

01188 {
01189    struct eventlist *events = data;
01190 
01191    if (!events) {
01192       return NULL;
01193    }
01194 
01195    ao2_ref(events, +1);
01196 
01197    return events;
01198 }

static struct ast_calendar* find_calendar ( const char *  name  )  [static, read]

Definition at line 295 of file res_calendar.c.

References ao2_find, ast_calendar::name, and OBJ_POINTER.

Referenced by build_calendar(), calendar_busy_exec(), calendar_query_exec(), calendar_write_exec(), calendarstate(), and handle_show_calendar().

00296 {
00297    struct ast_calendar tmp = {
00298       .name = name,
00299    };
00300    return ao2_find(calendars, &tmp, OBJ_POINTER);
00301 }

static struct ast_calendar_event* find_event ( struct ao2_container events,
const char *  uid 
) [static, read]

Definition at line 315 of file res_calendar.c.

References ao2_find, OBJ_POINTER, and ast_calendar_event::uid.

Referenced by merge_events_cb().

00316 {
00317    struct ast_calendar_event tmp = {
00318       .uid = uid,
00319    };
00320    return ao2_find(events, &tmp, OBJ_POINTER);
00321 }

static char* generate_random_string ( char *  buf,
size_t  size 
) [static]

Generate 32 byte random string (stolen from chan_sip.c).

Definition at line 704 of file res_calendar.c.

References ast_random().

00705 {
00706    unsigned long val[4];
00707    int x;
00708 
00709    for (x = 0; x < 4; x++) {
00710       val[x] = ast_random();
00711    }
00712    snprintf(buf, size, "%08lx%08lx%08lx%08lx", val[0], val[1], val[2], val[3]);
00713 
00714    return buf;
00715 }

static char* handle_dump_sched ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1671 of file res_calendar.c.

References ast_sched_dump(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, NULL, and ast_cli_entry::usage.

01672 {
01673    switch(cmd) {
01674    case CLI_INIT:
01675       e->command = "calendar dump sched";
01676       e->usage =
01677          "Usage: calendar dump sched\n"
01678          "       Dump the calendar sched context";
01679       return NULL;
01680 
01681    case CLI_GENERATE:
01682       return NULL;
01683    }
01684 
01685    ast_sched_dump(sched);
01686 
01687    return CLI_SUCCESS;
01688 }

static char* handle_show_calendar ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1591 of file res_calendar.c.

References ast_calendar_event::alarm, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_cli_args::argc, ast_cli_args::argv, ast_calendar_unref_event(), ast_cli(), ast_strdup, ast_calendar::autoreminder, buf, ast_calendar_event::categories, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_calendar_event::description, ast_calendar_event::end, epoch_to_string(), ast_calendar::events, ast_cli_args::fd, find_calendar(), FORMAT, FORMAT2, ast_calendar_event::location, ast_cli_args::n, ast_calendar::name, ast_calendar::notify_app, ast_calendar::notify_appdata, ast_calendar::notify_channel, ast_calendar::notify_context, ast_calendar::notify_extension, NULL, ast_calendar_event::organizer, ast_cli_args::pos, ast_calendar_event::priority, ast_calendar::refresh, ast_calendar_event::start, ast_calendar_event::summary, ast_calendar::timeframe, ast_calendar_event::uid, unref_calendar(), ast_cli_entry::usage, and ast_cli_args::word.

01592 {
01593 #define FORMAT "%-17.17s : %-20.20s\n"
01594 #define FORMAT2 "%-12.12s: %-40.60s\n"
01595    struct ao2_iterator i;
01596    struct ast_calendar *cal;
01597    struct ast_calendar_event *event;
01598    int which = 0;
01599    char *ret = NULL;
01600 
01601    switch(cmd) {
01602    case CLI_INIT:
01603       e->command = "calendar show calendar";
01604       e->usage =
01605          "Usage: calendar show calendar <calendar name>\n"
01606          "       Displays information about a calendar\n";
01607       return NULL;
01608 
01609    case CLI_GENERATE:
01610       if (a->pos != 3) {
01611          return NULL;
01612       }
01613       i = ao2_iterator_init(calendars, 0);
01614       while ((cal = ao2_iterator_next(&i))) {
01615          if (!strncasecmp(a->word, cal->name, strlen(a->word)) && ++which > a->n) {
01616             ret = ast_strdup(cal->name);
01617             cal = unref_calendar(cal);
01618             break;
01619          }
01620          cal = unref_calendar(cal);
01621       }
01622       ao2_iterator_destroy(&i);
01623       return ret;
01624    }
01625 
01626    if (a->argc != 4) {
01627       return CLI_SHOWUSAGE;
01628    }
01629 
01630    if (!(cal = find_calendar(a->argv[3]))) {
01631       return NULL;
01632    }
01633 
01634    ast_cli(a->fd, FORMAT, "Name", cal->name);
01635    ast_cli(a->fd, FORMAT, "Notify channel", cal->notify_channel);
01636    ast_cli(a->fd, FORMAT, "Notify context", cal->notify_context);
01637    ast_cli(a->fd, FORMAT, "Notify extension", cal->notify_extension);
01638    ast_cli(a->fd, FORMAT, "Notify application", cal->notify_app);
01639    ast_cli(a->fd, FORMAT, "Notify appdata", cal->notify_appdata);
01640    ast_cli(a->fd, "%-17.17s : %d\n", "Refresh time", cal->refresh);
01641    ast_cli(a->fd, "%-17.17s : %d\n", "Timeframe", cal->timeframe);
01642    ast_cli(a->fd, "%-17.17s : %d\n", "Autoreminder", cal->autoreminder);
01643    ast_cli(a->fd, "%s\n", "Events");
01644    ast_cli(a->fd, "%s\n", "------");
01645 
01646    i = ao2_iterator_init(cal->events, 0);
01647    while ((event = ao2_iterator_next(&i))) {
01648       char buf[100];
01649 
01650       ast_cli(a->fd, FORMAT2, "Summary", event->summary);
01651       ast_cli(a->fd, FORMAT2, "Description", event->description);
01652       ast_cli(a->fd, FORMAT2, "Organizer", event->organizer);
01653       ast_cli(a->fd, FORMAT2, "Location", event->location);
01654       ast_cli(a->fd, FORMAT2, "Categories", event->categories);
01655       ast_cli(a->fd, "%-12.12s: %d\n", "Priority", event->priority);
01656       ast_cli(a->fd, FORMAT2, "UID", event->uid);
01657       ast_cli(a->fd, FORMAT2, "Start", epoch_to_string(buf, sizeof(buf), event->start));
01658       ast_cli(a->fd, FORMAT2, "End", epoch_to_string(buf, sizeof(buf), event->end));
01659       ast_cli(a->fd, FORMAT2, "Alarm", epoch_to_string(buf, sizeof(buf), event->alarm));
01660       ast_cli(a->fd, "\n");
01661 
01662       event = ast_calendar_unref_event(event);
01663    }
01664    ao2_iterator_destroy(&i);
01665    cal = unref_calendar(cal);
01666    return CLI_SUCCESS;
01667 #undef FORMAT
01668 #undef FORMAT2
01669 }

static char* handle_show_calendars ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI command to list available calendars.

Definition at line 1515 of file res_calendar.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_cli(), calendar_is_busy(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, FORMAT, ast_calendar::name, NULL, ast_calendar::tech, ast_calendar_tech::type, unref_calendar(), and ast_cli_entry::usage.

01516 {
01517 #define FORMAT "%-20.20s %-10.10s %-6.6s\n"
01518    struct ao2_iterator i;
01519    struct ast_calendar *cal;
01520 
01521    switch(cmd) {
01522    case CLI_INIT:
01523       e->command = "calendar show calendars";
01524       e->usage =
01525          "Usage: calendar show calendars\n"
01526          "       Lists all registered calendars.\n";
01527       return NULL;
01528    case CLI_GENERATE:
01529       return NULL;
01530    }
01531 
01532    ast_cli(a->fd, FORMAT, "Calendar", "Type", "Status");
01533    ast_cli(a->fd, FORMAT, "--------", "----", "------");
01534    i = ao2_iterator_init(calendars, 0);
01535    while ((cal = ao2_iterator_next(&i))) {
01536       ast_cli(a->fd, FORMAT, cal->name, cal->tech->type, calendar_is_busy(cal) ? "busy" : "free");
01537       cal = unref_calendar(cal);
01538    }
01539    ao2_iterator_destroy(&i);
01540 
01541    return CLI_SUCCESS;
01542 #undef FORMAT
01543 }

static char* handle_show_calendars_types ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

CLI command to list of all calendars types currently loaded on the backend.

Definition at line 1546 of file res_calendar.c.

References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_calendar_tech::description, ast_cli_args::fd, FORMAT, evententry::list, NULL, ast_calendar_tech::type, and ast_cli_entry::usage.

01547 {
01548 #define FORMAT "%-10.10s %-30.30s\n"
01549         struct ast_calendar_tech *iter;
01550 
01551 
01552    switch(cmd) {
01553    case CLI_INIT:
01554       e->command = "calendar show types";
01555       e->usage =
01556          "Usage: calendar show types\n"
01557          "       Lists all registered calendars types.\n";
01558       return NULL;
01559    case CLI_GENERATE:
01560       return NULL;
01561    }
01562 
01563    ast_cli(a->fd, FORMAT, "Type", "Description");
01564    AST_LIST_LOCK(&techs);
01565    AST_LIST_TRAVERSE(&techs, iter, list) {
01566       ast_cli(a->fd, FORMAT, iter->type, iter->description);
01567    }
01568    AST_LIST_UNLOCK(&techs);
01569 
01570    return CLI_SUCCESS;
01571 #undef FORMAT
01572 }

static int load_config ( int  reload  )  [static]

Definition at line 1052 of file res_calendar.c.

References ast_config_destroy(), ast_config_load2(), ast_log, ast_rwlock_unlock, ast_rwlock_wrlock, calendar_config, CONFIG_FLAG_FILEUNCHANGED, config_lock, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, and LOG_ERROR.

01053 {
01054    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01055    struct ast_config *tmpcfg;
01056 
01057    if (!(tmpcfg = ast_config_load2("calendar.conf", "calendar", config_flags)) ||
01058       tmpcfg == CONFIG_STATUS_FILEINVALID) {
01059       ast_log(LOG_ERROR, "Unable to load config calendar.conf\n");
01060       return -1;
01061    }
01062 
01063    if (tmpcfg == CONFIG_STATUS_FILEUNCHANGED) {
01064       return 0;
01065    }
01066 
01067    ast_rwlock_wrlock(&config_lock);
01068    if (calendar_config) {
01069       ast_config_destroy(calendar_config);
01070    }
01071 
01072    calendar_config = tmpcfg;
01073    ast_rwlock_unlock(&config_lock);
01074 
01075    return 0;
01076 }

static int load_module ( void   )  [static]

Load the module.

Module loading including tests for configuration or dependencies. This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails tests return AST_MODULE_LOAD_FAILURE. If the module can not load the configuration file or other non-critical problem return AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.

Definition at line 1879 of file res_calendar.c.

References ao2_container_alloc, ARRAY_LEN, ast_cli_register_multiple(), ast_cond_init, ast_custom_function_register, ast_devstate_prov_add(), ast_log, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_mutex_init, ast_pthread_create_background, ast_sched_context_create(), CALENDAR_BUCKETS, calendar_busy_function, calendar_cli, calendar_cmp_fn(), calendar_event_function, calendar_hash_fn(), calendar_query_function, calendar_query_result_function, calendar_write_function, calendarstate(), do_refresh(), load_config(), LOG_ERROR, and NULL.

01880 {
01881    if (!(calendars = ao2_container_alloc(CALENDAR_BUCKETS, calendar_hash_fn, calendar_cmp_fn))) {
01882       ast_log(LOG_ERROR, "Unable to allocate calendars container!\n");
01883       return AST_MODULE_LOAD_FAILURE;
01884    }
01885 
01886    if (load_config(0)) {
01887       /* We don't have calendar support enabled */
01888       return AST_MODULE_LOAD_DECLINE;
01889    }
01890 
01891    ast_mutex_init(&refreshlock);
01892    ast_cond_init(&refresh_condition, NULL);
01893    ast_mutex_init(&reloadlock);
01894 
01895    if (!(sched = ast_sched_context_create())) {
01896       ast_log(LOG_ERROR, "Unable to create sched context\n");
01897       return AST_MODULE_LOAD_FAILURE;
01898    }
01899 
01900    if (ast_pthread_create_background(&refresh_thread, NULL, do_refresh, NULL) < 0) {
01901       ast_log(LOG_ERROR, "Unable to start refresh thread--notifications disabled!\n");
01902    }
01903 
01904    ast_custom_function_register(&calendar_busy_function);
01905    ast_custom_function_register(&calendar_event_function);
01906    ast_custom_function_register(&calendar_query_function);
01907    ast_custom_function_register(&calendar_query_result_function);
01908    ast_custom_function_register(&calendar_write_function);
01909    ast_cli_register_multiple(calendar_cli, ARRAY_LEN(calendar_cli));
01910 
01911    ast_devstate_prov_add("Calendar", calendarstate);
01912 
01913    return AST_MODULE_LOAD_SUCCESS;
01914 }

static int load_tech_calendars ( struct ast_calendar_tech tech  )  [static]

Definition at line 501 of file res_calendar.c.

References ast_calendar_unregister(), ast_category_browse(), ast_log, ast_rwlock_unlock, ast_rwlock_wrlock, ast_variable_retrieve(), build_calendar(), calendar_config, config_lock, LOG_WARNING, NULL, ast_calendar_tech::type, and unref_calendar().

Referenced by ast_calendar_register(), and reload().

00502 {
00503    struct ast_calendar *cal;
00504    const char *cat = NULL;
00505    const char *val;
00506 
00507    if (!calendar_config) {
00508       ast_log(LOG_WARNING, "Calendar support disabled, not loading %s calendar module\n", tech->type);
00509       return -1;
00510    }
00511 
00512    ast_rwlock_wrlock(&config_lock);
00513    while ((cat = ast_category_browse(calendar_config, cat))) {
00514       if (!strcasecmp(cat, "general")) {
00515          continue;
00516       }
00517 
00518       if (!(val = ast_variable_retrieve(calendar_config, cat, "type")) || strcasecmp(val, tech->type)) {
00519          continue;
00520       }
00521 
00522       /* A serious error occurred loading calendars from this tech and it should be disabled */
00523       if (!(cal = build_calendar(calendar_config, cat, tech))) {
00524          ast_calendar_unregister(tech);
00525          ast_rwlock_unlock(&config_lock);
00526          return -1;
00527       }
00528 
00529       cal = unref_calendar(cal);
00530    }
00531 
00532    ast_rwlock_unlock(&config_lock);
00533 
00534    return 0;
00535 }

static int match_caltech_cb ( void *  user_data,
void *  arg,
int  flags 
) [static]

Definition at line 563 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::tech.

Referenced by ast_calendar_unregister().

00564 {
00565    struct ast_calendar *cal = user_data;
00566    struct ast_calendar_tech *tech = arg;
00567 
00568    if (cal->tech == tech) {
00569       return CMP_MATCH;
00570    }
00571 
00572    return 0;
00573 }

static int merge_events_cb ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1003 of file res_calendar.c.

References ao2_unlink, ast_calendar_unref_event(), CMP_MATCH, copy_event_data(), destroy_event(), find_event(), ast_calendar_event::owner, schedule_calendar_event(), and ast_calendar_event::uid.

Referenced by ast_calendar_merge_events().

01004 {
01005    struct ast_calendar_event *old_event = obj, *new_event;
01006    struct ao2_container *new_events = arg;
01007 
01008    /* If we don't find the old_event in new_events, then we can safely delete the old_event */
01009    if (!(new_event = find_event(new_events, old_event->uid))) {
01010       old_event = destroy_event(old_event);
01011       return CMP_MATCH;
01012    }
01013 
01014    /* We have events to merge.  If any data that will affect a scheduler event has changed,
01015     * then we need to replace the scheduler event */
01016    schedule_calendar_event(old_event->owner, old_event, new_event);
01017 
01018    /* Since we don't want to mess with cancelling sched events and adding new ones, just
01019     * copy the internals of the new_event to the old_event */
01020    copy_event_data(old_event, new_event);
01021 
01022    /* Now we can go ahead and unlink the new_event from new_events and unref it so that only completely
01023     * new events remain in the container */
01024    ao2_unlink(new_events, new_event);
01025    new_event = ast_calendar_unref_event(new_event);
01026 
01027    return 0;
01028 }

static int null_chan_write ( struct ast_channel chan,
struct ast_frame frame 
) [static]

Definition at line 717 of file res_calendar.c.

00718 {
00719    return 0;
00720 }

static int reload ( void   )  [static]

Definition at line 1776 of file res_calendar.c.

References ao2_callback, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_mutex_lock, ast_mutex_unlock, cb_pending_deletion(), cb_rm_pending_deletion(), evententry::list, load_config(), load_tech_calendars(), LOG_WARNING, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, and ast_calendar_tech::type.

01777 {
01778    struct ast_calendar_tech *iter;
01779 
01780    ast_mutex_lock(&reloadlock);
01781 
01782    /* Mark existing calendars for deletion */
01783    ao2_callback(calendars, OBJ_NODATA | OBJ_MULTIPLE, cb_pending_deletion, NULL);
01784    load_config(1);
01785 
01786    AST_LIST_LOCK(&techs);
01787    AST_LIST_TRAVERSE(&techs, iter, list) {
01788       if (load_tech_calendars(iter)) {
01789          ast_log(LOG_WARNING, "Failed to reload %s calendars, module disabled\n", iter->type);
01790       }
01791    }
01792    AST_LIST_UNLOCK(&techs);
01793 
01794    /* Delete calendars that no longer show up in the config */
01795    ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, cb_rm_pending_deletion, NULL);
01796 
01797    ast_mutex_unlock(&reloadlock);
01798 
01799    return 0;
01800 }

static int schedule_calendar_event ( struct ast_calendar cal,
struct ast_calendar_event old_event,
struct ast_calendar_event cmp_event 
) [static]

Definition at line 941 of file res_calendar.c.

References ast_calendar_event::alarm, ao2_lock, ao2_unlock, ast_cond_signal, ast_debug, ast_mutex_lock, ast_mutex_unlock, AST_SCHED_REPLACE, ast_tvnow(), ast_calendar::autoreminder, ast_calendar_event::bs_end_sched, ast_calendar_event::bs_start_sched, calendar_devstate_change(), calendar_event_notify(), ast_calendar_event::end, ast_calendar_event::notify_sched, and ast_calendar_event::start.

Referenced by add_new_event_cb(), and merge_events_cb().

00942 {
00943    struct timeval now = ast_tvnow();
00944    struct ast_calendar_event *event;
00945    time_t alarm_notify_sched = 0, devstate_sched_start, devstate_sched_end;
00946    int changed = 0;
00947 
00948    event = cmp_event ? cmp_event : old_event;
00949 
00950    ao2_lock(event);
00951    if (!cmp_event || old_event->alarm != event->alarm) {
00952       changed = 1;
00953       if (cal->autoreminder) {
00954          alarm_notify_sched = (event->start - (60 * cal->autoreminder) - now.tv_sec) * 1000;
00955       } else if (event->alarm) {
00956          alarm_notify_sched = (event->alarm - now.tv_sec) * 1000;
00957       }
00958 
00959       /* For now, send the notification if we missed it, but the meeting hasn't happened yet */
00960       if (event->start >=  now.tv_sec) {
00961          if (alarm_notify_sched <= 0) {
00962             alarm_notify_sched = 1;
00963          }
00964          ast_mutex_lock(&refreshlock);
00965          AST_SCHED_REPLACE(old_event->notify_sched, sched, alarm_notify_sched, calendar_event_notify, old_event);
00966          ast_mutex_unlock(&refreshlock);
00967          ast_debug(3, "Calendar alarm event notification scheduled to happen in %ld ms\n", (long) alarm_notify_sched);
00968       }
00969    }
00970 
00971    if (!cmp_event || old_event->start != event->start) {
00972       changed = 1;
00973       devstate_sched_start = (event->start - now.tv_sec) * 1000;
00974 
00975       if (devstate_sched_start < 1) {
00976          devstate_sched_start = 1;
00977       }
00978 
00979       ast_mutex_lock(&refreshlock);
00980       AST_SCHED_REPLACE(old_event->bs_start_sched, sched, devstate_sched_start, calendar_devstate_change, old_event);
00981       ast_mutex_unlock(&refreshlock);
00982       ast_debug(3, "Calendar bs_start event notification scheduled to happen in %ld ms\n", (long) devstate_sched_start);
00983    }
00984 
00985    if (!cmp_event || old_event->end != event->end) {
00986       changed = 1;
00987       devstate_sched_end = (event->end - now.tv_sec) * 1000;
00988       ast_mutex_lock(&refreshlock);
00989       AST_SCHED_REPLACE(old_event->bs_end_sched, sched, devstate_sched_end, calendar_devstate_change, old_event);
00990       ast_mutex_unlock(&refreshlock);
00991       ast_debug(3, "Calendar bs_end event notification scheduled to happen in %ld ms\n", (long) devstate_sched_end);
00992    }
00993 
00994    if (changed) {
00995       ast_cond_signal(&refresh_condition);
00996    }
00997 
00998    ao2_unlock(event);
00999 
01000    return 0;
01001 }

static int unload_module ( void   )  [static]

Definition at line 1833 of file res_calendar.c.

References ao2_callback, ao2_cleanup, ARRAY_LEN, ast_cli_unregister_multiple(), ast_cond_signal, ast_config_destroy(), ast_custom_function_unregister(), ast_devstate_prov_del(), AST_LIST_LOCK, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_unload_resource(), calendar_busy_function, calendar_cli, calendar_config, calendar_event_function, calendar_query_function, calendar_query_result_function, calendar_write_function, evententry::list, ast_calendar_tech::module, NULL, OBJ_MULTIPLE, OBJ_NODATA, and OBJ_UNLINK.

static struct ast_calendar* unref_calendar ( struct ast_calendar cal  )  [static, read]

Definition at line 277 of file res_calendar.c.

References ao2_ref, and NULL.

Referenced by build_calendar(), calendar_busy_exec(), calendar_query_exec(), calendar_write_exec(), calendarstate(), handle_show_calendar(), handle_show_calendars(), and load_tech_calendars().

00278 {
00279    ao2_ref(cal, -1);
00280    return NULL;
00281 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER , .description = "Asterisk 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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, } [static]

Definition at line 1921 of file res_calendar.c.

Definition at line 1921 of file res_calendar.c.

Initial value:

 {
    .name = "CALENDAR_BUSY",
    .read = calendar_busy_exec,
}

Definition at line 1101 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ast_cli_entry calendar_cli[] [static]

Definition at line 1690 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ast_config* calendar_config [static]

Initial value:

 {
   .name = "CALENDAR_EVENT",
   .read = calendar_event_read,
}

Definition at line 1755 of file res_calendar.c.

Referenced by load_module(), and unload_module().

Initial value:

 {
    .name = "CALENDAR_QUERY",
    .read = calendar_query_exec,
}

Definition at line 1286 of file res_calendar.c.

Referenced by load_module(), and unload_module().

Initial value:

 {
   .name = "CALENDAR_QUERY_RESULT",
   .read = calendar_query_result_exec,
}

Definition at line 1397 of file res_calendar.c.

Referenced by load_module(), and unload_module().

Initial value:

 {
   .name = "CALENDAR_WRITE",
   .write = calendar_write_exec,
}

Definition at line 1509 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ao2_container* calendars [static]

Definition at line 224 of file res_calendar.c.

ast_rwlock_t config_lock = { {0} , NULL, 1 } [static]

Definition at line 258 of file res_calendar.c.

Initial value:

 {
   .type = "EventNotification",
   .destroy = event_notification_destroy,
   .duplicate = event_notification_duplicate,
}

Definition at line 237 of file res_calendar.c.

Initial value:

 {
   .type = "CalendarEventList",
   .destroy = eventlist_destroy,
   .duplicate = eventlist_duplicate,
}

Definition at line 243 of file res_calendar.c.

int module_unloading [static]

Definition at line 230 of file res_calendar.c.

struct ast_channel_tech null_tech [static]

Initial value:

 {
        .type = "NULL",
        .description = "Null channel (should not see this)",
      .write = null_chan_write,
}

Definition at line 722 of file res_calendar.c.

Definition at line 228 of file res_calendar.c.

pthread_t refresh_thread = AST_PTHREADT_NULL [static]

Definition at line 226 of file res_calendar.c.

Definition at line 229 of file res_calendar.c.

struct ast_sched_context* sched [static]

Definition at line 225 of file res_calendar.c.


Generated on Thu Apr 16 06:32:41 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6