Sat Mar 10 01:55:39 2012

Asterisk developer's documentation


res_calendar.c File Reference

Calendaring API. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/calendar.h"
#include "asterisk/utils.h"
#include "asterisk/astobj2.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/channel.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"

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   "%-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.
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.
ast_calendar_eventast_calendar_event_alloc (struct ast_calendar *cal)
 Allocate an astobj2 ast_calendar_event object.
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.
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 int load_config (void *data)
static int load_module (void)
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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 }
static struct ast_datastore_info event_notification_datastore
static struct ast_datastore_info eventlist_datastore_info
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 sched_contextsched


Detailed Description

Calendaring API.

Todo:
Support responding to a meeting invite

Support writing attendees

Definition in file res_calendar.c.


Define Documentation

#define CALENDAR_BUCKETS   19

Definition at line 199 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   "%-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 1760 of file res_calendar.c.

static void __unreg_module ( void   )  [static]

Definition at line 1760 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 1016 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, events, evententry::list, LOG_ERROR, ast_calendar_event::start, ast_calendar_event::summary, and ast_calendar_event::uid.

Referenced by calendar_query_exec().

01017 {
01018    struct evententry *entry, *iter;
01019    int event_startdiff = abs(start - event->start);
01020    int event_enddiff = abs(end - event->end);
01021    int i = 0;
01022 
01023    if (!(entry = ast_calloc(1, sizeof(*entry)))) {
01024       ast_log(LOG_ERROR, "Unable to allocate memory for event list\n");
01025       return -1;
01026    }
01027 
01028    entry->event = event;
01029    ao2_ref(event, +1);
01030 
01031    if (start == end) {
01032       AST_LIST_TRAVERSE_SAFE_BEGIN(events, iter, list) {
01033          int startdiff = abs(iter->event->start - start);
01034 
01035          ast_debug(10, "Comparing %s with startdiff %d to %s with startdiff %d\n", event->summary, event_startdiff, iter->event->summary, startdiff);
01036          ++i;
01037          if (startdiff > event_startdiff) {
01038             AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01039             return i;
01040          }
01041          if (startdiff == event_startdiff) {
01042             int enddiff = abs(iter->event->end - end);
01043 
01044             if (enddiff > event_enddiff) {
01045                AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01046                return i;
01047             }
01048             if (event_startdiff == enddiff) {
01049                if (strcmp(event->uid, iter->event->uid) < 0) {
01050                   AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01051                   return i;
01052                }
01053             }
01054          }
01055       }
01056       AST_LIST_TRAVERSE_SAFE_END;
01057 
01058       AST_LIST_INSERT_TAIL(events, entry, list);
01059 
01060       return i;
01061    }
01062 
01063    AST_LIST_TRAVERSE_SAFE_BEGIN(events, iter, list) {
01064       ++i;
01065       if (iter->event->start > event->start) {
01066          AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01067          return i;
01068       }
01069 
01070       if (iter->event->start == event->start) {
01071          if ((iter->event->end - iter->event->start) == (event->end - event->start)) {
01072             if (strcmp(event->uid, iter->event->uid) < 0) {
01073                AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01074                return i;
01075             }
01076          }
01077          if ((iter->event->end - iter->event->start) < (event->end - event->start)) {
01078             AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01079             return i;
01080          }
01081       }
01082    }
01083    AST_LIST_TRAVERSE_SAFE_END;
01084 
01085    AST_LIST_INSERT_TAIL(events, entry, list);
01086 
01087    return i;
01088 }

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

Definition at line 941 of file res_calendar.c.

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

Referenced by ast_calendar_merge_events().

00942 {
00943    struct ast_calendar_event *new_event = obj;
00944    struct ao2_container *events = arg;
00945 
00946    ao2_link(events, new_event);
00947    schedule_calendar_event(new_event->owner, new_event, NULL);
00948    return CMP_MATCH;
00949 }

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 589 of file res_calendar.c.

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

Referenced by calendar_destructor().

00590 {
00591    ast_debug(3, "Clearing all events for calendar %s\n", cal->name);
00592 
00593    ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, clear_events_cb, NULL);
00594 }

struct ast_config* ast_calendar_config_acquire ( void   ) 

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 236 of file res_calendar.c.

References ast_rwlock_rdlock, and ast_rwlock_unlock.

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

00237 {
00238    ast_rwlock_rdlock(&config_lock);
00239 
00240    if (!calendar_config) {
00241       ast_rwlock_unlock(&config_lock);
00242       return NULL;
00243    }
00244 
00245    return calendar_config;
00246 }

void ast_calendar_config_release ( void   ) 

Release the calendar config.

Definition at line 248 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().

00249 {
00250    ast_rwlock_unlock(&config_lock);
00251 }

struct ast_calendar_event* ast_calendar_event_alloc ( struct ast_calendar cal  ) 

Allocate an astobj2 ast_calendar_event object.

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

Definition at line 596 of file res_calendar.c.

References ao2_alloc, ast_calendar_unref_event(), AST_LIST_HEAD_INIT_NOLOCK, ast_string_field_init, and calendar_event_destructor().

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

00597 {
00598    struct ast_calendar_event *event;
00599    if (!(event = ao2_alloc(sizeof(*event), calendar_event_destructor))) {
00600       return NULL;
00601    }
00602 
00603    if (ast_string_field_init(event, 32)) {
00604       event = ast_calendar_unref_event(event);
00605       return NULL;
00606    }
00607 
00608    event->owner = cal;
00609    event->notify_sched = -1;
00610    event->bs_start_sched = -1;
00611    event->bs_end_sched = -1;
00612 
00613    AST_LIST_HEAD_INIT_NOLOCK(&event->attendees);
00614 
00615    return event;
00616 }

struct ao2_container* ast_calendar_event_container_alloc ( void   ) 

Allocate an astobj2 container for ast_calendar_event objects.

Returns:
a new event container

Definition at line 618 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 951 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().

00952 {
00953    /* Loop through all events attached to the calendar.  If there is a matching new event
00954     * merge its data over and handle any schedule changes that need to be made.  Then remove
00955     * the new_event from new_events so that we are left with only new_events that we can add later. */
00956    ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, merge_events_cb, new_events);
00957 
00958    /* Now, we should only have completely new events in new_events.  Loop through and add them */
00959    ao2_callback(new_events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, add_new_event_cb, cal->events);
00960 }

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 485 of file res_calendar.c.

References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_verb, ast_calendar_tech::description, ast_calendar_tech::list, load_tech_calendars(), LOG_WARNING, and ast_calendar_tech::type.

Referenced by load_module().

00486 {
00487    struct ast_calendar_tech *iter;
00488 
00489    AST_LIST_LOCK(&techs);
00490    AST_LIST_TRAVERSE(&techs, iter, list) {
00491       if(!strcasecmp(tech->type, iter->type)) {
00492          ast_log(LOG_WARNING, "Already have a handler for calendar type '%s'\n", tech->type);
00493          AST_LIST_UNLOCK(&techs);
00494          return -1;
00495       }
00496    }
00497    AST_LIST_INSERT_HEAD(&techs, tech, list);
00498    AST_LIST_UNLOCK(&techs);
00499 
00500    ast_verb(2, "Registered calendar type '%s' (%s)\n", tech->type, tech->description);
00501 
00502    return load_tech_calendars(tech);
00503 }

struct ast_calendar_event* ast_calendar_unref_event ( struct ast_calendar_event event  ) 

Unreference an ast_calendar_event.

Parameters:
event event to unref
Returns:
NULL

Definition at line 299 of file res_calendar.c.

References ao2_ref, and evententry::event.

Referenced by ast_calendar_event_alloc(), caldav_add_event(), calendar_devstate_change(), calendar_query_exec(), do_notify(), endelm(), event_notification_destroy(), handle_show_calendar(), icalendar_add_event(), merge_events_cb(), and parse_tag().

00300 {
00301    ao2_ref(event, -1);
00302    return NULL;
00303 }

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 517 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_verb, ast_calendar_tech::list, match_caltech_cb(), OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, and ast_calendar_tech::type.

Referenced by load_tech_calendars(), and unload_module().

