Sat Feb 11 06:36:20 2012

Asterisk developer's documentation


res_calendar.c File Reference

Calendaring API. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/calendar.h"
#include "asterisk/utils.h"
#include "asterisk/astobj2.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/channel.h"
#include "asterisk/devicestate.h"
#include "asterisk/linkedlists.h"
#include "asterisk/sched.h"
#include "asterisk/dial.h"
#include "asterisk/cli.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"

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   "%-10.10s %-30.30s\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 char * handle_show_calendars_types (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI command to list of all calendars types currently loaded on the backend.
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 = AST_BUILDOPT_SUM, .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 = { {0} , 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 ast_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 211 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   "%-10.10s %-30.30s\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 1862 of file res_calendar.c.

static void __unreg_module ( void   )  [static]

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

01071 {
01072    struct evententry *entry, *iter;
01073    int event_startdiff = abs(start - event->start);
01074    int event_enddiff = abs(end - event->end);
01075    int i = 0;
01076 
01077    if (!(entry = ast_calloc(1, sizeof(*entry)))) {
01078       ast_log(LOG_ERROR, "Unable to allocate memory for event list\n");
01079       return -1;
01080    }
01081 
01082    entry->event = event;
01083    ao2_ref(event, +1);
01084 
01085    if (start == end) {
01086       AST_LIST_TRAVERSE_SAFE_BEGIN(events, iter, list) {
01087          int startdiff = abs(iter->event->start - start);
01088 
01089          ast_debug(10, "Comparing %s with startdiff %d to %s with startdiff %d\n", event->summary, event_startdiff, iter->event->summary, startdiff);
01090          ++i;
01091          if (startdiff > event_startdiff) {
01092             AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01093             return i;
01094          }
01095          if (startdiff == event_startdiff) {
01096             int enddiff = abs(iter->event->end - end);
01097 
01098             if (enddiff > event_enddiff) {
01099                AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01100                return i;
01101             }
01102             if (event_startdiff == enddiff) {
01103                if (strcmp(event->uid, iter->event->uid) < 0) {
01104                   AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01105                   return i;
01106                }
01107             }
01108          }
01109       }
01110       AST_LIST_TRAVERSE_SAFE_END;
01111 
01112       AST_LIST_INSERT_TAIL(events, entry, list);
01113 
01114       return i;
01115    }
01116 
01117    AST_LIST_TRAVERSE_SAFE_BEGIN(events, iter, list) {
01118       ++i;
01119       if (iter->event->start > event->start) {
01120          AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01121          return i;
01122       }
01123 
01124       if (iter->event->start == event->start) {
01125          if ((iter->event->end - iter->event->start) == (event->end - event->start)) {
01126             if (strcmp(event->uid, iter->event->uid) < 0) {
01127                AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01128                return i;
01129             }
01130          }
01131          if ((iter->event->end - iter->event->start) < (event->end - event->start)) {
01132             AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
01133             return i;
01134          }
01135       }
01136    }
01137    AST_LIST_TRAVERSE_SAFE_END;
01138 
01139    AST_LIST_INSERT_TAIL(events, entry, list);
01140 
01141    return i;
01142 }

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

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

00996 {
00997    struct ast_calendar_event *new_event = obj;
00998    struct ao2_container *events = arg;
00999 
01000    ao2_link(events, new_event);
01001    schedule_calendar_event(new_event->owner, new_event, NULL);
01002    return CMP_MATCH;
01003 }

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

00627 {
00628    ast_debug(3, "Clearing all events for calendar %s\n", cal->name);
00629 
00630    ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, clear_events_cb, NULL);
00631 }

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

00250 {
00251    ast_rwlock_rdlock(&config_lock);
00252 
00253    if (!calendar_config) {
00254       ast_rwlock_unlock(&config_lock);
00255       return NULL;
00256    }
00257 
00258    return calendar_config;
00259 }

void ast_calendar_config_release ( void   ) 

Release the calendar config.

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

00262 {
00263    ast_rwlock_unlock(&config_lock);
00264 }

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 633 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(), parse_tag(), and startelm().

00634 {
00635    struct ast_calendar_event *event;
00636    if (!(event = ao2_alloc(sizeof(*event), calendar_event_destructor))) {
00637       return NULL;
00638    }
00639 
00640    if (ast_string_field_init(event, 32)) {
00641       event = ast_calendar_unref_event(event);
00642       return NULL;
00643    }
00644 
00645    event->owner = cal;
00646    event->notify_sched = -1;
00647    event->bs_start_sched = -1;
00648    event->bs_end_sched = -1;
00649 
00650    AST_LIST_HEAD_INIT_NOLOCK(&event->attendees);
00651 
00652    return event;
00653 }

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 655 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 1005 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().

01006 {
01007    /* Loop through all events attached to the calendar.  If there is a matching new event
01008     * merge its data over and handle any schedule changes that need to be made.  Then remove
01009     * the new_event from new_events so that we are left with only new_events that we can add later. */
01010    ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, merge_events_cb, new_events);
01011 
01012    /* Now, we should only have completely new events in new_events.  Loop through and add them */
01013    ao2_callback(new_events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, add_new_event_cb, cal->events);
01014 }

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

00523 {
00524    struct ast_calendar_tech *iter;
00525 
00526    AST_LIST_LOCK(&techs);
00527    AST_LIST_TRAVERSE(&techs, iter, list) {
00528       if(!strcasecmp(tech->type, iter->type)) {
00529          ast_log(LOG_WARNING, "Already have a handler for calendar type '%s'\n", tech->type);
00530          AST_LIST_UNLOCK(&techs);
00531          return -1;
00532       }
00533    }
00534    AST_LIST_INSERT_HEAD(&techs, tech, list);
00535    AST_LIST_UNLOCK(&techs);
00536 
00537    ast_verb(2, "Registered calendar type '%s' (%s)\n", tech->type, tech->description);
00538 
00539    return load_tech_calendars(tech);
00540 }

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

00313 {
00314    ao2_ref(event, -1);
00315    return NULL;
00316 }

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

00555 {
00556    struct ast_calendar_tech *iter;
00557 
00558    AST_LIST_LOCK(&techs);
00559    AST_LIST_TRAVERSE_SAFE_BEGIN(&techs, iter, list) {
00560       if (iter != tech) {
00561          continue;
00562       }
00563 
00564       ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, match_caltech_cb, tech);
00565 
00566       AST_LIST_REMOVE_CURRENT(list);
00567       ast_verb(2, "Unregistered calendar type '%s'\n", tech->type);
00568       break;
00569    }
00570    AST_LIST_TRAVERSE_SAFE_END;
00571    AST_LIST_UNLOCK(&techs);
00572 
00573 }

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

Definition at line 390 of file res_calendar.c.

References ao2_alloc, ao2_container_alloc, ao2_link, ao2_unlink, ast_cond_init, ast_free, ast_log(), ast_pthread_create, AST_PTHREADT_NULL, ast_strdup, ast_string_field_init, ast_string_field_set, ast_strip(), ast_variable_browse(), ast_variable_new(), ast_calendar::autoreminder, CALENDAR_BUCKETS, calendar_destructor(), event_cmp_fn(), event_hash_fn(), ast_calendar::events, find_calendar(), last, ast_calendar_tech::load_calendar, LOG_ERROR, LOG_WARNING, ast_variable::name, name, ast_variable::next, ast_calendar::notify_waittime, ast_calendar::pending_deletion, ast_calendar::refresh, strsep(), ast_calendar::tech, ast_calendar::thread, ast_calendar::timeframe, ast_calendar::unload, unref_calendar(), value, ast_variable::value, var, and ast_calendar::vars.

Referenced by load_tech_calendars().

