Mon Aug 31 12:30:42 2015

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.
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 (int reload)
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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, }
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_custom_function calendar_busy_function
static struct ast_cli_entry calendar_cli []
static struct ast_configcalendar_config
static struct ast_custom_function calendar_event_function
static struct ast_custom_function calendar_query_function
static struct ast_custom_function calendar_query_result_function
static struct ast_custom_function calendar_write_function
static struct ao2_containercalendars
static ast_rwlock_t config_lock = { PTHREAD_RWLOCK_INITIALIZER , NULL, 1 }
static struct ast_datastore_info event_notification_datastore
static struct ast_datastore_info eventlist_datastore_info
static int module_unloading
static struct ast_channel_tech null_tech
static ast_cond_t refresh_condition
static pthread_t refresh_thread = AST_PTHREADT_NULL
static ast_mutex_t refreshlock
static ast_mutex_t reloadlock
static struct sched_contextsched

Detailed Description

Calendaring API.

Todo:

Support responding to a meeting invite

Support writing attendees

Definition in file res_calendar.c.


Define Documentation

#define CALENDAR_BUCKETS   19

Definition at line 199 of file res_calendar.c.

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

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

Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1794 of file res_calendar.c.

static void __unreg_module ( void   )  [static]

Definition at line 1794 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 1027 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, and ast_calendar_event::start.

Referenced by calendar_query_exec().

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

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

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

00952 {
00953    struct ast_calendar_event *new_event = obj;
00954    struct ao2_container *events = arg;
00955 
00956    ao2_link(events, new_event);
00957    schedule_calendar_event(new_event->owner, new_event, NULL);
00958    return CMP_MATCH;
00959 }

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

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

Referenced by calendar_destructor().

00597 {
00598    ast_debug(3, "Clearing all events for calendar %s\n", cal->name);
00599 
00600    ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, clear_events_cb, NULL);
00601 }

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

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

void ast_calendar_config_release ( void   ) 

Release the calendar config.

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

00250 {
00251    ast_rwlock_unlock(&config_lock);
00252 }

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

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

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

00604 {
00605    struct ast_calendar_event *event;
00606    if (!(event = ao2_alloc(sizeof(*event), calendar_event_destructor))) {
00607       return NULL;
00608    }
00609 
00610    if (ast_string_field_init(event, 32)) {
00611       event = ast_calendar_unref_event(event);
00612       return NULL;
00613    }
00614 
00615    event->owner = cal;
00616    event->notify_sched = -1;
00617    event->bs_start_sched = -1;
00618    event->bs_end_sched = -1;
00619 
00620    AST_LIST_HEAD_INIT_NOLOCK(&event->attendees);
00621 
00622    return event;
00623 }

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 625 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 961 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().

00962 {
00963    /* Loop through all events attached to the calendar.  If there is a matching new event
00964     * merge its data over and handle any schedule changes that need to be made.  Then remove
00965     * the new_event from new_events so that we are left with only new_events that we can add later. */
00966    ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, merge_events_cb, new_events);
00967 
00968    /* Now, we should only have completely new events in new_events.  Loop through and add them */
00969    ao2_callback(new_events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, add_new_event_cb, cal->events);
00970 }

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

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

Referenced by load_module().

00491 {
00492    struct ast_calendar_tech *iter;
00493 
00494    AST_LIST_LOCK(&techs);
00495    AST_LIST_TRAVERSE(&techs, iter, list) {
00496       if(!strcasecmp(tech->type, iter->type)) {
00497          ast_log(LOG_WARNING, "Already have a handler for calendar type '%s'\n", tech->type);
00498          AST_LIST_UNLOCK(&techs);
00499          return -1;
00500       }
00501    }
00502    AST_LIST_INSERT_HEAD(&techs, tech, list);
00503    tech->user = ast_module_user_add(NULL);
00504    AST_LIST_UNLOCK(&techs);
00505 
00506    ast_verb(2, "Registered calendar type '%s' (%s)\n", tech->type, tech->description);
00507 
00508    return load_tech_calendars(tech);
00509 }

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 300 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(), endelm(), event_notification_destroy(), handle_show_calendar(), icalendar_add_event(), merge_events_cb(), and parse_tag().

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

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

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