00518 {
00519    struct ast_calendar_tech *iter;
00520 
00521    AST_LIST_LOCK(&techs);
00522    AST_LIST_TRAVERSE_SAFE_BEGIN(&techs, iter, list) {
00523       if (iter != tech) {
00524          continue;
00525       }
00526 
00527       ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, match_caltech_cb, tech);
00528 
00529       AST_LIST_REMOVE_CURRENT(list);
00530       ast_verb(2, "Unregistered calendar type '%s'\n", tech->type);
00531       break;
00532    }
00533    AST_LIST_TRAVERSE_SAFE_END;
00534    AST_LIST_UNLOCK(&techs);
00535 
00536 }

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

Definition at line 373 of file res_calendar.c.

References ao2_alloc, ao2_container_alloc, ast_log(), ast_string_field_init, ast_string_field_set, ast_variable_browse(), ast_calendar::autoreminder, CALENDAR_BUCKETS, calendar_destructor(), event_cmp_fn(), event_hash_fn(), find_calendar(), LOG_ERROR, ast_variable::name, name, ast_variable::next, ast_calendar::notify_waittime, ast_calendar::pending_deletion, ast_calendar::refresh, ast_calendar::tech, ast_calendar::timeframe, unref_calendar(), and ast_variable::value.

Referenced by load_tech_calendars().

00374 {
00375    struct ast_calendar *cal;
00376    struct ast_variable *v;
00377    int new_calendar = 0;
00378 
00379    if (!(cal = find_calendar(cat))) {
00380       new_calendar = 1;
00381       if (!(cal = ao2_alloc(sizeof(*cal), calendar_destructor))) {
00382          ast_log(LOG_ERROR, "Could not allocate calendar structure. Stopping.\n");
00383          return NULL;
00384       }
00385 
00386       if (!(cal->events = ao2_container_alloc(CALENDAR_BUCKETS, event_hash_fn, event_cmp_fn))) {
00387          ast_log(LOG_ERROR, "Could not allocate events container for %s\n", cat);
00388          cal = unref_calendar(cal);
00389          return NULL;
00390       }
00391 
00392       if (ast_string_field_init(cal, 32)) {
00393          ast_log(LOG_ERROR, "Couldn't create string fields for %s\n", cat);
00394          cal = unref_calendar(cal);
00395          return NULL;
00396       }
00397    } else {
00398       cal->pending_deletion = 0;
00399    }
00400 
00401    ast_string_field_set(cal, name, cat);
00402    cal->tech = tech;
00403 
00404    cal->refresh = 3600;
00405    cal->timeframe = 60;
00406    cal->notify_waittime = 30000;
00407 
00408    for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
00409       if (!strcasecmp(v->name, "autoreminder")) {
00410          cal->autoreminder = atoi(v->value);
00411       } else if (!strcasecmp(v->name, "channel")) {
00412          ast_string_field_set(cal, notify_channel, v->value);
00413       } else if (!strcasecmp(v->name, "context")) {
00414          ast_string_field_set(cal, notify_context, v->value);
00415       } else if (!strcasecmp(v->name, "extension")) {
00416          ast_string_field_set(cal, notify_extension, v->value);
00417       } else if (!strcasecmp(v->name, "waittime")) {
00418          int i = atoi(v->value);
00419          if (i > 0) {
00420             cal->notify_waittime = 1000 * i;
00421          }
00422       } else if (!strcasecmp(v->name, "app")) {
00423          ast_string_field_set(cal, notify_app, v->value);
00424       } else if (!strcasecmp(v->name, "appdata")) {
00425          ast_string_field_set(cal, notify_appdata, v->value);
00426       } else if (!strcasecmp(v->name, "refresh")) {
00427          cal->refresh = atoi(v->value);
00428       } else if (!strcasecmp(v->name, "timeframe")) {
00429          cal->timeframe = atoi(v->value);
00430       }
00431    }
00432 
00433    if (new_calendar) {
00434       cal->thread = AST_PTHREADT_NULL;
00435       ast_cond_init(&cal->unload, NULL);
00436       ao2_link(calendars, cal);
00437       if (ast_pthread_create(&cal->thread, NULL, cal->tech->load_calendar, cal)) {
00438          /* If we start failing to create threads, go ahead and return NULL
00439           * and the tech module will be unregistered
00440           */ 
00441          ao2_unlink(calendars, cal);
00442          cal = unref_calendar(cal);
00443       }
00444    }
00445 
00446    return cal;
00447 }

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

Definition at line 335 of file res_calendar.c.

References AST_CALENDAR_BS_FREE, ast_tvnow(), ast_calendar_event::busy_state, CMP_STOP, ast_calendar_event::end, evententry::event, and ast_calendar_event::start.

Referenced by calendar_is_busy().

00336 {
00337    struct ast_calendar_event *event = obj;
00338    int *is_busy = arg;
00339    struct timeval tv = ast_tvnow();
00340 
00341    if (tv.tv_sec >= event->start && tv.tv_sec <= event->end && event->busy_state > AST_CALENDAR_BS_FREE) {
00342       *is_busy = 1;
00343       return CMP_STOP;
00344    }
00345 
00346    return 0;
00347 }

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 990 of file res_calendar.c.

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

00991 {
00992    struct ast_calendar *cal;
00993 
00994    if (ast_strlen_zero(data)) {
00995       ast_log(LOG_WARNING, "CALENDAR_BUSY requires an argument: CALENDAR_BUSY(<calendar_name>)\n");
00996       return -1;
00997    }
00998 
00999    cal = find_calendar(data);
01000 
01001    if (!cal) {
01002       ast_log(LOG_WARNING, "Could not find calendar '%s'\n", data);
01003       return -1;
01004    }
01005 
01006    strcpy(buf, calendar_is_busy(cal) ? "1" : "0");
01007 
01008    return 0;
01009 }

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

Definition at line 265 of file res_calendar.c.

References CMP_MATCH, CMP_STOP, and ast_calendar::name.

Referenced by load_module().

00266 {
00267    const struct ast_calendar *one = obj, *two = arg;
00268    return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP: 0;
00269 }

static void calendar_destructor ( void *  obj  )  [static]

Definition at line 305 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_calendar::events, ast_calendar::name, ast_calendar::tech, ast_calendar::tech_pvt, ast_calendar::thread, ast_calendar::unload, ast_calendar::unloading, and ast_calendar_tech::unref_calendar.

Referenced by build_calendar().

00306 {
00307    struct ast_calendar *cal = obj;
00308 
00309    ast_debug(3, "Destroying calendar %s\n", cal->name);
00310 
00311    ao2_lock(cal);
00312    cal->unloading = 1;
00313    ast_cond_signal(&cal->unload);
00314    pthread_join(cal->thread, NULL);
00315    if (cal->tech_pvt) {
00316       cal->tech_pvt = cal->tech->unref_calendar(cal->tech_pvt);
00317    }
00318    ast_calendar_clear_events(cal);
00319    ast_string_field_free_memory(cal);
00320    ao2_ref(cal->events, -1);
00321    ao2_unlock(cal);
00322 }

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

Definition at line 790 of file res_calendar.c.

References ao2_ref, ast_calendar_unref_event(), AST_DEVICE_BUSY, AST_DEVICE_NOT_INUSE, ast_devstate_changed(), ast_log(), ast_tvnow(), ast_calendar_event::bs_end_sched, ast_calendar_event::bs_start_sched, calendar_is_busy(), ast_calendar_event::end, LOG_WARNING, ast_calendar::name, and ast_calendar_event::owner.

Referenced by schedule_calendar_event().

00791 {
00792    struct ast_calendar_event *event = (struct ast_calendar_event *)data;
00793    struct timeval now = ast_tvnow();
00794    int is_end_event;
00795 
00796    if (!event) {
00797       ast_log(LOG_WARNING, "Event was NULL!\n");
00798       return 0;
00799    }
00800 
00801    ao2_ref(event, +1);
00802 
00803    is_end_event = event->end <= now.tv_sec;
00804 
00805    if (is_end_event) {
00806       event->bs_end_sched = -1;
00807    } else {
00808       event->bs_start_sched = -1;
00809    }
00810 
00811    /* We can have overlapping events, so ignore the event->busy_state and check busy state
00812     * based on all events in the calendar */
00813    if (!calendar_is_busy(event->owner)) {
00814       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Calendar:%s", event->owner->name);
00815    } else {
00816       ast_devstate_changed(AST_DEVICE_BUSY, "Calendar:%s", event->owner->name);
00817    }
00818 
00819    event = ast_calendar_unref_event(event);
00820 
00821    return 0;
00822 }