00391 {
00392    struct ast_calendar *cal;
00393    struct ast_variable *v, *last = NULL;
00394    int new_calendar = 0;
00395 
00396    if (!(cal = find_calendar(cat))) {
00397       new_calendar = 1;
00398       if (!(cal = ao2_alloc(sizeof(*cal), calendar_destructor))) {
00399          ast_log(LOG_ERROR, "Could not allocate calendar structure. Stopping.\n");
00400          return NULL;
00401       }
00402 
00403       if (!(cal->events = ao2_container_alloc(CALENDAR_BUCKETS, event_hash_fn, event_cmp_fn))) {
00404          ast_log(LOG_ERROR, "Could not allocate events container for %s\n", cat);
00405          cal = unref_calendar(cal);
00406          return NULL;
00407       }
00408 
00409       if (ast_string_field_init(cal, 32)) {
00410          ast_log(LOG_ERROR, "Couldn't create string fields for %s\n", cat);
00411          cal = unref_calendar(cal);
00412          return NULL;
00413       }
00414    } else {
00415       cal->pending_deletion = 0;
00416    }
00417 
00418    ast_string_field_set(cal, name, cat);
00419    cal->tech = tech;
00420 
00421    cal->refresh = 3600;
00422    cal->timeframe = 60;
00423    cal->notify_waittime = 30000;
00424 
00425    for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
00426       if (!strcasecmp(v->name, "autoreminder")) {
00427          cal->autoreminder = atoi(v->value);
00428       } else if (!strcasecmp(v->name, "channel")) {
00429          ast_string_field_set(cal, notify_channel, v->value);
00430       } else if (!strcasecmp(v->name, "context")) {
00431          ast_string_field_set(cal, notify_context, v->value);
00432       } else if (!strcasecmp(v->name, "extension")) {
00433          ast_string_field_set(cal, notify_extension, v->value);
00434       } else if (!strcasecmp(v->name, "waittime")) {
00435          int i = atoi(v->value);
00436          if (i > 0) {
00437             cal->notify_waittime = 1000 * i;
00438          }
00439       } else if (!strcasecmp(v->name, "app")) {
00440          ast_string_field_set(cal, notify_app, v->value);
00441       } else if (!strcasecmp(v->name, "appdata")) {
00442          ast_string_field_set(cal, notify_appdata, v->value);
00443       } else if (!strcasecmp(v->name, "refresh")) {
00444          cal->refresh = atoi(v->value);
00445       } else if (!strcasecmp(v->name, "timeframe")) {
00446          cal->timeframe = atoi(v->value);
00447       } else if (!strcasecmp(v->name, "setvar")) {
00448          char *name, *value;
00449          struct ast_variable *var;
00450 
00451          if ((name = (value = ast_strdup(v->value)))) {
00452             strsep(&value, "=");
00453             if (value) {
00454                if ((var = ast_variable_new(ast_strip(name), ast_strip(value), ""))) {
00455                   if (last) {
00456                      last->next = var;
00457                   } else {
00458                      cal->vars = var;
00459                   }
00460                   last = var;
00461                }
00462             } else {
00463                ast_log(LOG_WARNING, "Malformed argument. Should be '%s: variable=value'\n", v->name);
00464             }
00465             ast_free(name);
00466          }
00467       }
00468    }
00469 
00470    if (new_calendar) {
00471       cal->thread = AST_PTHREADT_NULL;
00472       ast_cond_init(&cal->unload, NULL);
00473       ao2_link(calendars, cal);
00474       if (ast_pthread_create(&cal->thread, NULL, cal->tech->load_calendar, cal)) {
00475          /* If we start failing to create threads, go ahead and return NULL
00476           * and the tech module will be unregistered
00477           */ 
00478          ao2_unlink(calendars, cal);
00479          cal = unref_calendar(cal);
00480       }
00481    }
00482 
00483    return cal;
00484 }

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

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

00353 {
00354    struct ast_calendar_event *event = obj;
00355    int *is_busy = arg;
00356    struct timeval tv = ast_tvnow();
00357 
00358    if (tv.tv_sec >= event->start && tv.tv_sec <= event->end && event->busy_state > AST_CALENDAR_BS_FREE) {
00359       *is_busy = 1;
00360       return CMP_STOP;
00361    }
00362 
00363    return 0;
00364 }

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

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

01045 {
01046    struct ast_calendar *cal;
01047 
01048    if (ast_strlen_zero(data)) {
01049       ast_log(LOG_WARNING, "CALENDAR_BUSY requires an argument: CALENDAR_BUSY(<calendar_name>)\n");
01050       return -1;
01051    }
01052 
01053    cal = find_calendar(data);
01054 
01055    if (!cal) {
01056       ast_log(LOG_WARNING, "Could not find calendar '%s'\n", data);
01057       return -1;
01058    }
01059 
01060    strcpy(buf, calendar_is_busy(cal) ? "1" : "0");
01061 
01062    return 0;
01063 }

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

Definition at line 278 of file res_calendar.c.

References CMP_MATCH, CMP_STOP, and ast_calendar::name.

Referenced by load_module().

00279 {
00280    const struct ast_calendar *one = obj, *two = arg;
00281    return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP: 0;
00282 }

static void calendar_destructor ( void *  obj  )  [static]

Definition at line 318 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_variables_destroy(), ast_calendar::events, ast_calendar::name, ast_calendar::tech, ast_calendar::tech_pvt, ast_calendar::thread, ast_calendar::unload, ast_calendar::unloading, ast_calendar_tech::unref_calendar, and ast_calendar::vars.

Referenced by build_calendar().

00319 {
00320    struct ast_calendar *cal = obj;
00321 
00322    ast_debug(3, "Destroying calendar %s\n", cal->name);
00323 
00324    ao2_lock(cal);
00325    cal->unloading = 1;
00326    ast_cond_signal(&cal->unload);
00327    pthread_join(cal->thread, NULL);
00328    if (cal->tech_pvt) {
00329       cal->tech_pvt = cal->tech->unref_calendar(cal->tech_pvt);
00330    }
00331    ast_calendar_clear_events(cal);
00332    ast_string_field_free_memory(cal);
00333    if (cal->vars) {
00334       ast_variables_destroy(cal->vars);
00335       cal->vars = NULL;
00336    }
00337    ao2_ref(cal->events, -1);
00338    ao2_unlock(cal);
00339 }

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

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

00845 {
00846    struct ast_calendar_event *event = (struct ast_calendar_event *)data;
00847    struct timeval now = ast_tvnow();
00848    int is_end_event;
00849 
00850    if (!event) {
00851       ast_log(LOG_WARNING, "Event was NULL!\n");
00852       return 0;
00853    }
00854 
00855    ao2_ref(event, +1);
00856 
00857    is_end_event = event->end <= now.tv_sec;
00858 
00859    if (is_end_event) {
00860       event->bs_end_sched = -1;
00861    } else {
00862       event->bs_start_sched = -1;
00863    }
00864 
00865    /* We can have overlapping events, so ignore the event->busy_state and check busy state
00866     * based on all events in the calendar */
00867    if (!calendar_is_busy(event->owner)) {
00868       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Calendar:%s", event->owner->name);
00869    } else {
00870       ast_devstate_changed(AST_DEVICE_BUSY, "Calendar:%s", event->owner->name);
00871    }
00872 
00873    event = ast_calendar_unref_event(event);
00874 
00875    return 0;
00876 }

static void calendar_event_destructor ( void *  obj  )  [static]

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

00576 {
00577    struct ast_calendar_event *event = obj;
00578    struct ast_calendar_attendee *attendee;
00579 
00580    ast_debug(3, "Destroying event for calendar '%s'\n", event->owner->name);
00581    ast_string_field_free_memory(event);
00582    while ((attendee = AST_LIST_REMOVE_HEAD(&event->attendees, next))) {
00583       if (attendee->data) {
00584          ast_free(attendee->data);
00585       }
00586       ast_free(attendee);
00587    }
00588 }

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

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