Referenced by load_tech_calendars(), and unload_module().

00524 {
00525    struct ast_calendar_tech *iter;
00526 
00527    AST_LIST_LOCK(&techs);
00528    AST_LIST_TRAVERSE_SAFE_BEGIN(&techs, iter, list) {
00529       if (iter != tech) {
00530          continue;
00531       }
00532 
00533       ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, match_caltech_cb, tech);
00534 
00535       AST_LIST_REMOVE_CURRENT(list);
00536       ast_module_user_remove(iter->user);
00537       ast_verb(2, "Unregistered calendar type '%s'\n", tech->type);
00538       break;
00539    }
00540    AST_LIST_TRAVERSE_SAFE_END;
00541    AST_LIST_UNLOCK(&techs);
00542 
00543 }

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

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

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

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

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

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

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

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

01001 {
01002    struct ast_calendar *cal;
01003 
01004    if (ast_strlen_zero(data)) {
01005       ast_log(LOG_WARNING, "CALENDAR_BUSY requires an argument: CALENDAR_BUSY(<calendar_name>)\n");
01006       return -1;
01007    }
01008 
01009    cal = find_calendar(data);
01010 
01011    if (!cal) {
01012       ast_log(LOG_WARNING, "Could not find calendar '%s'\n", data);
01013       return -1;
01014    }
01015 
01016    strcpy(buf, calendar_is_busy(cal) ? "1" : "0");
01017    cal = unref_calendar(cal);
01018 
01019    return 0;
01020 }

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

Definition at line 266 of file res_calendar.c.

References CMP_MATCH, and CMP_STOP.

Referenced by load_module().

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

static void calendar_destructor ( void *  obj  )  [static]

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

Referenced by build_calendar().

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

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

Definition at line 800 of file res_calendar.c.

References ao2_ref, ast_calendar_unref_event(), AST_DEVICE_BUSY, AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_log(), ast_tvnow(), calendar_is_busy(), evententry::event, LOG_WARNING, and ast_calendar_event::owner.

Referenced by schedule_calendar_event().

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

static void calendar_event_destructor ( void *  obj  )  [static]

Definition at line 545 of file res_calendar.c.

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

Referenced by ast_calendar_event_alloc().

00546 {
00547    struct ast_calendar_event *event = obj;
00548    struct ast_calendar_attendee *attendee;
00549 
00550    ast_debug(3, "Destroying event for calendar '%s'\n", event->owner->name);
00551    ast_string_field_free_memory(event);
00552    while ((attendee = AST_LIST_REMOVE_HEAD(&event->attendees, next))) {
00553       if (attendee->data) {
00554          ast_free(attendee->data);
00555       }
00556       ast_free(attendee);
00557    }
00558 }

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

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

00777 {
00778    struct ast_calendar_event *event = (void *)data;
00779    int res = -1;
00780    pthread_t notify_thread = AST_PTHREADT_NULL;
00781 
00782    if (!(event && event->owner)) {
00783       ast_log(LOG_ERROR, "Extremely low-cal...in fact cal is NULL!\n");
00784       return res;
00785    }
00786 
00787    ao2_ref(event, +1);
00788    event->notify_sched = -1;
00789 
00790    if (ast_pthread_create_background(&notify_thread, NULL, do_notify, event) < 0) {
00791       ast_log(LOG_ERROR, "Could not create notification thread\n");
00792       return res;
00793    }
00794 
00795    res = 0;
00796 
00797    return res;
00798 }

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

Definition at line 1583 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::end, evententry::event, LOG_WARNING, ast_calendar_event::owner, ast_calendar_event::priority, and ast_calendar_event::start.

