Mon Jun 27 16:51:19 2011

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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .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 195 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 1757 of file res_calendar.c.

static void __unreg_module ( void   )  [static]

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

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

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

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

00938 {
00939    struct ast_calendar_event *new_event = obj;
00940    struct ao2_container *events = arg;
00941 
00942    ao2_link(events, new_event);
00943    schedule_calendar_event(new_event->owner, new_event, NULL);
00944    return CMP_MATCH;
00945 }

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 585 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().

00586 {
00587    ast_debug(3, "Clearing all events for calendar %s\n", cal->name);
00588 
00589    ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, clear_events_cb, NULL);
00590 }

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 232 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().

00233 {
00234    ast_rwlock_rdlock(&config_lock);
00235 
00236    if (!calendar_config) {
00237       ast_rwlock_unlock(&config_lock);
00238       return NULL;
00239    }
00240 
00241    return calendar_config;
00242 }

void ast_calendar_config_release ( void   ) 

Release the calendar config.

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

00245 {
00246    ast_rwlock_unlock(&config_lock);
00247 }

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 592 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().

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

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 614 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 947 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().

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

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 481 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().

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

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 295 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().

00296 {
00297    ao2_ref(event, -1);
00298    return NULL;
00299 }

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 513 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().

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

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

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

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

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

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

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

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

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

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

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

Definition at line 261 of file res_calendar.c.

References CMP_MATCH, CMP_STOP, and ast_calendar::name.

Referenced by load_module().

00262 {
00263    const struct ast_calendar *one = obj, *two = arg;
00264    return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP: 0;
00265 }

static void calendar_destructor ( void *  obj  )  [static]

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

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

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

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

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

static void calendar_event_destructor ( void *  obj  )  [static]

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

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

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

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

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

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

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

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

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

Definition at line 255 of file res_calendar.c.

References ast_str_case_hash(), and ast_calendar::name.

Referenced by load_module().

00256 {
00257    const struct ast_calendar *cal = obj;
00258    return ast_str_case_hash(cal->name);
00259 }

static int calendar_is_busy ( struct ast_calendar cal  )  [static]

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

00346 {
00347    int is_busy = 0;
00348 
00349    ao2_callback(cal->events, OBJ_NODATA, calendar_busy_callback, &is_busy);
00350 
00351    return is_busy;
00352 }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 1621 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::pending_deletion.

Referenced by reload().

01622 {
01623    struct ast_calendar *cal = user_data;
01624 
01625    cal->pending_deletion = 1;
01626 
01627    return CMP_MATCH;
01628 }

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

Definition at line 1630 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::pending_deletion.

Referenced by reload().

01631 {
01632    struct ast_calendar *cal = user_data;
01633 
01634    return cal->pending_deletion ? CMP_MATCH : 0;
01635 }

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

Definition at line 576 of file res_calendar.c.

References CMP_MATCH, and destroy_event().

Referenced by ast_calendar_clear_events().

00577 {
00578    struct ast_calendar_event *event = user_data;
00579 
00580    event = destroy_event(event);
00581 
00582    return CMP_MATCH;
00583 }

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 1441 of file res_calendar.c.

References ast_localtime(), and ast_strftime().

Referenced by handle_show_calendar().

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

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

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

00282 {
00283    const struct ast_calendar_event *one = obj, *two = arg;
00284    return !strcmp(one->uid, two->uid) ? CMP_MATCH | CMP_STOP : 0;
00285 }

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

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

00276 {
00277    const struct ast_calendar_event *event = obj;
00278    return ast_str_hash(event->uid);
00279 }

static void event_notification_destroy ( void *  data  )  [static]

Definition at line 619 of file res_calendar.c.

References ast_calendar_unref_event().

00620 {
00621    struct ast_calendar_event *event = data;
00622 
00623    event = ast_calendar_unref_event(event);
00624 
00625 }

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

Definition at line 627 of file res_calendar.c.

References ao2_ref.

00628 {
00629    struct ast_calendar_event *event = data;
00630 
00631    if (!event) {
00632       return NULL;
00633    }
00634 
00635    ao2_ref(event, +1);
00636 
00637    return event;
00638 }

static void eventlist_destroy ( void *  data  )  [static]

Definition at line 1086 of file res_calendar.c.

References ao2_ref, and events.

01087 {
01088    struct eventlist *events = data;
01089 
01090    ao2_ref(events, -1);
01091 }

static void eventlist_destructor ( void *  obj  )  [static]

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

00321 {
00322    struct eventlist *events = obj;
00323    struct evententry *entry;
00324 
00325    while ((entry = AST_LIST_REMOVE_HEAD(events, list))) {
00326       ao2_ref(entry->event, -1);
00327       ast_free(entry);
00328    }
00329 }

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

Definition at line 1093 of file res_calendar.c.

References ao2_ref, and events.

01094 {
01095    struct eventlist *events = data;
01096 
01097    if (!events) {
01098       return NULL;
01099    }
01100 
01101    ao2_ref(events, +1);
01102 
01103    return events;
01104 }

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

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

00268 {
00269    struct ast_calendar tmp = {
00270       .name = name,
00271    };
00272    return ao2_find(calendars, &tmp, OBJ_POINTER);
00273 }

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

Definition at line 287 of file res_calendar.c.

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

Referenced by merge_events_cb().

00288 {
00289    struct ast_calendar_event tmp = {
00290       .uid = uid,
00291    };
00292    return ao2_find(events, &tmp, OBJ_POINTER);
00293 }

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

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

Definition at line 641 of file res_calendar.c.

References ast_random().

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

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

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

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

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

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

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

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 1411 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.

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

static int load_config ( void *  data  )  [static]

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

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

static int load_module ( void   )  [static]

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

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

static int load_tech_calendars ( struct ast_calendar_tech tech  )  [static]

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

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

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

Definition at line 501 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::tech.

Referenced by ast_calendar_unregister().

00502 {
00503    struct ast_calendar *cal = user_data;
00504    struct ast_calendar_tech *tech = arg;
00505 
00506    if (cal->tech == tech) {
00507       return CMP_MATCH;
00508    }
00509 
00510    return 0;
00511 }

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

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

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

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

Definition at line 654 of file res_calendar.c.

00655 {
00656    return 0;
00657 }

static int reload ( void   )  [static]

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

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

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 848 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().

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

static int unload_module ( void   )  [static]

Definition at line 1688 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_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, 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 249 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().

00250 {
00251    ao2_ref(cal, -1);
00252    return NULL;
00253 }


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

Definition at line 1757 of file res_calendar.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1757 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 1007 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 1557 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ast_config* calendar_config [static]

Definition at line 229 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 1616 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 1187 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 1298 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 1405 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ao2_container* calendars [static]

Definition at line 197 of file res_calendar.c.

Referenced by find_calendar().

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

Definition at line 230 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 209 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 215 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 659 of file res_calendar.c.

ast_cond_t refresh_condition [static]

Definition at line 201 of file res_calendar.c.

pthread_t refresh_thread = AST_PTHREADT_NULL [static]

Definition at line 199 of file res_calendar.c.

ast_mutex_t refreshlock [static]

Definition at line 200 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 202 of file res_calendar.c.

struct sched_context* sched [static]

Definition at line 198 of file res_calendar.c.


Generated on Mon Jun 27 16:51:19 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7