Wed Apr 6 11:30:08 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 = { { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } , 1, PTHREAD_RWLOCK_INITIALIZER }
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 165 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 1727 of file res_calendar.c.

static void __unreg_module ( void   )  [static]

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

00983 {
00984    struct evententry *entry, *iter;
00985    int event_startdiff = abs(start - event->start);
00986    int event_enddiff = abs(end - event->end);
00987    int i = 0;
00988 
00989    if (!(entry = ast_calloc(1, sizeof(*entry)))) {
00990       ast_log(LOG_ERROR, "Unable to allocate memory for event list\n");
00991       return -1;
00992    }
00993 
00994    entry->event = event;
00995    ao2_ref(event, +1);
00996 
00997    if (start == end) {
00998       AST_LIST_TRAVERSE_SAFE_BEGIN(events, iter, list) {
00999          int startdiff = abs(iter->event->start - start);
01000 
01001          ast_debug(10, "Comparing %s with startdiff %d to %s with startdiff %d\n", event->summary, event_startdiff, iter->event->summary, startdiff);
01002          ++i;
01003          if (startdiff > event_startdiff) {
01004             AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01005             return i;
01006          }
01007          if (startdiff == event_startdiff) {
01008             int enddiff = abs(iter->event->end - end);
01009 
01010             if (enddiff > event_enddiff) {
01011                AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01012                return i;
01013             }
01014             if (event_startdiff == enddiff) {
01015                if (strcmp(event->uid, iter->event->uid) < 0) {
01016                   AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01017                   return i;
01018                }
01019             }
01020          }
01021       }
01022       AST_LIST_TRAVERSE_SAFE_END;
01023 
01024       AST_LIST_INSERT_TAIL(events, entry, list);
01025 
01026       return i;
01027    }
01028 
01029    AST_LIST_TRAVERSE_SAFE_BEGIN(events, iter, list) {
01030       ++i;
01031       if (iter->event->start > event->start) {
01032          AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01033          return i;
01034       }
01035 
01036       if (iter->event->start == event->start) {
01037          if ((iter->event->end - iter->event->start) == (event->end - event->start)) {
01038             if (strcmp(event->uid, iter->event->uid) < 0) {
01039                AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01040                return i;
01041             }
01042          }
01043          if ((iter->event->end - iter->event->start) < (event->end - event->start)) {
01044             AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01045             return i;
01046          }
01047       }
01048    }
01049    AST_LIST_TRAVERSE_SAFE_END;
01050 
01051    AST_LIST_INSERT_TAIL(events, entry, list);
01052 
01053    return i;
01054 }

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

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

00908 {
00909    struct ast_calendar_event *new_event = obj;
00910    struct ao2_container *events = arg;
00911 
00912    ao2_link(events, new_event);
00913    schedule_calendar_event(new_event->owner, new_event, NULL);
00914    return CMP_MATCH;
00915 }

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

00556 {
00557    ast_debug(3, "Clearing all events for calendar %s\n", cal->name);
00558 
00559    ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, clear_events_cb, NULL);
00560 }

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

00203 {
00204    ast_rwlock_rdlock(&config_lock);
00205 
00206    if (!calendar_config) {
00207       ast_rwlock_unlock(&config_lock);
00208       return NULL;
00209    }
00210 
00211    return calendar_config;
00212 }

void ast_calendar_config_release ( void   ) 

Release the calendar config.

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

00215 {
00216    ast_rwlock_unlock(&config_lock);
00217 }

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

00563 {
00564    struct ast_calendar_event *event;
00565    if (!(event = ao2_alloc(sizeof(*event), calendar_event_destructor))) {
00566       return NULL;
00567    }
00568 
00569    if (ast_string_field_init(event, 32)) {
00570       event = ast_calendar_unref_event(event);
00571       return NULL;
00572    }
00573 
00574    event->owner = cal;
00575    event->notify_sched = -1;
00576    event->bs_start_sched = -1;
00577    event->bs_end_sched = -1;
00578 
00579    AST_LIST_HEAD_INIT_NOLOCK(&event->attendees);
00580 
00581    return event;
00582 }

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 584 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 917 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().

00918 {
00919    /* Loop through all events attached to the calendar.  If there is a matching new event
00920     * merge its data over and handle any schedule changes that need to be made.  Then remove
00921     * the new_event from new_events so that we are left with only new_events that we can add later. */
00922    ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, merge_events_cb, new_events);
00923 
00924    /* Now, we should only have completely new events in new_events.  Loop through and add them */
00925    ao2_callback(new_events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, add_new_event_cb, cal->events);
00926 }

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

00452 {
00453    struct ast_calendar_tech *iter;
00454 
00455    AST_LIST_LOCK(&techs);
00456    AST_LIST_TRAVERSE(&techs, iter, list) {
00457       if(!strcasecmp(tech->type, iter->type)) {
00458          ast_log(LOG_WARNING, "Already have a handler for calendar type '%s'\n", tech->type);
00459          AST_LIST_UNLOCK(&techs);
00460          return -1;
00461       }
00462    }
00463    AST_LIST_INSERT_HEAD(&techs, tech, list);
00464    AST_LIST_UNLOCK(&techs);
00465 
00466    ast_verb(2, "Registered calendar type '%s' (%s)\n", tech->type, tech->description);
00467 
00468    return load_tech_calendars(tech);
00469 }

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

00266 {
00267    ao2_ref(event, -1);
00268    return NULL;
00269 }

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

00484 {
00485    struct ast_calendar_tech *iter;
00486 
00487    AST_LIST_LOCK(&techs);
00488    AST_LIST_TRAVERSE_SAFE_BEGIN(&techs, iter, list) {
00489       if (iter != tech) {
00490          continue;
00491       }
00492 
00493       ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, match_caltech_cb, tech);
00494 
00495       AST_LIST_REMOVE_CURRENT(list);
00496       ast_verb(2, "Unregistered calendar type '%s'\n", tech->type);
00497       break;
00498    }
00499    AST_LIST_TRAVERSE_SAFE_END;
00500    AST_LIST_UNLOCK(&techs);
00501 
00502 }

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

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