01584 {
01585    struct ast_datastore *datastore;
01586    struct ast_calendar_event *event;
01587 
01588    if (!chan) {
01589       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
01590       return -1;
01591    }
01592 
01593    if (ast_strlen_zero(data)) {
01594       ast_log(LOG_WARNING, "%s requires an argument\n", cmd);
01595       return -1;
01596    }
01597 
01598    ast_channel_lock(chan);
01599    if (!(datastore = ast_channel_datastore_find(chan, &event_notification_datastore, NULL))) {
01600       ast_log(LOG_WARNING, "There is no event notification datastore on '%s'!\n", chan->name);
01601       ast_channel_unlock(chan);
01602       return -1;
01603    }
01604    ast_channel_unlock(chan);
01605 
01606    if (!(event = datastore->data)) {
01607       ast_log(LOG_WARNING, "The datastore contains no data!\n");
01608       return -1;
01609    }
01610 
01611    if (!strcasecmp(data, "summary")) {
01612       ast_copy_string(buf, event->summary, len);
01613    } else if (!strcasecmp(data, "description")) {
01614       ast_copy_string(buf, event->description, len);
01615    } else if (!strcasecmp(data, "organizer")) {
01616       ast_copy_string(buf, event->organizer, len);
01617    } else if (!strcasecmp(data, "location")) {
01618       ast_copy_string(buf, event->location, len);
01619    } else if (!strcasecmp(data, "categories")) {
01620       ast_copy_string(buf, event->categories, len);
01621    } else if (!strcasecmp(data, "priority")) {
01622       snprintf(buf, len, "%d", event->priority);
01623    } else if (!strcasecmp(data, "calendar")) {
01624       ast_copy_string(buf, event->owner->name, len);
01625    } else if (!strcasecmp(data, "uid")) {
01626       ast_copy_string(buf, event->uid, len);
01627    } else if (!strcasecmp(data, "start")) {
01628       snprintf(buf, len, "%ld", (long)event->start);
01629    } else if (!strcasecmp(data, "end")) {
01630       snprintf(buf, len, "%ld", (long)event->end);
01631    } else if (!strcasecmp(data, "busystate")) {
01632       snprintf(buf, len, "%u", event->busy_state);
01633    } else if (!strcasecmp(data, "attendees")) {
01634       calendar_join_attendees(event, buf, len);
01635    }
01636 
01637 
01638    return 0;
01639 }

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

Definition at line 260 of file res_calendar.c.

References ast_str_case_hash().

Referenced by load_module().

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

static int calendar_is_busy ( struct ast_calendar cal  )  [static]

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

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

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

Definition at line 1212 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_attendee::data, LOG_ERROR, and evententry::next.

Referenced by calendar_event_read(), and calendar_query_result_exec().

01213 {
01214    struct ast_str *tmp;
01215    struct ast_calendar_attendee *attendee;
01216 
01217    if (!(tmp = ast_str_create(32))) {
01218       ast_log(LOG_ERROR, "Could not allocate memory for attendees!\n");
01219       return;
01220    }
01221 
01222    AST_LIST_TRAVERSE(&event->attendees, attendee, next) {
01223       ast_str_append(&tmp, 0, "%s%s", attendee == AST_LIST_FIRST(&event->attendees) ? "" : ",", attendee->data);
01224    }
01225 
01226    ast_copy_string(buf, ast_str_buffer(tmp), len);
01227    ast_free(tmp);
01228 }

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

Definition at line 1121 of file res_calendar.c.

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

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

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

Definition at line 1230 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_datastore::data, ast_calendar_event::end, evententry::event, events, evententry::list, LOG_WARNING, ast_calendar_event::owner, ast_calendar_event::priority, and ast_calendar_event::start.

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

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

Definition at line 1323 of file res_calendar.c.