00821 {
00822    struct ast_calendar_event *event = (void *)data;
00823    int res = -1;
00824    pthread_t notify_thread = AST_PTHREADT_NULL;
00825 
00826    if (!(event && event->owner)) {
00827       ast_log(LOG_ERROR, "Extremely low-cal...in fact cal is NULL!\n");
00828       return res;
00829    }
00830 
00831    ao2_ref(event, +1);
00832    event->notify_sched = -1;
00833 
00834    if (ast_pthread_create_background(&notify_thread, NULL, do_notify, event) < 0) {
00835       ast_log(LOG_ERROR, "Could not create notification thread\n");
00836       return res;
00837    }
00838 
00839    res = 0;
00840 
00841    return res;
00842 }

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

Definition at line 1656 of file res_calendar.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_copy_string(), ast_log(), ast_strlen_zero(), ast_calendar_event::busy_state, calendar_join_attendees(), ast_calendar_event::categories, ast_datastore::data, ast_calendar_event::description, ast_calendar_event::end, evententry::event, ast_calendar_event::location, LOG_WARNING, ast_calendar::name, ast_calendar_event::organizer, ast_calendar_event::owner, ast_calendar_event::priority, ast_calendar_event::start, ast_calendar_event::summary, and ast_calendar_event::uid.

01657 {
01658    struct ast_datastore *datastore;
01659    struct ast_calendar_event *event;
01660 
01661    if (ast_strlen_zero(data)) {
01662       ast_log(LOG_WARNING, "%s requires an argument\n", cmd);
01663       return -1;
01664    }
01665 
01666    ast_channel_lock(chan);
01667    if (!(datastore = ast_channel_datastore_find(chan, &event_notification_datastore, NULL))) {
01668       ast_log(LOG_WARNING, "There is no event notification datastore on '%s'!\n", ast_channel_name(chan));
01669       ast_channel_unlock(chan);
01670       return -1;
01671    }
01672    ast_channel_unlock(chan);
01673 
01674    if (!(event = datastore->data)) {
01675       ast_log(LOG_WARNING, "The datastore contains no data!\n");
01676       return -1;
01677    }
01678 
01679    if (!strcasecmp(data, "summary")) {
01680       ast_copy_string(buf, event->summary, len);
01681    } else if (!strcasecmp(data, "description")) {
01682       ast_copy_string(buf, event->description, len);
01683    } else if (!strcasecmp(data, "organizer")) {
01684       ast_copy_string(buf, event->organizer, len);
01685    } else if (!strcasecmp(data, "location")) {
01686       ast_copy_string(buf, event->location, len);
01687    } else if (!strcasecmp(data, "categories")) {
01688       ast_copy_string(buf, event->categories, len);
01689    } else if (!strcasecmp(data, "priority")) {
01690       snprintf(buf, len, "%d", event->priority);
01691    } else if (!strcasecmp(data, "calendar")) {
01692       ast_copy_string(buf, event->owner->name, len);
01693    } else if (!strcasecmp(data, "uid")) {
01694       ast_copy_string(buf, event->uid, len);
01695    } else if (!strcasecmp(data, "start")) {
01696       snprintf(buf, len, "%ld", (long)event->start);
01697    } else if (!strcasecmp(data, "end")) {
01698       snprintf(buf, len, "%ld", (long)event->end);
01699    } else if (!strcasecmp(data, "busystate")) {
01700       snprintf(buf, len, "%d", event->busy_state);
01701    } else if (!strcasecmp(data, "attendees")) {
01702       calendar_join_attendees(event, buf, len);
01703    }
01704 
01705 
01706    return 0;
01707 }

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

Definition at line 272 of file res_calendar.c.

References ast_str_case_hash(), and ast_calendar::name.

Referenced by load_module().

00273 {
00274    const struct ast_calendar *cal = obj;
00275    return ast_str_case_hash(cal->name);
00276 }

static int calendar_is_busy ( struct ast_calendar cal  )  [static]

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

00367 {
00368    int is_busy = 0;
00369 
00370    ao2_callback(cal->events, OBJ_NODATA, calendar_busy_callback, &is_busy);
00371 
00372    return is_busy;
00373 }

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

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

01251 {
01252    struct ast_str *tmp;
01253    struct ast_calendar_attendee *attendee;
01254 
01255    if (!(tmp = ast_str_create(32))) {
01256       ast_log(LOG_ERROR, "Could not allocate memory for attendees!\n");
01257       return;
01258    }
01259 
01260    AST_LIST_TRAVERSE(&event->attendees, attendee, next) {
01261       ast_str_append(&tmp, 0, "%s%s", attendee == AST_LIST_FIRST(&event->attendees) ? "" : ",", attendee->data);
01262    }
01263 
01264    ast_copy_string(buf, ast_str_buffer(tmp), len);
01265    ast_free(tmp);
01266 }

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

Definition at line 1164 of file res_calendar.c.

References add_event_to_list(), ao2_alloc, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, args, AST_APP_ARG, ast_calendar_unref_event(), ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_debug, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), ast_datastore::data, DATASTORE_INHERIT_FOREVER, ast_calendar_event::end, 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().

01165 {
01166    struct ast_calendar *cal;
01167    struct ao2_iterator i;
01168    struct ast_calendar_event *event;
01169    struct eventlist *events;
01170    time_t start = INT_MIN, end = INT_MAX;
01171    struct ast_datastore *eventlist_datastore;
01172    AST_DECLARE_APP_ARGS(args,
01173       AST_APP_ARG(calendar);
01174       AST_APP_ARG(start);
01175       AST_APP_ARG(end);
01176    );
01177 
01178    if (!chan) {
01179       ast_log(LOG_WARNING, "%s requires a channel to store the data on\n", cmd);
01180       return -1;
01181    }
01182 
01183    AST_STANDARD_APP_ARGS(args, data);
01184 
01185    if (ast_strlen_zero(args.calendar)) {
01186       ast_log(LOG_WARNING, "%s requires a calendar argument\n", cmd);
01187       return -1;
01188    }
01189 
01190    if (!(cal = find_calendar(args.calendar))) {
01191       ast_log(LOG_WARNING, "Unknown calendar '%s'\n", args.calendar);
01192       return -1;
01193    }
01194 
01195    if (!(events = ao2_alloc(sizeof(*events), eventlist_destructor))) {
01196       ast_log(LOG_ERROR, "Unable to allocate memory for event list\n");
01197       cal = unref_calendar(cal);
01198       return -1;
01199    }
01200 
01201    if (!ast_strlen_zero(args.start)) {
01202       start = atoi(args.start);
01203    }
01204 
01205    if (!ast_strlen_zero(args.end)) {
01206       end = atoi(args.end);
01207    }
01208 
01209    i = ao2_iterator_init(cal->events, 0);
01210    while ((event = ao2_iterator_next(&i))) {
01211       if (!(start > event->end || end < event->start)) {
01212          ast_debug(10, "%s (%ld - %ld) overlapped with (%ld - %ld)\n", event->summary, (long) event->start, (long) event->end, (long) start, (long) end);
01213          if (add_event_to_list(events, event, start, end) < 0) {
01214             event = ast_calendar_unref_event(event);
01215             ao2_iterator_destroy(&i);
01216             return -1;
01217          }
01218       }
01219 
01220       event = ast_calendar_unref_event(event);
01221    }
01222    ao2_iterator_destroy(&i);
01223 
01224    ast_channel_lock(chan);
01225    do {
01226       generate_random_string(buf, len);
01227    } while (ast_channel_datastore_find(chan, &eventlist_datastore_info, buf));
01228    ast_channel_unlock(chan);
01229 
01230    if (!(eventlist_datastore = ast_datastore_alloc(&eventlist_datastore_info, buf))) {
01231       ast_log(LOG_ERROR, "Could not allocate datastore!\n");
01232       return -1;
01233    }
01234 
01235    eventlist_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
01236    eventlist_datastore->data = events;
01237 
01238    ast_channel_lock(chan);
01239    ast_channel_datastore_add(chan, eventlist_datastore);
01240    ast_channel_unlock(chan);
01241 
01242    return 0;
01243 }

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

Definition at line 1268 of file res_calendar.c.