00340 {
00341    struct ast_calendar *cal;
00342    struct ast_variable *v;
00343    int new_calendar = 0;
00344 
00345    if (!(cal = find_calendar(cat))) {
00346       new_calendar = 1;
00347       if (!(cal = ao2_alloc(sizeof(*cal), calendar_destructor))) {
00348          ast_log(LOG_ERROR, "Could not allocate calendar structure. Stopping.\n");
00349          return NULL;
00350       }
00351 
00352       if (!(cal->events = ao2_container_alloc(CALENDAR_BUCKETS, event_hash_fn, event_cmp_fn))) {
00353          ast_log(LOG_ERROR, "Could not allocate events container for %s\n", cat);
00354          cal = unref_calendar(cal);
00355          return NULL;
00356       }
00357 
00358       if (ast_string_field_init(cal, 32)) {
00359          ast_log(LOG_ERROR, "Couldn't create string fields for %s\n", cat);
00360          cal = unref_calendar(cal);
00361          return NULL;
00362       }
00363    } else {
00364       cal->pending_deletion = 0;
00365    }
00366 
00367    ast_string_field_set(cal, name, cat);
00368    cal->tech = tech;
00369 
00370    cal->refresh = 3600;
00371    cal->timeframe = 60;
00372    cal->notify_waittime = 30000;
00373 
00374    for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
00375       if (!strcasecmp(v->name, "autoreminder")) {
00376          cal->autoreminder = atoi(v->value);
00377       } else if (!strcasecmp(v->name, "channel")) {
00378          ast_string_field_set(cal, notify_channel, v->value);
00379       } else if (!strcasecmp(v->name, "context")) {
00380          ast_string_field_set(cal, notify_context, v->value);
00381       } else if (!strcasecmp(v->name, "extension")) {
00382          ast_string_field_set(cal, notify_extension, v->value);
00383       } else if (!strcasecmp(v->name, "waittime")) {
00384          int i = atoi(v->value);
00385          if (i > 0) {
00386             cal->notify_waittime = 1000 * i;
00387          }
00388       } else if (!strcasecmp(v->name, "app")) {
00389          ast_string_field_set(cal, notify_app, v->value);
00390       } else if (!strcasecmp(v->name, "appdata")) {
00391          ast_string_field_set(cal, notify_appdata, v->value);
00392       } else if (!strcasecmp(v->name, "refresh")) {
00393          cal->refresh = atoi(v->value);
00394       } else if (!strcasecmp(v->name, "timeframe")) {
00395          cal->timeframe = atoi(v->value);
00396       }
00397    }
00398 
00399    if (new_calendar) {
00400       cal->thread = AST_PTHREADT_NULL;
00401       ast_cond_init(&cal->unload, NULL);
00402       ao2_link(calendars, cal);
00403       if (ast_pthread_create(&cal->thread, NULL, cal->tech->load_calendar, cal)) {
00404          /* If we start failing to create threads, go ahead and return NULL
00405           * and the tech module will be unregistered
00406           */ 
00407          ao2_unlink(calendars, cal);
00408          cal = unref_calendar(cal);
00409       }
00410    }
00411 
00412    return cal;
00413 }

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

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

00302 {
00303    struct ast_calendar_event *event = obj;
00304    int *is_busy = arg;
00305    struct timeval tv = ast_tvnow();
00306 
00307    if (tv.tv_sec >= event->start && tv.tv_sec <= event->end && event->busy_state > AST_CALENDAR_BS_FREE) {
00308       *is_busy = 1;
00309       return CMP_STOP;
00310    }
00311 
00312    return 0;
00313 }

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

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

00957 {
00958    struct ast_calendar *cal;
00959 
00960    if (ast_strlen_zero(data)) {
00961       ast_log(LOG_WARNING, "CALENDAR_BUSY requires an argument: CALENDAR_BUSY(<calendar_name>)\n");
00962       return -1;
00963    }
00964 
00965    cal = find_calendar(data);
00966 
00967    if (!cal) {
00968       ast_log(LOG_WARNING, "Could not find calendar '%s'\n", data);
00969       return -1;
00970    }
00971 
00972    strcpy(buf, calendar_is_busy(cal) ? "1" : "0");
00973 
00974    return 0;
00975 }

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

Definition at line 231 of file res_calendar.c.

References CMP_MATCH, CMP_STOP, and ast_calendar::name.

Referenced by load_module().

00232 {
00233    const struct ast_calendar *one = obj, *two = arg;
00234    return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP: 0;
00235 }

static void calendar_destructor ( void *  obj  )  [static]

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

00272 {
00273    struct ast_calendar *cal = obj;
00274 
00275    ast_debug(3, "Destroying calendar %s\n", cal->name);
00276 
00277    ao2_lock(cal);
00278    cal->unloading = 1;
00279    ast_cond_signal(&cal->unload);
00280    pthread_join(cal->thread, NULL);
00281    if (cal->tech_pvt) {
00282       cal->tech_pvt = cal->tech->unref_calendar(cal->tech_pvt);
00283    }
00284    ast_calendar_clear_events(cal);
00285    ast_string_field_free_memory(cal);
00286    ao2_ref(cal->events, -1);
00287    ao2_unlock(cal);
00288 }

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

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

00757 {
00758    struct ast_calendar_event *event = (struct ast_calendar_event *)data;
00759    struct timeval now = ast_tvnow();
00760    int is_end_event;
00761 
00762    if (!event) {
00763       ast_log(LOG_WARNING, "Event was NULL!\n");
00764       return 0;
00765    }
00766 
00767    ao2_ref(event, +1);
00768 
00769    is_end_event = event->end <= now.tv_sec;
00770 
00771    if (is_end_event) {
00772       event->bs_end_sched = -1;
00773    } else {
00774       event->bs_start_sched = -1;
00775    }
00776 
00777    /* We can have overlapping events, so ignore the event->busy_state and check busy state
00778     * based on all events in the calendar */
00779    if (!calendar_is_busy(event->owner)) {
00780       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Calendar:%s", event->owner->name);
00781    } else {
00782       ast_devstate_changed(AST_DEVICE_BUSY, "Calendar:%s", event->owner->name);
00783    }
00784 
00785    event = ast_calendar_unref_event(event);
00786 
00787    return 0;
00788 }

static void calendar_event_destructor ( void *  obj  )  [static]

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

00505 {
00506    struct ast_calendar_event *event = obj;
00507    struct ast_calendar_attendee *attendee;
00508 
00509    ast_debug(3, "Destroying event for calendar '%s'\n", event->owner->name);
00510    ast_string_field_free_memory(event);
00511    while ((attendee = AST_LIST_REMOVE_HEAD(&event->attendees, next))) {
00512       if (attendee->data) {
00513          ast_free(attendee->data);
00514       }
00515       ast_free(attendee);
00516    }
00517 }

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

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

00733 {
00734    struct ast_calendar_event *event = (void *)data;
00735    int res = -1;
00736    pthread_t notify_thread = AST_PTHREADT_NULL;
00737 
00738    if (!(event && event->owner)) {
00739       ast_log(LOG_ERROR, "Extremely low-cal...in fact cal is NULL!\n");
00740       return res;
00741    }
00742 
00743    ao2_ref(event, +1);
00744    event->notify_sched = -1;
00745 
00746    if (ast_pthread_create_background(&notify_thread, NULL, do_notify, event) < 0) {
00747       ast_log(LOG_ERROR, "Could not create notification thread\n");
00748       return res;
00749    }
00750 
00751    res = 0;
00752 
00753    return res;
00754 }

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

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

