Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
res_calendar.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2008 - 2009, Digium, Inc.
5 *
6 * Terry Wilson <twilson@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 * \brief Calendaring API
21 *
22 * \todo Support responding to a meeting invite
23 * \todo Support writing attendees
24 */
25
26/*! \li \ref res_calendar.c uses the configuration file \ref calendar.conf
27 * \addtogroup configuration_file Configuration Files
28 */
29
30/*!
31 * \page calendar.conf calendar.conf
32 * \verbinclude calendar.conf.sample
33 */
34
35/*** MODULEINFO
36 <support_level>extended</support_level>
37 ***/
38
39#include "asterisk.h"
40
41#include "asterisk/_private.h"
42#include "asterisk/channel.h"
43#include "asterisk/calendar.h"
44#include "asterisk/utils.h"
45#include "asterisk/astobj2.h"
46#include "asterisk/module.h"
47#include "asterisk/config.h"
48#include "asterisk/channel.h"
51#include "asterisk/sched.h"
52#include "asterisk/dial.h"
53#include "asterisk/cli.h"
54#include "asterisk/pbx.h"
55#include "asterisk/app.h"
57
58/*** DOCUMENTATION
59 <function name="CALENDAR_BUSY" language="en_US">
60 <since>
61 <version>1.8.0</version>
62 </since>
63 <synopsis>
64 Determine if the calendar is marked busy at this time.
65 </synopsis>
66 <syntax>
67 <parameter name="calendar" required="true" />
68 </syntax>
69 <description>
70 <para>Check the specified calendar's current busy status.</para>
71 </description>
72 <see-also>
73 <ref type="function">CALENDAR_EVENT</ref>
74 <ref type="function">CALENDAR_QUERY</ref>
75 <ref type="function">CALENDAR_QUERY_RESULT</ref>
76 <ref type="function">CALENDAR_WRITE</ref>
77 </see-also>
78 </function>
79 <function name="CALENDAR_EVENT" language="en_US">
80 <since>
81 <version>1.8.0</version>
82 </since>
83 <synopsis>
84 Get calendar event notification data from a notification call.
85 </synopsis>
86 <syntax>
87 <parameter name="field" required="true">
88 <enumlist>
89 <enum name="summary"><para>The VEVENT SUMMARY property or Exchange event 'subject'</para></enum>
90 <enum name="description"><para>The text description of the event</para></enum>
91 <enum name="organizer"><para>The organizer of the event</para></enum>
92 <enum name="location"><para>The location of the event</para></enum>
93 <enum name="categories"><para>The categories of the event</para></enum>
94 <enum name="priority"><para>The priority of the event</para></enum>
95 <enum name="calendar"><para>The name of the calendar associated with the event</para></enum>
96 <enum name="uid"><para>The unique identifier for this event</para></enum>
97 <enum name="start"><para>The start time of the event</para></enum>
98 <enum name="end"><para>The end time of the event</para></enum>
99 <enum name="busystate"><para>The busy state of the event 0=FREE, 1=TENTATIVE, 2=BUSY</para></enum>
100 </enumlist>
101 </parameter>
102 </syntax>
103 <description>
104 <para>Whenever a calendar event notification call is made, the event data
105 may be accessed with this function.</para>
106 </description>
107 <see-also>
108 <ref type="function">CALENDAR_BUSY</ref>
109 <ref type="function">CALENDAR_QUERY</ref>
110 <ref type="function">CALENDAR_QUERY_RESULT</ref>
111 <ref type="function">CALENDAR_WRITE</ref>
112 </see-also>
113 </function>
114 <function name="CALENDAR_QUERY" language="en_US">
115 <since>
116 <version>1.8.0</version>
117 </since>
118 <synopsis>Query a calendar server and store the data on a channel
119 </synopsis>
120 <syntax>
121 <parameter name="calendar" required="true">
122 <para>The calendar that should be queried</para>
123 </parameter>
124 <parameter name="start" required="false">
125 <para>The start time of the query (in seconds since epoch)</para>
126 </parameter>
127 <parameter name="end" required="false">
128 <para>The end time of the query (in seconds since epoch)</para>
129 </parameter>
130 </syntax>
131 <description>
132 <para>Get a list of events in the currently accessible timeframe of the <replaceable>calendar</replaceable>
133 The function returns the id for accessing the result with CALENDAR_QUERY_RESULT()</para>
134 </description>
135 <see-also>
136 <ref type="function">CALENDAR_BUSY</ref>
137 <ref type="function">CALENDAR_EVENT</ref>
138 <ref type="function">CALENDAR_QUERY_RESULT</ref>
139 <ref type="function">CALENDAR_WRITE</ref>
140 </see-also>
141 </function>
142 <function name="CALENDAR_QUERY_RESULT" language="en_US">
143 <since>
144 <version>1.8.0</version>
145 </since>
146 <synopsis>
147 Retrieve data from a previously run CALENDAR_QUERY() call
148 </synopsis>
149 <syntax>
150 <parameter name="id" required="true">
151 <para>The query ID returned by <literal>CALENDAR_QUERY</literal></para>
152 </parameter>
153 <parameter name="field" required="true">
154 <enumlist>
155 <enum name="getnum"><para>number of events occurring during time range</para></enum>
156 <enum name="summary"><para>A summary of the event</para></enum>
157 <enum name="description"><para>The full event description</para></enum>
158 <enum name="organizer"><para>The event organizer</para></enum>
159 <enum name="location"><para>The event location</para></enum>
160 <enum name="categories"><para>The categories of the event</para></enum>
161 <enum name="priority"><para>The priority of the event</para></enum>
162 <enum name="calendar"><para>The name of the calendar associted with the event</para></enum>
163 <enum name="uid"><para>The unique identifier for the event</para></enum>
164 <enum name="start"><para>The start time of the event (in seconds since epoch)</para></enum>
165 <enum name="end"><para>The end time of the event (in seconds since epoch)</para></enum>
166 <enum name="busystate"><para>The busy status of the event 0=FREE, 1=TENTATIVE, 2=BUSY</para></enum>
167 </enumlist>
168 </parameter>
169 <parameter name="entry" required="false" default="1">
170 <para>Return data from a specific event returned by the query</para>
171 </parameter>
172 </syntax>
173 <description>
174 <para>After running CALENDAR_QUERY and getting a result <replaceable>id</replaceable>, calling
175 <literal>CALENDAR_QUERY</literal> with that <replaceable>id</replaceable> and a <replaceable>field</replaceable>
176 will return the data for that field. If multiple events matched the query, and <replaceable>entry</replaceable>
177 is provided, information from that event will be returned.</para>
178 </description>
179 <see-also>
180 <ref type="function">CALENDAR_BUSY</ref>
181 <ref type="function">CALENDAR_EVENT</ref>
182 <ref type="function">CALENDAR_QUERY</ref>
183 <ref type="function">CALENDAR_WRITE</ref>
184 </see-also>
185 </function>
186 <function name="CALENDAR_WRITE" language="en_US">
187 <since>
188 <version>1.8.0</version>
189 </since>
190 <synopsis>Write an event to a calendar</synopsis>
191 <syntax>
192 <parameter name="calendar" required="true">
193 <para>The calendar to write to</para>
194 </parameter>
195 <parameter name="field" multiple="true" required="true">
196 <enumlist>
197 <enum name="summary"><para>A summary of the event</para></enum>
198 <enum name="description"><para>The full event description</para></enum>
199 <enum name="organizer"><para>The event organizer</para></enum>
200 <enum name="location"><para>The event location</para></enum>
201 <enum name="categories"><para>The categories of the event</para></enum>
202 <enum name="priority"><para>The priority of the event</para></enum>
203 <enum name="uid"><para>The unique identifier for the event</para></enum>
204 <enum name="start"><para>The start time of the event (in seconds since epoch)</para></enum>
205 <enum name="end"><para>The end time of the event (in seconds since epoch)</para></enum>
206 <enum name="busystate"><para>The busy status of the event 0=FREE, 1=TENTATIVE, 2=BUSY</para></enum>
207 </enumlist>
208 </parameter>
209 </syntax>
210 <description>
211 <example title="Set calendar fields">
212 same => n,Set(CALENDAR_WRITE(calendar,field1,field2,field3)=val1,val2,val3)
213 </example>
214 <para>The field and value arguments can easily be set/passed using the HASHKEYS() and HASH() functions</para>
215 <variablelist>
216 <variable name="CALENDAR_SUCCESS">
217 <para>The status of the write operation to the calendar</para>
218 <value name="1" >
219 The event was successfully written to the calendar.
220 </value>
221 <value name="0" >
222 The event was not written to the calendar due to network issues, permissions, etc.
223 </value>
224 </variable>
225 </variablelist>
226
227 </description>
228 <see-also>
229 <ref type="function">CALENDAR_BUSY</ref>
230 <ref type="function">CALENDAR_EVENT</ref>
231 <ref type="function">CALENDAR_QUERY</ref>
232 <ref type="function">CALENDAR_QUERY_RESULT</ref>
233 </see-also>
234 </function>
235
236***/
237#define CALENDAR_BUCKETS 19
238
246
247static void event_notification_destroy(void *data);
248static void *event_notification_duplicate(void *data);
249static void eventlist_destroy(void *data);
250static void *eventlist_duplicate(void *data);
251
253 .type = "EventNotification",
255 .duplicate = event_notification_duplicate,
256};
257
259 .type = "CalendarEventList",
260 .destroy = eventlist_destroy,
261 .duplicate = eventlist_duplicate,
262};
263
267};
268
271
274
276{
278
279 if (!calendar_config) {
281 return NULL;
282 }
283
284 return calendar_config;
285}
286
288{
290}
291
292static struct ast_calendar *unref_calendar(struct ast_calendar *cal)
293{
294 ao2_ref(cal, -1);
295 return NULL;
296}
297
298static int calendar_hash_fn(const void *obj, const int flags)
299{
300 const struct ast_calendar *cal = obj;
301 return ast_str_case_hash(cal->name);
302}
303
304static int calendar_cmp_fn(void *obj, void *arg, int flags)
305{
306 const struct ast_calendar *one = obj, *two = arg;
307 return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP: 0;
308}
309
310static struct ast_calendar *find_calendar(const char *name)
311{
312 struct ast_calendar tmp = {
313 .name = name,
314 };
315 return ao2_find(calendars, &tmp, OBJ_POINTER);
316}
317
318static int event_hash_fn(const void *obj, const int flags)
319{
320 const struct ast_calendar_event *event = obj;
321 return ast_str_hash(event->uid);
322}
323
324static int event_cmp_fn(void *obj, void *arg, int flags)
325{
326 const struct ast_calendar_event *one = obj, *two = arg;
327 return !strcmp(one->uid, two->uid) ? CMP_MATCH | CMP_STOP : 0;
328}
329
330static struct ast_calendar_event *find_event(struct ao2_container *events, const char *uid)
331{
332 struct ast_calendar_event tmp = {
333 .uid = uid,
334 };
335 return ao2_find(events, &tmp, OBJ_POINTER);
336}
337
339{
340 ao2_ref(event, -1);
341 return NULL;
342}
343
344static void calendar_destructor(void *obj)
345{
346 struct ast_calendar *cal = obj;
347
348 ast_debug(3, "Destroying calendar %s\n", cal->name);
349
350 ao2_lock(cal);
351 cal->unloading = 1;
352 ast_cond_signal(&cal->unload);
353 pthread_join(cal->thread, NULL);
354 if (cal->tech_pvt) {
355 cal->tech_pvt = cal->tech->unref_calendar(cal->tech_pvt);
356 }
360 ao2_ref(cal->events, -1);
361 ao2_unlock(cal);
362}
363
364static void eventlist_destructor(void *obj)
365{
366 struct eventlist *events = obj;
367 struct evententry *entry;
368
369 while ((entry = AST_LIST_REMOVE_HEAD(events, list))) {
370 ao2_ref(entry->event, -1);
371 ast_free(entry);
372 }
373}
374
375static int calendar_busy_callback(void *obj, void *arg, int flags)
376{
377 struct ast_calendar_event *event = obj;
378 int *is_busy = arg;
379 struct timeval tv = ast_tvnow();
380
381 if (tv.tv_sec >= event->start && tv.tv_sec <= event->end && event->busy_state > AST_CALENDAR_BS_FREE) {
382 *is_busy = 1;
383 return CMP_STOP;
384 }
385
386 return 0;
387}
388
389static int calendar_is_busy(struct ast_calendar *cal)
390{
391 int is_busy = 0;
392
394
395 return is_busy;
396}
397
398static enum ast_device_state calendarstate(const char *data)
399{
401 struct ast_calendar *cal;
402
403 if (ast_strlen_zero(data) || (!(cal = find_calendar(data)))) {
404 return AST_DEVICE_INVALID;
405 }
406
407 if (cal->tech->is_busy) {
409 } else {
411 }
412
413 cal = unref_calendar(cal);
414 return state;
415}
416
417static struct ast_calendar *build_calendar(struct ast_config *cfg, const char *cat, const struct ast_calendar_tech *tech)
418{
419 struct ast_calendar *cal;
420 struct ast_variable *v, *last = NULL;
421 int new_calendar = 0;
422
423 cal = find_calendar(cat);
424 if (cal && cal->fetch_again_at_reload) {
425 /** Create new calendar, old will be removed during reload */
426 cal = unref_calendar(cal);
427 }
428 if (!cal) {
429 new_calendar = 1;
430 if (!(cal = ao2_alloc(sizeof(*cal), calendar_destructor))) {
431 ast_log(LOG_ERROR, "Could not allocate calendar structure. Stopping.\n");
432 return NULL;
433 }
434
437 if (!cal->events) {
438 ast_log(LOG_ERROR, "Could not allocate events container for %s\n", cat);
439 cal = unref_calendar(cal);
440 return NULL;
441 }
442
443 if (ast_string_field_init(cal, 32)) {
444 ast_log(LOG_ERROR, "Couldn't create string fields for %s\n", cat);
445 cal = unref_calendar(cal);
446 return NULL;
447 }
448 } else {
449 cal->pending_deletion = 0;
450 }
451
452 ast_string_field_set(cal, name, cat);
453 cal->tech = tech;
454
455 cal->refresh = 3600;
456 cal->timeframe = 60;
457 cal->notify_waittime = 30000;
458 cal->fetch_again_at_reload = 0;
459
460 for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
461 if (!strcasecmp(v->name, "autoreminder")) {
462 cal->autoreminder = atoi(v->value);
463 } else if (!strcasecmp(v->name, "channel")) {
465 } else if (!strcasecmp(v->name, "context")) {
466 ast_string_field_set(cal, notify_context, v->value);
467 } else if (!strcasecmp(v->name, "extension")) {
468 ast_string_field_set(cal, notify_extension, v->value);
469 } else if (!strcasecmp(v->name, "waittime")) {
470 int i = atoi(v->value);
471 if (i > 0) {
472 cal->notify_waittime = 1000 * i;
473 }
474 } else if (!strcasecmp(v->name, "app")) {
475 ast_string_field_set(cal, notify_app, v->value);
476 } else if (!strcasecmp(v->name, "appdata")) {
477 ast_string_field_set(cal, notify_appdata, v->value);
478 } else if (!strcasecmp(v->name, "refresh")) {
479 cal->refresh = atoi(v->value);
480 } else if (!strcasecmp(v->name, "fetch_again_at_reload")) {
482 } else if (!strcasecmp(v->name, "timeframe")) {
483 cal->timeframe = atoi(v->value);
484 } else if (!strcasecmp(v->name, "setvar")) {
485 char *name, *value;
486 struct ast_variable *var;
487
488 if ((name = (value = ast_strdup(v->value)))) {
489 strsep(&value, "=");
490 if (value) {
492 if (last) {
493 last->next = var;
494 } else {
495 cal->vars = var;
496 }
497 last = var;
498 }
499 } else {
500 ast_log(LOG_WARNING, "Malformed argument. Should be '%s: variable=value'\n", v->name);
501 }
502 ast_free(name);
503 }
504 }
505 }
506
507 if (cal->autoreminder && ast_strlen_zero(cal->notify_channel)) {
509 "You have set 'autoreminder' but not 'channel' for calendar '%s.' "
510 "Notifications will not occur.\n",
511 cal->name);
512 }
513
514 if (new_calendar) {
516 ast_cond_init(&cal->unload, NULL);
517 ao2_link(calendars, cal);
518 if (ast_pthread_create(&cal->thread, NULL, cal->tech->load_calendar, cal)) {
519 /* If we start failing to create threads, go ahead and return NULL
520 * and the tech module will be unregistered
521 */
522 ao2_unlink(calendars, cal);
523 cal = unref_calendar(cal);
524 }
525 }
526
527 return cal;
528}
529
531{
532 struct ast_calendar *cal;
533 const char *cat = NULL;
534 const char *val;
535
536 if (!calendar_config) {
537 ast_log(LOG_WARNING, "Calendar support disabled, not loading %s calendar module\n", tech->type);
538 return -1;
539 }
540
542 while ((cat = ast_category_browse(calendar_config, cat))) {
543 if (!strcasecmp(cat, "general")) {
544 continue;
545 }
546
547 if (!(val = ast_variable_retrieve(calendar_config, cat, "type")) || strcasecmp(val, tech->type)) {
548 continue;
549 }
550
551 /* A serious error occurred loading calendars from this tech and it should be disabled */
552 if (!(cal = build_calendar(calendar_config, cat, tech))) {
555 return -1;
556 }
557
558 cal = unref_calendar(cal);
559 }
560
562
563 return 0;
564}
565
567{
568 struct ast_calendar_tech *iter;
569
570 if (!calendar_config) {
571 ast_log(LOG_WARNING, "Calendar support disabled, not loading %s calendar module\n", tech->type);
572 return -1;
573 }
574
576 AST_LIST_TRAVERSE(&techs, iter, list) {
577 if(!strcasecmp(tech->type, iter->type)) {
578 ast_log(LOG_WARNING, "Already have a handler for calendar type '%s'\n", tech->type);
580 return -1;
581 }
582 }
586
587 ast_verb(2, "Registered calendar type '%s' (%s)\n", tech->type, tech->description);
588
589 return load_tech_calendars(tech);
590}
591
592static int match_caltech_cb(void *user_data, void *arg, int flags)
593{
594 struct ast_calendar *cal = user_data;
595 struct ast_calendar_tech *tech = arg;
596
597 if (cal->tech == tech) {
598 return CMP_MATCH;
599 }
600
601 return 0;
602}
603
605{
606 struct ast_calendar_tech *iter;
607
610 if (iter != tech) {
611 continue;
612 }
613
615
618 ast_verb(2, "Unregistered calendar type '%s'\n", tech->type);
619 break;
620 }
623
624}
625
626static void calendar_event_destructor(void *obj)
627{
628 struct ast_calendar_event *event = obj;
629 struct ast_calendar_attendee *attendee;
630
631 ast_debug(3, "Destroying event for calendar '%s'\n", event->owner->name);
633 while ((attendee = AST_LIST_REMOVE_HEAD(&event->attendees, next))) {
634 if (attendee->data) {
635 ast_free(attendee->data);
636 }
637 ast_free(attendee);
638 }
639}
640
641/* This is only called from ao2_callbacks that are going to unref the event for us,
642 * so we don't unref the event here. */
644{
645 if (event->notify_sched > -1 && ast_sched_del(sched, event->notify_sched)) {
646 ast_debug(3, "Notification running, can't delete sched entry\n");
647 }
648 if (event->bs_start_sched > -1 && ast_sched_del(sched, event->bs_start_sched)) {
649 ast_debug(3, "Devicestate update (start) running, can't delete sched entry\n");
650 }
651 if (event->bs_end_sched > -1 && ast_sched_del(sched, event->bs_end_sched)) {
652 ast_debug(3, "Devicestate update (end) running, can't delete sched entry\n");
653 }
654
655 /* If an event is being deleted and we've fired an event changing the status at the beginning,
656 * but haven't hit the end event yet, go ahead and set the devicestate to the current busy status */
657 if (event->bs_start_sched < 0 && event->bs_end_sched >= 0) {
658 if (!calendar_is_busy(event->owner)) {
660 } else {
662 }
663 }
664
665 return NULL;
666}
667
668static int clear_events_cb(void *user_data, void *arg, int flags)
669{
670 struct ast_calendar_event *event = user_data;
671
672 event = destroy_event(event);
673
674 return CMP_MATCH;
675}
676
678{
679 ast_debug(3, "Clearing all events for calendar %s\n", cal->name);
680
682}
683
685{
687 if (!(event = ao2_alloc(sizeof(*event), calendar_event_destructor))) {
688 return NULL;
689 }
690
691 if (ast_string_field_init(event, 32)) {
693 return NULL;
694 }
695
696 event->owner = cal;
697 event->notify_sched = -1;
698 event->bs_start_sched = -1;
699 event->bs_end_sched = -1;
700
701 AST_LIST_HEAD_INIT_NOLOCK(&event->attendees);
702
703 return event;
704}
705
707{
710}
711
712static void event_notification_destroy(void *data)
713{
714 struct ast_calendar_event *event = data;
715
717
718}
719
720static void *event_notification_duplicate(void *data)
721{
722 struct ast_calendar_event *event = data;
723
724 if (!event) {
725 return NULL;
726 }
727
728 ao2_ref(event, +1);
729
730 return event;
731}
732
733/*! \brief Generate 32 byte random string (stolen from chan_sip.c)*/
734static char *generate_random_string(char *buf, size_t size)
735{
736 unsigned long val[4];
737 int x;
738
739 for (x = 0; x < 4; x++) {
740 val[x] = ast_random();
741 }
742 snprintf(buf, size, "%08lx%08lx%08lx%08lx", val[0], val[1], val[2], val[3]);
743
744 return buf;
745}
746
747static int null_chan_write(struct ast_channel *chan, struct ast_frame *frame)
748{
749 return 0;
750}
751
752static const struct ast_channel_tech null_tech = {
753 .type = "NULL",
754 .description = "Null channel (should not see this)",
755 .write = null_chan_write,
756};
757
758static void *do_notify(void *data)
759{
760 struct ast_calendar_event *event = data;
761 struct ast_dial *dial = NULL;
762 struct ast_str *apptext = NULL, *tmpstr = NULL;
763 struct ast_datastore *datastore;
764 enum ast_dial_result res;
765 struct ast_channel *chan = NULL;
766 struct ast_variable *itervar;
767 char *tech, *dest;
768 char buf[33];
769 struct ast_format_cap *caps;
770
771 tech = ast_strdupa(event->owner->notify_channel);
772
773 if ((dest = strchr(tech, '/'))) {
774 *dest = '\0';
775 dest++;
776 } else {
777 ast_log(LOG_WARNING, "Channel should be in form Tech/Dest (was '%s')\n", tech);
778 goto notify_cleanup;
779 }
780
781 if (!(dial = ast_dial_create())) {
782 ast_log(LOG_ERROR, "Could not create dial structure\n");
783 goto notify_cleanup;
784 }
785
786 if (ast_dial_append(dial, tech, dest, NULL) < 0) {
787 ast_log(LOG_ERROR, "Could not append channel\n");
788 goto notify_cleanup;
789 }
790
791 ast_dial_set_global_timeout(dial, event->owner->notify_waittime);
793
794 if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, 0, 0, 0, 0, 0, NULL, NULL, 0, "Calendar/%s-%s", event->owner->name, buf))) {
795 ast_log(LOG_ERROR, "Could not allocate notification channel\n");
796 goto notify_cleanup;
797 }
798
804
806 if (!caps) {
807 ast_log(LOG_ERROR, "Could not allocate capabilities, notification not being sent!\n");
808 goto notify_cleanup;
809 }
812 ao2_ref(caps, -1);
813
814 ast_channel_unlock(chan);
815
817 ast_log(LOG_ERROR, "Could not allocate datastore, notification not being sent!\n");
818 goto notify_cleanup;
819 }
820
821 datastore->data = event;
823
824 ao2_ref(event, +1);
825
826 ast_channel_lock(chan);
827 res = ast_channel_datastore_add(chan, datastore);
828 ast_channel_unlock(chan);
829
830 if (!(tmpstr = ast_str_create(32))) {
831 goto notify_cleanup;
832 }
833
834 for (itervar = event->owner->vars; itervar; itervar = itervar->next) {
835 ast_str_substitute_variables(&tmpstr, 0, chan, itervar->value);
836 pbx_builtin_setvar_helper(chan, itervar->name, ast_str_buffer(tmpstr));
837 }
838
839 if (!(apptext = ast_str_create(32))) {
840 goto notify_cleanup;
841 }
842
843 if (!ast_strlen_zero(event->owner->notify_app)) {
844 ast_str_set(&apptext, 0, "%s,%s", event->owner->notify_app, event->owner->notify_appdata);
846 } else {
847 }
848
849 ast_verb(3, "Dialing %s for notification on calendar %s\n", event->owner->notify_channel, event->owner->name);
850 res = ast_dial_run(dial, chan, 0);
851
852 if (res != AST_DIAL_RESULT_ANSWERED) {
853 ast_verb(3, "Notification call for %s was not completed\n", event->owner->name);
854 } else {
855 struct ast_channel *answered;
856
857 answered = ast_dial_answered_steal(dial);
858 if (ast_strlen_zero(event->owner->notify_app)) {
859 ast_channel_context_set(answered, event->owner->notify_context);
860 ast_channel_exten_set(answered, event->owner->notify_extension);
861 ast_channel_priority_set(answered, 1);
862 ast_pbx_run(answered);
863 }
864 }
865
866notify_cleanup:
867 if (apptext) {
868 ast_free(apptext);
869 }
870 if (tmpstr) {
871 ast_free(tmpstr);
872 }
873 if (dial) {
874 ast_dial_destroy(dial);
875 }
876 if (chan) {
878 }
879
881
882 return NULL;
883}
884
885static int calendar_event_notify(const void *data)
886{
887 struct ast_calendar_event *event = (void *)data;
888 int res = -1;
889 pthread_t notify_thread = AST_PTHREADT_NULL;
890
891 if (!(event && event->owner)) {
892 ast_log(LOG_ERROR, "Extremely low-cal...in fact cal is NULL!\n");
893 return res;
894 }
895
896 ao2_ref(event, +1);
897 event->notify_sched = -1;
898
899 if (ast_pthread_create_background(&notify_thread, NULL, do_notify, event) < 0) {
900 ast_log(LOG_ERROR, "Could not create notification thread\n");
901 return res;
902 }
903
904 res = 0;
905
906 return res;
907}
908
909static int calendar_devstate_change(const void *data)
910{
911 struct ast_calendar_event *event = (struct ast_calendar_event *)data;
912 struct timeval now = ast_tvnow();
913 int is_end_event;
914
915 if (!event) {
916 ast_log(LOG_WARNING, "Event was NULL!\n");
917 return 0;
918 }
919
920 ao2_ref(event, +1);
921
922 is_end_event = event->end <= now.tv_sec;
923
924 if (is_end_event) {
925 event->bs_end_sched = -1;
926 } else {
927 event->bs_start_sched = -1;
928 }
929
930 /* We can have overlapping events, so ignore the event->busy_state and check busy state
931 * based on all events in the calendar */
932 if (!calendar_is_busy(event->owner)) {
934 } else {
936 }
937
939
940 return 0;
941}
942
943static void copy_event_data(struct ast_calendar_event *dst, struct ast_calendar_event *src)
944{
945 struct ast_calendar_attendee *attendee;
946
947 ast_string_field_set(dst, summary, src->summary);
948 ast_string_field_set(dst, description, src->description);
949 ast_string_field_set(dst, organizer, src->organizer);
950 ast_string_field_set(dst, location, src->location);
951 ast_string_field_set(dst, uid, src->uid);
953 dst->priority = src->priority;
954 dst->owner = src->owner;
955 dst->start = src->start;
956 dst->end = src->end;
957 dst->alarm = src->alarm;
958 dst->busy_state = src->busy_state;
959
960 /* Delete any existing attendees */
961 while ((attendee = AST_LIST_REMOVE_HEAD(&dst->attendees, next))) {
962 ast_free(attendee);
963 }
964
965 /* Copy over the new attendees */
966 while ((attendee = AST_LIST_REMOVE_HEAD(&src->attendees, next))) {
967 AST_LIST_INSERT_TAIL(&dst->attendees, attendee, next);
968 }
969}
970
971static int schedule_calendar_event(struct ast_calendar *cal, struct ast_calendar_event *old_event, struct ast_calendar_event *cmp_event)
972{
973 struct timeval now = ast_tvnow();
975 time_t alarm_notify_sched = 0, devstate_sched_start, devstate_sched_end;
976 int changed = 0;
977
978 event = cmp_event ? cmp_event : old_event;
979
981 if (!ast_strlen_zero(cal->notify_channel) && (!cmp_event || old_event->alarm != event->alarm)) {
982 changed = 1;
983 if (cal->autoreminder) {
984 alarm_notify_sched = (event->start - (60 * cal->autoreminder) - now.tv_sec) * 1000;
985 } else if (event->alarm) {
986 alarm_notify_sched = (event->alarm - now.tv_sec) * 1000;
987 }
988
989 /* For now, send the notification if we missed it, but the meeting hasn't happened yet */
990 if (event->start >= now.tv_sec) {
991 if (alarm_notify_sched <= 0) {
992 alarm_notify_sched = 1;
993 }
995 AST_SCHED_REPLACE(old_event->notify_sched, sched, alarm_notify_sched, calendar_event_notify, old_event);
997 ast_debug(3, "Calendar alarm event notification scheduled to happen in %ld ms\n", (long) alarm_notify_sched);
998 }
999 }
1000
1001 if (!cmp_event || old_event->start != event->start) {
1002 changed = 1;
1003 devstate_sched_start = (event->start - now.tv_sec) * 1000;
1004
1005 if (devstate_sched_start < 1) {
1006 devstate_sched_start = 1;
1007 }
1008
1010 AST_SCHED_REPLACE(old_event->bs_start_sched, sched, devstate_sched_start, calendar_devstate_change, old_event);
1012 ast_debug(3, "Calendar bs_start event notification scheduled to happen in %ld ms\n", (long) devstate_sched_start);
1013 }
1014
1015 if (!cmp_event || old_event->end != event->end) {
1016 changed = 1;
1017 devstate_sched_end = (event->end - now.tv_sec) * 1000;
1018
1019 if (devstate_sched_end <= 0) { /* if we let this slip by, Asterisk will assert */
1020 ast_log(LOG_WARNING, "Whoops! Event end notification scheduled in the past: %ld ms\n", (long) devstate_sched_end);
1021 } else {
1023 AST_SCHED_REPLACE(old_event->bs_end_sched, sched, devstate_sched_end, calendar_devstate_change, old_event);
1025 ast_debug(3, "Calendar bs_end event notification scheduled to happen in %ld ms\n", (long) devstate_sched_end);
1026 }
1027 }
1028
1029 if (changed) {
1031 }
1032
1034
1035 return 0;
1036}
1037
1038static int merge_events_cb(void *obj, void *arg, int flags)
1039{
1040 struct ast_calendar_event *old_event = obj, *new_event;
1041 struct ao2_container *new_events = arg;
1042
1043 /* If we don't find the old_event in new_events, then we can safely delete the old_event */
1044 if (!(new_event = find_event(new_events, old_event->uid))) {
1045 old_event = destroy_event(old_event);
1046 return CMP_MATCH;
1047 }
1048
1049 /* We have events to merge. If any data that will affect a scheduler event has changed,
1050 * then we need to replace the scheduler event */
1051 schedule_calendar_event(old_event->owner, old_event, new_event);
1052
1053 /* Since we don't want to mess with cancelling sched events and adding new ones, just
1054 * copy the internals of the new_event to the old_event */
1055 copy_event_data(old_event, new_event);
1056
1057 /* Now we can go ahead and unlink the new_event from new_events and unref it so that only completely
1058 * new events remain in the container */
1059 ao2_unlink(new_events, new_event);
1060 new_event = ast_calendar_unref_event(new_event);
1061
1062 return 0;
1063}
1064
1065static int add_new_event_cb(void *obj, void *arg, int flags)
1066{
1067 struct ast_calendar_event *new_event = obj;
1068 struct ao2_container *events = arg;
1069
1070 ao2_link(events, new_event);
1071 schedule_calendar_event(new_event->owner, new_event, NULL);
1072 return CMP_MATCH;
1073}
1074
1075void ast_calendar_merge_events(struct ast_calendar *cal, struct ao2_container *new_events)
1076{
1077 /* Loop through all events attached to the calendar. If there is a matching new event
1078 * merge its data over and handle any schedule changes that need to be made. Then remove
1079 * the new_event from new_events so that we are left with only new_events that we can add later. */
1081
1082 /* Now, we should only have completely new events in new_events. Loop through and add them */
1084}
1085
1086
1087static int load_config(int reload)
1088{
1089 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1090 struct ast_config *tmpcfg;
1091
1092 if (!(tmpcfg = ast_config_load2("calendar.conf", "calendar", config_flags)) ||
1093 tmpcfg == CONFIG_STATUS_FILEINVALID) {
1094 ast_log(LOG_ERROR, "Unable to load config calendar.conf\n");
1095 return -1;
1096 }
1097
1098 if (tmpcfg == CONFIG_STATUS_FILEUNCHANGED) {
1099 return 0;
1100 }
1101
1103 if (calendar_config) {
1105 }
1106
1107 calendar_config = tmpcfg;
1109
1110 return 0;
1111}
1112
1113/*! \brief A dialplan function that can be used to determine the busy status of a calendar */
1114static int calendar_busy_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1115{
1116 struct ast_calendar *cal;
1117
1118 if (ast_strlen_zero(data)) {
1119 ast_log(LOG_WARNING, "CALENDAR_BUSY requires an argument: CALENDAR_BUSY(<calendar_name>)\n");
1120 return -1;
1121 }
1122
1123 cal = find_calendar(data);
1124
1125 if (!cal) {
1126 ast_log(LOG_WARNING, "Could not find calendar '%s'\n", data);
1127 return -1;
1128 }
1129
1130 strcpy(buf, calendar_is_busy(cal) ? "1" : "0");
1131 cal = unref_calendar(cal);
1132
1133 return 0;
1134}
1135
1137 .name = "CALENDAR_BUSY",
1138 .read = calendar_busy_exec,
1139};
1140
1141static int add_event_to_list(struct eventlist *events, struct ast_calendar_event *event, time_t start, time_t end)
1142{
1143 struct evententry *entry, *iter;
1144 long event_startdiff = labs(start - event->start);
1145 long event_enddiff = labs(end - event->end);
1146 int i = 0;
1147
1148 if (!(entry = ast_calloc(1, sizeof(*entry)))) {
1149 ast_log(LOG_ERROR, "Unable to allocate memory for event list\n");
1150 return -1;
1151 }
1152
1153 entry->event = event;
1154 ao2_ref(event, +1);
1155
1156 if (start == end) {
1158 long startdiff = labs(iter->event->start - start);
1159
1160 ast_debug(10, "Comparing %s with startdiff %ld to %s with startdiff %ld\n", event->summary, event_startdiff, iter->event->summary, startdiff);
1161 ++i;
1162 if (startdiff > event_startdiff) {
1164 return i;
1165 }
1166 if (startdiff == event_startdiff) {
1167 long enddiff = labs(iter->event->end - end);
1168
1169 if (enddiff > event_enddiff) {
1171 return i;
1172 }
1173 if (event_startdiff == enddiff) {
1174 if (strcmp(event->uid, iter->event->uid) < 0) {
1176 return i;
1177 }
1178 }
1179 }
1180 }
1182
1184
1185 return i;
1186 }
1187
1189 ++i;
1190 if (iter->event->start > event->start) {
1192 return i;
1193 }
1194
1195 if (iter->event->start == event->start) {
1196 if ((iter->event->end - iter->event->start) == (event->end - event->start)) {
1197 if (strcmp(event->uid, iter->event->uid) < 0) {
1199 return i;
1200 }
1201 }
1202 if ((iter->event->end - iter->event->start) < (event->end - event->start)) {
1204 return i;
1205 }
1206 }
1207 }
1209
1211
1212 return i;
1213}
1214
1215static void eventlist_destroy(void *data)
1216{
1217 struct eventlist *events = data;
1218
1219 ao2_ref(events, -1);
1220}
1221
1222static void *eventlist_duplicate(void *data)
1223{
1224 struct eventlist *events = data;
1225
1226 if (!events) {
1227 return NULL;
1228 }
1229
1230 ao2_ref(events, +1);
1231
1232 return events;
1233}
1234
1235static int calendar_query_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1236{
1237 struct ast_calendar *cal;
1238 struct ao2_iterator i;
1239 struct ast_calendar_event *event;
1240 struct eventlist *events;
1241 time_t start = INT_MIN, end = INT_MAX;
1242 struct ast_datastore *eventlist_datastore;
1244 AST_APP_ARG(calendar);
1245 AST_APP_ARG(start);
1247 );
1248
1249 if (!chan) {
1250 ast_log(LOG_WARNING, "%s requires a channel to store the data on\n", cmd);
1251 return -1;
1252 }
1253
1255
1256 if (ast_strlen_zero(args.calendar)) {
1257 ast_log(LOG_WARNING, "%s requires a calendar argument\n", cmd);
1258 return -1;
1259 }
1260
1261 if (!(cal = find_calendar(args.calendar))) {
1262 ast_log(LOG_WARNING, "Unknown calendar '%s'\n", args.calendar);
1263 return -1;
1264 }
1265
1266 if (!(events = ao2_alloc(sizeof(*events), eventlist_destructor))) {
1267 ast_log(LOG_ERROR, "Unable to allocate memory for event list\n");
1268 cal = unref_calendar(cal);
1269 return -1;
1270 }
1271
1272 if (!ast_strlen_zero(args.start)) {
1273 start = atoi(args.start);
1274 }
1275
1276 if (!ast_strlen_zero(args.end)) {
1277 end = atoi(args.end);
1278 }
1279
1280 i = ao2_iterator_init(cal->events, 0);
1281 while ((event = ao2_iterator_next(&i))) {
1282 if (!(start > event->end || end < event->start)) {
1283 ast_debug(10, "%s (%ld - %ld) overlapped with (%ld - %ld)\n", event->summary, (long) event->start, (long) event->end, (long) start, (long) end);
1284 if (add_event_to_list(events, event, start, end) < 0) {
1286 cal = unref_calendar(cal);
1287 ao2_ref(events, -1);
1289 return -1;
1290 }
1291 }
1292
1294 }
1296
1297 ast_channel_lock(chan);
1298 do {
1301 ast_channel_unlock(chan);
1302
1303 if (!(eventlist_datastore = ast_datastore_alloc(&eventlist_datastore_info, buf))) {
1304 ast_log(LOG_ERROR, "Could not allocate datastore!\n");
1305 cal = unref_calendar(cal);
1306 ao2_ref(events, -1);
1307 return -1;
1308 }
1309
1310 eventlist_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
1311 eventlist_datastore->data = events;
1312
1313 ast_channel_lock(chan);
1314 ast_channel_datastore_add(chan, eventlist_datastore);
1315 ast_channel_unlock(chan);
1316
1317 cal = unref_calendar(cal);
1318 return 0;
1319}
1320
1322 .name = "CALENDAR_QUERY",
1323 .read = calendar_query_exec,
1324};
1325
1326static void calendar_join_attendees(struct ast_calendar_event *event, char *buf, size_t len)
1327{
1328 struct ast_str *tmp;
1329 struct ast_calendar_attendee *attendee;
1330
1331 if (!(tmp = ast_str_create(32))) {
1332 ast_log(LOG_ERROR, "Could not allocate memory for attendees!\n");
1333 return;
1334 }
1335
1336 AST_LIST_TRAVERSE(&event->attendees, attendee, next) {
1337 ast_str_append(&tmp, 0, "%s%s", attendee == AST_LIST_FIRST(&event->attendees) ? "" : ",", attendee->data);
1338 }
1339
1341 ast_free(tmp);
1342}
1343
1344static int calendar_query_result_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1345{
1346 struct ast_datastore *datastore;
1347 struct eventlist *events;
1348 struct evententry *entry;
1349 int row = 1;
1350 size_t listlen = 0;
1352 AST_APP_ARG(id);
1353 AST_APP_ARG(field);
1354 AST_APP_ARG(row);
1355 );
1356
1357 if (!chan) {
1358 ast_log(LOG_WARNING, "%s requires a channel\n", cmd);
1359 return -1;
1360 }
1361
1363
1364 if (ast_strlen_zero(args.id) || ast_strlen_zero(args.field)) {
1365 ast_log(LOG_WARNING, "%s requires an id and a field", cmd);
1366 return -1;
1367 }
1368
1369 ast_channel_lock(chan);
1370 if (!(datastore = ast_channel_datastore_find(chan, &eventlist_datastore_info, args.id))) {
1371 ast_log(LOG_WARNING, "There is no event notification datastore with id '%s' on '%s'!\n", args.id, ast_channel_name(chan));
1372 ast_channel_unlock(chan);
1373 return -1;
1374 }
1375 ast_channel_unlock(chan);
1376
1377 if (!(events = datastore->data)) {
1378 ast_log(LOG_WARNING, "The datastore contains no data!\n");
1379 return -1;
1380 }
1381
1382 if (!ast_strlen_zero(args.row)) {
1383 row = atoi(args.row);
1384 }
1385
1386 AST_LIST_TRAVERSE(events, entry, list) {
1387 listlen++;
1388 }
1389
1390 if (!strcasecmp(args.field, "getnum")) {
1391 snprintf(buf, len, "%zu", listlen);
1392 return 0;
1393 }
1394
1395 AST_LIST_TRAVERSE(events, entry, list) {
1396 if (--row) {
1397 continue;
1398 }
1399 if (!strcasecmp(args.field, "summary")) {
1400 ast_copy_string(buf, entry->event->summary, len);
1401 } else if (!strcasecmp(args.field, "description")) {
1403 } else if (!strcasecmp(args.field, "organizer")) {
1405 } else if (!strcasecmp(args.field, "location")) {
1407 } else if (!strcasecmp(args.field, "categories")) {
1409 } else if (!strcasecmp(args.field, "priority")) {
1410 snprintf(buf, len, "%d", entry->event->priority);
1411 } else if (!strcasecmp(args.field, "calendar")) {
1412 ast_copy_string(buf, entry->event->owner->name, len);
1413 } else if (!strcasecmp(args.field, "uid")) {
1414 ast_copy_string(buf, entry->event->uid, len);
1415 } else if (!strcasecmp(args.field, "start")) {
1416 snprintf(buf, len, "%ld", (long) entry->event->start);
1417 } else if (!strcasecmp(args.field, "end")) {
1418 snprintf(buf, len, "%ld", (long) entry->event->end);
1419 } else if (!strcasecmp(args.field, "busystate")) {
1420 snprintf(buf, len, "%u", entry->event->busy_state);
1421 } else if (!strcasecmp(args.field, "attendees")) {
1423 } else {
1424 ast_log(LOG_WARNING, "Unknown field '%s'\n", args.field);
1425 }
1426 break;
1427 }
1428
1429 return 0;
1430}
1431
1433 .name = "CALENDAR_QUERY_RESULT",
1435};
1436
1437static int calendar_write_exec(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1438{
1439 int i, j, ret = -1;
1440 char *val_dup = NULL;
1441 struct ast_calendar *cal = NULL;
1442 struct ast_calendar_event *event = NULL;
1443 struct timeval tv = ast_tvnow();
1444 AST_DECLARE_APP_ARGS(fields,
1445 AST_APP_ARG(field)[10];
1446 );
1448 AST_APP_ARG(value)[10];
1449 );
1450
1451 if (!(val_dup = ast_strdup(value))) {
1452 ast_log(LOG_ERROR, "Could not allocate memory for values\n");
1453 goto write_cleanup;
1454 }
1455
1456 AST_STANDARD_APP_ARGS(fields, data);
1457 AST_STANDARD_APP_ARGS(values, val_dup);
1458
1459 /* XXX Eventually we will support unnamed calendars, so if we don't find one, we parse
1460 * for a calendar type and create it */
1461 if (!(cal = find_calendar(fields.field[0]))) {
1462 ast_log(LOG_WARNING, "Couldn't find calendar '%s'\n", fields.field[0]);
1463 goto write_cleanup;
1464 }
1465
1466 if (!(cal->tech->write_event)) {
1467 ast_log(LOG_WARNING, "Calendar '%s' has no write function!\n", cal->name);
1468 goto write_cleanup;
1469 }
1470
1471 if (!(event = ast_calendar_event_alloc(cal))) {
1472 goto write_cleanup;
1473 }
1474
1475 if (ast_strlen_zero(fields.field[0])) {
1476 ast_log(LOG_WARNING, "CALENDAR_WRITE requires a calendar name!\n");
1477 goto write_cleanup;
1478 }
1479
1480 if (fields.argc - 1 != values.argc) {
1481 ast_log(LOG_WARNING, "CALENDAR_WRITE should have the same number of fields (%u) and values (%u)!\n", fields.argc - 1, values.argc);
1482 goto write_cleanup;
1483 }
1484
1485 event->owner = cal;
1486
1487 for (i = 1, j = 0; i < fields.argc; i++, j++) {
1488 if (!strcasecmp(fields.field[i], "summary")) {
1489 ast_string_field_set(event, summary, values.value[j]);
1490 } else if (!strcasecmp(fields.field[i], "description")) {
1491 ast_string_field_set(event, description, values.value[j]);
1492 } else if (!strcasecmp(fields.field[i], "organizer")) {
1493 ast_string_field_set(event, organizer, values.value[j]);
1494 } else if (!strcasecmp(fields.field[i], "location")) {
1495 ast_string_field_set(event, location, values.value[j]);
1496 } else if (!strcasecmp(fields.field[i], "categories")) {
1498 } else if (!strcasecmp(fields.field[i], "priority")) {
1499 event->priority = atoi(values.value[j]);
1500 } else if (!strcasecmp(fields.field[i], "uid")) {
1501 ast_string_field_set(event, uid, values.value[j]);
1502 } else if (!strcasecmp(fields.field[i], "start")) {
1503 event->start = atoi(values.value[j]);
1504 } else if (!strcasecmp(fields.field[i], "end")) {
1505 event->end = atoi(values.value[j]);
1506 } else if (!strcasecmp(fields.field[i], "busystate")) {
1507 event->busy_state = atoi(values.value[j]);
1508 } else {
1509 ast_log(LOG_WARNING, "Unknown calendar event field '%s'\n", fields.field[i]);
1510 }
1511 }
1512
1513 if (!event->start) {
1514 event->start = tv.tv_sec;
1515 }
1516
1517 if (!event->end) {
1518 event->end = tv.tv_sec;
1519 }
1520
1521 if((ret = cal->tech->write_event(event))) {
1522 ast_log(LOG_WARNING, "Writing event to calendar '%s' failed!\n", cal->name);
1523 }
1524
1525write_cleanup:
1526 if (ret) {
1527 pbx_builtin_setvar_helper(chan, "CALENDAR_SUCCESS", "0");
1528 } else {
1529 pbx_builtin_setvar_helper(chan, "CALENDAR_SUCCESS", "1");
1530 }
1531 if (cal) {
1532 cal = unref_calendar(cal);
1533 }
1534 if (event) {
1536 }
1537 if (val_dup) {
1538 ast_free(val_dup);
1539 }
1540
1541 return ret;
1542}
1543
1545 .name = "CALENDAR_WRITE",
1546 .write = calendar_write_exec,
1547};
1548
1549/*! \brief CLI command to list available calendars */
1550static char *handle_show_calendars(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1551{
1552#define FORMAT "%-20.20s %-10.10s %-6.6s\n"
1553 struct ao2_iterator i;
1554 struct ast_calendar *cal;
1555
1556 switch(cmd) {
1557 case CLI_INIT:
1558 e->command = "calendar show calendars";
1559 e->usage =
1560 "Usage: calendar show calendars\n"
1561 " Lists all registered calendars.\n";
1562 return NULL;
1563 case CLI_GENERATE:
1564 return NULL;
1565 }
1566
1567 ast_cli(a->fd, FORMAT, "Calendar", "Type", "Status");
1568 ast_cli(a->fd, FORMAT, "--------", "----", "------");
1570 while ((cal = ao2_iterator_next(&i))) {
1571 ast_cli(a->fd, FORMAT, cal->name, cal->tech->type, calendar_is_busy(cal) ? "busy" : "free");
1572 cal = unref_calendar(cal);
1573 }
1575
1576 return CLI_SUCCESS;
1577#undef FORMAT
1578}
1579
1580/*! \brief CLI command to list of all calendars types currently loaded on the backend */
1581static char *handle_show_calendars_types(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1582{
1583#define FORMAT "%-10.10s %-30.30s\n"
1584 struct ast_calendar_tech *iter;
1585
1586
1587 switch(cmd) {
1588 case CLI_INIT:
1589 e->command = "calendar show types";
1590 e->usage =
1591 "Usage: calendar show types\n"
1592 " Lists all registered calendars types.\n";
1593 return NULL;
1594 case CLI_GENERATE:
1595 return NULL;
1596 }
1597
1598 ast_cli(a->fd, FORMAT, "Type", "Description");
1600 AST_LIST_TRAVERSE(&techs, iter, list) {
1601 ast_cli(a->fd, FORMAT, iter->type, iter->description);
1602 }
1604
1605 return CLI_SUCCESS;
1606#undef FORMAT
1607}
1608
1609static char *epoch_to_string(char *buf, size_t buflen, time_t epoch)
1610{
1611 struct ast_tm tm;
1612 struct timeval tv = {
1613 .tv_sec = epoch,
1614 };
1615
1616 if (!epoch) {
1617 *buf = '\0';
1618 return buf;
1619 }
1620 ast_localtime(&tv, &tm, NULL);
1621 ast_strftime(buf, buflen, "%F %r %z", &tm);
1622
1623 return buf;
1624}
1625
1627{
1628 switch (busy_state) {
1630 return "Free";
1632 return "Busy (Tentative)";
1634 return "Busy";
1635 default:
1636 return "Unknown (Busy)";
1637 }
1638}
1639
1640
1641static char *handle_show_calendar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1642{
1643#define FORMAT "%-18.18s : %-20.20s\n"
1644#define FORMAT2 "%-12.12s: %-40.60s\n"
1645 struct ao2_iterator i;
1646 struct ast_calendar *cal;
1647 struct ast_calendar_event *event;
1648 int which = 0;
1649 char *ret = NULL;
1650
1651 switch(cmd) {
1652 case CLI_INIT:
1653 e->command = "calendar show calendar";
1654 e->usage =
1655 "Usage: calendar show calendar <calendar name>\n"
1656 " Displays information about a calendar\n";
1657 return NULL;
1658
1659 case CLI_GENERATE:
1660 if (a->pos != 3) {
1661 return NULL;
1662 }
1664 while ((cal = ao2_iterator_next(&i))) {
1665 if (!strncasecmp(a->word, cal->name, strlen(a->word)) && ++which > a->n) {
1666 ret = ast_strdup(cal->name);
1667 cal = unref_calendar(cal);
1668 break;
1669 }
1670 cal = unref_calendar(cal);
1671 }
1673 return ret;
1674 }
1675
1676 if (a->argc != 4) {
1677 return CLI_SHOWUSAGE;
1678 }
1679
1680 if (!(cal = find_calendar(a->argv[3]))) {
1681 return NULL;
1682 }
1683
1684 ast_cli(a->fd, FORMAT, "Name", cal->name);
1685 ast_cli(a->fd, FORMAT, "Notify channel", cal->notify_channel);
1686 ast_cli(a->fd, FORMAT, "Notify context", cal->notify_context);
1687 ast_cli(a->fd, FORMAT, "Notify extension", cal->notify_extension);
1688 ast_cli(a->fd, FORMAT, "Notify application", cal->notify_app);
1689 ast_cli(a->fd, FORMAT, "Notify appdata", cal->notify_appdata);
1690 ast_cli(a->fd, "%-17.17s : %d\n", "Refresh time", cal->refresh);
1691 ast_cli(a->fd, "%-17.17s : %d\n", "Timeframe", cal->timeframe);
1692
1693 if (cal->autoreminder) {
1694 ast_cli(a->fd, "%-17.17s : %d minutes before event\n", "Autoreminder", cal->autoreminder);
1695 } else {
1696 ast_cli(a->fd, "%-17.17s : None\n", "Autoreminder");
1697 }
1698
1699 ast_cli(a->fd, "%s\n", "Events");
1700 ast_cli(a->fd, "%s\n", "------");
1701
1702 i = ao2_iterator_init(cal->events, 0);
1703 while ((event = ao2_iterator_next(&i))) {
1704 char buf[100];
1705
1706 ast_cli(a->fd, FORMAT2, "Summary", event->summary);
1707 ast_cli(a->fd, FORMAT2, "Description", event->description);
1708 ast_cli(a->fd, FORMAT2, "Organizer", event->organizer);
1709 ast_cli(a->fd, FORMAT2, "Location", event->location);
1710 ast_cli(a->fd, FORMAT2, "Categories", event->categories);
1711 ast_cli(a->fd, "%-12.12s: %d\n", "Priority", event->priority);
1712 ast_cli(a->fd, FORMAT2, "UID", event->uid);
1713 ast_cli(a->fd, FORMAT2, "Start", epoch_to_string(buf, sizeof(buf), event->start));
1714 ast_cli(a->fd, FORMAT2, "End", epoch_to_string(buf, sizeof(buf), event->end));
1715 ast_cli(a->fd, FORMAT2, "Alarm", epoch_to_string(buf, sizeof(buf), event->alarm));
1716 ast_cli(a->fd, FORMAT2, "Busy State", ast_calendar_busy_state_to_str(event->busy_state));
1717 ast_cli(a->fd, "\n");
1718
1720 }
1722 cal = unref_calendar(cal);
1723 return CLI_SUCCESS;
1724#undef FORMAT
1725#undef FORMAT2
1726}
1727
1728static char *handle_dump_sched(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1729{
1730 switch(cmd) {
1731 case CLI_INIT:
1732 e->command = "calendar dump sched";
1733 e->usage =
1734 "Usage: calendar dump sched\n"
1735 " Dump the calendar sched context";
1736 return NULL;
1737
1738 case CLI_GENERATE:
1739 return NULL;
1740 }
1741
1743
1744 return CLI_SUCCESS;
1745}
1746
1747static struct ast_cli_entry calendar_cli[] = {
1748 AST_CLI_DEFINE(handle_show_calendar, "Display information about a calendar"),
1749 AST_CLI_DEFINE(handle_show_calendars, "Show registered calendars"),
1750 AST_CLI_DEFINE(handle_dump_sched, "Dump calendar sched context"),
1751 AST_CLI_DEFINE(handle_show_calendars_types, "Show all calendar types loaded"),
1752};
1753
1754static int calendar_event_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1755{
1756 struct ast_datastore *datastore;
1757 struct ast_calendar_event *event;
1758
1759 if (!chan) {
1760 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1761 return -1;
1762 }
1763
1764 if (ast_strlen_zero(data)) {
1765 ast_log(LOG_WARNING, "%s requires an argument\n", cmd);
1766 return -1;
1767 }
1768
1769 ast_channel_lock(chan);
1770 if (!(datastore = ast_channel_datastore_find(chan, &event_notification_datastore, NULL))) {
1771 ast_log(LOG_WARNING, "There is no event notification datastore on '%s'!\n", ast_channel_name(chan));
1772 ast_channel_unlock(chan);
1773 return -1;
1774 }
1775 ast_channel_unlock(chan);
1776
1777 if (!(event = datastore->data)) {
1778 ast_log(LOG_WARNING, "The datastore contains no data!\n");
1779 return -1;
1780 }
1781
1782 if (!strcasecmp(data, "summary")) {
1783 ast_copy_string(buf, event->summary, len);
1784 } else if (!strcasecmp(data, "description")) {
1785 ast_copy_string(buf, event->description, len);
1786 } else if (!strcasecmp(data, "organizer")) {
1787 ast_copy_string(buf, event->organizer, len);
1788 } else if (!strcasecmp(data, "location")) {
1789 ast_copy_string(buf, event->location, len);
1790 } else if (!strcasecmp(data, "categories")) {
1791 ast_copy_string(buf, event->categories, len);
1792 } else if (!strcasecmp(data, "priority")) {
1793 snprintf(buf, len, "%d", event->priority);
1794 } else if (!strcasecmp(data, "calendar")) {
1795 ast_copy_string(buf, event->owner->name, len);
1796 } else if (!strcasecmp(data, "uid")) {
1797 ast_copy_string(buf, event->uid, len);
1798 } else if (!strcasecmp(data, "start")) {
1799 snprintf(buf, len, "%ld", (long)event->start);
1800 } else if (!strcasecmp(data, "end")) {
1801 snprintf(buf, len, "%ld", (long)event->end);
1802 } else if (!strcasecmp(data, "busystate")) {
1803 snprintf(buf, len, "%u", event->busy_state);
1804 } else if (!strcasecmp(data, "attendees")) {
1806 }
1807
1808
1809 return 0;
1810}
1811
1813 .name = "CALENDAR_EVENT",
1814 .read = calendar_event_read,
1815};
1816
1817static int cb_pending_deletion(void *user_data, void *arg, int flags)
1818{
1819 struct ast_calendar *cal = user_data;
1820
1821 cal->pending_deletion = 1;
1822
1823 return CMP_MATCH;
1824}
1825
1826static int cb_rm_pending_deletion(void *user_data, void *arg, int flags)
1827{
1828 struct ast_calendar *cal = user_data;
1829
1830 return cal->pending_deletion ? CMP_MATCH : 0;
1831}
1832
1833static int reload(void)
1834{
1835 struct ast_calendar_tech *iter;
1836
1838
1839 /* Mark existing calendars for deletion */
1841 load_config(1);
1842
1844 AST_LIST_TRAVERSE(&techs, iter, list) {
1845 if (load_tech_calendars(iter)) {
1846 ast_log(LOG_WARNING, "Failed to reload %s calendars, module disabled\n", iter->type);
1847 }
1848 }
1850
1851 /* Delete calendars that no longer show up in the config */
1853
1855
1856 return 0;
1857}
1858
1859static void *do_refresh(void *data)
1860{
1861 for (;;) {
1862 struct timeval now = ast_tvnow();
1863 struct timespec ts = {0,};
1864 int wait;
1865
1867
1868 while (!module_unloading) {
1869 if ((wait = ast_sched_wait(sched)) < 0) {
1870 wait = 1000;
1871 }
1872
1873 ts.tv_sec = (now.tv_sec + wait / 1000) + 1;
1874 if (ast_cond_timedwait(&refresh_condition, &refreshlock, &ts) == ETIMEDOUT) {
1875 break;
1876 }
1877 }
1879
1880 if (module_unloading) {
1881 break;
1882 }
1884 }
1885
1886 return NULL;
1887}
1888
1889/* If I were to allow unloading it would look something like this */
1890static int unload_module(void)
1891{
1892 struct ast_calendar_tech *tech;
1893
1894 ast_devstate_prov_del("calendar");
1901
1902 /* Remove all calendars */
1905 calendars = NULL;
1906
1908 module_unloading = 1;
1911 pthread_join(refresh_thread, NULL);
1912
1914
1917 ast_unload_resource(tech->module, 0);
1918 }
1921
1924
1925 return 0;
1926}
1927
1928/*!
1929 * \brief Load the module
1930 *
1931 * Module loading including tests for configuration or dependencies.
1932 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
1933 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
1934 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
1935 * configuration file or other non-critical problem return
1936 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
1937 */
1938static int load_module(void)
1939{
1942 if (!calendars) {
1943 ast_log(LOG_ERROR, "Unable to allocate calendars container!\n");
1945 }
1946
1947 if (load_config(0)) {
1948 /* We don't have calendar support enabled */
1950 }
1951
1955
1956 if (!(sched = ast_sched_context_create())) {
1957 ast_log(LOG_ERROR, "Unable to create sched context\n");
1961 }
1962
1964 ast_log(LOG_ERROR, "Unable to start refresh thread--notifications disabled!\n");
1965 }
1966
1973
1975
1977}
1979 .support_level = AST_MODULE_SUPPORT_EXTENDED,
1980 .load = load_module,
1981 .unload = unload_module,
1982 .reload = reload,
1983 .load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
Prototypes for public functions only of internal interest,.
static const struct adsi_event events[]
Definition: app_adsiprog.c:88
struct sla_ringing_trunk * last
Definition: app_sla.c:338
#define var
Definition: ast_expr2f.c:605
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
#define OBJ_POINTER
Definition: astobj2.h:1150
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ OBJ_UNLINK
Definition: astobj2.h:1039
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
A general API for managing calendar events with Asterisk.
ast_calendar_busy_state
Definition: calendar.h:83
@ AST_CALENDAR_BS_FREE
Definition: calendar.h:84
@ AST_CALENDAR_BS_BUSY_TENTATIVE
Definition: calendar.h:85
@ AST_CALENDAR_BS_BUSY
Definition: calendar.h:86
enum cc_state state
Definition: ccss.c:399
General Asterisk PBX channel definitions.
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2414
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1299
#define DATASTORE_INHERIT_FOREVER
Definition: channel.h:194
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
#define ast_channel_lock(chan)
Definition: channel.h:2970
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
struct ast_channel * ast_channel_release(struct ast_channel *chan)
Unlink and release reference to a channel.
Definition: channel.c:1611
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_context_set(struct ast_channel *chan, const char *value)
void ast_channel_priority_set(struct ast_channel *chan, int value)
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
#define ast_channel_unlock(chan)
Definition: channel.h:2971
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2428
@ AST_STATE_DOWN
Definition: channelstate.h:36
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
Device state management.
int ast_devstate_prov_del(const char *label)
Remove device state provider.
Definition: devicestate.c:421
@ AST_DEVSTATE_CACHABLE
Definition: devicestate.h:70
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:513
int ast_devstate_prov_add(const char *label, ast_devstate_prov_cb_type callback)
Add device state provider.
Definition: devicestate.c:394
ast_device_state
Device States.
Definition: devicestate.h:52
@ AST_DEVICE_INUSE
Definition: devicestate.h:55
@ AST_DEVICE_INVALID
Definition: devicestate.h:57
@ AST_DEVICE_BUSY
Definition: devicestate.h:56
@ AST_DEVICE_NOT_INUSE
Definition: devicestate.h:54
Dialing API.
ast_dial_result
List of return codes for dial run API calls.
Definition: dial.h:54
@ AST_DIAL_RESULT_ANSWERED
Definition: dial.h:61
int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device, const struct ast_assigned_ids *assignedids)
Append a channel.
Definition: dial.c:280
struct ast_dial * ast_dial_create(void)
New dialing structure.
Definition: dial.c:223
void ast_dial_set_global_timeout(struct ast_dial *dial, int timeout)
Set the maximum time (globally) allowed for trying to ring phones.
Definition: dial.c:1284
enum ast_dial_result ast_dial_run(struct ast_dial *dial, struct ast_channel *chan, int async)
Execute dialing synchronously or asynchronously.
Definition: dial.c:935
struct ast_channel * ast_dial_answered_steal(struct ast_dial *dial)
Steal the channel that answered.
Definition: dial.c:989
@ AST_DIAL_OPTION_ANSWER_EXEC
Definition: dial.h:44
int ast_dial_destroy(struct ast_dial *dial)
Destroys a dialing structure.
Definition: dial.c:1091
int ast_dial_option_global_enable(struct ast_dial *dial, enum ast_dial_option option, void *data)
Enables an option globally.
Definition: dial.c:1145
char * end
Definition: eagi_proxy.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Media Format Cache API.
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
Configuration File Parser.
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
Definition: main/config.c:3541
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3326
@ CONFIG_FLAG_FILEUNCHANGED
#define ast_variable_new(name, value, filename)
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:869
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
A set of macros to manage forward-linked lists.
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: linkedlists.h:291
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
Definition: linkedlists.h:599
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
#define ast_rwlock_wrlock(a)
Definition: lock.h:240
#define AST_PTHREADT_NULL
Definition: lock.h:70
#define ast_cond_init(cond, attr)
Definition: lock.h:205
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:210
#define ast_rwlock_rdlock(a)
Definition: lock.h:239
#define AST_RWLOCK_DEFINE_STATIC(rwlock)
Definition: lock.h:547
#define ast_mutex_init(pmutex)
Definition: lock.h:190
#define ast_mutex_unlock(a)
Definition: lock.h:194
pthread_cond_t ast_cond_t
Definition: lock.h:182
#define ast_rwlock_unlock(a)
Definition: lock.h:238
#define ast_mutex_lock(a)
Definition: lock.h:193
#define ast_cond_signal(cond)
Definition: lock.h:207
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:330
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode)
Unload a module.
Definition: loader.c:1457
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_DEVSTATE_PROVIDER
Definition: module.h:343
#define ast_module_user_remove(user)
Definition: module.h:441
@ AST_MODULE_SUPPORT_EXTENDED
Definition: module.h:122
#define ast_module_user_add(chan)
Definition: module.h:440
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Core PBX routines and definitions.
enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
Execute the PBX in the current thread.
Definition: pbx.c:4770
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1559
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
static int calendar_write_exec(struct ast_channel *chan, const char *cmd, char *data, const char *value)
static char * epoch_to_string(char *buf, size_t buflen, time_t epoch)
static int calendar_query_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static void calendar_join_attendees(struct ast_calendar_event *event, char *buf, size_t len)
static void * event_notification_duplicate(void *data)
Definition: res_calendar.c:720
void ast_calendar_unregister(struct ast_calendar_tech *tech)
Unregister a new calendar technology.
Definition: res_calendar.c:604
static const char * ast_calendar_busy_state_to_str(enum ast_calendar_busy_state busy_state)
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_dump_sched(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct ast_custom_function calendar_query_function
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.
static int calendar_query_result_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static struct ast_custom_function calendar_write_function
static struct ast_calendar * unref_calendar(struct ast_calendar *cal)
Definition: res_calendar.c:292
static void * eventlist_duplicate(void *data)
static ast_mutex_t refreshlock
Definition: res_calendar.c:242
static int add_new_event_cb(void *obj, void *arg, int flags)
static void * do_refresh(void *data)
static struct ast_sched_context * sched
Definition: res_calendar.c:240
static struct ast_custom_function calendar_query_result_function
static int clear_events_cb(void *user_data, void *arg, int flags)
Definition: res_calendar.c:668
static ast_mutex_t reloadlock
Definition: res_calendar.c:244
static const struct ast_datastore_info event_notification_datastore
Definition: res_calendar.c:252
static enum ast_device_state calendarstate(const char *data)
Definition: res_calendar.c:398
static void calendar_destructor(void *obj)
Definition: res_calendar.c:344
void ast_calendar_config_release(void)
Release the calendar config.
Definition: res_calendar.c:287
static struct ast_custom_function calendar_event_function
static int cb_pending_deletion(void *user_data, void *arg, int flags)
static struct ast_cli_entry calendar_cli[]
static struct ast_config * calendar_config
Definition: res_calendar.c:272
static struct ast_custom_function calendar_busy_function
static int match_caltech_cb(void *user_data, void *arg, int flags)
Definition: res_calendar.c:592
static void eventlist_destructor(void *obj)
Definition: res_calendar.c:364
static int calendar_event_notify(const void *data)
Definition: res_calendar.c:885
static const struct ast_channel_tech null_tech
Definition: res_calendar.c:752
static struct ast_calendar * build_calendar(struct ast_config *cfg, const char *cat, const struct ast_calendar_tech *tech)
Definition: res_calendar.c:417
static int schedule_calendar_event(struct ast_calendar *cal, struct ast_calendar_event *old_event, struct ast_calendar_event *cmp_event)
Definition: res_calendar.c:971
static ast_rwlock_t config_lock
Definition: res_calendar.c:273
struct ao2_container * ast_calendar_event_container_alloc(void)
Allocate an astobj2 container for ast_calendar_event objects.
Definition: res_calendar.c:706
static int load_tech_calendars(struct ast_calendar_tech *tech)
Definition: res_calendar.c:530
static int null_chan_write(struct ast_channel *chan, struct ast_frame *frame)
Definition: res_calendar.c:747
static int event_hash_fn(const void *obj, const int flags)
Definition: res_calendar.c:318
void ast_calendar_clear_events(struct ast_calendar *cal)
Remove all events from calendar.
Definition: res_calendar.c:677
static int calendar_hash_fn(const void *obj, const int flags)
Definition: res_calendar.c:298
static void copy_event_data(struct ast_calendar_event *dst, struct ast_calendar_event *src)
Definition: res_calendar.c:943
static int calendar_devstate_change(const void *data)
Definition: res_calendar.c:909
static int calendar_is_busy(struct ast_calendar *cal)
Definition: res_calendar.c:389
#define CALENDAR_BUCKETS
Definition: res_calendar.c:237
int ast_calendar_register(struct ast_calendar_tech *tech)
Register a new calendar technology.
Definition: res_calendar.c:566
static int cb_rm_pending_deletion(void *user_data, void *arg, int flags)
static struct ast_calendar_event * find_event(struct ao2_container *events, const char *uid)
Definition: res_calendar.c:330
static pthread_t refresh_thread
Definition: res_calendar.c:241
static struct ast_calendar_event * destroy_event(struct ast_calendar_event *event)
Definition: res_calendar.c:643
static int calendar_event_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static char * handle_show_calendar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * generate_random_string(char *buf, size_t size)
Generate 32 byte random string (stolen from chan_sip.c)
Definition: res_calendar.c:734
static const struct ast_datastore_info eventlist_datastore_info
Definition: res_calendar.c:258
static ast_cond_t refresh_condition
Definition: res_calendar.c:243
static struct ao2_container * calendars
Definition: res_calendar.c:239
static int merge_events_cb(void *obj, void *arg, int flags)
static int calendar_cmp_fn(void *obj, void *arg, int flags)
Definition: res_calendar.c:304
static int add_event_to_list(struct eventlist *events, struct ast_calendar_event *event, time_t start, time_t end)
static int load_module(void)
Load the module.
#define FORMAT
#define FORMAT2
static int unload_module(void)
static int load_config(int reload)
static void event_notification_destroy(void *data)
Definition: res_calendar.c:712
static int reload(void)
static int event_cmp_fn(void *obj, void *arg, int flags)
Definition: res_calendar.c:324
static int module_unloading
Definition: res_calendar.c:245
static struct ast_calendar * find_calendar(const char *name)
Definition: res_calendar.c:310
struct ast_calendar_event * ast_calendar_event_alloc(struct ast_calendar *cal)
Allocate an astobj2 ast_calendar_event object.
Definition: res_calendar.c:684
static int calendar_busy_callback(void *obj, void *arg, int flags)
Definition: res_calendar.c:375
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.
struct ast_calendar_event * ast_calendar_unref_event(struct ast_calendar_event *event)
Unreference an ast_calendar_event.
Definition: res_calendar.c:338
static void calendar_event_destructor(void *obj)
Definition: res_calendar.c:626
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.
const struct ast_config * ast_calendar_config_acquire(void)
Grab and lock pointer to the calendar config (read only)
Definition: res_calendar.c:275
static void eventlist_destroy(void *data)
static void * do_notify(void *data)
Definition: res_calendar.c:758
static int notify_channel(void *obj)
#define NULL
Definition: resample.c:96
Scheduler Routines (derived from cheops)
#define AST_SCHED_REPLACE(id, sched, when, callback, data)
Definition: sched.h:127
int ast_sched_del(struct ast_sched_context *con, int id) attribute_warn_unused_result
Deletes a scheduled event.
Definition: sched.c:614
void ast_sched_dump(struct ast_sched_context *con)
Dumps the scheduler contents.
Definition: sched.c:743
void ast_sched_context_destroy(struct ast_sched_context *c)
destroys a schedule context
Definition: sched.c:271
int ast_sched_runq(struct ast_sched_context *con)
Runs the queue.
Definition: sched.c:786
struct ast_sched_context * ast_sched_context_create(void)
Create a scheduler context.
Definition: sched.c:238
int ast_sched_wait(struct ast_sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place.
Definition: sched.c:433
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1303
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
struct ast_calendar_attendee * next
Definition: calendar.h:91
Calendar events.
Definition: calendar.h:95
const ast_string_field uid
Definition: calendar.h:103
enum ast_calendar_busy_state busy_state
Definition: calendar.h:109
struct ast_calendar * owner
Definition: calendar.h:105
const ast_string_field location
Definition: calendar.h:103
const ast_string_field description
Definition: calendar.h:103
const ast_string_field categories
Definition: calendar.h:103
const ast_string_field organizer
Definition: calendar.h:103
struct ast_calendar_event::attendees attendees
const ast_string_field summary
Definition: calendar.h:103
Individual calendaring technology data.
Definition: calendar.h:71
struct ast_calendar_tech::@203 list
const char * description
Definition: calendar.h:73
const char * type
Definition: calendar.h:72
const char * module
Definition: calendar.h:74
struct ast_module_user * user
Definition: calendar.h:75
int(* is_busy)(struct ast_calendar *calendar)
Definition: calendar.h:76
int(* write_event)(struct ast_calendar_event *event)
Definition: calendar.h:79
void *(* unref_calendar)(void *obj)
Definition: calendar.h:78
void *(* load_calendar)(void *data)
Definition: calendar.h:77
Asterisk calendar structure.
Definition: calendar.h:119
pthread_t thread
Definition: calendar.h:136
struct ast_variable * vars
Definition: calendar.h:130
void * tech_pvt
Definition: calendar.h:121
const struct ast_calendar_tech * tech
Definition: calendar.h:120
int autoreminder
Definition: calendar.h:131
int timeframe
Definition: calendar.h:135
struct ao2_container * events
Definition: calendar.h:140
int fetch_again_at_reload
Definition: calendar.h:134
const ast_string_field notify_context
Definition: calendar.h:129
const ast_string_field notify_app
Definition: calendar.h:129
unsigned int pending_deletion
Definition: calendar.h:139
const ast_string_field notify_channel
Definition: calendar.h:129
ast_cond_t unload
Definition: calendar.h:137
int notify_waittime
Definition: calendar.h:132
unsigned int unloading
Definition: calendar.h:138
const ast_string_field name
Definition: calendar.h:129
const ast_string_field notify_extension
Definition: calendar.h:129
const ast_string_field notify_appdata
Definition: calendar.h:129
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition: channel.h:648
const char *const type
Definition: channel.h:649
Main Channel structure associated with a channel.
const char * data
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
const char * name
Definition: pbx.h:119
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
unsigned int inheritance
Definition: datastore.h:69
Main dialing structure. Contains global options, channels being dialed, and more!
Definition: dial.c:48
Structure used to handle boolean flags.
Definition: utils.h:199
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Data structure associated with a single frame of data.
Structure for mutex and tracking information.
Definition: lock.h:139
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Definition: astman.c:222
struct evententry::@426 list
struct ast_calendar_event * event
Definition: res_calendar.c:265
Definition: sched.c:76
struct sla_ringing_trunk * next
Definition: app_sla.c:314
Definition: ast_expr2.c:325
int value
Definition: syslog.c:37
struct association categories[]
const char * args
static struct test_val a
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
Utility functions.
#define ast_pthread_create(a, b, c, d)
Definition: utils.h:584
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:592
long int ast_random(void)
Definition: utils.c:2312
#define ARRAY_LEN(a)
Definition: utils.h:666