References args, AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_TRAVERSE, ast_log(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), ast_calendar_event::busy_state, calendar_join_attendees(), ast_calendar_event::categories, ast_datastore::data, ast_calendar_event::description, ast_calendar_event::end, evententry::event, events, evententry::list, ast_calendar_event::location, LOG_WARNING, ast_calendar::name, ast_calendar_event::organizer, ast_calendar_event::owner, ast_calendar_event::priority, ast_calendar_event::start, ast_calendar_event::summary, and ast_calendar_event::uid.

01269 {
01270    struct ast_datastore *datastore;
01271    struct eventlist *events;
01272    struct evententry *entry;
01273    int row = 1;
01274    size_t listlen = 0;
01275    AST_DECLARE_APP_ARGS(args,
01276       AST_APP_ARG(id);
01277       AST_APP_ARG(field);
01278       AST_APP_ARG(row);
01279    );
01280 
01281    if (!chan) {
01282       ast_log(LOG_WARNING, "%s requires a channel\n", cmd);
01283       return -1;
01284    }
01285 
01286    AST_STANDARD_APP_ARGS(args, data);
01287 
01288    if (ast_strlen_zero(args.id) || ast_strlen_zero(args.field)) {
01289       ast_log(LOG_WARNING, "%s requires an id and a field", cmd);
01290       return -1;
01291    }
01292 
01293    ast_channel_lock(chan);
01294    if (!(datastore = ast_channel_datastore_find(chan, &eventlist_datastore_info, args.id))) {
01295       ast_log(LOG_WARNING, "There is no event notification datastore with id '%s' on '%s'!\n", args.id, ast_channel_name(chan));
01296       ast_channel_unlock(chan);
01297       return -1;
01298    }
01299    ast_channel_unlock(chan);
01300 
01301    if (!(events = datastore->data)) {
01302       ast_log(LOG_WARNING, "The datastore contains no data!\n");
01303       return -1;
01304    }
01305 
01306    if (!ast_strlen_zero(args.row)) {
01307       row = atoi(args.row);
01308    }
01309 
01310    AST_LIST_TRAVERSE(events, entry, list) {
01311       listlen++;
01312    }
01313 
01314    if (!strcasecmp(args.field, "getnum")) {
01315       snprintf(buf, len, "%zu", listlen);
01316       return 0;
01317    }
01318 
01319    AST_LIST_TRAVERSE(events, entry, list) {
01320       if (--row) {
01321          continue;
01322       }
01323       if (!strcasecmp(args.field, "summary")) {
01324          ast_copy_string(buf, entry->event->summary, len);
01325       } else if (!strcasecmp(args.field, "description")) {
01326          ast_copy_string(buf, entry->event->description, len);
01327       } else if (!strcasecmp(args.field, "organizer")) {
01328          ast_copy_string(buf, entry->event->organizer, len);
01329       } else if (!strcasecmp(args.field, "location")) {
01330          ast_copy_string(buf, entry->event->location, len);
01331       } else if (!strcasecmp(args.field, "categories")) {
01332          ast_copy_string(buf, entry->event->categories, len);
01333       } else if (!strcasecmp(args.field, "priority")) {
01334          snprintf(buf, len, "%d", entry->event->priority);
01335       } else if (!strcasecmp(args.field, "calendar")) {
01336          ast_copy_string(buf, entry->event->owner->name, len);
01337       } else if (!strcasecmp(args.field, "uid")) {
01338          ast_copy_string(buf, entry->event->uid, len);
01339       } else if (!strcasecmp(args.field, "start")) {
01340          snprintf(buf, len, "%ld", (long) entry->event->start);
01341       } else if (!strcasecmp(args.field, "end")) {
01342          snprintf(buf, len, "%ld", (long) entry->event->end);
01343       } else if (!strcasecmp(args.field, "busystate")) {
01344          snprintf(buf, len, "%d", entry->event->busy_state);
01345       } else if (!strcasecmp(args.field, "attendees")) {
01346          calendar_join_attendees(entry->event, buf, len);
01347       } else {
01348          ast_log(LOG_WARNING, "Unknown field '%s'\n", args.field);
01349       }
01350       break;
01351    }
01352 
01353    return 0;
01354 }

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

Definition at line 1361 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::name, pbx_builtin_setvar_helper(), ast_calendar_event::start, ast_calendar::tech, unref_calendar(), and ast_calendar_tech::write_event.

01362 {
01363    int i, j, ret = -1;
01364    char *val_dup = NULL;
01365    struct ast_calendar *cal = NULL;
01366    struct ast_calendar_event *event = NULL;
01367    struct timeval tv = ast_tvnow();
01368    AST_DECLARE_APP_ARGS(fields,
01369       AST_APP_ARG(field)[10];
01370    );
01371    AST_DECLARE_APP_ARGS(values,
01372       AST_APP_ARG(value)[10];
01373    );
01374 
01375    if (!(val_dup = ast_strdup(value))) {
01376       ast_log(LOG_ERROR, "Could not allocate memory for values\n");
01377       goto write_cleanup;
01378    }
01379 
01380    AST_STANDARD_APP_ARGS(fields, data);
01381    AST_STANDARD_APP_ARGS(values, val_dup);
01382 
01383    /* XXX Eventually we will support unnamed calendars, so if we don't find one, we parse
01384     * for a calendar type and create it */
01385    if (!(cal = find_calendar(fields.field[0]))) {
01386       ast_log(LOG_WARNING, "Couldn't find calendar '%s'\n", fields.field[0]);
01387       goto write_cleanup;
01388    }
01389 
01390    if (!(cal->tech->write_event)) {
01391       ast_log(LOG_WARNING, "Calendar '%s' has no write function!\n", cal->name);
01392       goto write_cleanup;
01393    }
01394 
01395    if (!(event = ast_calendar_event_alloc(cal))) {
01396       goto write_cleanup;
01397    }
01398 
01399    if (ast_strlen_zero(fields.field[0])) {
01400       ast_log(LOG_WARNING, "CALENDAR_WRITE requires a calendar name!\n");
01401       goto write_cleanup;
01402    }
01403 
01404    if (fields.argc - 1 != values.argc) {
01405       ast_log(LOG_WARNING, "CALENDAR_WRITE should have the same number of fields (%d) and values (%d)!\n", fields.argc - 1, values.argc);
01406       goto write_cleanup;
01407    }
01408 
01409    event->owner = cal;
01410 
01411    for (i = 1, j = 0; i < fields.argc; i++, j++) {
01412       if (!strcasecmp(fields.field[i], "summary")) {
01413          ast_string_field_set(event, summary, values.value[j]);
01414       } else if (!strcasecmp(fields.field[i], "description")) {
01415          ast_string_field_set(event, description, values.value[j]);
01416       } else if (!strcasecmp(fields.field[i], "organizer")) {
01417          ast_string_field_set(event, organizer, values.value[j]);
01418       } else if (!strcasecmp(fields.field[i], "location")) {
01419          ast_string_field_set(event, location, values.value[j]);
01420       } else if (!strcasecmp(fields.field[i], "categories")) {
01421          ast_string_field_set(event, categories, values.value[j]);
01422       } else if (!strcasecmp(fields.field[i], "priority")) {
01423          event->priority = atoi(values.value[j]);
01424       } else if (!strcasecmp(fields.field[i], "uid")) {
01425          ast_string_field_set(event, uid, values.value[j]);
01426       } else if (!strcasecmp(fields.field[i], "start")) {
01427          event->start = atoi(values.value[j]);
01428       } else if (!strcasecmp(fields.field[i], "end")) {
01429          event->end = atoi(values.value[j]);
01430       } else if (!strcasecmp(fields.field[i], "busystate")) {
01431          event->busy_state = atoi(values.value[j]);
01432       } else {
01433          ast_log(LOG_WARNING, "Unknown calendar event field '%s'\n", fields.field[i]);
01434       }
01435    }
01436 
01437    if (!event->start) {
01438       event->start = tv.tv_sec;
01439    }
01440 
01441    if (!event->end) {
01442       event->end = tv.tv_sec;
01443    }
01444 
01445    if((ret = cal->tech->write_event(event))) {
01446       ast_log(LOG_WARNING, "Writing event to calendar '%s' failed!\n", cal->name);
01447    }
01448 
01449 write_cleanup:
01450    if (ret) {
01451       pbx_builtin_setvar_helper(chan, "CALENDAR_SUCCESS", "0");
01452    } else {
01453       pbx_builtin_setvar_helper(chan, "CALENDAR_SUCCESS", "1");
01454    }
01455    if (cal) {
01456       cal = unref_calendar(cal);
01457    }
01458    if (event) {
01459       event = ast_calendar_unref_event(event);
01460    }
01461    if (val_dup) {
01462       ast_free(val_dup);
01463    }
01464 
01465    return ret;
01466 }

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

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

