Wed Oct 28 13:33:24 2009

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"

Include dependency graph for res_calendar.c:

Go to the source code of this file.

Data Structures

struct  evententry
struct  eventlist
struct  techs

Defines

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

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int add_event_to_list (struct eventlist *events, struct ast_calendar_event *event, time_t start, time_t end)
static int add_new_event_cb (void *obj, void *arg, int flags)
void ast_calendar_clear_events (struct ast_calendar *cal)
 Remove all events from calendar.
struct ast_configast_calendar_config_acquire (void)
 Grab and lock pointer to the calendar config (read only).
void ast_calendar_config_release (void)
 Release the calendar config.
struct ast_calendar_eventast_calendar_event_alloc (struct ast_calendar *cal)
 Allocate an astobj2 ast_calendar_event object.
struct ao2_containerast_calendar_event_container_alloc (void)
 Allocate an astobj2 container for ast_calendar_event objects.
void ast_calendar_merge_events (struct ast_calendar *cal, struct ao2_container *new_events)
 Add an event to the list of events for a calendar.
int ast_calendar_register (struct ast_calendar_tech *tech)
 Register a new calendar technology.
struct ast_calendar_eventast_calendar_unref_event (struct ast_calendar_event *event)
 Unreference an ast_calendar_event.
void ast_calendar_unregister (struct ast_calendar_tech *tech)
 Unregister a new calendar technology.