References AST_APP_ARG, ast_calendar_event_alloc(), ast_calendar_unref_event(), AST_DECLARE_APP_ARGS, ast_free, ast_log(), AST_STANDARD_APP_ARGS, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_tvnow(), ast_calendar_event::end, evententry::event, find_calendar(), LOG_ERROR, LOG_WARNING, ast_calendar_event::start, ast_calendar::tech, unref_calendar(), and ast_calendar_tech::write_event.

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

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

Definition at line 359 of file res_calendar.c.

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

Referenced by load_module().

00360 {
00361    enum ast_device_state state;
00362    struct ast_calendar *cal;
00363 
00364    if (ast_strlen_zero(data) || (!(cal = find_calendar(data)))) {
00365       return AST_DEVICE_INVALID;
00366    }
00367 
00368    if (cal->tech->is_busy) {
00369       state = cal->tech->is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
00370    } else {
00371       state = calendar_is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
00372    }
00373 
00374    cal = unref_calendar(cal);
00375    return state;
00376 }

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

Definition at line 1646 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::pending_deletion.

Referenced by reload().

01647 {
01648    struct ast_calendar *cal = user_data;
01649 
01650    cal->pending_deletion = 1;
01651 
01652    return CMP_MATCH;
01653 }

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

Definition at line 1655 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::pending_deletion.

Referenced by reload().

01656 {
01657    struct ast_calendar *cal = user_data;
01658 
01659    return cal->pending_deletion ? CMP_MATCH : 0;
01660 }

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

Definition at line 587 of file res_calendar.c.

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

Referenced by ast_calendar_clear_events().

00588 {
00589    struct ast_calendar_event *event = user_data;
00590 
00591    event = destroy_event(event);
00592 
00593    return CMP_MATCH;
00594 }

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

Definition at line 834 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::busy_state, ast_calendar_event::end, evententry::next, ast_calendar_event::owner, ast_calendar_event::priority, and ast_calendar_event::start.

Referenced by merge_events_cb().

00835 {
00836    struct ast_calendar_attendee *attendee;
00837 
00838    ast_string_field_set(dst, summary, src->summary);
00839    ast_string_field_set(dst, description, src->description);
00840    ast_string_field_set(dst, organizer, src->organizer);
00841    ast_string_field_set(dst, location, src->location);
00842    ast_string_field_set(dst, uid, src->uid);
00843    ast_string_field_set(dst, categories, src->categories);
00844    dst->priority = src->priority;
00845    dst->owner = src->owner;
00846    dst->start = src->start;
00847    dst->end = src->end;
00848    dst->alarm = src->alarm;
00849    dst->busy_state = src->busy_state;
00850 
00851    /* Delete any existing attendees */
00852    while ((attendee = AST_LIST_REMOVE_HEAD(&dst->attendees, next))) {
00853       ast_free(attendee);
00854    }
00855 
00856    /* Copy over the new attendees */
00857    while ((attendee = AST_LIST_REMOVE_HEAD(&src->attendees, next))) {
00858       AST_LIST_INSERT_TAIL(&dst->attendees, attendee, next);
00859    }
00860 }

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

Definition at line 562 of file res_calendar.c.

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

Referenced by clear_events_cb(), and merge_events_cb().

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

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

Definition at line 676 of file res_calendar.c.

References ao2_ref, ast_calendar_unref_event(), ast_channel_alloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_release(), ast_channel_unlock, 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, evententry::event, ast_channel::exten, generate_random_string(), ast_datastore::inheritance, LOG_ERROR, LOG_WARNING, ast_channel::nativeformats, 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().

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

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

Definition at line 1688 of file res_calendar.c.

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

Referenced by load_module().