00376 {
00377    struct ast_calendar *cal;
00378 
00379    if (ast_strlen_zero(data) || (!(cal = find_calendar(data)))) {
00380       return AST_DEVICE_INVALID;
00381    }
00382 
00383    if (cal->tech->is_busy) {
00384       return cal->tech->is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
00385    }
00386 
00387    return calendar_is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
00388 }

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

Definition at line 1714 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::pending_deletion.

Referenced by reload().

01715 {
01716    struct ast_calendar *cal = user_data;
01717 
01718    cal->pending_deletion = 1;
01719 
01720    return CMP_MATCH;
01721 }

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

Definition at line 1723 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::pending_deletion.

Referenced by reload().

01724 {
01725    struct ast_calendar *cal = user_data;
01726 
01727    return cal->pending_deletion ? CMP_MATCH : 0;
01728 }

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

Definition at line 617 of file res_calendar.c.

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

Referenced by ast_calendar_clear_events().

00618 {
00619    struct ast_calendar_event *event = user_data;
00620 
00621    event = destroy_event(event);
00622 
00623    return CMP_MATCH;
00624 }

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

Definition at line 878 of file res_calendar.c.

References ast_calendar_event::alarm, ast_free, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_HEAD, ast_string_field_set, ast_calendar_event::attendees, ast_calendar_event::busy_state, ast_calendar_event::categories, ast_calendar_event::description, ast_calendar_event::end, ast_calendar_event::location, evententry::next, ast_calendar_event::organizer, ast_calendar_event::owner, ast_calendar_event::priority, ast_calendar_event::start, ast_calendar_event::summary, and ast_calendar_event::uid.

Referenced by merge_events_cb().

00879 {
00880    struct ast_calendar_attendee *attendee;
00881 
00882    ast_string_field_set(dst, summary, src->summary);
00883    ast_string_field_set(dst, description, src->description);
00884    ast_string_field_set(dst, organizer, src->organizer);
00885    ast_string_field_set(dst, location, src->location);
00886    ast_string_field_set(dst, uid, src->uid);
00887    ast_string_field_set(dst, categories, src->categories);
00888    dst->priority = src->priority;
00889    dst->owner = src->owner;
00890    dst->start = src->start;
00891    dst->end = src->end;
00892    dst->alarm = src->alarm;
00893    dst->busy_state = src->busy_state;
00894 
00895    /* Delete any existing attendees */
00896    while ((attendee = AST_LIST_REMOVE_HEAD(&dst->attendees, next))) {
00897       ast_free(attendee);
00898    }
00899 
00900    /* Copy over the new attendees */
00901    while ((attendee = AST_LIST_REMOVE_HEAD(&src->attendees, next))) {
00902       AST_LIST_INSERT_TAIL(&dst->attendees, attendee, next);
00903    }
00904 }

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

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

00593 {
00594    if (event->notify_sched > -1 && ast_sched_del(sched, event->notify_sched)) {
00595       ast_debug(3, "Notification running, can't delete sched entry\n");
00596    }
00597    if (event->bs_start_sched > -1 && ast_sched_del(sched, event->bs_start_sched)) {
00598       ast_debug(3, "Devicestate update (start) running, can't delete sched entry\n");
00599    }
00600    if (event->bs_end_sched > -1 && ast_sched_del(sched, event->bs_end_sched)) {
00601       ast_debug(3, "Devicestate update (end) running, can't delete sched entry\n");
00602    }
00603 
00604    /* If an event is being deleted and we've fired an event changing the status at the beginning,
00605     * but haven't hit the end event yet, go ahead and set the devicestate to the current busy status */
00606    if (event->bs_start_sched < 0 && event->bs_end_sched >= 0) {
00607       if (!calendar_is_busy(event->owner)) {
00608          ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Calendar:%s", event->owner->name);
00609       } else {
00610          ast_devstate_changed(AST_DEVICE_BUSY, "Calendar:%s", event->owner->name);
00611       }
00612    }
00613 
00614    return NULL;
00615 }

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

Definition at line 706 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_cap_set(), ast_format_set(), AST_FORMAT_SLINEAR, ast_free, ast_log(), ast_pbx_run(), AST_STATE_DOWN, ast_str_buffer(), ast_str_create(), ast_str_set(), ast_str_substitute_variables(), 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_variable::name, ast_calendar::name, ast_channel::nativeformats, ast_variable::next, 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, pbx_builtin_setvar_helper(), ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::tech, ast_variable::value, ast_calendar::vars, and ast_channel::writeformat.

Referenced by calendar_event_notify().

00707 {
00708    struct ast_calendar_event *event = data;
00709    struct ast_dial *dial = NULL;
00710    struct ast_str *apptext = NULL, *tmpstr = NULL;
00711    struct ast_datastore *datastore;
00712    enum ast_dial_result res;
00713    struct ast_channel *chan = NULL;
00714    struct ast_variable *itervar;
00715    char *tech, *dest;
00716    char buf[8];
00717 
00718    tech = ast_strdupa(event->owner->notify_channel);
00719 
00720    if ((dest = strchr(tech, '/'))) {
00721       *dest = '\0';
00722       dest++;
00723    } else {
00724       ast_log(LOG_WARNING, "Channel should be in form Tech/Dest (was '%s')\n", tech);
00725       goto notify_cleanup;
00726    }
00727 
00728    if (!(dial = ast_dial_create())) {
00729       ast_log(LOG_ERROR, "Could not create dial structure\n");
00730       goto notify_cleanup;
00731    }
00732 
00733    if (ast_dial_append(dial, tech, dest) < 0) {
00734       ast_log(LOG_ERROR, "Could not append channel\n");
00735       goto notify_cleanup;
00736    }
00737 
00738    ast_dial_set_global_timeout(dial, event->owner->notify_waittime);
00739    generate_random_string(buf, sizeof(buf));
00740 
00741    if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, 0, 0, 0, 0, 0, 0, 0, "Calendar/%s-%s", event->owner->name, buf))) {
00742       ast_log(LOG_ERROR, "Could not allocate notification channel\n");
00743       goto notify_cleanup;
00744    }
00745 
00746    chan->tech = &null_tech;
00747    ast_format_set(&chan->writeformat, AST_FORMAT_SLINEAR, 0);
00748    ast_format_set(&chan->readformat, AST_FORMAT_SLINEAR, 0);
00749    ast_format_set(&chan->rawwriteformat, AST_FORMAT_SLINEAR, 0);
00750    ast_format_set(&chan->rawreadformat, AST_FORMAT_SLINEAR, 0);
00751    /* clear native formats and set to slinear. write format is signlear so just use that to set it */
00752    ast_format_cap_set(chan->nativeformats, &chan->writeformat);
00753 
00754    if (!(datastore = ast_datastore_alloc(&event_notification_datastore, NULL))) {
00755       ast_log(LOG_ERROR, "Could not allocate datastore, notification not being sent!\n");
00756       goto notify_cleanup;
00757    }
00758 
00759    datastore->data = event;
00760    datastore->inheritance = DATASTORE_INHERIT_FOREVER;
00761 
00762    ao2_ref(event, +1);
00763    res = ast_channel_datastore_add(chan, datastore);
00764 
00765    if (!(tmpstr = ast_str_create(32))) {
00766       goto notify_cleanup;
00767    }
00768 
00769    for (itervar = event->owner->vars; itervar; itervar = itervar->next) {
00770       ast_str_substitute_variables(&tmpstr, 0, chan, itervar->value);
00771       pbx_builtin_setvar_helper(chan, itervar->name, tmpstr->str);
00772    }
00773 
00774    if (!(apptext = ast_str_create(32))) {
00775       goto notify_cleanup;
00776    }
00777 
00778    if (!ast_strlen_zero(event->owner->notify_app)) {
00779       ast_str_set(&apptext, 0, "%s,%s", event->owner->notify_app, event->owner->notify_appdata);
00780       ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, ast_str_buffer(apptext));
00781    } else {
00782    }
00783 
00784    ast_verb(3, "Dialing %s for notification on calendar %s\n", event->owner->notify_channel, event->owner->name);
00785    res = ast_dial_run(dial, chan, 0);
00786 
00787    if (res != AST_DIAL_RESULT_ANSWERED) {
00788       ast_verb(3, "Notification call for %s was not completed\n", event->owner->name);
00789    } else {
00790       struct ast_channel *answered;
00791 
00792       answered = ast_dial_answered_steal(dial);
00793       if (ast_strlen_zero(event->owner->notify_app)) {
00794          ast_copy_string(answered->context, event->owner->notify_context, sizeof(answered->context));
00795          ast_copy_string(answered->exten, event->owner->notify_extension, sizeof(answered->exten));
00796          answered->priority = 1;
00797          ast_pbx_run(answered);
00798       }
00799    }
00800 
00801 notify_cleanup:
00802    if (apptext) {
00803       ast_free(apptext);
00804    }
00805    if (tmpstr) {
00806       ast_free(tmpstr);
00807    }
00808    if (dial) {
00809       ast_dial_destroy(dial);
00810    }
00811    if (chan) {
00812       ast_channel_release(chan);
00813    }
00814 
00815    event = ast_calendar_unref_event(event);
00816 
00817    return NULL;
00818 }

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