static void calendar_event_destructor ( void *  obj  )  [static]

Definition at line 538 of file res_calendar.c.

References ast_debug, ast_free, AST_LIST_REMOVE_HEAD, ast_string_field_free_memory, ast_calendar_event::attendees, ast_calendar_attendee::data, ast_calendar::name, ast_calendar_attendee::next, and ast_calendar_event::owner.

Referenced by ast_calendar_event_alloc().

00539 {
00540    struct ast_calendar_event *event = obj;
00541    struct ast_calendar_attendee *attendee;
00542 
00543    ast_debug(3, "Destroying event for calendar '%s'\n", event->owner->name);
00544    ast_string_field_free_memory(event);
00545    while ((attendee = AST_LIST_REMOVE_HEAD(&event->attendees, next))) {
00546       if (attendee->data) {
00547          ast_free(attendee->data);
00548       }
00549       ast_free(attendee);
00550    }
00551 }

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

Definition at line 766 of file res_calendar.c.

References ao2_ref, ast_log(), ast_pthread_create_background, AST_PTHREADT_NULL, do_notify(), LOG_ERROR, ast_calendar_event::notify_sched, and ast_calendar_event::owner.

Referenced by schedule_calendar_event().

00767 {
00768    struct ast_calendar_event *event = (void *)data;
00769    int res = -1;
00770    pthread_t notify_thread = AST_PTHREADT_NULL;
00771 
00772    if (!(event && event->owner)) {
00773       ast_log(LOG_ERROR, "Extremely low-cal...in fact cal is NULL!\n");
00774       return res;
00775    }
00776 
00777    ao2_ref(event, +1);
00778    event->notify_sched = -1;
00779 
00780    if (ast_pthread_create_background(&notify_thread, NULL, do_notify, event) < 0) {
00781       ast_log(LOG_ERROR, "Could not create notification thread\n");
00782       return res;
00783    }
00784 
00785    res = 0;
00786 
00787    return res;
00788 }

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

Definition at line 1567 of file res_calendar.c.

References ast_channel_datastore_find(), ast_channel_lock, 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, event_notification_datastore, ast_calendar_event::location, LOG_WARNING, ast_calendar::name, ast_channel::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.

01568 {
01569    struct ast_datastore *datastore;
01570    struct ast_calendar_event *event;
01571 
01572    if (ast_strlen_zero(data)) {
01573       ast_log(LOG_WARNING, "%s requires an argument\n", cmd);
01574       return -1;
01575    }
01576 
01577    ast_channel_lock(chan);
01578    if (!(datastore = ast_channel_datastore_find(chan, &event_notification_datastore, NULL))) {
01579       ast_log(LOG_WARNING, "There is no event notification datastore on '%s'!\n", chan->name);
01580       ast_channel_unlock(chan);
01581       return -1;
01582    }
01583    ast_channel_unlock(chan);
01584 
01585    if (!(event = datastore->data)) {
01586       ast_log(LOG_WARNING, "The datastore contains no data!\n");
01587       return -1;
01588    }
01589 
01590    if (!strcasecmp(data, "summary")) {
01591       ast_copy_string(buf, event->summary, len);
01592    } else if (!strcasecmp(data, "description")) {
01593       ast_copy_string(buf, event->description, len);
01594    } else if (!strcasecmp(data, "organizer")) {
01595       ast_copy_string(buf, event->organizer, len);
01596    } else if (!strcasecmp(data, "location")) {
01597       ast_copy_string(buf, event->location, len);
01598    } else if (!strcasecmp(data, "categories")) {
01599       ast_copy_string(buf, event->categories, len);
01600    } else if (!strcasecmp(data, "priority")) {
01601       snprintf(buf, len, "%d", event->priority);
01602    } else if (!strcasecmp(data, "calendar")) {
01603       ast_copy_string(buf, event->owner->name, len);
01604    } else if (!strcasecmp(data, "uid")) {
01605       ast_copy_string(buf, event->uid, len);
01606    } else if (!strcasecmp(data, "start")) {
01607       snprintf(buf, len, "%ld", (long)event->start);
01608    } else if (!strcasecmp(data, "end")) {
01609       snprintf(buf, len, "%ld", (long)event->end);
01610    } else if (!strcasecmp(data, "busystate")) {
01611       snprintf(buf, len, "%d", event->busy_state);
01612    } else if (!strcasecmp(data, "attendees")) {
01613       calendar_join_attendees(event, buf, len);
01614    }
01615 
01616 
01617    return 0;
01618 }

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

Definition at line 259 of file res_calendar.c.

References ast_str_case_hash(), and ast_calendar::name.

Referenced by load_module().

00260 {
00261    const struct ast_calendar *cal = obj;
00262    return ast_str_case_hash(cal->name);
00263 }

static int calendar_is_busy ( struct ast_calendar cal  )  [static]

Definition at line 349 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().

00350 {
00351    int is_busy = 0;
00352 
00353    ao2_callback(cal->events, OBJ_NODATA, calendar_busy_callback, &is_busy);
00354 
00355    return is_busy;
00356 }

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

Definition at line 1196 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, and ast_calendar_attendee::next.

Referenced by calendar_event_read(), and calendar_query_result_exec().

01197 {
01198    struct ast_str *tmp;
01199    struct ast_calendar_attendee *attendee;
01200 
01201    if (!(tmp = ast_str_create(32))) {
01202       ast_log(LOG_ERROR, "Could not allocate memory for attendees!\n");
01203       return;
01204    }
01205 
01206    AST_LIST_TRAVERSE(&event->attendees, attendee, next) {
01207       ast_str_append(&tmp, 0, "%s%s", attendee == AST_LIST_FIRST(&event->attendees) ? "" : ",", attendee->data);
01208    }
01209 
01210    ast_copy_string(buf, ast_str_buffer(tmp), len);
01211    ast_free(tmp);
01212 }

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

Definition at line 1110 of file res_calendar.c.

References add_event_to_list(), ao2_alloc, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, 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, eventlist_datastore_info, 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().

01111 {
01112    struct ast_calendar *cal;
01113    struct ao2_iterator i;
01114    struct ast_calendar_event *event;
01115    struct eventlist *events;
01116    time_t start = INT_MIN, end = INT_MAX;
01117    struct ast_datastore *eventlist_datastore;
01118    AST_DECLARE_APP_ARGS(args,
01119       AST_APP_ARG(calendar);
01120       AST_APP_ARG(start);
01121       AST_APP_ARG(end);
01122    );
01123 
01124    if (!chan) {
01125       ast_log(LOG_WARNING, "%s requires a channel to store the data on\n", cmd);
01126       return -1;
01127    }
01128 
01129    AST_STANDARD_APP_ARGS(args, data);
01130 
01131    if (ast_strlen_zero(args.calendar)) {
01132       ast_log(LOG_WARNING, "%s requires a calendar argument\n", cmd);
01133       return -1;
01134    }
01135 
01136    if (!(cal = find_calendar(args.calendar))) {
01137       ast_log(LOG_WARNING, "Unknown calendar '%s'\n", args.calendar);
01138       return -1;
01139    }
01140 
01141    if (!(events = ao2_alloc(sizeof(*events), eventlist_destructor))) {
01142       ast_log(LOG_ERROR, "Unable to allocate memory for event list\n");
01143       cal = unref_calendar(cal);
01144       return -1;
01145    }
01146 
01147    if (!ast_strlen_zero(args.start)) {
01148       start = atoi(args.start);
01149    }
01150 
01151    if (!ast_strlen_zero(args.end)) {
01152       end = atoi(args.end);
01153    }
01154 
01155    i = ao2_iterator_init(cal->events, 0);
01156    while ((event = ao2_iterator_next(&i))) {
01157       if (!(start > event->end || end < event->start)) {
01158          ast_debug(10, "%s (%ld - %ld) overlapped with (%ld - %ld)\n", event->summary, (long) event->start, (long) event->end, (long) start, (long) end);
01159          if (add_event_to_list(events, event, start, end) < 0) {
01160             event = ast_calendar_unref_event(event);
01161             ao2_iterator_destroy(&i);
01162             return -1;
01163          }
01164       }
01165 
01166       event = ast_calendar_unref_event(event);
01167    }
01168    ao2_iterator_destroy(&i);
01169 
01170    ast_channel_lock(chan);
01171    do {
01172       generate_random_string(buf, len);
01173    } while (ast_channel_datastore_find(chan, &eventlist_datastore_info, buf));
01174    ast_channel_unlock(chan);
01175 
01176    if (!(eventlist_datastore = ast_datastore_alloc(&eventlist_datastore_info, buf))) {
01177       ast_log(LOG_ERROR, "Could not allocate datastore!\n");
01178       return -1;
01179    }
01180 
01181    eventlist_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
01182    eventlist_datastore->data = events;
01183 
01184    ast_channel_lock(chan);
01185    ast_channel_datastore_add(chan, eventlist_datastore);
01186    ast_channel_unlock(chan);
01187 
01188    return 0;
01189 }

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