01534 {
01535    struct ast_datastore *datastore;
01536    struct ast_calendar_event *event;
01537 
01538    if (ast_strlen_zero(data)) {
01539       ast_log(LOG_WARNING, "%s requires an argument\n", cmd);
01540       return -1;
01541    }
01542 
01543    ast_channel_lock(chan);
01544    if (!(datastore = ast_channel_datastore_find(chan, &event_notification_datastore, NULL))) {
01545       ast_log(LOG_WARNING, "There is no event notification datastore on '%s'!\n", chan->name);
01546       ast_channel_unlock(chan);
01547       return -1;
01548    }
01549    ast_channel_unlock(chan);
01550 
01551    if (!(event = datastore->data)) {
01552       ast_log(LOG_WARNING, "The datastore contains no data!\n");
01553       return -1;
01554    }
01555 
01556    if (!strcasecmp(data, "summary")) {
01557       ast_copy_string(buf, event->summary, len);
01558    } else if (!strcasecmp(data, "description")) {
01559       ast_copy_string(buf, event->description, len);
01560    } else if (!strcasecmp(data, "organizer")) {
01561       ast_copy_string(buf, event->organizer, len);
01562    } else if (!strcasecmp(data, "location")) {
01563       ast_copy_string(buf, event->location, len);
01564    } else if (!strcasecmp(data, "categories")) {
01565       ast_copy_string(buf, event->categories, len);
01566    } else if (!strcasecmp(data, "priority")) {
01567       snprintf(buf, len, "%d", event->priority);
01568    } else if (!strcasecmp(data, "calendar")) {
01569       ast_copy_string(buf, event->owner->name, len);
01570    } else if (!strcasecmp(data, "uid")) {
01571       ast_copy_string(buf, event->uid, len);
01572    } else if (!strcasecmp(data, "start")) {
01573       snprintf(buf, len, "%ld", (long)event->start);
01574    } else if (!strcasecmp(data, "end")) {
01575       snprintf(buf, len, "%ld", (long)event->end);
01576    } else if (!strcasecmp(data, "busystate")) {
01577       snprintf(buf, len, "%d", event->busy_state);
01578    } else if (!strcasecmp(data, "attendees")) {
01579       calendar_join_attendees(event, buf, len);
01580    }
01581 
01582 
01583    return 0;
01584 }

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

Definition at line 225 of file res_calendar.c.

References ast_str_case_hash(), and ast_calendar::name.

Referenced by load_module().

00226 {
00227    const struct ast_calendar *cal = obj;
00228    return ast_str_case_hash(cal->name);
00229 }

static int calendar_is_busy ( struct ast_calendar cal  )  [static]

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

00316 {
00317    int is_busy = 0;
00318 
00319    ao2_callback(cal->events, OBJ_NODATA, calendar_busy_callback, &is_busy);
00320 
00321    return is_busy;
00322 }

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

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

01163 {
01164    struct ast_str *tmp;
01165    struct ast_calendar_attendee *attendee;
01166 
01167    if (!(tmp = ast_str_create(32))) {
01168       ast_log(LOG_ERROR, "Could not allocate memory for attendees!\n");
01169       return;
01170    }
01171 
01172    AST_LIST_TRAVERSE(&event->attendees, attendee, next) {
01173       ast_str_append(&tmp, 0, "%s%s", attendee == AST_LIST_FIRST(&event->attendees) ? "" : ",", attendee->data);
01174    }
01175 
01176    ast_copy_string(buf, ast_str_buffer(tmp), len);
01177    ast_free(tmp);
01178 }

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

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

01077 {
01078    struct ast_calendar *cal;
01079    struct ao2_iterator i;
01080    struct ast_calendar_event *event;
01081    struct eventlist *events;
01082    time_t start = INT_MIN, end = INT_MAX;
01083    struct ast_datastore *eventlist_datastore;
01084    AST_DECLARE_APP_ARGS(args,
01085       AST_APP_ARG(calendar);
01086       AST_APP_ARG(start);
01087       AST_APP_ARG(end);
01088    );
01089 
01090    if (!chan) {
01091       ast_log(LOG_WARNING, "%s requires a channel to store the data on\n", cmd);
01092       return -1;
01093    }
01094 
01095    AST_STANDARD_APP_ARGS(args, data);
01096 
01097    if (ast_strlen_zero(args.calendar)) {
01098       ast_log(LOG_WARNING, "%s requires a calendar argument\n", cmd);
01099       return -1;
01100    }
01101 
01102    if (!(cal = find_calendar(args.calendar))) {
01103       ast_log(LOG_WARNING, "Unknown calendar '%s'\n", args.calendar);
01104       return -1;
01105    }
01106 
01107    if (!(events = ao2_alloc(sizeof(*events), eventlist_destructor))) {
01108       ast_log(LOG_ERROR, "Unable to allocate memory for event list\n");
01109       cal = unref_calendar(cal);
01110       return -1;
01111    }
01112 
01113    if (!ast_strlen_zero(args.start)) {
01114       start = atoi(args.start);
01115    }
01116 
01117    if (!ast_strlen_zero(args.end)) {
01118       end = atoi(args.end);
01119    }
01120 
01121    i = ao2_iterator_init(cal->events, 0);
01122    while ((event = ao2_iterator_next(&i))) {
01123       if (!(start > event->end || end < event->start)) {
01124          ast_debug(10, "%s (%ld - %ld) overlapped with (%ld - %ld)\n", event->summary, (long) event->start, (long) event->end, (long) start, (long) end);
01125          if (add_event_to_list(events, event, start, end) < 0) {
01126             event = ast_calendar_unref_event(event);
01127             ao2_iterator_destroy(&i);
01128             return -1;
01129          }
01130       }
01131 
01132       event = ast_calendar_unref_event(event);
01133    }
01134    ao2_iterator_destroy(&i);
01135 
01136    ast_channel_lock(chan);
01137    do {
01138       generate_random_string(buf, len);
01139    } while (ast_channel_datastore_find(chan, &eventlist_datastore_info, buf));
01140    ast_channel_unlock(chan);
01141 
01142    if (!(eventlist_datastore = ast_datastore_alloc(&eventlist_datastore_info, buf))) {
01143       ast_log(LOG_ERROR, "Could not allocate datastore!\n");
01144       return -1;
01145    }
01146 
01147    eventlist_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
01148    eventlist_datastore->data = events;
01149 
01150    ast_channel_lock(chan);
01151    ast_channel_datastore_add(chan, eventlist_datastore);
01152    ast_channel_unlock(chan);
01153 
01154    return 0;
01155 }

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

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