Definition at line 1756 of file res_calendar.c.

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

01757 {
01758    for (;;) {
01759       struct timeval now = ast_tvnow();
01760       struct timespec ts = {0,};
01761       int wait;
01762 
01763       ast_mutex_lock(&refreshlock);
01764 
01765       while (!module_unloading) {
01766          if ((wait = ast_sched_wait(sched)) < 0) {
01767             wait = 1000;
01768          }
01769 
01770          ts.tv_sec = (now.tv_sec + wait / 1000) + 1;
01771          if (ast_cond_timedwait(&refresh_condition, &refreshlock, &ts) == ETIMEDOUT) {
01772             break;
01773          }
01774       }
01775       ast_mutex_unlock(&refreshlock);
01776 
01777       if (module_unloading) {
01778          break;
01779       }
01780       ast_sched_runq(sched);
01781    }
01782 
01783    return NULL;
01784 }

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

Definition at line 1533 of file res_calendar.c.

References ast_localtime(), and ast_strftime().

Referenced by handle_show_calendar().

01534 {
01535    struct ast_tm tm;
01536    struct timeval tv = {
01537       .tv_sec = epoch,
01538    };
01539 
01540    if (!epoch) {
01541       *buf = '\0';
01542       return buf;
01543    }
01544    ast_localtime(&tv, &tm, NULL);
01545    ast_strftime(buf, buflen, "%F %r %z", &tm);
01546 
01547    return buf;
01548 }

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

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

00299 {
00300    const struct ast_calendar_event *one = obj, *two = arg;
00301    return !strcmp(one->uid, two->uid) ? CMP_MATCH | CMP_STOP : 0;
00302 }

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

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

00293 {
00294    const struct ast_calendar_event *event = obj;
00295    return ast_str_hash(event->uid);
00296 }

static void event_notification_destroy ( void *  data  )  [static]

Definition at line 660 of file res_calendar.c.

References ast_calendar_unref_event(), and evententry::event.

00661 {
00662    struct ast_calendar_event *event = data;
00663 
00664    event = ast_calendar_unref_event(event);
00665 
00666 }

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

Definition at line 668 of file res_calendar.c.

References ao2_ref, and evententry::event.

00669 {
00670    struct ast_calendar_event *event = data;
00671 
00672    if (!event) {
00673       return NULL;
00674    }
00675 
00676    ao2_ref(event, +1);
00677 
00678    return event;
00679 }

static void eventlist_destroy ( void *  data  )  [static]

Definition at line 1144 of file res_calendar.c.

References ao2_ref, and events.

01145 {
01146    struct eventlist *events = data;
01147 
01148    ao2_ref(events, -1);
01149 }

static void eventlist_destructor ( void *  obj  )  [static]

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

00342 {
00343    struct eventlist *events = obj;
00344    struct evententry *entry;
00345 
00346    while ((entry = AST_LIST_REMOVE_HEAD(events, list))) {
00347       ao2_ref(entry->event, -1);
00348       ast_free(entry);
00349    }
00350 }

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

Definition at line 1151 of file res_calendar.c.

References ao2_ref, and events.

01152 {
01153    struct eventlist *events = data;
01154 
01155    if (!events) {
01156       return NULL;
01157    }
01158 
01159    ao2_ref(events, +1);
01160 
01161    return events;
01162 }

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

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

00285 {
00286    struct ast_calendar tmp = {
00287       .name = name,
00288    };
00289    return ao2_find(calendars, &tmp, OBJ_POINTER);
00290 }

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

Definition at line 304 of file res_calendar.c.

References ao2_find, OBJ_POINTER, and ast_calendar_event::uid.

Referenced by merge_events_cb().

00305 {
00306    struct ast_calendar_event tmp = {
00307       .uid = uid,
00308    };
00309    return ao2_find(events, &tmp, OBJ_POINTER);
00310 }

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

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

Definition at line 682 of file res_calendar.c.

References ast_random().

00683 {
00684    long val[4];
00685    int x;
00686 
00687    for (x = 0; x < 4; x++) {
00688       val[x] = ast_random();
00689    }
00690    snprintf(buf, size, "%08lx%08lx%08lx%08lx", val[0], val[1], val[2], val[3]);
00691 
00692    return buf;
00693 }

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

Definition at line 1630 of file res_calendar.c.

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

01631 {
01632    switch(cmd) {
01633    case CLI_INIT:
01634       e->command = "calendar dump sched";
01635       e->usage =
01636          "Usage: calendar dump sched\n"
01637          "       Dump the calendar sched context";
01638       return NULL;
01639 
01640    case CLI_GENERATE:
01641       return NULL;
01642    }
01643 
01644    ast_sched_dump(sched);
01645 
01646    return CLI_SUCCESS;
01647 }

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

Definition at line 1550 of file res_calendar.c.

References ast_calendar_event::alarm, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ast_cli_args::argc, ast_cli_args::argv, ast_calendar_unref_event(), ast_cli(), ast_strdup, ast_calendar::autoreminder, ast_calendar_event::categories, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_calendar_event::description, ast_calendar_event::end, epoch_to_string(), 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_event::priority, ast_calendar::refresh, ast_calendar_event::start, ast_calendar_event::summary, ast_calendar::timeframe, ast_calendar_event::uid, unref_calendar(), ast_cli_entry::usage, and ast_cli_args::word.