01689 {
01690    for (;;) {
01691       struct timeval now = ast_tvnow();
01692       struct timespec ts = {0,};
01693       int wait;
01694 
01695       ast_mutex_lock(&refreshlock);
01696 
01697       while (!module_unloading) {
01698          if ((wait = ast_sched_wait(sched)) < 0) {
01699             wait = 1000;
01700          }
01701 
01702          ts.tv_sec = (now.tv_sec + wait / 1000) + 1;
01703          if (ast_cond_timedwait(&refresh_condition, &refreshlock, &ts) == ETIMEDOUT) {
01704             break;
01705          }
01706       }
01707       ast_mutex_unlock(&refreshlock);
01708 
01709       if (module_unloading) {
01710          break;
01711       }
01712       ast_sched_runq(sched);
01713    }
01714 
01715    return NULL;
01716 }

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

Definition at line 1461 of file res_calendar.c.

References ast_localtime(), and ast_strftime().

Referenced by handle_show_calendar().

01462 {
01463    struct ast_tm tm;
01464    struct timeval tv = {
01465       .tv_sec = epoch,
01466    };
01467 
01468    if (!epoch) {
01469       *buf = '\0';
01470       return buf;
01471    }
01472    ast_localtime(&tv, &tm, NULL);
01473    ast_strftime(buf, buflen, "%F %r %z", &tm);
01474 
01475    return buf;
01476 }

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

Definition at line 286 of file res_calendar.c.

References CMP_MATCH, and CMP_STOP.

Referenced by ast_calendar_event_container_alloc(), and build_calendar().

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

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

Definition at line 280 of file res_calendar.c.

References ast_str_hash(), and evententry::event.

Referenced by ast_calendar_event_container_alloc(), and build_calendar().

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

static void event_notification_destroy ( void *  data  )  [static]

Definition at line 630 of file res_calendar.c.

References ast_calendar_unref_event(), and evententry::event.

00631 {
00632    struct ast_calendar_event *event = data;
00633 
00634    event = ast_calendar_unref_event(event);
00635 
00636 }

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

Definition at line 638 of file res_calendar.c.

References ao2_ref, and evententry::event.

00639 {
00640    struct ast_calendar_event *event = data;
00641 
00642    if (!event) {
00643       return NULL;
00644    }
00645 
00646    ao2_ref(event, +1);
00647 
00648    return event;
00649 }

static void eventlist_destroy ( void *  data  )  [static]

Definition at line 1101 of file res_calendar.c.

References ao2_ref, and events.

01102 {
01103    struct eventlist *events = data;
01104 
01105    ao2_ref(events, -1);
01106 }

static void eventlist_destructor ( void *  obj  )  [static]

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

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

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

Definition at line 1108 of file res_calendar.c.

References ao2_ref, and events.

01109 {
01110    struct eventlist *events = data;
01111 
01112    if (!events) {
01113       return NULL;
01114    }
01115 
01116    ao2_ref(events, +1);
01117 
01118    return events;
01119 }

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

Definition at line 272 of file res_calendar.c.

References ao2_find, and OBJ_POINTER.

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

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

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

Definition at line 292 of file res_calendar.c.

References ao2_find, and OBJ_POINTER.

Referenced by merge_events_cb().

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

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

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

Definition at line 652 of file res_calendar.c.

References ast_random().

Referenced by calendar_query_exec(), and do_notify().

00653 {
00654    unsigned long val[4];
00655    int x;
00656 
00657    for (x = 0; x < 4; x++) {
00658       val[x] = ast_random();
00659    }
00660    snprintf(buf, size, "%08lx%08lx%08lx%08lx", val[0], val[1], val[2], val[3]);
00661 
00662    return buf;
00663 }

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

Definition at line 1558 of file res_calendar.c.

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

01559 {
01560    switch(cmd) {
01561    case CLI_INIT:
01562       e->command = "calendar dump sched";
01563       e->usage =
01564          "Usage: calendar dump sched\n"
01565          "       Dump the calendar sched context";
01566       return NULL;
01567 
01568    case CLI_GENERATE:
01569       return NULL;
01570    }
01571 
01572    ast_sched_dump(sched);
01573 
01574    return CLI_SUCCESS;
01575 }

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