01181 {
01182    struct ast_datastore *datastore;
01183    struct eventlist *events;
01184    struct evententry *entry;
01185    int row = 1;
01186    size_t listlen = 0;
01187    AST_DECLARE_APP_ARGS(args,
01188       AST_APP_ARG(id);
01189       AST_APP_ARG(field);
01190       AST_APP_ARG(row);
01191    );
01192 
01193    if (!chan) {
01194       ast_log(LOG_WARNING, "%s requires a channel\n", cmd);
01195       return -1;
01196    }
01197 
01198    AST_STANDARD_APP_ARGS(args, data);
01199 
01200    if (ast_strlen_zero(args.id) || ast_strlen_zero(args.field)) {
01201       ast_log(LOG_WARNING, "%s requires an id and a field", cmd);
01202       return -1;
01203    }
01204 
01205    ast_channel_lock(chan);
01206    if (!(datastore = ast_channel_datastore_find(chan, &eventlist_datastore_info, args.id))) {
01207       ast_log(LOG_WARNING, "There is no event notification datastore with id '%s' on '%s'!\n", args.id, chan->name);
01208       ast_channel_unlock(chan);
01209       return -1;
01210    }
01211    ast_channel_unlock(chan);
01212 
01213    if (!(events = datastore->data)) {
01214       ast_log(LOG_WARNING, "The datastore contains no data!\n");
01215       return -1;
01216    }
01217 
01218    if (!ast_strlen_zero(args.row)) {
01219       row = atoi(args.row);
01220    }
01221 
01222    AST_LIST_TRAVERSE(events, entry, list) {
01223       listlen++;
01224    }
01225 
01226    if (!strcasecmp(args.field, "getnum")) {
01227       snprintf(buf, len, "%zu", listlen);
01228       return 0;
01229    }
01230 
01231    AST_LIST_TRAVERSE(events, entry, list) {
01232       if (--row) {
01233          continue;
01234       }
01235       if (!strcasecmp(args.field, "summary")) {
01236          ast_copy_string(buf, entry->event->summary, len);
01237       } else if (!strcasecmp(args.field, "description")) {
01238          ast_copy_string(buf, entry->event->description, len);
01239       } else if (!strcasecmp(args.field, "organizer")) {
01240          ast_copy_string(buf, entry->event->organizer, len);
01241       } else if (!strcasecmp(args.field, "location")) {
01242          ast_copy_string(buf, entry->event->location, len);
01243       } else if (!strcasecmp(args.field, "categories")) {
01244          ast_copy_string(buf, entry->event->categories, len);
01245       } else if (!strcasecmp(args.field, "priority")) {
01246          snprintf(buf, len, "%d", entry->event->priority);
01247       } else if (!strcasecmp(args.field, "calendar")) {
01248          ast_copy_string(buf, entry->event->owner->name, len);
01249       } else if (!strcasecmp(args.field, "uid")) {
01250          ast_copy_string(buf, entry->event->uid, len);
01251       } else if (!strcasecmp(args.field, "start")) {
01252          snprintf(buf, len, "%ld", (long) entry->event->start);
01253       } else if (!strcasecmp(args.field, "end")) {
01254          snprintf(buf, len, "%ld", (long) entry->event->end);
01255       } else if (!strcasecmp(args.field, "busystate")) {
01256          snprintf(buf, len, "%d", entry->event->busy_state);
01257       } else if (!strcasecmp(args.field, "attendees")) {
01258          calendar_join_attendees(entry->event, buf, len);
01259       } else {
01260          ast_log(LOG_WARNING, "Unknown field '%s'\n", args.field);
01261       }
01262       break;
01263    }
01264 
01265    return 0;
01266 }

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

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

01274 {
01275    int i, j, ret = -1;
01276    char *val_dup = NULL;
01277    struct ast_calendar *cal = NULL;
01278    struct ast_calendar_event *event = NULL;
01279    struct timeval tv = ast_tvnow();
01280    AST_DECLARE_APP_ARGS(fields,
01281       AST_APP_ARG(field)[10];
01282    );
01283    AST_DECLARE_APP_ARGS(values,
01284       AST_APP_ARG(value)[10];
01285    );
01286 
01287    if (!(val_dup = ast_strdup(value))) {
01288       ast_log(LOG_ERROR, "Could not allocate memory for values\n");
01289       return -1;
01290    }
01291 
01292    AST_STANDARD_APP_ARGS(fields, data);
01293    AST_STANDARD_APP_ARGS(values, val_dup);
01294 
01295    /* XXX Eventually we will support unnamed calendars, so if we don't find one, we parse
01296     * for a calendar type and create it */
01297    if (!(cal = find_calendar(fields.field[0]))) {
01298       ast_log(LOG_WARNING, "Couldn't find calendar '%s'\n", fields.field[0]);
01299       goto write_cleanup;
01300    }
01301 
01302    if (!(cal->tech->write_event)) {
01303       ast_log(LOG_WARNING, "Calendar '%s' has no write function!\n", cal->name);
01304       goto write_cleanup;
01305    }
01306 
01307    if (!(event = ast_calendar_event_alloc(cal))) {
01308       goto write_cleanup;
01309    }
01310 
01311    if (ast_strlen_zero(fields.field[0])) {
01312       ast_log(LOG_WARNING, "CALENDAR_WRITE requires a calendar name!\n");
01313       goto write_cleanup;
01314    }
01315 
01316    if (fields.argc - 1 != values.argc) {
01317       ast_log(LOG_WARNING, "CALENDAR_WRITE should have the same number of fields (%d) and values (%d)!\n", fields.argc - 1, values.argc);
01318       goto write_cleanup;
01319    }
01320 
01321    event->owner = cal;
01322 
01323    for (i = 1, j = 0; i < fields.argc; i++, j++) {
01324       if (!strcasecmp(fields.field[i], "summary")) {
01325          ast_string_field_set(event, summary, values.value[j]);
01326       } else if (!strcasecmp(fields.field[i], "description")) {
01327          ast_string_field_set(event, description, values.value[j]);
01328       } else if (!strcasecmp(fields.field[i], "organizer")) {
01329          ast_string_field_set(event, organizer, values.value[j]);
01330       } else if (!strcasecmp(fields.field[i], "location")) {
01331          ast_string_field_set(event, location, values.value[j]);
01332       } else if (!strcasecmp(fields.field[i], "categories")) {
01333          ast_string_field_set(event, categories, values.value[j]);
01334       } else if (!strcasecmp(fields.field[i], "priority")) {
01335          event->priority = atoi(values.value[j]);
01336       } else if (!strcasecmp(fields.field[i], "uid")) {
01337          ast_string_field_set(event, uid, values.value[j]);
01338       } else if (!strcasecmp(fields.field[i], "start")) {
01339          event->start = atoi(values.value[j]);
01340       } else if (!strcasecmp(fields.field[i], "end")) {
01341          event->end = atoi(values.value[j]);
01342       } else if (!strcasecmp(fields.field[i], "busystate")) {
01343          event->busy_state = atoi(values.value[j]);
01344       } else {
01345          ast_log(LOG_WARNING, "Unknown calendar event field '%s'\n", fields.field[i]);
01346       }
01347    }
01348 
01349    if (!event->start) {
01350       event->start = tv.tv_sec;
01351    }
01352 
01353    if (!event->end) {
01354       event->end = tv.tv_sec;
01355    }
01356 
01357    if((ret = cal->tech->write_event(event))) {
01358       ast_log(LOG_WARNING, "Writing event to calendar '%s' failed!\n", cal->name);
01359    }
01360 
01361 write_cleanup:
01362    if (cal) {
01363       cal = unref_calendar(cal);
01364    }
01365    if (event) {
01366       event = ast_calendar_unref_event(event);
01367    }
01368    if (val_dup) {
01369       ast_free(val_dup);
01370    }
01371 
01372    return ret;
01373 }

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

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