Definition at line 1214 of file res_calendar.c.

References args, AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, 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, eventlist_datastore_info, events, evententry::list, ast_calendar_event::location, LOG_WARNING, ast_calendar::name, ast_channel::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.

01215 {
01216    struct ast_datastore *datastore;
01217    struct eventlist *events;
01218    struct evententry *entry;
01219    int row = 1;
01220    size_t listlen = 0;
01221    AST_DECLARE_APP_ARGS(args,
01222       AST_APP_ARG(id);
01223       AST_APP_ARG(field);
01224       AST_APP_ARG(row);
01225    );
01226 
01227    if (!chan) {
01228       ast_log(LOG_WARNING, "%s requires a channel\n", cmd);
01229       return -1;
01230    }
01231 
01232    AST_STANDARD_APP_ARGS(args, data);
01233 
01234    if (ast_strlen_zero(args.id) || ast_strlen_zero(args.field)) {
01235       ast_log(LOG_WARNING, "%s requires an id and a field", cmd);
01236       return -1;
01237    }
01238 
01239    ast_channel_lock(chan);
01240    if (!(datastore = ast_channel_datastore_find(chan, &eventlist_datastore_info, args.id))) {
01241       ast_log(LOG_WARNING, "There is no event notification datastore with id '%s' on '%s'!\n", args.id, chan->name);
01242       ast_channel_unlock(chan);
01243       return -1;
01244    }
01245    ast_channel_unlock(chan);
01246 
01247    if (!(events = datastore->data)) {
01248       ast_log(LOG_WARNING, "The datastore contains no data!\n");
01249       return -1;
01250    }
01251 
01252    if (!ast_strlen_zero(args.row)) {
01253       row = atoi(args.row);
01254    }
01255 
01256    AST_LIST_TRAVERSE(events, entry, list) {
01257       listlen++;
01258    }
01259 
01260    if (!strcasecmp(args.field, "getnum")) {
01261       snprintf(buf, len, "%zu", listlen);
01262       return 0;
01263    }
01264 
01265    AST_LIST_TRAVERSE(events, entry, list) {
01266       if (--row) {
01267          continue;
01268       }
01269       if (!strcasecmp(args.field, "summary")) {
01270          ast_copy_string(buf, entry->event->summary, len);
01271       } else if (!strcasecmp(args.field, "description")) {
01272          ast_copy_string(buf, entry->event->description, len);
01273       } else if (!strcasecmp(args.field, "organizer")) {
01274          ast_copy_string(buf, entry->event->organizer, len);
01275       } else if (!strcasecmp(args.field, "location")) {
01276          ast_copy_string(buf, entry->event->location, len);
01277       } else if (!strcasecmp(args.field, "categories")) {
01278          ast_copy_string(buf, entry->event->categories, len);
01279       } else if (!strcasecmp(args.field, "priority")) {
01280          snprintf(buf, len, "%d", entry->event->priority);
01281       } else if (!strcasecmp(args.field, "calendar")) {
01282          ast_copy_string(buf, entry->event->owner->name, len);
01283       } else if (!strcasecmp(args.field, "uid")) {
01284          ast_copy_string(buf, entry->event->uid, len);
01285       } else if (!strcasecmp(args.field, "start")) {
01286          snprintf(buf, len, "%ld", (long) entry->event->start);
01287       } else if (!strcasecmp(args.field, "end")) {
01288          snprintf(buf, len, "%ld", (long) entry->event->end);
01289       } else if (!strcasecmp(args.field, "busystate")) {
01290          snprintf(buf, len, "%d", entry->event->busy_state);
01291       } else if (!strcasecmp(args.field, "attendees")) {
01292          calendar_join_attendees(entry->event, buf, len);
01293       } else {
01294          ast_log(LOG_WARNING, "Unknown field '%s'\n", args.field);
01295       }
01296       break;
01297    }
01298 
01299    return 0;
01300 }

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

Definition at line 1307 of file res_calendar.c.

References AST_APP_ARG, ast_calendar_event_alloc(), AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_tvnow(), find_calendar(), LOG_ERROR, LOG_WARNING, ast_calendar::name, ast_calendar_event::owner, ast_calendar::tech, and ast_calendar_tech::write_event.

01308 {
01309    int i, j, ret = -1;
01310    char *val_dup = NULL;
01311    struct ast_calendar *cal = NULL;
01312    struct ast_calendar_event *event = NULL;
01313    struct timeval tv = ast_tvnow();
01314    AST_DECLARE_APP_ARGS(fields,
01315       AST_APP_ARG(field)[10];
01316    );
01317    AST_DECLARE_APP_ARGS(values,
01318       AST_APP_ARG(value)[10];
01319    );
01320 
01321    if (!(val_dup = ast_strdup(value))) {
01322       ast_log(LOG_ERROR, "Could not allocate memory for values\n");
01323       return -1;
01324    }
01325 
01326    AST_STANDARD_APP_ARGS(fields, data);
01327    AST_STANDARD_APP_ARGS(values, val_dup);
01328 
01329    /* XXX Eventually we will support unnamed calendars, so if we don't find one, we parse
01330     * for a calendar type and create it */
01331    if (!(cal = find_calendar(fields.field[0]))) {
01332       ast_log(LOG_WARNING, "Couldn't find calendar '%s'\n", fields.field[0]);
01333       goto write_cleanup;
01334    }
01335 
01336    if (!(cal->tech->write_event)) {
01337       ast_log(LOG_WARNING, "Calendar '%s' has no write function!\n", cal->name);
01338       goto write_cleanup;
01339    }
01340 
01341    if (!(event = ast_calendar_event_alloc(cal))) {
01342       goto write_cleanup;
01343    }
01344 
01345    if (ast_strlen_zero(fields.field[0])) {
01346       ast_log(LOG_WARNING, "CALENDAR_WRITE requires a calendar name!\n");
01347       goto write_cleanup;
01348    }
01349 
01350    if (fields.argc - 1 != values.argc) {
01351       ast_log(LOG_WARNING, "CALENDAR_WRITE should have the same number of fields (%d) and values (%d)!\n", fields.argc - 1, values.argc);
01352       goto write_cleanup;
01353    }
01354 
01355    event->owner = cal;
01356 
01357    for (i = 1, j = 0; i < fields.argc; i++, j++) {
01358       if (!strcasecmp(fields.field[i], "summary")) {
01359          ast_string_field_set(event, summary, values.value[j]);
01360       } else if (!strcasecmp(fields.field[i], "description")) {
01361          ast_string_field_set(event, description, values.value[j]);
01362       } else if (!strcasecmp(fields.field[i], "organizer")) {
01363          ast_string_field_set(event, organizer, values.value[j]);
01364       } else if (!strcasecmp(fields.field[i], "location")) {
01365          ast_string_field_set(event, location, values.value[j]);
01366       } else if (!strcasecmp(fields.field[i], "categories")) {
01367          ast_string_field_set(event, categories, values.value[j]);
01368       } else if (!strcasecmp(fields.field[i], "priority")) {
01369          event->priority = atoi(values.value[j]);
01370       } else if (!strcasecmp(fields.field[i], "uid")) {
01371          ast_string_field_set(event, uid, values.value[j]);
01372       } else if (!strcasecmp(fields.field[i], "start")) {
01373          event->start = atoi(values.value[j]);
01374       } else if (!strcasecmp(fields.field[i], "end")) {
01375          event->end = atoi(values.value[j]);
01376       } else if (!strcasecmp(fields.field[i], "busystate")) {
01377          event->busy_state = atoi(values.value[j]);
01378       } else {
01379          ast_log(LOG_WARNING, "Unknown calendar event field '%s'\n", fields.field[i]);
01380       }
01381    }
01382 
01383    if (!event->start) {
01384       event->start = tv.tv_sec;
01385    }
01386 
01387    if (!event->end) {
01388       event->end = tv.tv_sec;
01389    }
01390 
01391    if((ret = cal->tech->write_event(event))) {
01392       ast_log(LOG_WARNING, "Writing event to calendar '%s' failed!\n", cal->name);
01393    }
01394 
01395 write_cleanup:
01396    if (cal) {
01397       cal = unref_calendar(cal);
01398    }
01399    if (event) {
01400       event = ast_calendar_unref_event(event);
01401    }
01402    if (val_dup) {
01403       ast_free(val_dup);
01404    }
01405 
01406    return ret;
01407 }

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