Definition at line 1478 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, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_calendar_event::end, epoch_to_string(), evententry::event, ast_calendar::events, ast_cli_args::fd, find_calendar(), FORMAT, FORMAT2, ast_cli_args::n, ast_cli_args::pos, ast_calendar_event::priority, ast_calendar::refresh, ast_calendar_event::start, ast_calendar::timeframe, unref_calendar(), ast_cli_entry::usage, and ast_cli_args::word.

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

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

01432 {
01433 #define FORMAT "%-20.20s %-10.10s %-6.6s\n"
01434    struct ao2_iterator i;
01435    struct ast_calendar *cal;
01436 
01437    switch(cmd) {
01438    case CLI_INIT:
01439       e->command = "calendar show calendars";
01440       e->usage =
01441          "Usage: calendar show calendars\n"
01442          "       Lists all registered calendars.\n";
01443       return NULL;
01444    case CLI_GENERATE:
01445       return NULL;
01446    }
01447 
01448    ast_cli(a->fd, FORMAT, "Calendar", "Type", "Status");
01449    ast_cli(a->fd, FORMAT, "--------", "----", "------");
01450    i = ao2_iterator_init(calendars, 0);
01451    while ((cal = ao2_iterator_next(&i))) {
01452       ast_cli(a->fd, FORMAT, cal->name, cal->tech->type, calendar_is_busy(cal) ? "busy" : "free");
01453       cal = unref_calendar(cal);
01454    }
01455    ao2_iterator_destroy(&i);
01456 
01457    return CLI_SUCCESS;
01458 #undef FORMAT
01459 }

static int load_config ( int  reload  )  [static]

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

Referenced by load_module(), and reload().

00974 {
00975    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
00976    struct ast_config *tmpcfg;
00977 
00978    if (!(tmpcfg = ast_config_load2("calendar.conf", "calendar", config_flags)) ||
00979       tmpcfg == CONFIG_STATUS_FILEINVALID) {
00980       ast_log(LOG_ERROR, "Unable to load config calendar.conf\n");
00981       return -1;
00982    }
00983 
00984    if (tmpcfg == CONFIG_STATUS_FILEUNCHANGED) {
00985       return 0;
00986    }
00987 
00988    ast_rwlock_wrlock(&config_lock);
00989    if (calendar_config) {
00990       ast_config_destroy(calendar_config);
00991    }
00992 
00993    calendar_config = tmpcfg;
00994    ast_rwlock_unlock(&config_lock);
00995 
00996    return 0;
00997 }

static int load_module ( void   )  [static]

Definition at line 1753 of file res_calendar.c.

References ao2_container_alloc, ARRAY_LEN, ast_cli_register_multiple(), ast_cond_init, ast_custom_function_register, ast_devstate_prov_add(), ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_mutex_init, ast_pthread_create_background, 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().

01754 {
01755    if (!(calendars = ao2_container_alloc(CALENDAR_BUCKETS, calendar_hash_fn, calendar_cmp_fn))) {
01756       ast_log(LOG_ERROR, "Unable to allocate calendars container!\n");
01757       return AST_MODULE_LOAD_FAILURE;
01758    }
01759 
01760    if (load_config(0)) {
01761       /* We don't have calendar support enabled */
01762       return AST_MODULE_LOAD_DECLINE;
01763    }
01764 
01765    ast_mutex_init(&refreshlock);
01766    ast_cond_init(&refresh_condition, NULL);
01767    ast_mutex_init(&reloadlock);
01768 
01769    if (!(sched = sched_context_create())) {
01770       ast_log(LOG_ERROR, "Unable to create sched context\n");
01771       return AST_MODULE_LOAD_FAILURE;
01772    }
01773 
01774    if (ast_pthread_create_background(&refresh_thread, NULL, do_refresh, NULL) < 0) {
01775       ast_log(LOG_ERROR, "Unable to start refresh thread--notifications disabled!\n");
01776    }
01777 
01778    ast_custom_function_register(&calendar_busy_function);
01779    ast_custom_function_register(&calendar_event_function);
01780    ast_custom_function_register(&calendar_query_function);
01781    ast_custom_function_register(&calendar_query_result_function);
01782    ast_custom_function_register(&calendar_write_function);
01783    ast_cli_register_multiple(calendar_cli, ARRAY_LEN(calendar_cli));
01784 
01785    ast_devstate_prov_add("Calendar", calendarstate);
01786 
01787    return AST_MODULE_LOAD_SUCCESS;
01788 }