00325 {
00326    struct ast_calendar *cal;
00327 
00328    if (ast_strlen_zero(data) || (!(cal = find_calendar(data)))) {
00329       return AST_DEVICE_INVALID;
00330    }
00331 
00332    if (cal->tech->is_busy) {
00333       return cal->tech->is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
00334    }
00335 
00336    return calendar_is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
00337 }

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

Definition at line 1591 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::pending_deletion.

Referenced by reload().

01592 {
01593    struct ast_calendar *cal = user_data;
01594 
01595    cal->pending_deletion = 1;
01596 
01597    return CMP_MATCH;
01598 }

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

Definition at line 1600 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::pending_deletion.

Referenced by reload().

01601 {
01602    struct ast_calendar *cal = user_data;
01603 
01604    return cal->pending_deletion ? CMP_MATCH : 0;
01605 }

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

Definition at line 546 of file res_calendar.c.

References CMP_MATCH, and destroy_event().

Referenced by ast_calendar_clear_events().

00547 {
00548    struct ast_calendar_event *event = user_data;
00549 
00550    event = destroy_event(event);
00551 
00552    return CMP_MATCH;
00553 }

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

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

00791 {
00792    struct ast_calendar_attendee *attendee;
00793 
00794    ast_string_field_set(dst, summary, src->summary);
00795    ast_string_field_set(dst, description, src->description);
00796    ast_string_field_set(dst, organizer, src->organizer);
00797    ast_string_field_set(dst, location, src->location);
00798    ast_string_field_set(dst, uid, src->uid);
00799    ast_string_field_set(dst, categories, src->categories);
00800    dst->priority = src->priority;
00801    dst->owner = src->owner;
00802    dst->start = src->start;
00803    dst->end = src->end;
00804    dst->alarm = src->alarm;
00805    dst->busy_state = src->busy_state;
00806 
00807    /* Delete any existing attendees */
00808    while ((attendee = AST_LIST_REMOVE_HEAD(&dst->attendees, next))) {
00809       ast_free(attendee);
00810    }
00811 
00812    /* Copy over the new attendees */
00813    while ((attendee = AST_LIST_REMOVE_HEAD(&src->attendees, next))) {
00814       AST_LIST_INSERT_TAIL(&dst->attendees, attendee, next);
00815    }
00816 }

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

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

00522 {
00523    if (event->notify_sched > -1 && ast_sched_del(sched, event->notify_sched)) {
00524       ast_debug(3, "Notification running, can't delete sched entry\n");
00525    }
00526    if (event->bs_start_sched > -1 && ast_sched_del(sched, event->bs_start_sched)) {
00527       ast_debug(3, "Devicestate update (start) running, can't delete sched entry\n");
00528    }
00529    if (event->bs_end_sched > -1 && ast_sched_del(sched, event->bs_end_sched)) {
00530       ast_debug(3, "Devicestate update (end) running, can't delete sched entry\n");
00531    }
00532 
00533    /* If an event is being deleted and we've fired an event changing the status at the beginning,
00534     * but haven't hit the end event yet, go ahead and set the devicestate to the current busy status */
00535    if (event->bs_start_sched < 0 && event->bs_end_sched >= 0) {
00536       if (!calendar_is_busy(event->owner)) {
00537          ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Calendar:%s", event->owner->name);
00538       } else {
00539          ast_devstate_changed(AST_DEVICE_BUSY, "Calendar:%s", event->owner->name);
00540       }
00541    }
00542 
00543    return NULL;
00544 }

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

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

00636 {
00637    struct ast_calendar_event *event = data;
00638    struct ast_dial *dial = NULL;
00639    struct ast_str *apptext = NULL;
00640    struct ast_datastore *datastore;
00641    enum ast_dial_result res;
00642    struct ast_channel *chan = NULL;
00643    char *tech, *dest;
00644    char buf[8];
00645 
00646    tech = ast_strdupa(event->owner->notify_channel);
00647 
00648    if ((dest = strchr(tech, '/'))) {
00649       *dest = '\0';
00650       dest++;
00651    } else {
00652       ast_log(LOG_WARNING, "Channel should be in form Tech/Dest (was '%s')\n", tech);
00653       goto notify_cleanup;
00654    }
00655 
00656    if (!(dial = ast_dial_create())) {
00657       ast_log(LOG_ERROR, "Could not create dial structure\n");
00658       goto notify_cleanup;
00659    }
00660 
00661    if (ast_dial_append(dial, tech, dest) < 0) {
00662       ast_log(LOG_ERROR, "Could not append channel\n");
00663       goto notify_cleanup;
00664    }
00665 
00666    ast_dial_set_global_timeout(dial, event->owner->notify_waittime);
00667    generate_random_string(buf, sizeof(buf));
00668 
00669    if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, 0, 0, 0, 0, 0, 0, 0, "Calendar/%s-%s", event->owner->name, buf))) {
00670       ast_log(LOG_ERROR, "Could not allocate notification channel\n");
00671       goto notify_cleanup;
00672    }
00673 
00674    chan->tech = &null_tech;
00675    chan->nativeformats = chan->writeformat = chan->rawwriteformat =
00676       chan->readformat = chan->rawreadformat = AST_FORMAT_SLINEAR;
00677 
00678    if (!(datastore = ast_datastore_alloc(&event_notification_datastore, NULL))) {
00679       ast_log(LOG_ERROR, "Could not allocate datastore, notification not being sent!\n");
00680       goto notify_cleanup;
00681    }
00682 
00683    datastore->data = event;
00684    datastore->inheritance = DATASTORE_INHERIT_FOREVER;
00685 
00686    ao2_ref(event, +1);
00687    res = ast_channel_datastore_add(chan, datastore);
00688 
00689    if (!(apptext = ast_str_create(32))) {
00690       goto notify_cleanup;
00691    }
00692 
00693    if (!ast_strlen_zero(event->owner->notify_app)) {
00694       ast_str_set(&apptext, 0, "%s,%s", event->owner->notify_app, event->owner->notify_appdata);
00695       ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, ast_str_buffer(apptext));
00696    } else {
00697    }
00698 
00699    ast_verb(3, "Dialing %s for notification on calendar %s\n", event->owner->notify_channel, event->owner->name);
00700    res = ast_dial_run(dial, chan, 0);
00701 
00702    if (res != AST_DIAL_RESULT_ANSWERED) {
00703       ast_verb(3, "Notification call for %s was not completed\n", event->owner->name);
00704    } else {
00705       struct ast_channel *answered;
00706 
00707       answered = ast_dial_answered_steal(dial);
00708       if (ast_strlen_zero(event->owner->notify_app)) {
00709          ast_copy_string(answered->context, event->owner->notify_context, sizeof(answered->context));
00710          ast_copy_string(answered->exten, event->owner->notify_extension, sizeof(answered->exten));
00711          answered->priority = 1;
00712          ast_pbx_run(answered);
00713       }
00714    }
00715 
00716 notify_cleanup:
00717    if (apptext) {
00718       ast_free(apptext);
00719    }
00720    if (dial) {
00721       ast_dial_destroy(dial);
00722    }
00723    if (chan) {
00724       ast_channel_release(chan);
00725    }
00726 
00727    event = ast_calendar_unref_event(event);
00728 
00729    return NULL;
00730 }

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

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