Definition at line 358 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, and ast_calendar::tech.

Referenced by load_module().

00359 {
00360    struct ast_calendar *cal;
00361 
00362    if (ast_strlen_zero(data) || (!(cal = find_calendar(data)))) {
00363       return AST_DEVICE_INVALID;
00364    }
00365 
00366    if (cal->tech->is_busy) {
00367       return cal->tech->is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
00368    }
00369 
00370    return calendar_is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
00371 }

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

Definition at line 1625 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::pending_deletion.

Referenced by reload().

01626 {
01627    struct ast_calendar *cal = user_data;
01628 
01629    cal->pending_deletion = 1;
01630 
01631    return CMP_MATCH;
01632 }

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

Definition at line 1634 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::pending_deletion.

Referenced by reload().

01635 {
01636    struct ast_calendar *cal = user_data;
01637 
01638    return cal->pending_deletion ? CMP_MATCH : 0;
01639 }

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

Definition at line 580 of file res_calendar.c.

References CMP_MATCH, and destroy_event().

Referenced by ast_calendar_clear_events().

00581 {
00582    struct ast_calendar_event *event = user_data;
00583 
00584    event = destroy_event(event);
00585 
00586    return CMP_MATCH;
00587 }

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

Definition at line 824 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, ast_calendar_event::description, ast_calendar_event::end, ast_calendar_event::location, ast_calendar_attendee::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().

00825 {
00826    struct ast_calendar_attendee *attendee;
00827 
00828    ast_string_field_set(dst, summary, src->summary);
00829    ast_string_field_set(dst, description, src->description);
00830    ast_string_field_set(dst, organizer, src->organizer);
00831    ast_string_field_set(dst, location, src->location);
00832    ast_string_field_set(dst, uid, src->uid);
00833    ast_string_field_set(dst, categories, src->categories);
00834    dst->priority = src->priority;
00835    dst->owner = src->owner;
00836    dst->start = src->start;
00837    dst->end = src->end;
00838    dst->alarm = src->alarm;
00839    dst->busy_state = src->busy_state;
00840 
00841    /* Delete any existing attendees */
00842    while ((attendee = AST_LIST_REMOVE_HEAD(&dst->attendees, next))) {
00843       ast_free(attendee);
00844    }
00845 
00846    /* Copy over the new attendees */
00847    while ((attendee = AST_LIST_REMOVE_HEAD(&src->attendees, next))) {
00848       AST_LIST_INSERT_TAIL(&dst->attendees, attendee, next);
00849    }
00850 }

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

Definition at line 555 of file res_calendar.c.

References ast_debug, AST_DEVICE_BUSY, AST_DEVICE_NOT_INUSE, 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, ast_calendar_event::owner, and sched.

Referenced by clear_events_cb(), and merge_events_cb().

00556 {
00557    if (event->notify_sched > -1 && ast_sched_del(sched, event->notify_sched)) {
00558       ast_debug(3, "Notification running, can't delete sched entry\n");
00559    }
00560    if (event->bs_start_sched > -1 && ast_sched_del(sched, event->bs_start_sched)) {
00561       ast_debug(3, "Devicestate update (start) running, can't delete sched entry\n");
00562    }
00563    if (event->bs_end_sched > -1 && ast_sched_del(sched, event->bs_end_sched)) {
00564       ast_debug(3, "Devicestate update (end) running, can't delete sched entry\n");
00565    }
00566 
00567    /* If an event is being deleted and we've fired an event changing the status at the beginning,
00568     * but haven't hit the end event yet, go ahead and set the devicestate to the current busy status */
00569    if (event->bs_start_sched < 0 && event->bs_end_sched >= 0) {
00570       if (!calendar_is_busy(event->owner)) {
00571          ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Calendar:%s", event->owner->name);
00572       } else {
00573          ast_devstate_changed(AST_DEVICE_BUSY, "Calendar:%s", event->owner->name);
00574       }
00575    }
00576 
00577    return NULL;
00578 }

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

Definition at line 669 of file res_calendar.c.

References ao2_ref, ast_calendar_unref_event(), ast_channel_alloc, ast_channel_datastore_add(), ast_channel_release(), ast_copy_string(), 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_SLINEAR, ast_free, ast_log(), ast_pbx_run(), AST_STATE_DOWN, ast_str_buffer(), ast_str_create(), ast_str_set(), ast_strdupa, ast_strlen_zero(), ast_verb, ast_channel::context, ast_datastore::data, DATASTORE_INHERIT_FOREVER, event_notification_datastore, ast_channel::exten, generate_random_string(), ast_datastore::inheritance, LOG_ERROR, LOG_WARNING, ast_calendar::name, ast_channel::nativeformats, ast_calendar::notify_app, ast_calendar::notify_appdata, ast_calendar::notify_channel, ast_calendar::notify_context, ast_calendar::notify_extension, ast_calendar::notify_waittime, null_tech, ast_calendar_event::owner, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::tech, and ast_channel::writeformat.

Referenced by calendar_event_notify().

00670 {
00671    struct ast_calendar_event *event = data;
00672    struct ast_dial *dial = NULL;
00673    struct ast_str *apptext = NULL;
00674    struct ast_datastore *datastore;
00675    enum ast_dial_result res;
00676    struct ast_channel *chan = NULL;
00677    char *tech, *dest;
00678    char buf[8];
00679 
00680    tech = ast_strdupa(event->owner->notify_channel);
00681 
00682    if ((dest = strchr(tech, '/'))) {
00683       *dest = '\0';
00684       dest++;
00685    } else {
00686       ast_log(LOG_WARNING, "Channel should be in form Tech/Dest (was '%s')\n", tech);
00687       goto notify_cleanup;
00688    }
00689 
00690    if (!(dial = ast_dial_create())) {
00691       ast_log(LOG_ERROR, "Could not create dial structure\n");
00692       goto notify_cleanup;
00693    }
00694 
00695    if (ast_dial_append(dial, tech, dest) < 0) {
00696       ast_log(LOG_ERROR, "Could not append channel\n");
00697       goto notify_cleanup;
00698    }
00699 
00700    ast_dial_set_global_timeout(dial, event->owner->notify_waittime);
00701    generate_random_string(buf, sizeof(buf));
00702 
00703    if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, 0, 0, 0, 0, 0, 0, 0, "Calendar/%s-%s", event->owner->name, buf))) {
00704       ast_log(LOG_ERROR, "Could not allocate notification channel\n");
00705       goto notify_cleanup;
00706    }
00707 
00708    chan->tech = &null_tech;
00709    chan->nativeformats = chan->writeformat = chan->rawwriteformat =
00710       chan->readformat = chan->rawreadformat = AST_FORMAT_SLINEAR;
00711 
00712    if (!(datastore = ast_datastore_alloc(&event_notification_datastore, NULL))) {
00713       ast_log(LOG_ERROR, "Could not allocate datastore, notification not being sent!\n");
00714       goto notify_cleanup;
00715    }
00716 
00717    datastore->data = event;
00718    datastore->inheritance = DATASTORE_INHERIT_FOREVER;
00719 
00720    ao2_ref(event, +1);
00721    res = ast_channel_datastore_add(chan, datastore);
00722 
00723    if (!(apptext = ast_str_create(32))) {
00724       goto notify_cleanup;
00725    }
00726 
00727    if (!ast_strlen_zero(event->owner->notify_app)) {
00728       ast_str_set(&apptext, 0, "%s,%s", event->owner->notify_app, event->owner->notify_appdata);
00729       ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, ast_str_buffer(apptext));
00730    } else {
00731    }
00732 
00733    ast_verb(3, "Dialing %s for notification on calendar %s\n", event->owner->notify_channel, event->owner->name);
00734    res = ast_dial_run(dial, chan, 0);
00735 
00736    if (res != AST_DIAL_RESULT_ANSWERED) {
00737       ast_verb(3, "Notification call for %s was not completed\n", event->owner->name);
00738    } else {
00739       struct ast_channel *answered;
00740 
00741       answered = ast_dial_answered_steal(dial);
00742       if (ast_strlen_zero(event->owner->notify_app)) {
00743          ast_copy_string(answered->context, event->owner->notify_context, sizeof(answered->context));
00744          ast_copy_string(answered->exten, event->owner->notify_extension, sizeof(answered->exten));
00745          answered->priority = 1;
00746          ast_pbx_run(answered);
00747       }
00748    }
00749 
00750 notify_cleanup:
00751    if (apptext) {
00752       ast_free(apptext);
00753    }
00754    if (dial) {
00755       ast_dial_destroy(dial);
00756    }
00757    if (chan) {
00758       ast_channel_release(chan);
00759    }
00760 
00761    event = ast_calendar_unref_event(event);
00762 
00763    return NULL;
00764 }

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