static int load_tech_calendars ( struct ast_calendar_tech tech  )  [static]

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

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

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

Definition at line 511 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::tech.

Referenced by ast_calendar_unregister().

00512 {
00513    struct ast_calendar *cal = user_data;
00514    struct ast_calendar_tech *tech = arg;
00515 
00516    if (cal->tech == tech) {
00517       return CMP_MATCH;
00518    }
00519 
00520    return 0;
00521 }

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

Definition at line 924 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, and schedule_calendar_event().

Referenced by ast_calendar_merge_events().

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

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

Definition at line 665 of file res_calendar.c.

00666 {
00667    return 0;
00668 }

static int reload ( void   )  [static]

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

01663 {
01664    struct ast_calendar_tech *iter;
01665 
01666    ast_mutex_lock(&reloadlock);
01667 
01668    /* Mark existing calendars for deletion */
01669    ao2_callback(calendars, OBJ_NODATA | OBJ_MULTIPLE, cb_pending_deletion, NULL);
01670    load_config(1);
01671 
01672    AST_LIST_LOCK(&techs);
01673    AST_LIST_TRAVERSE(&techs, iter, list) {
01674       if (load_tech_calendars(iter)) {
01675          ast_log(LOG_WARNING, "Failed to reload %s calendars, module disabled\n", iter->type);
01676       }
01677    }
01678    AST_LIST_UNLOCK(&techs);
01679 
01680    /* Delete calendars that no longer show up in the config */
01681    ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, cb_rm_pending_deletion, NULL);
01682 
01683    ast_mutex_unlock(&reloadlock);
01684 
01685    return 0;
01686 }

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

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

static int unload_module ( void   )  [static]

Definition at line 1719 of file res_calendar.c.

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

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

Definition at line 254 of file res_calendar.c.

References ao2_ref.

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

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


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

Definition at line 1794 of file res_calendar.c.

Definition at line 1794 of file res_calendar.c.

Initial value:
 {
    .name = "CALENDAR_BUSY",
    .read = calendar_busy_exec,
}

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

Referenced by load_module(), and unload_module().

struct ast_config* calendar_config [static]

Definition at line 234 of file res_calendar.c.

Referenced by load_config(), load_tech_calendars(), and unload_module().

Initial value:
 {
   .name = "CALENDAR_EVENT",
   .read = calendar_event_read,
}

Definition at line 1641 of file res_calendar.c.

Referenced by load_module(), and unload_module().

Initial value:
 {
    .name = "CALENDAR_QUERY",
    .read = calendar_query_exec,
}

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

Referenced by load_module(), and unload_module().

Initial value:
 {
   .name = "CALENDAR_WRITE",
   .write = calendar_write_exec,
}

Definition at line 1425 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ao2_container* calendars [static]

Definition at line 201 of file res_calendar.c.

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

Definition at line 235 of file res_calendar.c.

Referenced by ast_calendar_config_release(), load_config(), and load_tech_calendars().

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

Definition at line 214 of file res_calendar.c.

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

Definition at line 220 of file res_calendar.c.

int module_unloading [static]

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

Referenced by do_notify().

Definition at line 205 of file res_calendar.c.

pthread_t refresh_thread = AST_PTHREADT_NULL [static]

Definition at line 203 of file res_calendar.c.

Definition at line 206 of file res_calendar.c.

struct sched_context* sched [static]

Definition at line 202 of file res_calendar.c.


Generated on 31 Aug 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1