01634 {
01635    for (;;) {
01636       struct timeval now = ast_tvnow();
01637       struct timespec ts = {0,};
01638       int res, wait;
01639 
01640       ast_mutex_lock(&refreshlock);
01641 
01642       if ((wait = ast_sched_wait(sched)) < 0) {
01643          wait = 1000;
01644       }
01645 
01646       ts.tv_sec = (now.tv_sec + wait / 1000) + 1;
01647       res = ast_cond_timedwait(&refresh_condition, &refreshlock, &ts);
01648 
01649       ast_mutex_unlock(&refreshlock);
01650 
01651       ast_sched_runq(sched);
01652    }
01653 
01654    return NULL;
01655 }

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

Definition at line 1411 of file res_calendar.c.

References ast_localtime(), and ast_strftime().

Referenced by handle_show_calendar().

01412 {
01413    struct ast_tm tm;
01414    struct timeval tv = {
01415       .tv_sec = epoch,
01416    };
01417 
01418    if (!epoch) {
01419       *buf = '\0';
01420       return buf;
01421    }
01422    ast_localtime(&tv, &tm, NULL);
01423    ast_strftime(buf, buflen, "%F %r %z", &tm);
01424 
01425    return buf;
01426 }

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

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

00252 {
00253    const struct ast_calendar_event *one = obj, *two = arg;
00254    return !strcmp(one->uid, two->uid) ? CMP_MATCH | CMP_STOP : 0;
00255 }

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

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

00246 {
00247    const struct ast_calendar_event *event = obj;
00248    return ast_str_hash(event->uid);
00249 }

static void event_notification_destroy ( void *  data  )  [static]

Definition at line 589 of file res_calendar.c.

References ast_calendar_unref_event().

00590 {
00591    struct ast_calendar_event *event = data;
00592 
00593    event = ast_calendar_unref_event(event);
00594 
00595 }

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

Definition at line 597 of file res_calendar.c.

References ao2_ref.

00598 {
00599    struct ast_calendar_event *event = data;
00600 
00601    if (!event) {
00602       return NULL;
00603    }
00604 
00605    ao2_ref(event, +1);
00606 
00607    return event;
00608 }

static void eventlist_destroy ( void *  data  )  [static]

Definition at line 1056 of file res_calendar.c.

References ao2_ref, and events.

01057 {
01058    struct eventlist *events = data;
01059 
01060    ao2_ref(events, -1);
01061 }

static void eventlist_destructor ( void *  obj  )  [static]

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

00291 {
00292    struct eventlist *events = obj;
00293    struct evententry *entry;
00294 
00295    while ((entry = AST_LIST_REMOVE_HEAD(events, list))) {
00296       ao2_ref(entry->event, -1);
00297       ast_free(entry);
00298    }
00299 }

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

Definition at line 1063 of file res_calendar.c.

References ao2_ref, and events.

01064 {
01065    struct eventlist *events = data;
01066 
01067    if (!events) {
01068       return NULL;
01069    }
01070 
01071    ao2_ref(events, +1);
01072 
01073    return events;
01074 }

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

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

00238 {
00239    struct ast_calendar tmp = {
00240       .name = name,
00241    };
00242    return ao2_find(calendars, &tmp, OBJ_POINTER);
00243 }

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

Definition at line 257 of file res_calendar.c.

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

Referenced by merge_events_cb().

00258 {
00259    struct ast_calendar_event tmp = {
00260       .uid = uid,
00261    };
00262    return ao2_find(events, &tmp, OBJ_POINTER);
00263 }

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

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

Definition at line 611 of file res_calendar.c.

References ast_random().

00612 {
00613    long val[4];
00614    int x;
00615 
00616    for (x = 0; x < 4; x++) {
00617       val[x] = ast_random();
00618    }
00619    snprintf(buf, size, "%08lx%08lx%08lx%08lx", val[0], val[1], val[2], val[3]);
00620 
00621    return buf;
00622 }

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

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

01509 {
01510    switch(cmd) {
01511    case CLI_INIT:
01512       e->command = "calendar dump sched";
01513       e->usage =
01514          "Usage: calendar dump sched\n"
01515          "       Dump the calendar sched context";
01516       return NULL;
01517 
01518    case CLI_GENERATE:
01519       return NULL;
01520    }
01521 
01522    ast_sched_dump(sched);
01523 
01524    return CLI_SUCCESS;
01525 }

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

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