01551 {
01552 #define FORMAT "%-17.17s : %-20.20s\n"
01553 #define FORMAT2 "%-12.12s: %-40.60s\n"
01554    struct ao2_iterator i;
01555    struct ast_calendar *cal;
01556    struct ast_calendar_event *event;
01557    int which = 0;
01558    char *ret = NULL;
01559 
01560    switch(cmd) {
01561    case CLI_INIT:
01562       e->command = "calendar show calendar";
01563       e->usage =
01564          "Usage: calendar show calendar <calendar name>\n"
01565          "       Displays information about a calendar\n";
01566       return NULL;
01567 
01568    case CLI_GENERATE:
01569       if (a->pos != 3) {
01570          return NULL;
01571       }
01572       i = ao2_iterator_init(calendars, 0);
01573       while ((cal = ao2_iterator_next(&i))) {
01574          if (!strncasecmp(a->word, cal->name, strlen(a->word)) && ++which > a->n) {
01575             ret = ast_strdup(cal->name);
01576             cal = unref_calendar(cal);
01577             break;
01578          }
01579          cal = unref_calendar(cal);
01580       }
01581       ao2_iterator_destroy(&i);
01582       return ret;
01583    }
01584 
01585    if (a->argc != 4) {
01586       return CLI_SHOWUSAGE;
01587    }
01588 
01589    if (!(cal = find_calendar(a->argv[3]))) {
01590       return NULL;
01591    }
01592 
01593    ast_cli(a->fd, FORMAT, "Name", cal->name);
01594    ast_cli(a->fd, FORMAT, "Notify channel", cal->notify_channel);
01595    ast_cli(a->fd, FORMAT, "Notify context", cal->notify_context);
01596    ast_cli(a->fd, FORMAT, "Notify extension", cal->notify_extension);
01597    ast_cli(a->fd, FORMAT, "Notify application", cal->notify_app);
01598    ast_cli(a->fd, FORMAT, "Notify appdata", cal->notify_appdata);
01599    ast_cli(a->fd, "%-17.17s : %d\n", "Refresh time", cal->refresh);
01600    ast_cli(a->fd, "%-17.17s : %d\n", "Timeframe", cal->timeframe);
01601    ast_cli(a->fd, "%-17.17s : %d\n", "Autoreminder", cal->autoreminder);
01602    ast_cli(a->fd, "%s\n", "Events");
01603    ast_cli(a->fd, "%s\n", "------");
01604 
01605    i = ao2_iterator_init(cal->events, 0);
01606    while ((event = ao2_iterator_next(&i))) {
01607       char buf[100];
01608 
01609       ast_cli(a->fd, FORMAT2, "Summary", event->summary);
01610       ast_cli(a->fd, FORMAT2, "Description", event->description);
01611       ast_cli(a->fd, FORMAT2, "Organizer", event->organizer);
01612       ast_cli(a->fd, FORMAT2, "Location", event->location);
01613       ast_cli(a->fd, FORMAT2, "Categories", event->categories);
01614       ast_cli(a->fd, "%-12.12s: %d\n", "Priority", event->priority);
01615       ast_cli(a->fd, FORMAT2, "UID", event->uid);
01616       ast_cli(a->fd, FORMAT2, "Start", epoch_to_string(buf, sizeof(buf), event->start));
01617       ast_cli(a->fd, FORMAT2, "End", epoch_to_string(buf, sizeof(buf), event->end));
01618       ast_cli(a->fd, FORMAT2, "Alarm", epoch_to_string(buf, sizeof(buf), event->alarm));
01619       ast_cli(a->fd, "\n");
01620 
01621       event = ast_calendar_unref_event(event);
01622    }
01623    ao2_iterator_destroy(&i);
01624    cal = unref_calendar(cal);
01625    return CLI_SUCCESS;
01626 #undef FORMAT
01627 #undef FORMAT2
01628 }

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

01475 {
01476 #define FORMAT "%-20.20s %-10.10s %-6.6s\n"
01477    struct ao2_iterator i;
01478    struct ast_calendar *cal;
01479 
01480    switch(cmd) {
01481    case CLI_INIT:
01482       e->command = "calendar show calendars";
01483       e->usage =
01484          "Usage: calendar show calendars\n"
01485          "       Lists all registered calendars.\n";
01486       return NULL;
01487    case CLI_GENERATE:
01488       return NULL;
01489    }
01490 
01491    ast_cli(a->fd, FORMAT, "Calendar", "Type", "Status");
01492    ast_cli(a->fd, FORMAT, "--------", "----", "------");
01493    i = ao2_iterator_init(calendars, 0);
01494    while ((cal = ao2_iterator_next(&i))) {
01495       ast_cli(a->fd, FORMAT, cal->name, cal->tech->type, calendar_is_busy(cal) ? "busy" : "free");
01496       cal = unref_calendar(cal);
01497    }
01498    ao2_iterator_destroy(&i);
01499 
01500    return CLI_SUCCESS;
01501 #undef FORMAT
01502 }

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

CLI command to list of all calendars types currently loaded on the backend.

Definition at line 1505 of file res_calendar.c.

References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_calendar_tech::description, ast_cli_args::fd, FORMAT, evententry::list, ast_calendar_tech::type, and ast_cli_entry::usage.

01506 {
01507 #define FORMAT "%-10.10s %-30.30s\n"
01508         struct ast_calendar_tech *iter;
01509 
01510 
01511    switch(cmd) {
01512    case CLI_INIT:
01513       e->command = "calendar show types";
01514       e->usage =
01515          "Usage: calendar show types\n"
01516          "       Lists all registered calendars types.\n";
01517       return NULL;
01518    case CLI_GENERATE:
01519       return NULL;
01520    }
01521 
01522    ast_cli(a->fd, FORMAT, "Type", "Description");
01523    AST_LIST_LOCK(&techs);
01524    AST_LIST_TRAVERSE(&techs, iter, list) {
01525       ast_cli(a->fd, FORMAT, iter->type, iter->description);
01526    }
01527    AST_LIST_UNLOCK(&techs);
01528 
01529    return CLI_SUCCESS;
01530 #undef FORMAT
01531 }

static int load_config ( int  reload  )  [static]

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

01018 {
01019    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01020    struct ast_config *tmpcfg;
01021 
01022    if (!(tmpcfg = ast_config_load2("calendar.conf", "calendar", config_flags)) ||
01023       tmpcfg == CONFIG_STATUS_FILEINVALID) {
01024       ast_log(LOG_ERROR, "Unable to load config calendar.conf\n");
01025       return -1;
01026    }
01027 
01028    if (tmpcfg == CONFIG_STATUS_FILEUNCHANGED) {
01029       return 0;
01030    }
01031 
01032    ast_rwlock_wrlock(&config_lock);
01033    if (calendar_config) {
01034       ast_config_destroy(calendar_config);
01035    }
01036 
01037    calendar_config = tmpcfg;
01038    ast_rwlock_unlock(&config_lock);
01039 
01040    return 0;
01041 }

static int load_module ( void   )  [static]

Definition at line 1821 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, ast_sched_context_create(), 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(), and LOG_ERROR.

01822 {
01823    if (!(calendars = ao2_container_alloc(CALENDAR_BUCKETS, calendar_hash_fn, calendar_cmp_fn))) {
01824       ast_log(LOG_ERROR, "Unable to allocate calendars container!\n");
01825       return AST_MODULE_LOAD_FAILURE;
01826    }
01827 
01828    if (load_config(0)) {
01829       /* We don't have calendar support enabled */
01830       return AST_MODULE_LOAD_DECLINE;
01831    }
01832 
01833    ast_mutex_init(&refreshlock);
01834    ast_cond_init(&refresh_condition, NULL);
01835    ast_mutex_init(&reloadlock);
01836 
01837    if (!(sched = ast_sched_context_create())) {
01838       ast_log(LOG_ERROR, "Unable to create sched context\n");
01839       return AST_MODULE_LOAD_FAILURE;
01840    }
01841 
01842    if (ast_pthread_create_background(&refresh_thread, NULL, do_refresh, NULL) < 0) {
01843       ast_log(LOG_ERROR, "Unable to start refresh thread--notifications disabled!\n");
01844    }
01845 
01846    ast_custom_function_register(&calendar_busy_function);
01847    ast_custom_function_register(&calendar_event_function);
01848    ast_custom_function_register(&calendar_query_function);
01849    ast_custom_function_register(&calendar_query_result_function);
01850    ast_custom_function_register(&calendar_write_function);
01851    ast_cli_register_multiple(calendar_cli, ARRAY_LEN(calendar_cli));
01852 
01853    ast_devstate_prov_add("Calendar", calendarstate);
01854 
01855    return AST_MODULE_LOAD_SUCCESS;
01856 }