Definition at line 1667 of file res_calendar.c.

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

01668 {
01669    for (;;) {
01670       struct timeval now = ast_tvnow();
01671       struct timespec ts = {0,};
01672       int wait;
01673 
01674       ast_mutex_lock(&refreshlock);
01675 
01676       if ((wait = ast_sched_wait(sched)) < 0) {
01677          wait = 1000;
01678       }
01679 
01680       ts.tv_sec = (now.tv_sec + wait / 1000) + 1;
01681       ast_cond_timedwait(&refresh_condition, &refreshlock, &ts);
01682 
01683       ast_mutex_unlock(&refreshlock);
01684 
01685       ast_sched_runq(sched);
01686    }
01687 
01688    return NULL;
01689 }

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

Definition at line 1445 of file res_calendar.c.

References ast_localtime(), and ast_strftime().

Referenced by handle_show_calendar().

01446 {
01447    struct ast_tm tm;
01448    struct timeval tv = {
01449       .tv_sec = epoch,
01450    };
01451 
01452    if (!epoch) {
01453       *buf = '\0';
01454       return buf;
01455    }
01456    ast_localtime(&tv, &tm, NULL);
01457    ast_strftime(buf, buflen, "%F %r %z", &tm);
01458 
01459    return buf;
01460 }

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

Definition at line 285 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().

00286 {
00287    const struct ast_calendar_event *one = obj, *two = arg;
00288    return !strcmp(one->uid, two->uid) ? CMP_MATCH | CMP_STOP : 0;
00289 }

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

Definition at line 279 of file res_calendar.c.

References ast_str_hash(), evententry::event, and ast_calendar_event::uid.

Referenced by ast_calendar_event_container_alloc(), and build_calendar().

00280 {
00281    const struct ast_calendar_event *event = obj;
00282    return ast_str_hash(event->uid);
00283 }

static void event_notification_destroy ( void *  data  )  [static]

Definition at line 623 of file res_calendar.c.

References ast_calendar_unref_event().

00624 {
00625    struct ast_calendar_event *event = data;
00626 
00627    event = ast_calendar_unref_event(event);
00628 
00629 }

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

Definition at line 631 of file res_calendar.c.

References ao2_ref.

00632 {
00633    struct ast_calendar_event *event = data;
00634 
00635    if (!event) {
00636       return NULL;
00637    }
00638 
00639    ao2_ref(event, +1);
00640 
00641    return event;
00642 }

static void eventlist_destroy ( void *  data  )  [static]

Definition at line 1090 of file res_calendar.c.

References ao2_ref, and events.

01091 {
01092    struct eventlist *events = data;
01093 
01094    ao2_ref(events, -1);
01095 }

static void eventlist_destructor ( void *  obj  )  [static]

Definition at line 324 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().

00325 {
00326    struct eventlist *events = obj;
00327    struct evententry *entry;
00328 
00329    while ((entry = AST_LIST_REMOVE_HEAD(events, list))) {
00330       ao2_ref(entry->event, -1);
00331       ast_free(entry);
00332    }
00333 }

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

Definition at line 1097 of file res_calendar.c.

References ao2_ref, and events.

01098 {
01099    struct eventlist *events = data;
01100 
01101    if (!events) {
01102       return NULL;
01103    }
01104 
01105    ao2_ref(events, +1);
01106 
01107    return events;
01108 }

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

Definition at line 271 of file res_calendar.c.

References ao2_find, calendars, ast_calendar::name, and OBJ_POINTER.

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

00272 {
00273    struct ast_calendar tmp = {
00274       .name = name,
00275    };
00276    return ao2_find(calendars, &tmp, OBJ_POINTER);
00277 }

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

Definition at line 291 of file res_calendar.c.

References ao2_find, events, OBJ_POINTER, and ast_calendar_event::uid.

Referenced by merge_events_cb().

00292 {
00293    struct ast_calendar_event tmp = {
00294       .uid = uid,
00295    };
00296    return ao2_find(events, &tmp, OBJ_POINTER);
00297 }

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

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

Definition at line 645 of file res_calendar.c.

References ast_random().

00646 {
00647    long val[4];
00648    int x;
00649 
00650    for (x = 0; x < 4; x++) {
00651       val[x] = ast_random();
00652    }
00653    snprintf(buf, size, "%08lx%08lx%08lx%08lx", val[0], val[1], val[2], val[3]);
00654 
00655    return buf;
00656 }

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

Definition at line 1542 of file res_calendar.c.

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

01543 {
01544    switch(cmd) {
01545    case CLI_INIT:
01546       e->command = "calendar dump sched";
01547       e->usage =
01548          "Usage: calendar dump sched\n"
01549          "       Dump the calendar sched context";
01550       return NULL;
01551 
01552    case CLI_GENERATE:
01553       return NULL;
01554    }
01555 
01556    ast_sched_dump(sched);
01557 
01558    return CLI_SUCCESS;
01559 }

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

Definition at line 1462 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, 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, 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.