01429 {
01430 #define FORMAT "%-17.17s : %-20.20s\n"
01431 #define FORMAT2 "%-12.12s: %-40.60s\n"
01432    struct ao2_iterator i;
01433    struct ast_calendar *cal;
01434    struct ast_calendar_event *event;
01435    int which = 0;
01436    char *ret = NULL;
01437 
01438    switch(cmd) {
01439    case CLI_INIT:
01440       e->command = "calendar show calendar";
01441       e->usage =
01442          "Usage: calendar show calendar <calendar name>\n"
01443          "       Displays information about a calendar\n";
01444       return NULL;
01445 
01446    case CLI_GENERATE:
01447       if (a->pos != 3) {
01448          return NULL;
01449       }
01450       i = ao2_iterator_init(calendars, 0);
01451       while ((cal = ao2_iterator_next(&i))) {
01452          if (!strncasecmp(a->word, cal->name, strlen(a->word)) && ++which > a->n) {
01453             ret = ast_strdup(cal->name);
01454             cal = unref_calendar(cal);
01455             break;
01456          }
01457          cal = unref_calendar(cal);
01458       }
01459       ao2_iterator_destroy(&i);
01460       return ret;
01461    }
01462 
01463    if (a->argc != 4) {
01464       return CLI_SHOWUSAGE;
01465    }
01466 
01467    if (!(cal = find_calendar(a->argv[3]))) {
01468       return NULL;
01469    }
01470 
01471    ast_cli(a->fd, FORMAT, "Name", cal->name);
01472    ast_cli(a->fd, FORMAT, "Notify channel", cal->notify_channel);
01473    ast_cli(a->fd, FORMAT, "Notify context", cal->notify_context);
01474    ast_cli(a->fd, FORMAT, "Notify extension", cal->notify_extension);
01475    ast_cli(a->fd, FORMAT, "Notify application", cal->notify_app);
01476    ast_cli(a->fd, FORMAT, "Notify appdata", cal->notify_appdata);
01477    ast_cli(a->fd, "%-17.17s : %d\n", "Refresh time", cal->refresh);
01478    ast_cli(a->fd, "%-17.17s : %d\n", "Timeframe", cal->timeframe);
01479    ast_cli(a->fd, "%-17.17s : %d\n", "Autoreminder", cal->autoreminder);
01480    ast_cli(a->fd, "%s\n", "Events");
01481    ast_cli(a->fd, "%s\n", "------");
01482 
01483    i = ao2_iterator_init(cal->events, 0);
01484    while ((event = ao2_iterator_next(&i))) {
01485       char buf[100];
01486 
01487       ast_cli(a->fd, FORMAT2, "Summary", event->summary);
01488       ast_cli(a->fd, FORMAT2, "Description", event->description);
01489       ast_cli(a->fd, FORMAT2, "Organizer", event->organizer);
01490       ast_cli(a->fd, FORMAT2, "Location", event->location);
01491       ast_cli(a->fd, FORMAT2, "Cartegories", event->categories);
01492       ast_cli(a->fd, "%-12.12s: %d\n", "Priority", event->priority);
01493       ast_cli(a->fd, FORMAT2, "UID", event->uid);
01494       ast_cli(a->fd, FORMAT2, "Start", epoch_to_string(buf, sizeof(buf), event->start));
01495       ast_cli(a->fd, FORMAT2, "End", epoch_to_string(buf, sizeof(buf), event->end));
01496       ast_cli(a->fd, FORMAT2, "Alarm", epoch_to_string(buf, sizeof(buf), event->alarm));
01497       ast_cli(a->fd, "\n");
01498 
01499       event = ast_calendar_unref_event(event);
01500    }
01501    ao2_iterator_destroy(&i);
01502    cal = unref_calendar(cal);
01503    return CLI_SUCCESS;
01504 #undef FORMAT
01505 #undef FORMAT2
01506 }

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

01382 {
01383 #define FORMAT "%-20.20s %-10.10s %-6.6s\n"
01384    struct ao2_iterator i;
01385    struct ast_calendar *cal;
01386 
01387    switch(cmd) {
01388    case CLI_INIT:
01389       e->command = "calendar show calendars";
01390       e->usage =
01391          "Usage: calendar show calendars\n"
01392          "       Lists all registered calendars.\n";
01393       return NULL;
01394    case CLI_GENERATE:
01395       return NULL;
01396    }
01397 
01398    ast_cli(a->fd, FORMAT, "Calendar", "Type", "Status");
01399    ast_cli(a->fd, FORMAT, "--------", "----", "------");
01400    i = ao2_iterator_init(calendars, 0);
01401    while ((cal = ao2_iterator_next(&i))) {
01402       ast_cli(a->fd, FORMAT, cal->name, cal->tech->type, calendar_is_busy(cal) ? "busy" : "free");
01403       cal = unref_calendar(cal);
01404    }
01405    ao2_iterator_destroy(&i);
01406 
01407    return CLI_SUCCESS;
01408 #undef FORMAT
01409 }

static int load_config ( void *  data  )  [static]

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

00930 {
00931    struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
00932    struct ast_config *tmpcfg;
00933 
00934    if (!(tmpcfg = ast_config_load2("calendar.conf", "calendar", config_flags)) ||
00935       tmpcfg == CONFIG_STATUS_FILEINVALID) {
00936       ast_log(LOG_ERROR, "Unable to load config calendar.conf\n");
00937       return -1;
00938    }
00939 
00940    if (tmpcfg == CONFIG_STATUS_FILEUNCHANGED) {
00941       return 0;
00942    }
00943 
00944    ast_rwlock_wrlock(&config_lock);
00945    if (calendar_config) {
00946       ast_config_destroy(calendar_config);
00947    }
00948 
00949    calendar_config = tmpcfg;
00950    ast_rwlock_unlock(&config_lock);
00951 
00952    return 0;
00953 }

static int load_module ( void   )  [static]

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

01684 {
01685    if (!(calendars = ao2_container_alloc(CALENDAR_BUCKETS, calendar_hash_fn, calendar_cmp_fn))) {
01686       ast_log(LOG_ERROR, "Unable to allocate calendars container!\n");
01687       return AST_MODULE_LOAD_FAILURE;
01688    }
01689 
01690    if (load_config(NULL)) {
01691       /* We don't have calendar support enabled */
01692       return AST_MODULE_LOAD_DECLINE;
01693    }
01694 
01695    ast_mutex_init(&refreshlock);
01696    ast_cond_init(&refresh_condition, NULL);
01697    ast_mutex_init(&reloadlock);
01698 
01699    if (!(sched = sched_context_create())) {
01700       ast_log(LOG_ERROR, "Unable to create sched context\n");
01701       return AST_MODULE_LOAD_FAILURE;
01702    }
01703 
01704    if (ast_pthread_create_background(&refresh_thread, NULL, do_refresh, NULL) < 0) {
01705       ast_log(LOG_ERROR, "Unable to start refresh thread--notifications disabled!\n");
01706    }
01707 
01708    ast_custom_function_register(&calendar_busy_function);
01709    ast_custom_function_register(&calendar_event_function);
01710    ast_custom_function_register(&calendar_query_function);
01711    ast_custom_function_register(&calendar_query_result_function);
01712    ast_custom_function_register(&calendar_write_function);
01713    ast_cli_register_multiple(calendar_cli, ARRAY_LEN(calendar_cli));
01714 
01715    ast_devstate_prov_add("Calendar", calendarstate);
01716 
01717    /* Since other modules depend on this, disable unloading */
01718    ast_module_ref(ast_module_info->self);
01719 
01720    return AST_MODULE_LOAD_SUCCESS;
01721 }

static int load_tech_calendars ( struct ast_calendar_tech tech  )  [static]

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