static int load_tech_calendars ( struct ast_calendar_tech tech  )  [static]

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

00487 {
00488    struct ast_calendar *cal;
00489    const char *cat = NULL;
00490    const char *val;
00491 
00492    if (!calendar_config) {
00493       ast_log(LOG_WARNING, "Calendar support disabled, not loading %s calendar module\n", tech->type);
00494       return -1;
00495    }
00496 
00497    ast_rwlock_wrlock(&config_lock);
00498    while ((cat = ast_category_browse(calendar_config, cat))) {
00499       if (!strcasecmp(cat, "general")) {
00500          continue;
00501       }
00502 
00503       if (!(val = ast_variable_retrieve(calendar_config, cat, "type")) || strcasecmp(val, tech->type)) {
00504          continue;
00505       }
00506 
00507       /* A serious error occurred loading calendars from this tech and it should be disabled */
00508       if (!(cal = build_calendar(calendar_config, cat, tech))) {
00509          ast_calendar_unregister(tech);
00510          ast_rwlock_unlock(&config_lock);
00511          return -1;
00512       }
00513 
00514       cal = unref_calendar(cal);
00515    }
00516 
00517    ast_rwlock_unlock(&config_lock);
00518 
00519    return 0;
00520 }

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

Definition at line 542 of file res_calendar.c.

References CMP_MATCH, and ast_calendar::tech.

Referenced by ast_calendar_unregister().

00543 {
00544    struct ast_calendar *cal = user_data;
00545    struct ast_calendar_tech *tech = arg;
00546 
00547    if (cal->tech == tech) {
00548       return CMP_MATCH;
00549    }
00550 
00551    return 0;
00552 }

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

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

00969 {
00970    struct ast_calendar_event *old_event = obj, *new_event;
00971    struct ao2_container *new_events = arg;
00972 
00973    /* If we don't find the old_event in new_events, then we can safely delete the old_event */
00974    if (!(new_event = find_event(new_events, old_event->uid))) {
00975       old_event = destroy_event(old_event);
00976       return CMP_MATCH;
00977    }
00978 
00979    /* We have events to merge.  If any data that will affect a scheduler event has changed,
00980     * then we need to replace the scheduler event */
00981    schedule_calendar_event(old_event->owner, old_event, new_event);
00982 
00983    /* Since we don't want to mess with cancelling sched events and adding new ones, just
00984     * copy the internals of the new_event to the old_event */
00985    copy_event_data(old_event, new_event);
00986 
00987    /* Now we can go ahead and unlink the new_event from new_events and unref it so that only completely
00988     * new events remain in the container */
00989    ao2_unlink(new_events, new_event);
00990    new_event = ast_calendar_unref_event(new_event);
00991 
00992    return 0;
00993 }

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

Definition at line 695 of file res_calendar.c.

00696 {
00697    return 0;
00698 }

static int reload ( void   )  [static]

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

01731 {
01732    struct ast_calendar_tech *iter;
01733 
01734    ast_mutex_lock(&reloadlock);
01735 
01736    /* Mark existing calendars for deletion */
01737    ao2_callback(calendars, OBJ_NODATA | OBJ_MULTIPLE, cb_pending_deletion, NULL);
01738    load_config(1);
01739 
01740    AST_LIST_LOCK(&techs);
01741    AST_LIST_TRAVERSE(&techs, iter, list) {
01742       if (load_tech_calendars(iter)) {
01743          ast_log(LOG_WARNING, "Failed to reload %s calendars, module disabled\n", iter->type);
01744       }
01745    }
01746    AST_LIST_UNLOCK(&techs);
01747 
01748    /* Delete calendars that no longer show up in the config */
01749    ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, cb_rm_pending_deletion, NULL);
01750 
01751    ast_mutex_unlock(&reloadlock);
01752 
01753    return 0;
01754 }

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

00907 {
00908    struct timeval now = ast_tvnow();
00909    struct ast_calendar_event *event;
00910    time_t alarm_notify_sched = 0, devstate_sched_start, devstate_sched_end;
00911    int changed = 0;
00912 
00913    event = cmp_event ? cmp_event : old_event;
00914 
00915    ao2_lock(event);
00916    if (!cmp_event || old_event->alarm != event->alarm) {
00917       changed = 1;
00918       if (cal->autoreminder) {
00919          alarm_notify_sched = (event->start - (60 * cal->autoreminder) - now.tv_sec) * 1000;
00920       } else if (event->alarm) {
00921          alarm_notify_sched = (event->alarm - now.tv_sec) * 1000;
00922       }
00923 
00924       /* For now, send the notification if we missed it, but the meeting hasn't happened yet */
00925       if (event->start >=  now.tv_sec) {
00926          if (alarm_notify_sched <= 0) {
00927             alarm_notify_sched = 1;
00928          }
00929          ast_mutex_lock(&refreshlock);
00930          AST_SCHED_REPLACE(old_event->notify_sched, sched, alarm_notify_sched, calendar_event_notify, old_event);
00931          ast_mutex_unlock(&refreshlock);
00932          ast_debug(3, "Calendar alarm event notification scheduled to happen in %ld ms\n", (long) alarm_notify_sched);
00933       }
00934    }
00935 
00936    if (!cmp_event || old_event->start != event->start) {
00937       changed = 1;
00938       devstate_sched_start = (event->start - now.tv_sec) * 1000;
00939 
00940       if (devstate_sched_start < 1) {
00941          devstate_sched_start = 1;
00942       }
00943 
00944       ast_mutex_lock(&refreshlock);
00945       AST_SCHED_REPLACE(old_event->bs_start_sched, sched, devstate_sched_start, calendar_devstate_change, old_event);
00946       ast_mutex_unlock(&refreshlock);
00947       ast_debug(3, "Calendar bs_start event notification scheduled to happen in %ld ms\n", (long) devstate_sched_start);
00948    }
00949 
00950    if (!cmp_event || old_event->end != event->end) {
00951       changed = 1;
00952       devstate_sched_end = (event->end - now.tv_sec) * 1000;
00953       ast_mutex_lock(&refreshlock);
00954       AST_SCHED_REPLACE(old_event->bs_end_sched, sched, devstate_sched_end, calendar_devstate_change, old_event);
00955       ast_mutex_unlock(&refreshlock);
00956       ast_debug(3, "Calendar bs_end event notification scheduled to happen in %ld ms\n", (long) devstate_sched_end);
00957    }
00958 
00959    if (changed) {
00960       ast_cond_signal(&refresh_condition);
00961    }
00962 
00963    ao2_unlock(event);
00964 
00965    return 0;
00966 }

static int unload_module ( void   )  [static]

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

00267 {
00268    ao2_ref(cal, -1);
00269    return NULL;
00270 }


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

Definition at line 1862 of file res_calendar.c.

Definition at line 1862 of file res_calendar.c.

Initial value:

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

Definition at line 1065 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ast_cli_entry calendar_cli[] [static]

Definition at line 1649 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ast_config* calendar_config [static]

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

Referenced by load_module(), and unload_module().

Initial value:

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

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

Referenced by load_module(), and unload_module().

Initial value:

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

Definition at line 1468 of file res_calendar.c.

Referenced by load_module(), and unload_module().

struct ao2_container* calendars [static]

Definition at line 213 of file res_calendar.c.

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

Definition at line 247 of file res_calendar.c.

Initial value:

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

Definition at line 226 of file res_calendar.c.

Initial value:

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

Definition at line 232 of file res_calendar.c.

int module_unloading [static]

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

Definition at line 217 of file res_calendar.c.

pthread_t refresh_thread = AST_PTHREADT_NULL [static]

Definition at line 215 of file res_calendar.c.

Definition at line 218 of file res_calendar.c.

struct ast_sched_context* sched [static]

Definition at line 214 of file res_calendar.c.


Generated on Sat Feb 11 06:36:20 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6