01463 {
01464 #define FORMAT "%-17.17s : %-20.20s\n"
01465 #define FORMAT2 "%-12.12s: %-40.60s\n"
01466    struct ao2_iterator i;
01467    struct ast_calendar *cal;
01468    struct ast_calendar_event *event;
01469    int which = 0;
01470    char *ret = NULL;
01471 
01472    switch(cmd) {
01473    case CLI_INIT:
01474       e->command = "calendar show calendar";
01475       e->usage =
01476          "Usage: calendar show calendar <calendar name>\n"
01477          "       Displays information about a calendar\n";
01478       return NULL;
01479 
01480    case CLI_GENERATE:
01481       if (a->pos != 3) {
01482          return NULL;
01483       }
01484       i = ao2_iterator_init(calendars, 0);
01485       while ((cal = ao2_iterator_next(&i))) {
01486          if (!strncasecmp(a->word, cal->name, strlen(a->word)) && ++which > a->n) {
01487             ret = ast_strdup(cal->name);
01488             cal = unref_calendar(cal);
01489             break;
01490          }
01491          cal = unref_calendar(cal);
01492       }
01493       ao2_iterator_destroy(&i);
01494       return ret;
01495    }
01496 
01497    if (a->argc != 4) {
01498       return CLI_SHOWUSAGE;
01499    }
01500 
01501    if (!(cal = find_calendar(a->argv[3]))) {
01502       return NULL;
01503    }
01504 
01505    ast_cli(a->fd, FORMAT, "Name", cal->name);
01506    ast_cli(a->fd, FORMAT, "Notify channel", cal->notify_channel);
01507    ast_cli(a->fd, FORMAT, "Notify context", cal->notify_context);
01508    ast_cli(a->fd, FORMAT, "Notify extension", cal->notify_extension);
01509    ast_cli(a->fd, FORMAT, "Notify application", cal->notify_app);
01510    ast_cli(a->fd, FORMAT, "Notify appdata", cal->notify_appdata);
01511    ast_cli(a->fd, "%-17.17s : %d\n", "Refresh time", cal->refresh);
01512    ast_cli(a->fd, "%-17.17s : %d\n", "Timeframe", cal->timeframe);
01513    ast_cli(a->fd, "%-17.17s : %d\n", "Autoreminder", cal->autoreminder);
01514    ast_cli(a->fd, "%s\n", "Events");
01515    ast_cli(a->fd, "%s\n", "------");
01516 
01517    i = ao2_iterator_init(cal->events, 0);
01518    while ((event = ao2_iterator_next(&i))) {
01519       char buf[100];
01520 
01521       ast_cli(a->fd, FORMAT2, "Summary", event->summary);
01522       ast_cli(a->fd, FORMAT2, "Description", event->description);
01523       ast_cli(a->fd, FORMAT2, "Organizer", event->organizer);
01524       ast_cli(a->fd, FORMAT2, "Location", event->location);
01525       ast_cli(a->fd, FORMAT2, "Categories", event->categories);
01526       ast_cli(a->fd, "%-12.12s: %d\n", "Priority", event->priority);
01527       ast_cli(a->fd, FORMAT2, "UID", event->uid);
01528       ast_cli(a->fd, FORMAT2, "Start", epoch_to_string(buf, sizeof(buf), event->start));
01529       ast_cli(a->fd, FORMAT2, "End", epoch_to_string(buf, sizeof(buf), event->end));
01530       ast_cli(a->fd, FORMAT2, "Alarm", epoch_to_string(buf, sizeof(buf), event->alarm));
01531       ast_cli(a->fd, "\n");
01532 
01533       event = ast_calendar_unref_event(event);
01534    }
01535    ao2_iterator_destroy(&i);
01536    cal = unref_calendar(cal);
01537    return CLI_SUCCESS;
01538 #undef FORMAT
01539 #undef FORMAT2
01540 }

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 1415 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, ast_calendar::tech, ast_calendar_tech::type, unref_calendar(), and ast_cli_entry::usage.

01416 {
01417 #define FORMAT "%-20.20s %-10.10s %-6.6s\n"
01418    struct ao2_iterator i;
01419    struct ast_calendar *cal;
01420 
01421    switch(cmd) {
01422    case CLI_INIT:
01423       e->command = "calendar show calendars";
01424       e->usage =
01425          "Usage: calendar show calendars\n"
01426          "       Lists all registered calendars.\n";
01427       return NULL;
01428    case CLI_GENERATE:
01429       return NULL;
01430    }
01431 
01432    ast_cli(a->fd, FORMAT, "Calendar", "Type", "Status");
01433    ast_cli(a->fd, FORMAT, "--------", "----", "------");
01434    i = ao2_iterator_init(calendars, 0);
01435    while ((cal = ao2_iterator_next(&i))) {
01436       ast_cli(a->fd, FORMAT, cal->name, cal->tech->type, calendar_is_busy(cal) ? "busy" : "free");
01437       cal = unref_calendar(cal);
01438    }
01439    ao2_iterator_destroy(&i);
01440 
01441    return CLI_SUCCESS;
01442 #undef FORMAT
01443 }

static int load_config ( void *  data  )  [static]

Definition at line 963 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_flags, config_lock, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, and LOG_ERROR.

00964 {
00965    struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
00966    struct ast_config *tmpcfg;
00967 
00968    if (!(tmpcfg = ast_config_load2("calendar.conf", "calendar", config_flags)) ||
00969       tmpcfg == CONFIG_STATUS_FILEINVALID) {
00970       ast_log(LOG_ERROR, "Unable to load config calendar.conf\n");
00971       return -1;
00972    }
00973 
00974    if (tmpcfg == CONFIG_STATUS_FILEUNCHANGED) {
00975       return 0;
00976    }
00977 
00978    ast_rwlock_wrlock(&config_lock);
00979    if (calendar_config) {
00980       ast_config_destroy(calendar_config);
00981    }
00982 
00983    calendar_config = tmpcfg;
00984    ast_rwlock_unlock(&config_lock);
00985 
00986    return 0;
00987 }

static int load_module ( void   )  [static]

Definition at line 1716 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_module_ref(), ast_mutex_init, ast_pthread_create_background, 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, refreshlock, reloadlock, sched, and sched_context_create().

01717 {
01718    if (!(calendars = ao2_container_alloc(CALENDAR_BUCKETS, calendar_hash_fn, calendar_cmp_fn))) {
01719       ast_log(LOG_ERROR, "Unable to allocate calendars container!\n");
01720       return AST_MODULE_LOAD_FAILURE;
01721    }
01722 
01723    if (load_config(NULL)) {
01724       /* We don't have calendar support enabled */
01725       return AST_MODULE_LOAD_DECLINE;
01726    }
01727 
01728    ast_mutex_init(&refreshlock);
01729    ast_cond_init(&refresh_condition, NULL);
01730    ast_mutex_init(&reloadlock);
01731 
01732    if (!(sched = sched_context_create())) {
01733       ast_log(LOG_ERROR, "Unable to create sched context\n");
01734       return AST_MODULE_LOAD_FAILURE;
01735    }
01736 
01737    if (ast_pthread_create_background(&refresh_thread, NULL, do_refresh, NULL) < 0) {
01738       ast_log(LOG_ERROR, "Unable to start refresh thread--notifications disabled!\n");
01739    }
01740 
01741    ast_custom_function_register(&calendar_busy_function);
01742    ast_custom_function_register(&calendar_event_function);
01743    ast_custom_function_register(&calendar_query_function);
01744    ast_custom_function_register(&calendar_query_result_function);
01745    ast_custom_function_register(&calendar_write_function);
01746    ast_cli_register_multiple(calendar_cli, ARRAY_LEN(calendar_cli));
01747 
01748    ast_devstate_prov_add("Calendar", calendarstate);
01749 
01750    /* Since other modules depend on this, disable unloading */
01751    ast_module_ref(ast_module_info->self);
01752 
01753    return AST_MODULE_LOAD_SUCCESS;
01754 }

static int load_tech_calendars ( struct ast_calendar_tech tech  )  [static]

Definition at line 449 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, ast_calendar::tech, ast_calendar_tech::type, and unref_calendar().

Referenced by ast_calendar_register(), and reload().

00450 {
00451    struct ast_calendar *cal;
00452    const char *cat = NULL;
00453    const char *val;
00454 
00455    if (!calendar_config) {
00456       ast_log(LOG_WARNING, "Calendar support disabled, not loading %s calendar module\n", tech->type);
00457       return -1;
00458    }
00459 
00460    ast_rwlock_wrlock(&config_lock);
00461    while ((cat = ast_category_browse(calendar_config, cat))) {
00462       if (!strcasecmp(cat, "general")) {
00463          continue;
00464       }
00465 
00466       if (!(val = ast_variable_retrieve(calendar_config, cat, "type")) || strcasecmp(val, tech->type)) {
00467          continue;
00468       }
00469 
00470       /* A serious error occurred loading calendars from this tech and it should be disabled */
00471       if (!(cal = build_calendar(calendar_config, cat, tech))) {
00472          ast_calendar_unregister(tech);
00473          ast_rwlock_unlock(&config_lock);
00474          return -1;
00475       }
00476 
00477       cal = unref_calendar(cal);
00478    }
00479 
00480    ast_rwlock_unlock(&config_lock);
00481 
00482    return 0;
00483 }

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

Definition at line 505 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::tech.

Referenced by ast_calendar_unregister().

00506 {
00507    struct ast_calendar *cal = user_data;
00508    struct ast_calendar_tech *tech = arg;
00509 
00510    if (cal->tech == tech) {
00511       return CMP_MATCH;
00512    }
00513 
00514    return 0;
00515 }

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