static struct ast_calendarbuild_calendar (struct ast_config *cfg, const char *cat, const struct ast_calendar_tech *tech)
static int calendar_busy_callback (void *obj, void *arg, int flags)
static int calendar_busy_exec (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 A dialplan function that can be used to determine the busy status of a calendar.
static int calendar_cmp_fn (void *obj, void *arg, int flags)
static void calendar_destructor (void *obj)
static int calendar_devstate_change (const void *data)
static void calendar_event_destructor (void *obj)
static int calendar_event_notify (const void *data)
static int calendar_event_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int calendar_hash_fn (const void *obj, const int flags)
static int calendar_is_busy (struct ast_calendar *cal)
static void calendar_join_attendees (struct ast_calendar_event *event, char *buf, size_t len)
static int calendar_query_exec (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int calendar_query_result_exec (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int calendar_write_exec (struct ast_channel *chan, const char *cmd, char *data, const char *value)
static enum ast_device_state calendarstate (const char *data)
static int cb_pending_deletion (void *user_data, void *arg, int flags)
static int cb_rm_pending_deletion (void *user_data, void *arg, int flags)
static int clear_events_cb (void *user_data, void *arg, int flags)
static void copy_event_data (struct ast_calendar_event *dst, struct ast_calendar_event *src)
static struct ast_calendar_eventdestroy_event (struct ast_calendar_event *event)
static void * do_notify (void *data)
static void * do_refresh (void *data)
static char * epoch_to_string (char *buf, size_t buflen, time_t epoch)
static int event_cmp_fn (void *obj, void *arg, int flags)
static int event_hash_fn (const void *obj, const int flags)
static void event_notification_destroy (void *data)
static void * event_notification_duplicate (void *data)
static void eventlist_destroy (void *data)
static void eventlist_destructor (void *obj)
static void * eventlist_duplicate (void *data)
static struct ast_calendarfind_calendar (const char *name)
static struct ast_calendar_eventfind_event (struct ao2_container *events, const char *uid)
static char * generate_random_string (char *buf, size_t size)
 Generate 32 byte random string (stolen from chan_sip.c).
static char * handle_dump_sched (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_calendar (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_show_calendars (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to list available calendars.
static 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 , .description = "Asterisk Calendar integration" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_custom_function calendar_busy_function
static struct ast_cli_entry calendar_cli []
static struct ast_configcalendar_config
static struct ast_custom_function calendar_event_function
static struct ast_custom_function calendar_query_function
static struct ast_custom_function calendar_query_result_function
static struct ast_custom_function calendar_write_function
static struct ao2_containercalendars
static ast_rwlock_t config_lock = { 0 }
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
Todo:
Support writing attendees

Definition in file res_calendar.c.


Define Documentation

#define CALENDAR_BUCKETS   19

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

static void __unreg_module ( void   )  [static]

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

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

Referenced by calendar_query_exec().

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

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

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

00896 {
00897    struct ast_calendar_event *new_event = obj;
00898    struct ao2_container *events = arg;
00899 
00900    ao2_link(events, new_event);
00901    schedule_calendar_event(new_event->owner, new_event, NULL);
00902    return CMP_MATCH;
00903 }

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

00546 {
00547    ast_debug(3, "Clearing all events for calendar %s\n", cal->name);
00548 
00549    ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, clear_events_cb, NULL);
00550 }

struct ast_config* ast_calendar_config_acquire ( void   )  [read]

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

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

Definition at line 196 of file res_calendar.c.

References ast_rwlock_rdlock(), and ast_rwlock_unlock().

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

00197 {
00198    ast_rwlock_rdlock(&config_lock);
00199 
00200    if (!calendar_config) {
00201       ast_rwlock_unlock(&config_lock);
00202       return NULL;
00203    }
00204 
00205    return calendar_config;
00206 }

void ast_calendar_config_release ( void   ) 

Release the calendar config.

Definition at line 208 of file res_calendar.c.

References ast_rwlock_unlock(), and config_lock.

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

00209 {
00210    ast_rwlock_unlock(&config_lock);
00211 }

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

Allocate an astobj2 ast_calendar_event object.

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

Definition at line 552 of file res_calendar.c.

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

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

00553 {
00554    struct ast_calendar_event *event;
00555    if (!(event = ao2_alloc(sizeof(*event), calendar_event_destructor))) {
00556       return NULL;
00557    }
00558 
00559    if (ast_string_field_init(event, 32)) {
00560       event = ast_calendar_unref_event(event);
00561       return NULL;
00562    }
00563 
00564    event->owner = cal;
00565    event->notify_sched = -1;
00566    event->bs_start_sched = -1;
00567    event->bs_end_sched = -1;
00568 
00569    AST_LIST_HEAD_INIT_NOLOCK(&event->attendees);
00570 
00571    return event;
00572 }

struct ao2_container* ast_calendar_event_container_alloc ( void   )  [read]

Allocate an astobj2 container for ast_calendar_event objects.

Returns:
a new event container

Definition at line 574 of file res_calendar.c.

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

Referenced by caldav_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 905 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 icalendar_update_events(), update_caldav(), and update_exchangecal().

00906 {
00907    /* Loop through all events attached to the calendar.  If there is a matching new event
00908     * merge its data over and handle any schedule changes that need to be made.  Then remove
00909     * the new_event from new_events so that we are left with only new_events that we can add later. */
00910    ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, merge_events_cb, new_events);
00911 
00912    /* Now, we should only have completely new events in new_events.  Loop through and add them */
00913    ao2_callback(new_events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, add_new_event_cb, cal->events);
00914 }

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 441 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, evententry::list, load_tech_calendars(), LOG_WARNING, and ast_calendar_tech::type.

Referenced by load_module().

00442 {
00443    struct ast_calendar_tech *iter;
00444 
00445    AST_LIST_LOCK(&techs);
00446    AST_LIST_TRAVERSE(&techs, iter, list) {
00447       if(!strcasecmp(tech->type, iter->type)) {
00448          ast_log(LOG_WARNING, "Already have a handler for calendar type '%s'\n", tech->type);
00449          AST_LIST_UNLOCK(&techs);
00450          return -1;
00451       }
00452    }
00453    AST_LIST_INSERT_HEAD(&techs, tech, list);
00454    AST_LIST_UNLOCK(&techs);
00455 
00456    ast_verb(2, "Registered calendar type '%s' (%s)\n", tech->type, tech->description);
00457 
00458    return load_tech_calendars(tech);
00459 }

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

Unreference an ast_calendar_event.

Parameters:
event event to unref
Returns:
NULL

Definition at line 259 of file res_calendar.c.

References ao2_ref.

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

00260 {
00261    ao2_ref(event, -1);
00262    return NULL;
00263 }

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

Referenced by load_tech_calendars(), and unload_module().

00474 {
00475    struct ast_calendar_tech *iter;
00476 
00477    AST_LIST_LOCK(&techs);
00478    AST_LIST_TRAVERSE_SAFE_BEGIN(&techs, iter, list) {
00479       if (iter != tech) {
00480          continue;
00481       }
00482 
00483       ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, match_caltech_cb, tech);
00484 
00485       AST_LIST_REMOVE_CURRENT(list);
00486       ast_verb(2, "Unregistered calendar type '%s'\n", tech->type);
00487       break;
00488    }
00489    AST_LIST_TRAVERSE_SAFE_END;
00490    AST_LIST_UNLOCK(&techs);
00491 
00492 }

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

Definition at line 333 of file res_calendar.c.

References ao2_alloc, ao2_container_alloc, ao2_link, ao2_unlink, ast_cond_init(), ast_log(), ast_pthread_create, AST_PTHREADT_NULL, ast_string_field_init, ast_string_field_set, ast_variable_browse(), ast_calendar::autoreminder, CALENDAR_BUCKETS, calendar_destructor(), event_cmp_fn(), event_hash_fn(), ast_calendar::events, find_calendar(), ast_calendar_tech::load_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::thread, ast_calendar::timeframe, ast_calendar::unload, unref_calendar(), and ast_variable::value.

Referenced by load_tech_calendars().

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

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

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

00296 {
00297    struct ast_calendar_event *event = obj;
00298    int *is_busy = arg;
00299    struct timeval tv = ast_tvnow();
00300 
00301    if (tv.tv_sec >= event->start && tv.tv_sec <= event->end && event->busy_state > AST_CALENDAR_BS_FREE) {
00302       *is_busy = 1;
00303       return CMP_STOP;
00304    }
00305 
00306    return 0;
00307 }

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

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

00945 {
00946    struct ast_calendar *cal;
00947 
00948    if (ast_strlen_zero(data)) {
00949       ast_log(LOG_WARNING, "CALENDAR_BUSY requires an argument: CALENDAR_BUSY(<calendar_name>)\n");
00950       return -1;
00951    }
00952 
00953    cal = find_calendar(data);
00954 
00955    if (!cal) {
00956       ast_log(LOG_WARNING, "Could not find calendar '%s'\n", data);
00957       return -1;
00958    }
00959 
00960    strcpy(buf, calendar_is_busy(cal) ? "1" : "0");
00961 
00962    return 0;
00963 }

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

Definition at line 225 of file res_calendar.c.

References CMP_MATCH, CMP_STOP, and ast_calendar::name.

Referenced by load_module().

00226 {
00227    const struct ast_calendar *one = obj, *two = arg;
00228    return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP: 0;
00229 }

static void calendar_destructor ( void *  obj  )  [static]

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

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

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

Definition at line 746 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(), calendar_is_busy(), evententry::event, LOG_WARNING, ast_calendar::name, and ast_calendar_event::owner.

Referenced by schedule_calendar_event().

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

static void calendar_event_destructor ( void *  obj  )  [static]

Definition at line 494 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, evententry::event, ast_calendar::name, evententry::next, and ast_calendar_event::owner.

Referenced by ast_calendar_event_alloc().

00495 {
00496    struct ast_calendar_event *event = obj;
00497    struct ast_calendar_attendee *attendee;
00498 
00499    ast_debug(3, "Destroying event for calendar '%s'\n", event->owner->name);
00500    ast_string_field_free_memory(event);
00501    while ((attendee = AST_LIST_REMOVE_HEAD(&event->attendees, next))) {
00502       if (attendee->data) {
00503          ast_free(attendee->data);
00504       }
00505       ast_free(attendee);
00506    }
00507 }

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

Definition at line 722 of file res_calendar.c.

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

Referenced by schedule_calendar_event().

00723 {
00724    struct ast_calendar_event *event = (void *)data;
00725    int res = -1;
00726    pthread_t notify_thread = AST_PTHREADT_NULL;
00727 
00728    if (!(event && event->owner)) {
00729       ast_log(LOG_ERROR, "Extremely low-cal...in fact cal is NULL!\n");
00730       return res;
00731    }
00732 
00733    ao2_ref(event, +1);
00734    event->notify_sched = -1;
00735 
00736    if (ast_pthread_create_background(&notify_thread, NULL, do_notify, event) < 0) {
00737       ast_log(LOG_ERROR, "Could not create notification thread\n");
00738       return res;
00739    }
00740 
00741    res = 0;
00742 
00743    return res;
00744 }

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

Definition at line 1502 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_datastore::data, ast_calendar_event::description, ast_calendar_event::end, evententry::event, ast_calendar_event::location, LOG_WARNING, ast_calendar::name, ast_channel::name, ast_calendar_event::organizer, ast_calendar_event::owner, ast_calendar_event::start, ast_calendar_event::summary, and ast_calendar_event::uid.

01503 {
01504    struct ast_datastore *datastore;
01505    struct ast_calendar_event *event;
01506 
01507    if (ast_strlen_zero(data)) {
01508       ast_log(LOG_WARNING, "%s requires an argument\n", cmd);
01509       return -1;
01510    }
01511 
01512    ast_channel_lock(chan);
01513    if (!(datastore = ast_channel_datastore_find(chan, &event_notification_datastore, NULL))) {
01514       ast_log(LOG_WARNING, "There is no event notification datastore on '%s'!\n", chan->name);
01515       ast_channel_unlock(chan);
01516       return -1;
01517    }
01518    ast_channel_unlock(chan);
01519 
01520    if (!(event = datastore->data)) {
01521       ast_log(LOG_WARNING, "The datastore contains no data!\n");
01522       return -1;
01523    }
01524 
01525    if (!strcasecmp(data, "summary")) {
01526       ast_copy_string(buf, event->summary, len);
01527    } else if (!strcasecmp(data, "description")) {
01528       ast_copy_string(buf, event->description, len);
01529    } else if (!strcasecmp(data, "organizer")) {
01530       ast_copy_string(buf, event->organizer, len);
01531    } else if (!strcasecmp(data, "location")) {
01532       ast_copy_string(buf, event->location, len);
01533    } else if (!strcasecmp(data, "calendar")) {
01534       ast_copy_string(buf, event->owner->name, len);
01535    } else if (!strcasecmp(data, "uid")) {
01536       ast_copy_string(buf, event->uid, len);
01537    } else if (!strcasecmp(data, "start")) {
01538       snprintf(buf, len, "%ld", (long)event->start);
01539    } else if (!strcasecmp(data, "end")) {
01540       snprintf(buf, len, "%ld", (long)event->end);
01541    } else if (!strcasecmp(data, "busystate")) {
01542       snprintf(buf, len, "%d", event->busy_state);
01543    } else if (!strcasecmp(data, "attendees")) {
01544       calendar_join_attendees(event, buf, len);
01545    }
01546 
01547 
01548    return 0;
01549 }

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

Definition at line 219 of file res_calendar.c.

References ast_str_case_hash(), and ast_calendar::name.

Referenced by load_module().

00220 {
00221    const struct ast_calendar *cal = obj;
00222    return ast_str_case_hash(cal->name);
00223 }

static int calendar_is_busy ( struct ast_calendar cal  )  [static]

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

00310 {
00311    int is_busy = 0;
00312 
00313    ao2_callback(cal->events, OBJ_NODATA, calendar_busy_callback, &is_busy);
00314 
00315    return is_busy;
00316 }

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

Definition at line 1150 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 evententry::next.

Referenced by calendar_event_read(), and calendar_query_result_exec().

01151 {
01152    struct ast_str *tmp;
01153    struct ast_calendar_attendee *attendee;
01154 
01155    if (!(tmp = ast_str_create(32))) {
01156       ast_log(LOG_ERROR, "Could not allocate memory for attendees!\n");
01157       return;
01158    }
01159 
01160    AST_LIST_TRAVERSE(&event->attendees, attendee, next) {
01161       ast_str_append(&tmp, 0, "%s%s", attendee == AST_LIST_FIRST(&event->attendees) ? "" : ",", attendee->data);
01162    }
01163 
01164    ast_copy_string(buf, ast_str_buffer(tmp), len);
01165    ast_free(tmp);
01166 }

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

Definition at line 1064 of file res_calendar.c.

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

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

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

Definition at line 1168 of file res_calendar.c.

References 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_datastore::data, ast_calendar_event::description, ast_calendar_event::end, evententry::event, events, evententry::list, ast_calendar_event::location, LOG_WARNING, ast_calendar::name, ast_channel::name, ast_calendar_event::organizer, ast_calendar_event::owner, ast_calendar_event::start, ast_calendar_event::summary, and ast_calendar_event::uid.

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

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

Definition at line 1257 of file res_calendar.c.

References AST_APP_ARG, ast_calendar_event_alloc(), ast_calendar_unref_event(), AST_DECLARE_APP_ARGS, ast_free, ast_log(), AST_STANDARD_APP_ARGS, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_calendar_event::description, evententry::event, find_calendar(), ast_calendar_event::location, LOG_ERROR, LOG_WARNING, ast_calendar::name, ast_calendar_event::organizer, ast_calendar_event::summary, ast_calendar::tech, ast_calendar_event::uid, unref_calendar(), and ast_calendar_tech::write_event.

01258 {
01259    int i, j, ret = -1;
01260    char *val_dup = NULL;
01261    struct ast_calendar *cal = NULL;
01262    struct ast_calendar_event *event = NULL;
01263    AST_DECLARE_APP_ARGS(fields,
01264       AST_APP_ARG(field)[10];
01265    );
01266    AST_DECLARE_APP_ARGS(values,
01267       AST_APP_ARG(value)[10];
01268    );
01269 
01270    if (!(val_dup = ast_strdup(value))) {
01271       ast_log(LOG_ERROR, "Could not allocate memory for values\n");
01272       return -1;
01273    }
01274 
01275    AST_STANDARD_APP_ARGS(fields, data);
01276    AST_STANDARD_APP_ARGS(values, val_dup);
01277 
01278    /* XXX Eventually we will support unnamed calendars, so if we don't find one, we parse
01279     * for a calendar type and create it */
01280    if (!(cal = find_calendar(fields.field[0]))) {
01281       ast_log(LOG_WARNING, "Couldn't find calendar '%s'\n", fields.field[0]);
01282       goto write_cleanup;
01283    }
01284 
01285    if (!(cal->tech->write_event)) {
01286       ast_log(LOG_WARNING, "Calendar '%s' has no write function!\n", cal->name);
01287       goto write_cleanup;
01288    }
01289 
01290    if (!(event = ast_calendar_event_alloc(cal))) {
01291       goto write_cleanup;
01292    }
01293 
01294    if (ast_strlen_zero(fields.field[0])) {
01295       ast_log(LOG_WARNING, "CALENDAR_WRITE requires a calendar name!\n");
01296       goto write_cleanup;
01297    }
01298 
01299    if (fields.argc - 1 != values.argc) {
01300       ast_log(LOG_WARNING, "CALENDAR_WRITE should have the same number of fields (%d) and values (%d)!\n", fields.argc - 1, values.argc);
01301       goto write_cleanup;
01302    }
01303 
01304    event->owner = cal;
01305 
01306    for (i = 1, j = 0; i < fields.argc; i++, j++) {
01307       if (!strcasecmp(fields.field[i], "summary")) {
01308          ast_string_field_set(event, summary, values.value[j]);
01309       } else if (!strcasecmp(fields.field[i], "description")) {
01310          ast_string_field_set(event, description, values.value[j]);
01311       } else if (!strcasecmp(fields.field[i], "organizer")) {
01312          ast_string_field_set(event, organizer, values.value[j]);
01313       } else if (!strcasecmp(fields.field[i], "location")) {
01314          ast_string_field_set(event, location, values.value[j]);
01315       } else if (!strcasecmp(fields.field[i], "uid")) {
01316          ast_string_field_set(event, uid, values.value[j]);
01317       } else if (!strcasecmp(fields.field[i], "start")) {
01318          event->start = atoi(values.value[j]);
01319       } else if (!strcasecmp(fields.field[i], "end")) {
01320          event->end = atoi(values.value[j]);
01321       } else if (!strcasecmp(fields.field[i], "busystate")) {
01322          event->busy_state = atoi(values.value[j]);
01323       } else {
01324          ast_log(LOG_WARNING, "Unknown calendar event field '%s'\n", fields.field[i]);
01325       }
01326    }
01327 
01328    if((ret = cal->tech->write_event(event))) {
01329       ast_log(LOG_WARNING, "Writing event to calendar '%s' failed!\n", cal->name);
01330    }
01331 
01332 write_cleanup:
01333    if (cal) {
01334       cal = unref_calendar(cal);
01335    }
01336    if (event) {
01337       event = ast_calendar_unref_event(event);
01338    }
01339    if (val_dup) {
01340       ast_free(val_dup);
01341    }
01342 
01343    return ret;
01344 }

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

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

00319 {
00320    struct ast_calendar *cal;
00321 
00322    if (ast_strlen_zero(data) || (!(cal = find_calendar(data)))) {
00323       return AST_DEVICE_INVALID;
00324    }
00325 
00326    if (cal->tech->is_busy) {
00327       return cal->tech->is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
00328    }
00329 
00330    return calendar_is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
00331 }

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

Definition at line 1556 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::pending_deletion.

Referenced by reload().

01557 {
01558    struct ast_calendar *cal = user_data;
01559 
01560    cal->pending_deletion = 1;
01561 
01562    return CMP_MATCH;
01563 }

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

Definition at line 1565 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::pending_deletion.

Referenced by reload().

01566 {
01567    struct ast_calendar *cal = user_data;
01568 
01569    return cal->pending_deletion ? CMP_MATCH : 0;
01570 }

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

Definition at line 536 of file res_calendar.c.

References CMP_MATCH, destroy_event(), and evententry::event.

Referenced by ast_calendar_clear_events().

00537 {
00538    struct ast_calendar_event *event = user_data;
00539 
00540    event = destroy_event(event);
00541 
00542    return CMP_MATCH;
00543 }

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

Definition at line 780 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::description, ast_calendar_event::end, ast_calendar_event::location, evententry::next, ast_calendar_event::organizer, ast_calendar_event::owner, ast_calendar_event::start, ast_calendar_event::summary, and ast_calendar_event::uid.

Referenced by merge_events_cb().

00781 {
00782    struct ast_calendar_attendee *attendee;
00783 
00784    ast_string_field_set(dst, summary, src->summary);
00785    ast_string_field_set(dst, description, src->description);
00786    ast_string_field_set(dst, organizer, src->organizer);
00787    ast_string_field_set(dst, location, src->location);
00788    ast_string_field_set(dst, uid, src->uid);
00789    dst->owner = src->owner;
00790    dst->start = src->start;
00791    dst->end = src->end;
00792    dst->alarm = src->alarm;
00793    dst->busy_state = src->busy_state;
00794 
00795    /* Delete any existing attendees */
00796    while ((attendee = AST_LIST_REMOVE_HEAD(&dst->attendees, next))) {
00797       ast_free(attendee);
00798    }
00799 
00800    /* Copy over the new attendees */
00801    while ((attendee = AST_LIST_REMOVE_HEAD(&src->attendees, next))) {
00802       AST_LIST_INSERT_TAIL(&dst->attendees, attendee, next);
00803    }
00804 }

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

Definition at line 511 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, and ast_calendar_event::owner.

Referenced by clear_events_cb(), and merge_events_cb().

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

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

Definition at line 625 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, buf, chan, ast_channel::context, ast_datastore::data, DATASTORE_INHERIT_FOREVER, evententry::event, 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().

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

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

Definition at line 1598 of file res_calendar.c.

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

01599 {
01600    for (;;) {
01601       struct timeval now = ast_tvnow();
01602       struct timespec ts = {0,};
01603       int res, wait;
01604 
01605       ast_mutex_lock(&refreshlock);
01606 
01607       if ((wait = ast_sched_wait(sched)) < 0) {
01608          wait = 1000;
01609       }
01610 
01611       ts.tv_sec = (now.tv_sec + wait / 1000) + 1;
01612       res = ast_cond_timedwait(&refresh_condition, &refreshlock, &ts);
01613 
01614       ast_mutex_unlock(&refreshlock);
01615 
01616       ast_sched_runq(sched);
01617    }
01618 
01619    return NULL;
01620 }

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

Definition at line 1382 of file res_calendar.c.

References ast_localtime(), and ast_strftime().

Referenced by handle_show_calendar().

01383 {
01384    struct ast_tm tm;
01385    struct timeval tv = {
01386       .tv_sec = epoch,
01387    };
01388 
01389    if (!epoch) {
01390       *buf = '\0';
01391       return buf;
01392    }
01393    ast_localtime(&tv, &tm, NULL);
01394    ast_strftime(buf, buflen, "%F %r %z", &tm);
01395 
01396    return buf;
01397 }

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

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

00246 {
00247    const struct ast_calendar_event *one = obj, *two = arg;
00248    return !strcmp(one->uid, two->uid) ? CMP_MATCH | CMP_STOP : 0;
00249 }

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

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

00240 {
00241    const struct ast_calendar_event *event = obj;
00242    return ast_str_hash(event->uid);
00243 }

static void event_notification_destroy ( void *  data  )  [static]

Definition at line 579 of file res_calendar.c.

References ast_calendar_unref_event(), and evententry::event.

00580 {
00581    struct ast_calendar_event *event = data;
00582 
00583    event = ast_calendar_unref_event(event);
00584 
00585 }

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

Definition at line 587 of file res_calendar.c.

References ao2_ref, and evententry::event.

00588 {
00589    struct ast_calendar_event *event = data;
00590 
00591    if (!event) {
00592       return NULL;
00593    }
00594 
00595    ao2_ref(event, +1);
00596 
00597    return event;
00598 }

static void eventlist_destroy ( void *  data  )  [static]

Definition at line 1044 of file res_calendar.c.

References ao2_ref, and events.

01045 {
01046    struct eventlist *events = data;
01047 
01048    ao2_ref(events, -1);
01049 }

static void eventlist_destructor ( void *  obj  )  [static]

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

00285 {
00286    struct eventlist *events = obj;
00287    struct evententry *entry;
00288 
00289    while ((entry = AST_LIST_REMOVE_HEAD(events, list))) {
00290       ao2_ref(entry->event, -1);
00291       ast_free(entry);
00292    }
00293 }

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

Definition at line 1051 of file res_calendar.c.

References ao2_ref, and events.

01052 {
01053    struct eventlist *events = data;
01054 
01055    if (!events) {
01056       return NULL;
01057    }
01058 
01059    ao2_ref(events, +1);
01060 
01061    return events;
01062 }

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

Definition at line 231 of file res_calendar.c.

References ao2_find, ast_calendar::name, and OBJ_POINTER.

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

00232 {
00233    struct ast_calendar tmp = {
00234       .name = name,
00235    };
00236    return ao2_find(calendars, &tmp, OBJ_POINTER);
00237 }

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

Definition at line 251 of file res_calendar.c.

References ao2_find, OBJ_POINTER, and ast_calendar_event::uid.

Referenced by merge_events_cb().

00252 {
00253    struct ast_calendar_event tmp = {
00254       .uid = uid,
00255    };
00256    return ao2_find(events, &tmp, OBJ_POINTER);
00257 }

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

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

Definition at line 601 of file res_calendar.c.

References ast_random().

00602 {
00603    long val[4];
00604    int x;
00605 
00606    for (x = 0; x < 4; x++) {
00607       val[x] = ast_random();
00608    }
00609    snprintf(buf, size, "%08lx%08lx%08lx%08lx", val[0], val[1], val[2], val[3]);
00610 
00611    return buf;
00612 }

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

Definition at line 1477 of file res_calendar.c.

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

01478 {
01479    switch(cmd) {
01480    case CLI_INIT:
01481       e->command = "calendar dump sched";
01482       e->usage =
01483          "Usage: calendar dump sched\n"
01484          "       Dump the calendar sched context";
01485       return NULL;
01486 
01487    case CLI_GENERATE:
01488       return NULL;
01489    }
01490 
01491    ast_sched_dump(sched);
01492 
01493    return CLI_SUCCESS;
01494 }

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

Definition at line 1399 of file res_calendar.c.

References ast_calendar_event::alarm, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_cli_args::argc, ast_cli_args::argv, ast_calendar_unref_event(), ast_cli(), ast_strdup, ast_calendar::autoreminder, buf, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_calendar_event::description, ast_calendar_event::end, epoch_to_string(), evententry::event, 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::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.

01400 {
01401 #define FORMAT "%-17.17s : %-20.20s\n"
01402 #define FORMAT2 "%-12.12s: %-40.60s\n"
01403    struct ao2_iterator i;
01404    struct ast_calendar *cal;
01405    struct ast_calendar_event *event;
01406    int which = 0;
01407    char *ret = NULL;
01408 
01409    switch(cmd) {
01410    case CLI_INIT:
01411       e->command = "calendar show calendar";
01412       e->usage =
01413          "Usage: calendar show calendar <calendar name>\n"
01414          "       Displays information about a calendar\n";
01415       return NULL;
01416 
01417    case CLI_GENERATE:
01418       if (a->pos != 3) {
01419          return NULL;
01420       }
01421       i = ao2_iterator_init(calendars, 0);
01422       while ((cal = ao2_iterator_next(&i))) {
01423          if (!strncasecmp(a->word, cal->name, strlen(a->word)) && ++which > a->n) {
01424             ret = ast_strdup(cal->name);
01425             cal = unref_calendar(cal);
01426             break;
01427          }
01428          cal = unref_calendar(cal);
01429       }
01430       ao2_iterator_destroy(&i);
01431       return ret;
01432    }
01433 
01434    if (a->argc != 4) {
01435       return CLI_SHOWUSAGE;
01436    }
01437 
01438    if (!(cal = find_calendar(a->argv[3]))) {
01439       return NULL;
01440    }
01441 
01442    ast_cli(a->fd, FORMAT, "Name", cal->name);
01443    ast_cli(a->fd, FORMAT, "Notify channel", cal->notify_channel);
01444    ast_cli(a->fd, FORMAT, "Notify context", cal->notify_context);
01445    ast_cli(a->fd, FORMAT, "Notify extension", cal->notify_extension);
01446    ast_cli(a->fd, FORMAT, "Notify application", cal->notify_app);
01447    ast_cli(a->fd, FORMAT, "Notify appdata", cal->notify_appdata);
01448    ast_cli(a->fd, "%-17.17s : %d\n", "Refresh time", cal->refresh);
01449    ast_cli(a->fd, "%-17.17s : %d\n", "Timeframe", cal->timeframe);
01450    ast_cli(a->fd, "%-17.17s : %d\n", "Autoreminder", cal->autoreminder);
01451    ast_cli(a->fd, "%s\n", "Events");
01452    ast_cli(a->fd, "%s\n", "------");
01453 
01454    i = ao2_iterator_init(cal->events, 0);
01455    while ((event = ao2_iterator_next(&i))) {
01456       char buf[100];
01457 
01458       ast_cli(a->fd, FORMAT2, "Summary", event->summary);
01459       ast_cli(a->fd, FORMAT2, "Description", event->description);
01460       ast_cli(a->fd, FORMAT2, "Organizer", event->organizer);
01461       ast_cli(a->fd, FORMAT2, "Location", event->location);
01462       ast_cli(a->fd, FORMAT2, "UID", event->uid);
01463       ast_cli(a->fd, FORMAT2, "Start", epoch_to_string(buf, sizeof(buf), event->start));
01464       ast_cli(a->fd, FORMAT2, "End", epoch_to_string(buf, sizeof(buf), event->end));
01465       ast_cli(a->fd, FORMAT2, "Alarm", epoch_to_string(buf, sizeof(buf), event->alarm));
01466       ast_cli(a->fd, "\n");
01467 
01468       event = ast_calendar_unref_event(event);
01469    }
01470    ao2_iterator_destroy(&i);
01471    cal = unref_calendar(cal);
01472    return CLI_SUCCESS;
01473 #undef FORMAT
01474 #undef FORMAT2
01475 }

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

01353 {
01354 #define FORMAT "%-20.20s %-10.10s %-6.6s\n"
01355    struct ao2_iterator i;
01356    struct ast_calendar *cal;
01357 
01358    switch(cmd) {
01359    case CLI_INIT:
01360       e->command = "calendar show calendars";
01361       e->usage =
01362          "Usage: calendar show calendars\n"
01363          "       Lists all registered calendars.\n";
01364       return NULL;
01365    case CLI_GENERATE:
01366       return NULL;
01367    }
01368 
01369    ast_cli(a->fd, FORMAT, "Calendar", "Type", "Status");
01370    ast_cli(a->fd, FORMAT, "--------", "----", "------");
01371    i = ao2_iterator_init(calendars, 0);
01372    while ((cal = ao2_iterator_next(&i))) {
01373       ast_cli(a->fd, FORMAT, cal->name, cal->tech->type, calendar_is_busy(cal) ? "busy" : "free");
01374       cal = unref_calendar(cal);
01375    }
01376    ao2_iterator_destroy(&i);
01377 
01378    return CLI_SUCCESS;
01379 #undef FORMAT
01380 }

static int load_config ( void *  data  )  [static]

Definition at line 917 of file res_calendar.c.

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

00918 {
00919    struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };
00920    struct ast_config *tmpcfg;
00921 
00922    if (!(tmpcfg = ast_config_load2("calendar.conf", "calendar", config_flags)) ||
00923       tmpcfg == CONFIG_STATUS_FILEINVALID) {
00924       ast_log(LOG_ERROR, "Unable to load config calendar.conf\n");
00925       return -1;
00926    }
00927 
00928    if (tmpcfg == CONFIG_STATUS_FILEUNCHANGED) {
00929       return 0;
00930    }
00931 
00932    ast_rwlock_wrlock(&config_lock);
00933    if (calendar_config) {
00934       ast_config_destroy(calendar_config);
00935    }
00936 
00937    calendar_config = tmpcfg;
00938    ast_rwlock_unlock(&config_lock);
00939 
00940    return 0;
00941 }

static int load_module ( void   )  [static]

Definition at line 1648 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_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, and sched_context_create().

01649 {
01650    if (load_config(NULL)) {
01651       /* We don't have calendar support enabled */
01652       return 0;
01653    }
01654 
01655    if (!(calendars = ao2_container_alloc(CALENDAR_BUCKETS, calendar_hash_fn, calendar_cmp_fn))) {
01656       ast_log(LOG_ERROR, "Unable to allocate calendars container!\n");
01657       return -1;
01658    }
01659 
01660    ast_mutex_init(&refreshlock);
01661    ast_cond_init(&refresh_condition, NULL);
01662    ast_mutex_init(&reloadlock);
01663 
01664    if (!(sched = sched_context_create())) {
01665       ast_log(LOG_ERROR, "Unable to create sched context\n");
01666       return -1;
01667    }
01668 
01669    if (ast_pthread_create_background(&refresh_thread, NULL, do_refresh, NULL) < 0) {
01670       ast_log(LOG_ERROR, "Unable to start refresh thread--notifications disabled!\n");
01671    }
01672 
01673    ast_custom_function_register(&calendar_busy_function);
01674    ast_custom_function_register(&calendar_event_function);
01675    ast_custom_function_register(&calendar_query_function);
01676    ast_custom_function_register(&calendar_query_result_function);
01677    ast_custom_function_register(&calendar_write_function);
01678    ast_cli_register_multiple(calendar_cli, ARRAY_LEN(calendar_cli));
01679 
01680    ast_devstate_prov_add("Calendar", calendarstate);
01681 
01682    /* Since other modules depend on this, disable unloading */
01683    ast_module_ref(ast_module_info->self);
01684 
01685    return 0;
01686 }

static int load_tech_calendars ( struct ast_calendar_tech tech  )  [static]

Definition at line 405 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::type, and unref_calendar().

Referenced by ast_calendar_register(), and reload().

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

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

Definition at line 461 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::tech.

Referenced by ast_calendar_unregister().

00462 {
00463    struct ast_calendar *cal = user_data;
00464    struct ast_calendar_tech *tech = arg;
00465 
00466    if (cal->tech == tech) {
00467       return CMP_MATCH;
00468    }
00469 
00470    return 0;
00471 }

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

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

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

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

Definition at line 614 of file res_calendar.c.

00615 {
00616    return 0;
00617 }

static int reload ( void   )  [static]

Definition at line 1572 of file res_calendar.c.

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

01573 {
01574    struct ast_calendar_tech *iter;
01575 
01576    ast_mutex_lock(&reloadlock);
01577 
01578    /* Mark existing calendars for deletion */
01579    ao2_callback(calendars, OBJ_NODATA | OBJ_MULTIPLE, cb_pending_deletion, NULL);
01580    load_config(NULL);
01581 
01582    AST_LIST_LOCK(&techs);
01583    AST_LIST_TRAVERSE(&techs, iter, list) {
01584       if (load_tech_calendars(iter)) {
01585          ast_log(LOG_WARNING, "Failed to reload %s calendars, module disabled\n", iter->type);
01586       }
01587    }
01588    AST_LIST_UNLOCK(&techs);
01589 
01590    /* Delete calendars that no longer show up in the config */
01591    ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, cb_rm_pending_deletion, NULL);
01592 
01593    ast_mutex_unlock(&reloadlock);
01594 
01595    return 0;
01596 }

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 806 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, evententry::event, ast_calendar_event::notify_sched, and ast_calendar_event::start.

Referenced by add_new_event_cb(), and merge_events_cb().

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

static int unload_module ( void   )  [static]

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

Definition at line 213 of file res_calendar.c.

References ao2_ref.

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

00214 {
00215    ao2_ref(cal, -1);
00216    return NULL;
00217 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS , .description = "Asterisk Calendar integration" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 1691 of file res_calendar.c.

Definition at line 1691 of file res_calendar.c.

Initial value:

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

Definition at line 965 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ast_cli_entry calendar_cli[] [static]

Initial value:

 {
   AST_CLI_DEFINE(handle_show_calendar, "Display information about a calendar"),
   AST_CLI_DEFINE(handle_show_calendars, "Show registered calendars"),
   AST_CLI_DEFINE(handle_dump_sched, "Dump calendar sched context"),
}

Definition at line 1496 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ast_config* calendar_config [static]

Definition at line 193 of file res_calendar.c.

Referenced by load_config(), and load_tech_calendars().

Initial value:

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

Definition at line 1551 of file res_calendar.c.

Referenced by load_module(), and unload_module().

Initial value:

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

Definition at line 1145 of file res_calendar.c.

Referenced by load_module(), and unload_module().

Initial value:

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

Definition at line 1252 of file res_calendar.c.

Referenced by load_module(), and unload_module().

Initial value:

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

Definition at line 1346 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ao2_container* calendars [static]

Definition at line 161 of file res_calendar.c.

ast_rwlock_t config_lock = { 0 } [static]

Definition at line 194 of file res_calendar.c.

Initial value:

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

Definition at line 173 of file res_calendar.c.

Initial value:

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

Definition at line 179 of file res_calendar.c.

struct ast_channel_tech null_tech [static]

Initial value:

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

Definition at line 619 of file res_calendar.c.

Definition at line 165 of file res_calendar.c.

pthread_t refresh_thread = AST_PTHREADT_NULL [static]

Definition at line 163 of file res_calendar.c.

Definition at line 166 of file res_calendar.c.

struct sched_context* sched [static]

Definition at line 162 of file res_calendar.c.


Generated on Wed Oct 28 13:33:25 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6