00416 {
00417    struct ast_calendar *cal;
00418    const char *cat = NULL;
00419    const char *val;
00420 
00421    if (!calendar_config) {
00422       ast_log(LOG_WARNING, "Calendar support disabled, not loading %s calendar module\n", tech->type);
00423       return -1;
00424    }
00425 
00426    ast_rwlock_wrlock(&config_lock);
00427    while ((cat = ast_category_browse(calendar_config, cat))) {
00428       if (!strcasecmp(cat, "general")) {
00429          continue;
00430       }
00431 
00432       if (!(val = ast_variable_retrieve(calendar_config, cat, "type")) || strcasecmp(val, tech->type)) {
00433          continue;
00434       }
00435 
00436       /* A serious error occurred loading calendars from this tech and it should be disabled */
00437       if (!(cal = build_calendar(calendar_config, cat, tech))) {
00438          ast_calendar_unregister(tech);
00439          ast_rwlock_unlock(&config_lock);
00440          return -1;
00441       }
00442 
00443       cal = unref_calendar(cal);
00444    }
00445 
00446    ast_rwlock_unlock(&config_lock);
00447 
00448    return 0;
00449 }

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

Definition at line 471 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::tech.

Referenced by ast_calendar_unregister().

00472 {
00473    struct ast_calendar *cal = user_data;
00474    struct ast_calendar_tech *tech = arg;
00475 
00476    if (cal->tech == tech) {
00477       return CMP_MATCH;
00478    }
00479 
00480    return 0;
00481 }

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

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

00881 {
00882    struct ast_calendar_event *old_event = obj, *new_event;
00883    struct ao2_container *new_events = arg;
00884 
00885    /* If we don't find the old_event in new_events, then we can safely delete the old_event */
00886    if (!(new_event = find_event(new_events, old_event->uid))) {
00887       old_event = destroy_event(old_event);
00888       return CMP_MATCH;
00889    }
00890 
00891    /* We have events to merge.  If any data that will affect a scheduler event has changed,
00892     * then we need to replace the scheduler event */
00893    schedule_calendar_event(old_event->owner, old_event, new_event);
00894 
00895    /* Since we don't want to mess with cancelling sched events and adding new ones, just
00896     * copy the internals of the new_event to the old_event */
00897    copy_event_data(old_event, new_event);
00898 
00899    /* Now we can go ahead and unlink the new_event from new_events and unref it so that only completely
00900     * new events remain in the container */
00901    ao2_unlink(new_events, new_event);
00902    new_event = ast_calendar_unref_event(new_event);
00903 
00904    return 0;
00905 }

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

Definition at line 624 of file res_calendar.c.

00625 {
00626    return 0;
00627 }

static int reload ( void   )  [static]

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

01608 {
01609    struct ast_calendar_tech *iter;
01610 
01611    ast_mutex_lock(&reloadlock);
01612 
01613    /* Mark existing calendars for deletion */
01614    ao2_callback(calendars, OBJ_NODATA | OBJ_MULTIPLE, cb_pending_deletion, NULL);
01615    load_config(NULL);
01616 
01617    AST_LIST_LOCK(&techs);
01618    AST_LIST_TRAVERSE(&techs, iter, list) {
01619       if (load_tech_calendars(iter)) {
01620          ast_log(LOG_WARNING, "Failed to reload %s calendars, module disabled\n", iter->type);
01621       }
01622    }
01623    AST_LIST_UNLOCK(&techs);
01624 
01625    /* Delete calendars that no longer show up in the config */
01626    ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, cb_rm_pending_deletion, NULL);
01627 
01628    ast_mutex_unlock(&reloadlock);
01629 
01630    return 0;
01631 }

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

00819 {
00820    struct timeval now = ast_tvnow();
00821    struct ast_calendar_event *event;
00822    time_t alarm_notify_sched = 0, devstate_sched_start, devstate_sched_end;
00823    int changed = 0;
00824 
00825    event = cmp_event ? cmp_event : old_event;
00826 
00827    ao2_lock(event);
00828    if (!cmp_event || old_event->alarm != event->alarm) {
00829       changed = 1;
00830       if (cal->autoreminder) {
00831          alarm_notify_sched = (event->start - (60 * cal->autoreminder) - now.tv_sec) * 1000;
00832       } else if (event->alarm) {
00833          alarm_notify_sched = (event->alarm - now.tv_sec) * 1000;
00834       }
00835 
00836       /* For now, send the notification if we missed it, but the meeting hasn't happened yet */
00837       if (event->start >=  now.tv_sec) {
00838          if (alarm_notify_sched <= 0) {
00839             alarm_notify_sched = 1;
00840          }
00841          ast_mutex_lock(&refreshlock);
00842          AST_SCHED_REPLACE(old_event->notify_sched, sched, alarm_notify_sched, calendar_event_notify, old_event);
00843          ast_mutex_unlock(&refreshlock);
00844          ast_debug(3, "Calendar alarm event notification scheduled to happen in %ld ms\n", (long) alarm_notify_sched);
00845       }
00846    }
00847 
00848    if (!cmp_event || old_event->start != event->start) {
00849       changed = 1;
00850       devstate_sched_start = (event->start - now.tv_sec) * 1000;
00851 
00852       if (devstate_sched_start < 1) {
00853          devstate_sched_start = 1;
00854       }
00855 
00856       ast_mutex_lock(&refreshlock);
00857       AST_SCHED_REPLACE(old_event->bs_start_sched, sched, devstate_sched_start, calendar_devstate_change, old_event);
00858       ast_mutex_unlock(&refreshlock);
00859       ast_debug(3, "Calendar bs_start event notification scheduled to happen in %ld ms\n", (long) devstate_sched_start);
00860    }
00861 
00862    if (!cmp_event || old_event->end != event->end) {
00863       changed = 1;
00864       devstate_sched_end = (event->end - now.tv_sec) * 1000;
00865       ast_mutex_lock(&refreshlock);
00866       AST_SCHED_REPLACE(old_event->bs_end_sched, sched, devstate_sched_end, calendar_devstate_change, old_event);
00867       ast_mutex_unlock(&refreshlock);
00868       ast_debug(3, "Calendar bs_end event notification scheduled to happen in %ld ms\n", (long) devstate_sched_end);
00869    }
00870 
00871    if (changed) {
00872       ast_cond_signal(&refresh_condition);
00873    }
00874 
00875    ao2_unlock(event);
00876 
00877    return 0;
00878 }

static int unload_module ( void   )  [static]

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

00220 {
00221    ao2_ref(cal, -1);
00222    return NULL;
00223 }


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

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1727 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 977 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 1527 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ast_config* calendar_config [static]

Definition at line 199 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 1586 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 1157 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 1268 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 1375 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ao2_container* calendars [static]

Definition at line 167 of file res_calendar.c.

Referenced by find_calendar().

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

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

ast_cond_t refresh_condition [static]

Definition at line 171 of file res_calendar.c.

pthread_t refresh_thread = AST_PTHREADT_NULL [static]

Definition at line 169 of file res_calendar.c.

ast_mutex_t refreshlock [static]

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

struct sched_context* sched [static]

Definition at line 168 of file res_calendar.c.


Generated on Wed Apr 6 11:30:08 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7