Definition at line 914 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().

00915 {
00916    struct ast_calendar_event *old_event = obj, *new_event;
00917    struct ao2_container *new_events = arg;
00918 
00919    /* If we don't find the old_event in new_events, then we can safely delete the old_event */
00920    if (!(new_event = find_event(new_events, old_event->uid))) {
00921       old_event = destroy_event(old_event);
00922       return CMP_MATCH;
00923    }
00924 
00925    /* We have events to merge.  If any data that will affect a scheduler event has changed,
00926     * then we need to replace the scheduler event */
00927    schedule_calendar_event(old_event->owner, old_event, new_event);
00928 
00929    /* Since we don't want to mess with cancelling sched events and adding new ones, just
00930     * copy the internals of the new_event to the old_event */
00931    copy_event_data(old_event, new_event);
00932 
00933    /* Now we can go ahead and unlink the new_event from new_events and unref it so that only completely
00934     * new events remain in the container */
00935    ao2_unlink(new_events, new_event);
00936    new_event = ast_calendar_unref_event(new_event);
00937 
00938    return 0;
00939 }

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

Definition at line 658 of file res_calendar.c.

00659 {
00660    return 0;
00661 }

static int reload ( void   )  [static]

Definition at line 1641 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(), ast_calendar_tech::list, load_config(), load_tech_calendars(), LOG_WARNING, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, reloadlock, and ast_calendar_tech::type.

01642 {
01643    struct ast_calendar_tech *iter;
01644 
01645    ast_mutex_lock(&reloadlock);
01646 
01647    /* Mark existing calendars for deletion */
01648    ao2_callback(calendars, OBJ_NODATA | OBJ_MULTIPLE, cb_pending_deletion, NULL);
01649    load_config(NULL);
01650 
01651    AST_LIST_LOCK(&techs);
01652    AST_LIST_TRAVERSE(&techs, iter, list) {
01653       if (load_tech_calendars(iter)) {
01654          ast_log(LOG_WARNING, "Failed to reload %s calendars, module disabled\n", iter->type);
01655       }
01656    }
01657    AST_LIST_UNLOCK(&techs);
01658 
01659    /* Delete calendars that no longer show up in the config */
01660    ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, cb_rm_pending_deletion, NULL);
01661 
01662    ast_mutex_unlock(&reloadlock);
01663 
01664    return 0;
01665 }

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 852 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, refreshlock, sched, and ast_calendar_event::start.

Referenced by add_new_event_cb(), and merge_events_cb().

00853 {
00854    struct timeval now = ast_tvnow();
00855    struct ast_calendar_event *event;
00856    time_t alarm_notify_sched = 0, devstate_sched_start, devstate_sched_end;
00857    int changed = 0;
00858 
00859    event = cmp_event ? cmp_event : old_event;
00860 
00861    ao2_lock(event);
00862    if (!cmp_event || old_event->alarm != event->alarm) {
00863       changed = 1;
00864       if (cal->autoreminder) {
00865          alarm_notify_sched = (event->start - (60 * cal->autoreminder) - now.tv_sec) * 1000;
00866       } else if (event->alarm) {
00867          alarm_notify_sched = (event->alarm - now.tv_sec) * 1000;
00868       }
00869 
00870       /* For now, send the notification if we missed it, but the meeting hasn't happened yet */
00871       if (event->start >=  now.tv_sec) {
00872          if (alarm_notify_sched <= 0) {
00873             alarm_notify_sched = 1;
00874          }
00875          ast_mutex_lock(&refreshlock);
00876          AST_SCHED_REPLACE(old_event->notify_sched, sched, alarm_notify_sched, calendar_event_notify, old_event);
00877          ast_mutex_unlock(&refreshlock);
00878          ast_debug(3, "Calendar alarm event notification scheduled to happen in %ld ms\n", (long) alarm_notify_sched);
00879       }
00880    }
00881 
00882    if (!cmp_event || old_event->start != event->start) {
00883       changed = 1;
00884       devstate_sched_start = (event->start - now.tv_sec) * 1000;
00885 
00886       if (devstate_sched_start < 1) {
00887          devstate_sched_start = 1;
00888       }
00889 
00890       ast_mutex_lock(&refreshlock);
00891       AST_SCHED_REPLACE(old_event->bs_start_sched, sched, devstate_sched_start, calendar_devstate_change, old_event);
00892       ast_mutex_unlock(&refreshlock);
00893       ast_debug(3, "Calendar bs_start event notification scheduled to happen in %ld ms\n", (long) devstate_sched_start);
00894    }
00895 
00896    if (!cmp_event || old_event->end != event->end) {
00897       changed = 1;
00898       devstate_sched_end = (event->end - now.tv_sec) * 1000;
00899       ast_mutex_lock(&refreshlock);
00900       AST_SCHED_REPLACE(old_event->bs_end_sched, sched, devstate_sched_end, calendar_devstate_change, old_event);
00901       ast_mutex_unlock(&refreshlock);
00902       ast_debug(3, "Calendar bs_end event notification scheduled to happen in %ld ms\n", (long) devstate_sched_end);
00903    }
00904 
00905    if (changed) {
00906       ast_cond_signal(&refresh_condition);
00907    }
00908 
00909    ao2_unlock(event);
00910 
00911    return 0;
00912 }

static int unload_module ( void   )  [static]

Definition at line 1692 of file res_calendar.c.

References ao2_callback, ARRAY_LEN, ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_devstate_prov_del(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_unload_resource(), calendar_busy_function, calendar_cli, calendar_event_function, calendar_query_function, calendar_query_result_function, calendar_write_function, ast_calendar_tech::list, ast_calendar_tech::module, OBJ_MULTIPLE, OBJ_NODATA, and OBJ_UNLINK.

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

Definition at line 253 of file res_calendar.c.

References ao2_ref.

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

00254 {
00255    ao2_ref(cal, -1);
00256    return NULL;
00257 }


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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, } [static]

Definition at line 1760 of file res_calendar.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1760 of file res_calendar.c.

struct ast_custom_function calendar_busy_function [static]

Initial value:

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

Definition at line 1011 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ast_cli_entry calendar_cli[] [static]

Initial value:

 {
   { .handler =  handle_show_calendar , .summary =  "Display information about a calendar" ,__VA_ARGS__ },
   { .handler =  handle_show_calendars , .summary =  "Show registered calendars" ,__VA_ARGS__ },
   { .handler =  handle_dump_sched , .summary =  "Dump calendar sched context" ,__VA_ARGS__ },
}

Definition at line 1561 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ast_config* calendar_config [static]

Definition at line 233 of file res_calendar.c.

Referenced by load_config(), and load_tech_calendars().

struct ast_custom_function calendar_event_function [static]

Initial value:

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

Definition at line 1620 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function calendar_query_function [static]

Initial value:

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

Definition at line 1191 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function calendar_query_result_function [static]

Initial value:

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

Definition at line 1302 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function calendar_write_function [static]

Initial value:

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

Definition at line 1409 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ao2_container* calendars [static]

Definition at line 201 of file res_calendar.c.

Referenced by find_calendar().

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

Definition at line 234 of file res_calendar.c.

struct ast_datastore_info event_notification_datastore [static]

Initial value:

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

Definition at line 213 of file res_calendar.c.

Referenced by calendar_event_read(), and do_notify().

struct ast_datastore_info eventlist_datastore_info [static]

Initial value:

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

Definition at line 219 of file res_calendar.c.

Referenced by calendar_query_exec(), and calendar_query_result_exec().

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 663 of file res_calendar.c.

ast_cond_t refresh_condition [static]

Definition at line 205 of file res_calendar.c.

pthread_t refresh_thread = AST_PTHREADT_NULL [static]

Definition at line 203 of file res_calendar.c.

ast_mutex_t refreshlock [static]

Definition at line 204 of file res_calendar.c.

Referenced by caldav_load_calendar(), do_refresh(), ewscal_load_calendar(), exchangecal_load_calendar(), ical_load_calendar(), load_module(), and schedule_calendar_event().

ast_mutex_t reloadlock [static]

Definition at line 206 of file res_calendar.c.

struct sched_context* sched [static]

Definition at line 202 of file res_calendar.c.


Generated on Sat Mar 10 01:55:39 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7