res_calendar.c 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914
  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. /*! \file
  19. * \brief Calendaring API
  20. *
  21. * \todo Support responding to a meeting invite
  22. * \todo Support writing attendees
  23. */
  24. /*! \li \ref res_calendar.c uses the configuration file \ref calendar.conf
  25. * \addtogroup configuration_file Configuration Files
  26. */
  27. /*!
  28. * \page calendar.conf calendar.conf
  29. * \verbinclude calendar.conf.sample
  30. */
  31. /*** MODULEINFO
  32. <support_level>core</support_level>
  33. ***/
  34. #include "asterisk.h"
  35. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  36. #include "asterisk/_private.h"
  37. #include "asterisk/channel.h"
  38. #include "asterisk/calendar.h"
  39. #include "asterisk/utils.h"
  40. #include "asterisk/astobj2.h"
  41. #include "asterisk/module.h"
  42. #include "asterisk/config.h"
  43. #include "asterisk/channel.h"
  44. #include "asterisk/devicestate.h"
  45. #include "asterisk/linkedlists.h"
  46. #include "asterisk/sched.h"
  47. #include "asterisk/dial.h"
  48. #include "asterisk/cli.h"
  49. #include "asterisk/pbx.h"
  50. #include "asterisk/app.h"
  51. #include "asterisk/format_cache.h"
  52. /*** DOCUMENTATION
  53. <function name="CALENDAR_BUSY" language="en_US">
  54. <synopsis>
  55. Determine if the calendar is marked busy at this time.
  56. </synopsis>
  57. <syntax>
  58. <parameter name="calendar" required="true" />
  59. </syntax>
  60. <description>
  61. <para>Check the specified calendar's current busy status.</para>
  62. </description>
  63. <see-also>
  64. <ref type="function">CALENDAR_EVENT</ref>
  65. <ref type="function">CALENDAR_QUERY</ref>
  66. <ref type="function">CALENDAR_QUERY_RESULT</ref>
  67. <ref type="function">CALENDAR_WRITE</ref>
  68. </see-also>
  69. </function>
  70. <function name="CALENDAR_EVENT" language="en_US">
  71. <synopsis>
  72. Get calendar event notification data from a notification call.
  73. </synopsis>
  74. <syntax>
  75. <parameter name="field" required="true">
  76. <enumlist>
  77. <enum name="summary"><para>The VEVENT SUMMARY property or Exchange event 'subject'</para></enum>
  78. <enum name="description"><para>The text description of the event</para></enum>
  79. <enum name="organizer"><para>The organizer of the event</para></enum>
  80. <enum name="location"><para>The location of the eventt</para></enum>
  81. <enum name="categories"><para>The categories of the event</para></enum>
  82. <enum name="priority"><para>The priority of the event</para></enum>
  83. <enum name="calendar"><para>The name of the calendar associated with the event</para></enum>
  84. <enum name="uid"><para>The unique identifier for this event</para></enum>
  85. <enum name="start"><para>The start time of the event</para></enum>
  86. <enum name="end"><para>The end time of the event</para></enum>
  87. <enum name="busystate"><para>The busy state of the event 0=FREE, 1=TENTATIVE, 2=BUSY</para></enum>
  88. </enumlist>
  89. </parameter>
  90. </syntax>
  91. <description>
  92. <para>Whenever a calendar event notification call is made, the event data
  93. may be accessed with this function.</para>
  94. </description>
  95. <see-also>
  96. <ref type="function">CALENDAR_BUSY</ref>
  97. <ref type="function">CALENDAR_QUERY</ref>
  98. <ref type="function">CALENDAR_QUERY_RESULT</ref>
  99. <ref type="function">CALENDAR_WRITE</ref>
  100. </see-also>
  101. </function>
  102. <function name="CALENDAR_QUERY" language="en_US">
  103. <synopsis>Query a calendar server and store the data on a channel
  104. </synopsis>
  105. <syntax>
  106. <parameter name="calendar" required="true">
  107. <para>The calendar that should be queried</para>
  108. </parameter>
  109. <parameter name="start" required="false">
  110. <para>The start time of the query (in seconds since epoch)</para>
  111. </parameter>
  112. <parameter name="end" required="false">
  113. <para>The end time of the query (in seconds since epoch)</para>
  114. </parameter>
  115. </syntax>
  116. <description>
  117. <para>Get a list of events in the currently accessible timeframe of the <replaceable>calendar</replaceable>
  118. The function returns the id for accessing the result with CALENDAR_QUERY_RESULT()</para>
  119. </description>
  120. <see-also>
  121. <ref type="function">CALENDAR_BUSY</ref>
  122. <ref type="function">CALENDAR_EVENT</ref>
  123. <ref type="function">CALENDAR_QUERY_RESULT</ref>
  124. <ref type="function">CALENDAR_WRITE</ref>
  125. </see-also>
  126. </function>
  127. <function name="CALENDAR_QUERY_RESULT" language="en_US">
  128. <synopsis>
  129. Retrieve data from a previously run CALENDAR_QUERY() call
  130. </synopsis>
  131. <syntax>
  132. <parameter name="id" required="true">
  133. <para>The query ID returned by <literal>CALENDAR_QUERY</literal></para>
  134. </parameter>
  135. <parameter name="field" required="true">
  136. <enumlist>
  137. <enum name="getnum"><para>number of events occurring during time range</para></enum>
  138. <enum name="summary"><para>A summary of the event</para></enum>
  139. <enum name="description"><para>The full event description</para></enum>
  140. <enum name="organizer"><para>The event organizer</para></enum>
  141. <enum name="location"><para>The event location</para></enum>
  142. <enum name="categories"><para>The categories of the event</para></enum>
  143. <enum name="priority"><para>The priority of the event</para></enum>
  144. <enum name="calendar"><para>The name of the calendar associted with the event</para></enum>
  145. <enum name="uid"><para>The unique identifier for the event</para></enum>
  146. <enum name="start"><para>The start time of the event (in seconds since epoch)</para></enum>
  147. <enum name="end"><para>The end time of the event (in seconds since epoch)</para></enum>
  148. <enum name="busystate"><para>The busy status of the event 0=FREE, 1=TENTATIVE, 2=BUSY</para></enum>
  149. </enumlist>
  150. </parameter>
  151. <parameter name="entry" required="false" default="1">
  152. <para>Return data from a specific event returned by the query</para>
  153. </parameter>
  154. </syntax>
  155. <description>
  156. <para>After running CALENDAR_QUERY and getting a result <replaceable>id</replaceable>, calling
  157. <literal>CALENDAR_QUERY</literal> with that <replaceable>id</replaceable> and a <replaceable>field</replaceable>
  158. will return the data for that field. If multiple events matched the query, and <replaceable>entry</replaceable>
  159. is provided, information from that event will be returned.</para>
  160. </description>
  161. <see-also>
  162. <ref type="function">CALENDAR_BUSY</ref>
  163. <ref type="function">CALENDAR_EVENT</ref>
  164. <ref type="function">CALENDAR_QUERY</ref>
  165. <ref type="function">CALENDAR_WRITE</ref>
  166. </see-also>
  167. </function>
  168. <function name="CALENDAR_WRITE" language="en_US">
  169. <synopsis>Write an event to a calendar</synopsis>
  170. <syntax>
  171. <parameter name="calendar" required="true">
  172. <para>The calendar to write to</para>
  173. </parameter>
  174. <parameter name="field" multiple="true" required="true">
  175. <enumlist>
  176. <enum name="summary"><para>A summary of the event</para></enum>
  177. <enum name="description"><para>The full event description</para></enum>
  178. <enum name="organizer"><para>The event organizer</para></enum>
  179. <enum name="location"><para>The event location</para></enum>
  180. <enum name="categories"><para>The categories of the event</para></enum>
  181. <enum name="priority"><para>The priority of the event</para></enum>
  182. <enum name="uid"><para>The unique identifier for the event</para></enum>
  183. <enum name="start"><para>The start time of the event (in seconds since epoch)</para></enum>
  184. <enum name="end"><para>The end time of the event (in seconds since epoch)</para></enum>
  185. <enum name="busystate"><para>The busy status of the event 0=FREE, 1=TENTATIVE, 2=BUSY</para></enum>
  186. </enumlist>
  187. </parameter>
  188. </syntax>
  189. <description>
  190. <para>Example: CALENDAR_WRITE(calendar,field1,field2,field3)=val1,val2,val3</para>
  191. <para>The field and value arguments can easily be set/passed using the HASHKEYS() and HASH() functions</para>
  192. <variablelist>
  193. <variable name="CALENDAR_SUCCESS">
  194. <para>The status of the write operation to the calendar</para>
  195. <value name="1" >
  196. The event was successfully written to the calendar.
  197. </value>
  198. <value name="0" >
  199. The event was not written to the calendar due to network issues, permissions, etc.
  200. </value>
  201. </variable>
  202. </variablelist>
  203. </description>
  204. <see-also>
  205. <ref type="function">CALENDAR_BUSY</ref>
  206. <ref type="function">CALENDAR_EVENT</ref>
  207. <ref type="function">CALENDAR_QUERY</ref>
  208. <ref type="function">CALENDAR_QUERY_RESULT</ref>
  209. </see-also>
  210. </function>
  211. ***/
  212. #define CALENDAR_BUCKETS 19
  213. static struct ao2_container *calendars;
  214. static struct ast_sched_context *sched;
  215. static pthread_t refresh_thread = AST_PTHREADT_NULL;
  216. static ast_mutex_t refreshlock;
  217. static ast_cond_t refresh_condition;
  218. static ast_mutex_t reloadlock;
  219. static int module_unloading;
  220. static void event_notification_destroy(void *data);
  221. static void *event_notification_duplicate(void *data);
  222. static void eventlist_destroy(void *data);
  223. static void *eventlist_duplicate(void *data);
  224. static const struct ast_datastore_info event_notification_datastore = {
  225. .type = "EventNotification",
  226. .destroy = event_notification_destroy,
  227. .duplicate = event_notification_duplicate,
  228. };
  229. static const struct ast_datastore_info eventlist_datastore_info = {
  230. .type = "CalendarEventList",
  231. .destroy = eventlist_destroy,
  232. .duplicate = eventlist_duplicate,
  233. };
  234. struct evententry {
  235. struct ast_calendar_event *event;
  236. AST_LIST_ENTRY(evententry) list;
  237. };
  238. static AST_LIST_HEAD_STATIC(techs, ast_calendar_tech);
  239. AST_LIST_HEAD_NOLOCK(eventlist, evententry); /* define the type */
  240. static struct ast_config *calendar_config;
  241. AST_RWLOCK_DEFINE_STATIC(config_lock);
  242. const struct ast_config *ast_calendar_config_acquire(void)
  243. {
  244. ast_rwlock_rdlock(&config_lock);
  245. if (!calendar_config) {
  246. ast_rwlock_unlock(&config_lock);
  247. return NULL;
  248. }
  249. return calendar_config;
  250. }
  251. void ast_calendar_config_release(void)
  252. {
  253. ast_rwlock_unlock(&config_lock);
  254. }
  255. static struct ast_calendar *unref_calendar(struct ast_calendar *cal)
  256. {
  257. ao2_ref(cal, -1);
  258. return NULL;
  259. }
  260. static int calendar_hash_fn(const void *obj, const int flags)
  261. {
  262. const struct ast_calendar *cal = obj;
  263. return ast_str_case_hash(cal->name);
  264. }
  265. static int calendar_cmp_fn(void *obj, void *arg, int flags)
  266. {
  267. const struct ast_calendar *one = obj, *two = arg;
  268. return !strcasecmp(one->name, two->name) ? CMP_MATCH | CMP_STOP: 0;
  269. }
  270. static struct ast_calendar *find_calendar(const char *name)
  271. {
  272. struct ast_calendar tmp = {
  273. .name = name,
  274. };
  275. return ao2_find(calendars, &tmp, OBJ_POINTER);
  276. }
  277. static int event_hash_fn(const void *obj, const int flags)
  278. {
  279. const struct ast_calendar_event *event = obj;
  280. return ast_str_hash(event->uid);
  281. }
  282. static int event_cmp_fn(void *obj, void *arg, int flags)
  283. {
  284. const struct ast_calendar_event *one = obj, *two = arg;
  285. return !strcmp(one->uid, two->uid) ? CMP_MATCH | CMP_STOP : 0;
  286. }
  287. static struct ast_calendar_event *find_event(struct ao2_container *events, const char *uid)
  288. {
  289. struct ast_calendar_event tmp = {
  290. .uid = uid,
  291. };
  292. return ao2_find(events, &tmp, OBJ_POINTER);
  293. }
  294. struct ast_calendar_event *ast_calendar_unref_event(struct ast_calendar_event *event)
  295. {
  296. ao2_ref(event, -1);
  297. return NULL;
  298. }
  299. static void calendar_destructor(void *obj)
  300. {
  301. struct ast_calendar *cal = obj;
  302. ast_debug(3, "Destroying calendar %s\n", cal->name);
  303. ao2_lock(cal);
  304. cal->unloading = 1;
  305. ast_cond_signal(&cal->unload);
  306. pthread_join(cal->thread, NULL);
  307. if (cal->tech_pvt) {
  308. cal->tech_pvt = cal->tech->unref_calendar(cal->tech_pvt);
  309. }
  310. ast_calendar_clear_events(cal);
  311. ast_string_field_free_memory(cal);
  312. ast_variables_destroy(cal->vars);
  313. ao2_ref(cal->events, -1);
  314. ao2_unlock(cal);
  315. }
  316. static void eventlist_destructor(void *obj)
  317. {
  318. struct eventlist *events = obj;
  319. struct evententry *entry;
  320. while ((entry = AST_LIST_REMOVE_HEAD(events, list))) {
  321. ao2_ref(entry->event, -1);
  322. ast_free(entry);
  323. }
  324. }
  325. static int calendar_busy_callback(void *obj, void *arg, int flags)
  326. {
  327. struct ast_calendar_event *event = obj;
  328. int *is_busy = arg;
  329. struct timeval tv = ast_tvnow();
  330. if (tv.tv_sec >= event->start && tv.tv_sec <= event->end && event->busy_state > AST_CALENDAR_BS_FREE) {
  331. *is_busy = 1;
  332. return CMP_STOP;
  333. }
  334. return 0;
  335. }
  336. static int calendar_is_busy(struct ast_calendar *cal)
  337. {
  338. int is_busy = 0;
  339. ao2_callback(cal->events, OBJ_NODATA, calendar_busy_callback, &is_busy);
  340. return is_busy;
  341. }
  342. static enum ast_device_state calendarstate(const char *data)
  343. {
  344. enum ast_device_state state;
  345. struct ast_calendar *cal;
  346. if (ast_strlen_zero(data) || (!(cal = find_calendar(data)))) {
  347. return AST_DEVICE_INVALID;
  348. }
  349. if (cal->tech->is_busy) {
  350. state = cal->tech->is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
  351. } else {
  352. state = calendar_is_busy(cal) ? AST_DEVICE_INUSE : AST_DEVICE_NOT_INUSE;
  353. }
  354. cal = unref_calendar(cal);
  355. return state;
  356. }
  357. static struct ast_calendar *build_calendar(struct ast_config *cfg, const char *cat, const struct ast_calendar_tech *tech)
  358. {
  359. struct ast_calendar *cal;
  360. struct ast_variable *v, *last = NULL;
  361. if (!(cal = ao2_alloc(sizeof(*cal), calendar_destructor))) {
  362. ast_log(LOG_ERROR, "Could not allocate calendar structure. Stopping.\n");
  363. return NULL;
  364. }
  365. cal->events = ast_calendar_event_container_alloc();
  366. if (!cal->events) {
  367. ast_log(LOG_ERROR, "Could not allocate events container for %s\n", cat);
  368. cal = unref_calendar(cal);
  369. return NULL;
  370. }
  371. if (ast_string_field_init(cal, 32)) {
  372. ast_log(LOG_ERROR, "Couldn't create string fields for %s\n", cat);
  373. cal = unref_calendar(cal);
  374. return NULL;
  375. }
  376. ast_string_field_set(cal, name, cat);
  377. cal->tech = tech;
  378. cal->refresh = 3600;
  379. cal->timeframe = 60;
  380. cal->notify_waittime = 30000;
  381. for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
  382. if (!strcasecmp(v->name, "autoreminder")) {
  383. cal->autoreminder = atoi(v->value);
  384. } else if (!strcasecmp(v->name, "channel")) {
  385. ast_string_field_set(cal, notify_channel, v->value);
  386. } else if (!strcasecmp(v->name, "context")) {
  387. ast_string_field_set(cal, notify_context, v->value);
  388. } else if (!strcasecmp(v->name, "extension")) {
  389. ast_string_field_set(cal, notify_extension, v->value);
  390. } else if (!strcasecmp(v->name, "waittime")) {
  391. int i = atoi(v->value);
  392. if (i > 0) {
  393. cal->notify_waittime = 1000 * i;
  394. }
  395. } else if (!strcasecmp(v->name, "app")) {
  396. ast_string_field_set(cal, notify_app, v->value);
  397. } else if (!strcasecmp(v->name, "appdata")) {
  398. ast_string_field_set(cal, notify_appdata, v->value);
  399. } else if (!strcasecmp(v->name, "refresh")) {
  400. cal->refresh = atoi(v->value);
  401. } else if (!strcasecmp(v->name, "timeframe")) {
  402. cal->timeframe = atoi(v->value);
  403. } else if (!strcasecmp(v->name, "setvar")) {
  404. char *name, *value;
  405. struct ast_variable *var;
  406. if ((name = (value = ast_strdup(v->value)))) {
  407. strsep(&value, "=");
  408. if (value) {
  409. if ((var = ast_variable_new(ast_strip(name), ast_strip(value), ""))) {
  410. if (last) {
  411. last->next = var;
  412. } else {
  413. cal->vars = var;
  414. }
  415. last = var;
  416. }
  417. } else {
  418. ast_log(LOG_WARNING, "Malformed argument. Should be '%s: variable=value'\n", v->name);
  419. }
  420. ast_free(name);
  421. }
  422. }
  423. }
  424. if (cal->autoreminder && ast_strlen_zero(cal->notify_channel)) {
  425. ast_log(LOG_WARNING,
  426. "You have set 'autoreminder' but not 'channel' for calendar '%s.' "
  427. "Notifications will not occur.\n",
  428. cal->name);
  429. }
  430. cal->thread = AST_PTHREADT_NULL;
  431. ast_cond_init(&cal->unload, NULL);
  432. ao2_link(calendars, cal);
  433. if (ast_pthread_create(&cal->thread, NULL, cal->tech->load_calendar, cal)) {
  434. /* If we start failing to create threads, go ahead and return NULL
  435. * and the tech module will be unregistered
  436. */
  437. ao2_unlink(calendars, cal);
  438. cal = unref_calendar(cal);
  439. }
  440. return cal;
  441. }
  442. static int load_tech_calendars(struct ast_calendar_tech *tech)
  443. {
  444. struct ast_calendar *cal;
  445. const char *cat = NULL;
  446. const char *val;
  447. if (!calendar_config) {
  448. ast_log(LOG_WARNING, "Calendar support disabled, not loading %s calendar module\n", tech->type);
  449. return -1;
  450. }
  451. ast_rwlock_wrlock(&config_lock);
  452. while ((cat = ast_category_browse(calendar_config, cat))) {
  453. if (!strcasecmp(cat, "general")) {
  454. continue;
  455. }
  456. if (!(val = ast_variable_retrieve(calendar_config, cat, "type")) || strcasecmp(val, tech->type)) {
  457. continue;
  458. }
  459. /* A serious error occurred loading calendars from this tech and it should be disabled */
  460. if (!(cal = build_calendar(calendar_config, cat, tech))) {
  461. ast_calendar_unregister(tech);
  462. ast_rwlock_unlock(&config_lock);
  463. return -1;
  464. }
  465. cal = unref_calendar(cal);
  466. }
  467. ast_rwlock_unlock(&config_lock);
  468. return 0;
  469. }
  470. int ast_calendar_register(struct ast_calendar_tech *tech)
  471. {
  472. struct ast_calendar_tech *iter;
  473. if (!calendar_config) {
  474. ast_log(LOG_WARNING, "Calendar support disabled, not loading %s calendar module\n", tech->type);
  475. return -1;
  476. }
  477. AST_LIST_LOCK(&techs);
  478. AST_LIST_TRAVERSE(&techs, iter, list) {
  479. if(!strcasecmp(tech->type, iter->type)) {
  480. ast_log(LOG_WARNING, "Already have a handler for calendar type '%s'\n", tech->type);
  481. AST_LIST_UNLOCK(&techs);
  482. return -1;
  483. }
  484. }
  485. AST_LIST_INSERT_HEAD(&techs, tech, list);
  486. tech->user = ast_module_user_add(NULL);
  487. AST_LIST_UNLOCK(&techs);
  488. ast_verb(2, "Registered calendar type '%s' (%s)\n", tech->type, tech->description);
  489. return load_tech_calendars(tech);
  490. }
  491. static int match_caltech_cb(void *user_data, void *arg, int flags)
  492. {
  493. struct ast_calendar *cal = user_data;
  494. struct ast_calendar_tech *tech = arg;
  495. if (cal->tech == tech) {
  496. return CMP_MATCH;
  497. }
  498. return 0;
  499. }
  500. void ast_calendar_unregister(struct ast_calendar_tech *tech)
  501. {
  502. struct ast_calendar_tech *iter;
  503. AST_LIST_LOCK(&techs);
  504. AST_LIST_TRAVERSE_SAFE_BEGIN(&techs, iter, list) {
  505. if (iter != tech) {
  506. continue;
  507. }
  508. ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, match_caltech_cb, tech);
  509. AST_LIST_REMOVE_CURRENT(list);
  510. ast_module_user_remove(iter->user);
  511. ast_verb(2, "Unregistered calendar type '%s'\n", tech->type);
  512. break;
  513. }
  514. AST_LIST_TRAVERSE_SAFE_END;
  515. AST_LIST_UNLOCK(&techs);
  516. }
  517. static void calendar_event_destructor(void *obj)
  518. {
  519. struct ast_calendar_event *event = obj;
  520. struct ast_calendar_attendee *attendee;
  521. ast_debug(3, "Destroying event for calendar '%s'\n", event->owner->name);
  522. ast_string_field_free_memory(event);
  523. while ((attendee = AST_LIST_REMOVE_HEAD(&event->attendees, next))) {
  524. if (attendee->data) {
  525. ast_free(attendee->data);
  526. }
  527. ast_free(attendee);
  528. }
  529. }
  530. /* This is only called from ao2_callbacks that are going to unref the event for us,
  531. * so we don't unref the event here. */
  532. static struct ast_calendar_event *destroy_event(struct ast_calendar_event *event)
  533. {
  534. if (event->notify_sched > -1 && ast_sched_del(sched, event->notify_sched)) {
  535. ast_debug(3, "Notification running, can't delete sched entry\n");
  536. }
  537. if (event->bs_start_sched > -1 && ast_sched_del(sched, event->bs_start_sched)) {
  538. ast_debug(3, "Devicestate update (start) running, can't delete sched entry\n");
  539. }
  540. if (event->bs_end_sched > -1 && ast_sched_del(sched, event->bs_end_sched)) {
  541. ast_debug(3, "Devicestate update (end) running, can't delete sched entry\n");
  542. }
  543. /* If an event is being deleted and we've fired an event changing the status at the beginning,
  544. * but haven't hit the end event yet, go ahead and set the devicestate to the current busy status */
  545. if (event->bs_start_sched < 0 && event->bs_end_sched >= 0) {
  546. if (!calendar_is_busy(event->owner)) {
  547. ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
  548. } else {
  549. ast_devstate_changed(AST_DEVICE_BUSY, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
  550. }
  551. }
  552. return NULL;
  553. }
  554. static int clear_events_cb(void *user_data, void *arg, int flags)
  555. {
  556. struct ast_calendar_event *event = user_data;
  557. event = destroy_event(event);
  558. return CMP_MATCH;
  559. }
  560. void ast_calendar_clear_events(struct ast_calendar *cal)
  561. {
  562. ast_debug(3, "Clearing all events for calendar %s\n", cal->name);
  563. ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, clear_events_cb, NULL);
  564. }
  565. struct ast_calendar_event *ast_calendar_event_alloc(struct ast_calendar *cal)
  566. {
  567. struct ast_calendar_event *event;
  568. if (!(event = ao2_alloc(sizeof(*event), calendar_event_destructor))) {
  569. return NULL;
  570. }
  571. if (ast_string_field_init(event, 32)) {
  572. event = ast_calendar_unref_event(event);
  573. return NULL;
  574. }
  575. event->owner = cal;
  576. event->notify_sched = -1;
  577. event->bs_start_sched = -1;
  578. event->bs_end_sched = -1;
  579. AST_LIST_HEAD_INIT_NOLOCK(&event->attendees);
  580. return event;
  581. }
  582. struct ao2_container *ast_calendar_event_container_alloc(void)
  583. {
  584. return ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, CALENDAR_BUCKETS,
  585. event_hash_fn, NULL, event_cmp_fn);
  586. }
  587. static void event_notification_destroy(void *data)
  588. {
  589. struct ast_calendar_event *event = data;
  590. event = ast_calendar_unref_event(event);
  591. }
  592. static void *event_notification_duplicate(void *data)
  593. {
  594. struct ast_calendar_event *event = data;
  595. if (!event) {
  596. return NULL;
  597. }
  598. ao2_ref(event, +1);
  599. return event;
  600. }
  601. /*! \brief Generate 32 byte random string (stolen from chan_sip.c)*/
  602. static char *generate_random_string(char *buf, size_t size)
  603. {
  604. unsigned long val[4];
  605. int x;
  606. for (x = 0; x < 4; x++) {
  607. val[x] = ast_random();
  608. }
  609. snprintf(buf, size, "%08lx%08lx%08lx%08lx", val[0], val[1], val[2], val[3]);
  610. return buf;
  611. }
  612. static int null_chan_write(struct ast_channel *chan, struct ast_frame *frame)
  613. {
  614. return 0;
  615. }
  616. static const struct ast_channel_tech null_tech = {
  617. .type = "NULL",
  618. .description = "Null channel (should not see this)",
  619. .write = null_chan_write,
  620. };
  621. static void *do_notify(void *data)
  622. {
  623. struct ast_calendar_event *event = data;
  624. struct ast_dial *dial = NULL;
  625. struct ast_str *apptext = NULL, *tmpstr = NULL;
  626. struct ast_datastore *datastore;
  627. enum ast_dial_result res;
  628. struct ast_channel *chan = NULL;
  629. struct ast_variable *itervar;
  630. char *tech, *dest;
  631. char buf[33];
  632. struct ast_format_cap *caps;
  633. tech = ast_strdupa(event->owner->notify_channel);
  634. if ((dest = strchr(tech, '/'))) {
  635. *dest = '\0';
  636. dest++;
  637. } else {
  638. ast_log(LOG_WARNING, "Channel should be in form Tech/Dest (was '%s')\n", tech);
  639. goto notify_cleanup;
  640. }
  641. if (!(dial = ast_dial_create())) {
  642. ast_log(LOG_ERROR, "Could not create dial structure\n");
  643. goto notify_cleanup;
  644. }
  645. if (ast_dial_append(dial, tech, dest, NULL) < 0) {
  646. ast_log(LOG_ERROR, "Could not append channel\n");
  647. goto notify_cleanup;
  648. }
  649. ast_dial_set_global_timeout(dial, event->owner->notify_waittime);
  650. generate_random_string(buf, sizeof(buf));
  651. if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, 0, 0, 0, 0, 0, NULL, NULL, 0, "Calendar/%s-%s", event->owner->name, buf))) {
  652. ast_log(LOG_ERROR, "Could not allocate notification channel\n");
  653. goto notify_cleanup;
  654. }
  655. ast_channel_tech_set(chan, &null_tech);
  656. ast_channel_set_writeformat(chan, ast_format_slin);
  657. ast_channel_set_readformat(chan, ast_format_slin);
  658. ast_channel_set_rawwriteformat(chan, ast_format_slin);
  659. ast_channel_set_rawreadformat(chan, ast_format_slin);
  660. caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
  661. if (!caps) {
  662. ast_log(LOG_ERROR, "Could not allocate capabilities, notification not being sent!\n");
  663. goto notify_cleanup;
  664. }
  665. ast_format_cap_append(caps, ast_format_slin, 0);
  666. ast_channel_nativeformats_set(chan, caps);
  667. ao2_ref(caps, -1);
  668. ast_channel_unlock(chan);
  669. if (!(datastore = ast_datastore_alloc(&event_notification_datastore, NULL))) {
  670. ast_log(LOG_ERROR, "Could not allocate datastore, notification not being sent!\n");
  671. goto notify_cleanup;
  672. }
  673. datastore->data = event;
  674. datastore->inheritance = DATASTORE_INHERIT_FOREVER;
  675. ao2_ref(event, +1);
  676. ast_channel_lock(chan);
  677. res = ast_channel_datastore_add(chan, datastore);
  678. ast_channel_unlock(chan);
  679. if (!(tmpstr = ast_str_create(32))) {
  680. goto notify_cleanup;
  681. }
  682. for (itervar = event->owner->vars; itervar; itervar = itervar->next) {
  683. ast_str_substitute_variables(&tmpstr, 0, chan, itervar->value);
  684. pbx_builtin_setvar_helper(chan, itervar->name, ast_str_buffer(tmpstr));
  685. }
  686. if (!(apptext = ast_str_create(32))) {
  687. goto notify_cleanup;
  688. }
  689. if (!ast_strlen_zero(event->owner->notify_app)) {
  690. ast_str_set(&apptext, 0, "%s,%s", event->owner->notify_app, event->owner->notify_appdata);
  691. ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, ast_str_buffer(apptext));
  692. } else {
  693. }
  694. ast_verb(3, "Dialing %s for notification on calendar %s\n", event->owner->notify_channel, event->owner->name);
  695. res = ast_dial_run(dial, chan, 0);
  696. if (res != AST_DIAL_RESULT_ANSWERED) {
  697. ast_verb(3, "Notification call for %s was not completed\n", event->owner->name);
  698. } else {
  699. struct ast_channel *answered;
  700. answered = ast_dial_answered_steal(dial);
  701. if (ast_strlen_zero(event->owner->notify_app)) {
  702. ast_channel_context_set(answered, event->owner->notify_context);
  703. ast_channel_exten_set(answered, event->owner->notify_extension);
  704. ast_channel_priority_set(answered, 1);
  705. ast_pbx_run(answered);
  706. }
  707. }
  708. notify_cleanup:
  709. if (apptext) {
  710. ast_free(apptext);
  711. }
  712. if (tmpstr) {
  713. ast_free(tmpstr);
  714. }
  715. if (dial) {
  716. ast_dial_destroy(dial);
  717. }
  718. if (chan) {
  719. ast_channel_release(chan);
  720. }
  721. event = ast_calendar_unref_event(event);
  722. return NULL;
  723. }
  724. static int calendar_event_notify(const void *data)
  725. {
  726. struct ast_calendar_event *event = (void *)data;
  727. int res = -1;
  728. pthread_t notify_thread = AST_PTHREADT_NULL;
  729. if (!(event && event->owner)) {
  730. ast_log(LOG_ERROR, "Extremely low-cal...in fact cal is NULL!\n");
  731. return res;
  732. }
  733. ao2_ref(event, +1);
  734. event->notify_sched = -1;
  735. if (ast_pthread_create_background(&notify_thread, NULL, do_notify, event) < 0) {
  736. ast_log(LOG_ERROR, "Could not create notification thread\n");
  737. return res;
  738. }
  739. res = 0;
  740. return res;
  741. }
  742. static int calendar_devstate_change(const void *data)
  743. {
  744. struct ast_calendar_event *event = (struct ast_calendar_event *)data;
  745. struct timeval now = ast_tvnow();
  746. int is_end_event;
  747. if (!event) {
  748. ast_log(LOG_WARNING, "Event was NULL!\n");
  749. return 0;
  750. }
  751. ao2_ref(event, +1);
  752. is_end_event = event->end <= now.tv_sec;
  753. if (is_end_event) {
  754. event->bs_end_sched = -1;
  755. } else {
  756. event->bs_start_sched = -1;
  757. }
  758. /* We can have overlapping events, so ignore the event->busy_state and check busy state
  759. * based on all events in the calendar */
  760. if (!calendar_is_busy(event->owner)) {
  761. ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
  762. } else {
  763. ast_devstate_changed(AST_DEVICE_BUSY, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name);
  764. }
  765. event = ast_calendar_unref_event(event);
  766. return 0;
  767. }
  768. static void copy_event_data(struct ast_calendar_event *dst, struct ast_calendar_event *src)
  769. {
  770. struct ast_calendar_attendee *attendee;
  771. ast_string_field_set(dst, summary, src->summary);
  772. ast_string_field_set(dst, description, src->description);
  773. ast_string_field_set(dst, organizer, src->organizer);
  774. ast_string_field_set(dst, location, src->location);
  775. ast_string_field_set(dst, uid, src->uid);
  776. ast_string_field_set(dst, categories, src->categories);
  777. dst->priority = src->priority;
  778. dst->owner = src->owner;
  779. dst->start = src->start;
  780. dst->end = src->end;
  781. dst->alarm = src->alarm;
  782. dst->busy_state = src->busy_state;
  783. /* Delete any existing attendees */
  784. while ((attendee = AST_LIST_REMOVE_HEAD(&dst->attendees, next))) {
  785. ast_free(attendee);
  786. }
  787. /* Copy over the new attendees */
  788. while ((attendee = AST_LIST_REMOVE_HEAD(&src->attendees, next))) {
  789. AST_LIST_INSERT_TAIL(&dst->attendees, attendee, next);
  790. }
  791. }
  792. static int schedule_calendar_event(struct ast_calendar *cal, struct ast_calendar_event *old_event, struct ast_calendar_event *cmp_event)
  793. {
  794. struct timeval now = ast_tvnow();
  795. struct ast_calendar_event *event;
  796. time_t alarm_notify_sched = 0, devstate_sched_start, devstate_sched_end;
  797. int changed = 0;
  798. event = cmp_event ? cmp_event : old_event;
  799. ao2_lock(event);
  800. if (!ast_strlen_zero(cal->notify_channel) && (!cmp_event || old_event->alarm != event->alarm)) {
  801. changed = 1;
  802. if (cal->autoreminder) {
  803. alarm_notify_sched = (event->start - (60 * cal->autoreminder) - now.tv_sec) * 1000;
  804. } else if (event->alarm) {
  805. alarm_notify_sched = (event->alarm - now.tv_sec) * 1000;
  806. }
  807. /* For now, send the notification if we missed it, but the meeting hasn't happened yet */
  808. if (event->start >= now.tv_sec) {
  809. if (alarm_notify_sched <= 0) {
  810. alarm_notify_sched = 1;
  811. }
  812. ast_mutex_lock(&refreshlock);
  813. AST_SCHED_REPLACE(old_event->notify_sched, sched, alarm_notify_sched, calendar_event_notify, old_event);
  814. ast_mutex_unlock(&refreshlock);
  815. ast_debug(3, "Calendar alarm event notification scheduled to happen in %ld ms\n", (long) alarm_notify_sched);
  816. }
  817. }
  818. if (!cmp_event || old_event->start != event->start) {
  819. changed = 1;
  820. devstate_sched_start = (event->start - now.tv_sec) * 1000;
  821. if (devstate_sched_start < 1) {
  822. devstate_sched_start = 1;
  823. }
  824. ast_mutex_lock(&refreshlock);
  825. AST_SCHED_REPLACE(old_event->bs_start_sched, sched, devstate_sched_start, calendar_devstate_change, old_event);
  826. ast_mutex_unlock(&refreshlock);
  827. ast_debug(3, "Calendar bs_start event notification scheduled to happen in %ld ms\n", (long) devstate_sched_start);
  828. }
  829. if (!cmp_event || old_event->end != event->end) {
  830. changed = 1;
  831. devstate_sched_end = (event->end - now.tv_sec) * 1000;
  832. ast_mutex_lock(&refreshlock);
  833. AST_SCHED_REPLACE(old_event->bs_end_sched, sched, devstate_sched_end, calendar_devstate_change, old_event);
  834. ast_mutex_unlock(&refreshlock);
  835. ast_debug(3, "Calendar bs_end event notification scheduled to happen in %ld ms\n", (long) devstate_sched_end);
  836. }
  837. if (changed) {
  838. ast_cond_signal(&refresh_condition);
  839. }
  840. ao2_unlock(event);
  841. return 0;
  842. }
  843. static int merge_events_cb(void *obj, void *arg, int flags)
  844. {
  845. struct ast_calendar_event *old_event = obj, *new_event;
  846. struct ao2_container *new_events = arg;
  847. /* If we don't find the old_event in new_events, then we can safely delete the old_event */
  848. if (!(new_event = find_event(new_events, old_event->uid))) {
  849. old_event = destroy_event(old_event);
  850. return CMP_MATCH;
  851. }
  852. /* We have events to merge. If any data that will affect a scheduler event has changed,
  853. * then we need to replace the scheduler event */
  854. schedule_calendar_event(old_event->owner, old_event, new_event);
  855. /* Since we don't want to mess with cancelling sched events and adding new ones, just
  856. * copy the internals of the new_event to the old_event */
  857. copy_event_data(old_event, new_event);
  858. /* Now we can go ahead and unlink the new_event from new_events and unref it so that only completely
  859. * new events remain in the container */
  860. ao2_unlink(new_events, new_event);
  861. new_event = ast_calendar_unref_event(new_event);
  862. return 0;
  863. }
  864. static int add_new_event_cb(void *obj, void *arg, int flags)
  865. {
  866. struct ast_calendar_event *new_event = obj;
  867. struct ao2_container *events = arg;
  868. ao2_link(events, new_event);
  869. schedule_calendar_event(new_event->owner, new_event, NULL);
  870. return CMP_MATCH;
  871. }
  872. void ast_calendar_merge_events(struct ast_calendar *cal, struct ao2_container *new_events)
  873. {
  874. /* Loop through all events attached to the calendar. If there is a matching new event
  875. * merge its data over and handle any schedule changes that need to be made. Then remove
  876. * the new_event from new_events so that we are left with only new_events that we can add later. */
  877. ao2_callback(cal->events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, merge_events_cb, new_events);
  878. /* Now, we should only have completely new events in new_events. Loop through and add them */
  879. ao2_callback(new_events, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, add_new_event_cb, cal->events);
  880. }
  881. static int load_config(int reload)
  882. {
  883. struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
  884. struct ast_config *tmpcfg;
  885. if (!(tmpcfg = ast_config_load2("calendar.conf", "calendar", config_flags)) ||
  886. tmpcfg == CONFIG_STATUS_FILEINVALID) {
  887. ast_log(LOG_ERROR, "Unable to load config calendar.conf\n");
  888. return -1;
  889. }
  890. if (tmpcfg == CONFIG_STATUS_FILEUNCHANGED) {
  891. return 0;
  892. }
  893. ast_rwlock_wrlock(&config_lock);
  894. if (calendar_config) {
  895. ast_config_destroy(calendar_config);
  896. }
  897. calendar_config = tmpcfg;
  898. ast_rwlock_unlock(&config_lock);
  899. return 0;
  900. }
  901. /*! \brief A dialplan function that can be used to determine the busy status of a calendar */
  902. static int calendar_busy_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
  903. {
  904. struct ast_calendar *cal;
  905. if (ast_strlen_zero(data)) {
  906. ast_log(LOG_WARNING, "CALENDAR_BUSY requires an argument: CALENDAR_BUSY(<calendar_name>)\n");
  907. return -1;
  908. }
  909. cal = find_calendar(data);
  910. if (!cal) {
  911. ast_log(LOG_WARNING, "Could not find calendar '%s'\n", data);
  912. return -1;
  913. }
  914. strcpy(buf, calendar_is_busy(cal) ? "1" : "0");
  915. cal = unref_calendar(cal);
  916. return 0;
  917. }
  918. static struct ast_custom_function calendar_busy_function = {
  919. .name = "CALENDAR_BUSY",
  920. .read = calendar_busy_exec,
  921. };
  922. static int add_event_to_list(struct eventlist *events, struct ast_calendar_event *event, time_t start, time_t end)
  923. {
  924. struct evententry *entry, *iter;
  925. long event_startdiff = labs(start - event->start);
  926. long event_enddiff = labs(end - event->end);
  927. int i = 0;
  928. if (!(entry = ast_calloc(1, sizeof(*entry)))) {
  929. ast_log(LOG_ERROR, "Unable to allocate memory for event list\n");
  930. return -1;
  931. }
  932. entry->event = event;
  933. ao2_ref(event, +1);
  934. if (start == end) {
  935. AST_LIST_TRAVERSE_SAFE_BEGIN(events, iter, list) {
  936. long startdiff = labs(iter->event->start - start);
  937. ast_debug(10, "Comparing %s with startdiff %ld to %s with startdiff %ld\n", event->summary, event_startdiff, iter->event->summary, startdiff);
  938. ++i;
  939. if (startdiff > event_startdiff) {
  940. AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
  941. return i;
  942. }
  943. if (startdiff == event_startdiff) {
  944. long enddiff = labs(iter->event->end - end);
  945. if (enddiff > event_enddiff) {
  946. AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
  947. return i;
  948. }
  949. if (event_startdiff == enddiff) {
  950. if (strcmp(event->uid, iter->event->uid) < 0) {
  951. AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
  952. return i;
  953. }
  954. }
  955. }
  956. }
  957. AST_LIST_TRAVERSE_SAFE_END;
  958. AST_LIST_INSERT_TAIL(events, entry, list);
  959. return i;
  960. }
  961. AST_LIST_TRAVERSE_SAFE_BEGIN(events, iter, list) {
  962. ++i;
  963. if (iter->event->start > event->start) {
  964. AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
  965. return i;
  966. }
  967. if (iter->event->start == event->start) {
  968. if ((iter->event->end - iter->event->start) == (event->end - event->start)) {
  969. if (strcmp(event->uid, iter->event->uid) < 0) {
  970. AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
  971. return i;
  972. }
  973. }
  974. if ((iter->event->end - iter->event->start) < (event->end - event->start)) {
  975. AST_LIST_INSERT_BEFORE_CURRENT(entry, list);
  976. return i;
  977. }
  978. }
  979. }
  980. AST_LIST_TRAVERSE_SAFE_END;
  981. AST_LIST_INSERT_TAIL(events, entry, list);
  982. return i;
  983. }
  984. static void eventlist_destroy(void *data)
  985. {
  986. struct eventlist *events = data;
  987. ao2_ref(events, -1);
  988. }
  989. static void *eventlist_duplicate(void *data)
  990. {
  991. struct eventlist *events = data;
  992. if (!events) {
  993. return NULL;
  994. }
  995. ao2_ref(events, +1);
  996. return events;
  997. }
  998. static int calendar_query_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
  999. {
  1000. struct ast_calendar *cal;
  1001. struct ao2_iterator i;
  1002. struct ast_calendar_event *event;
  1003. struct eventlist *events;
  1004. time_t start = INT_MIN, end = INT_MAX;
  1005. struct ast_datastore *eventlist_datastore;
  1006. AST_DECLARE_APP_ARGS(args,
  1007. AST_APP_ARG(calendar);
  1008. AST_APP_ARG(start);
  1009. AST_APP_ARG(end);
  1010. );
  1011. if (!chan) {
  1012. ast_log(LOG_WARNING, "%s requires a channel to store the data on\n", cmd);
  1013. return -1;
  1014. }
  1015. AST_STANDARD_APP_ARGS(args, data);
  1016. if (ast_strlen_zero(args.calendar)) {
  1017. ast_log(LOG_WARNING, "%s requires a calendar argument\n", cmd);
  1018. return -1;
  1019. }
  1020. if (!(cal = find_calendar(args.calendar))) {
  1021. ast_log(LOG_WARNING, "Unknown calendar '%s'\n", args.calendar);
  1022. return -1;
  1023. }
  1024. if (!(events = ao2_alloc(sizeof(*events), eventlist_destructor))) {
  1025. ast_log(LOG_ERROR, "Unable to allocate memory for event list\n");
  1026. cal = unref_calendar(cal);
  1027. return -1;
  1028. }
  1029. if (!ast_strlen_zero(args.start)) {
  1030. start = atoi(args.start);
  1031. }
  1032. if (!ast_strlen_zero(args.end)) {
  1033. end = atoi(args.end);
  1034. }
  1035. i = ao2_iterator_init(cal->events, 0);
  1036. while ((event = ao2_iterator_next(&i))) {
  1037. if (!(start > event->end || end < event->start)) {
  1038. ast_debug(10, "%s (%ld - %ld) overlapped with (%ld - %ld)\n", event->summary, (long) event->start, (long) event->end, (long) start, (long) end);
  1039. if (add_event_to_list(events, event, start, end) < 0) {
  1040. event = ast_calendar_unref_event(event);
  1041. cal = unref_calendar(cal);
  1042. ao2_ref(events, -1);
  1043. ao2_iterator_destroy(&i);
  1044. return -1;
  1045. }
  1046. }
  1047. event = ast_calendar_unref_event(event);
  1048. }
  1049. ao2_iterator_destroy(&i);
  1050. ast_channel_lock(chan);
  1051. do {
  1052. generate_random_string(buf, len);
  1053. } while (ast_channel_datastore_find(chan, &eventlist_datastore_info, buf));
  1054. ast_channel_unlock(chan);
  1055. if (!(eventlist_datastore = ast_datastore_alloc(&eventlist_datastore_info, buf))) {
  1056. ast_log(LOG_ERROR, "Could not allocate datastore!\n");
  1057. cal = unref_calendar(cal);
  1058. ao2_ref(events, -1);
  1059. return -1;
  1060. }
  1061. eventlist_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
  1062. eventlist_datastore->data = events;
  1063. ast_channel_lock(chan);
  1064. ast_channel_datastore_add(chan, eventlist_datastore);
  1065. ast_channel_unlock(chan);
  1066. cal = unref_calendar(cal);
  1067. return 0;
  1068. }
  1069. static struct ast_custom_function calendar_query_function = {
  1070. .name = "CALENDAR_QUERY",
  1071. .read = calendar_query_exec,
  1072. };
  1073. static void calendar_join_attendees(struct ast_calendar_event *event, char *buf, size_t len)
  1074. {
  1075. struct ast_str *tmp;
  1076. struct ast_calendar_attendee *attendee;
  1077. if (!(tmp = ast_str_create(32))) {
  1078. ast_log(LOG_ERROR, "Could not allocate memory for attendees!\n");
  1079. return;
  1080. }
  1081. AST_LIST_TRAVERSE(&event->attendees, attendee, next) {
  1082. ast_str_append(&tmp, 0, "%s%s", attendee == AST_LIST_FIRST(&event->attendees) ? "" : ",", attendee->data);
  1083. }
  1084. ast_copy_string(buf, ast_str_buffer(tmp), len);
  1085. ast_free(tmp);
  1086. }
  1087. static int calendar_query_result_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
  1088. {
  1089. struct ast_datastore *datastore;
  1090. struct eventlist *events;
  1091. struct evententry *entry;
  1092. int row = 1;
  1093. size_t listlen = 0;
  1094. AST_DECLARE_APP_ARGS(args,
  1095. AST_APP_ARG(id);
  1096. AST_APP_ARG(field);
  1097. AST_APP_ARG(row);
  1098. );
  1099. if (!chan) {
  1100. ast_log(LOG_WARNING, "%s requires a channel\n", cmd);
  1101. return -1;
  1102. }
  1103. AST_STANDARD_APP_ARGS(args, data);
  1104. if (ast_strlen_zero(args.id) || ast_strlen_zero(args.field)) {
  1105. ast_log(LOG_WARNING, "%s requires an id and a field", cmd);
  1106. return -1;
  1107. }
  1108. ast_channel_lock(chan);
  1109. if (!(datastore = ast_channel_datastore_find(chan, &eventlist_datastore_info, args.id))) {
  1110. ast_log(LOG_WARNING, "There is no event notification datastore with id '%s' on '%s'!\n", args.id, ast_channel_name(chan));
  1111. ast_channel_unlock(chan);
  1112. return -1;
  1113. }
  1114. ast_channel_unlock(chan);
  1115. if (!(events = datastore->data)) {
  1116. ast_log(LOG_WARNING, "The datastore contains no data!\n");
  1117. return -1;
  1118. }
  1119. if (!ast_strlen_zero(args.row)) {
  1120. row = atoi(args.row);
  1121. }
  1122. AST_LIST_TRAVERSE(events, entry, list) {
  1123. listlen++;
  1124. }
  1125. if (!strcasecmp(args.field, "getnum")) {
  1126. snprintf(buf, len, "%zu", listlen);
  1127. return 0;
  1128. }
  1129. AST_LIST_TRAVERSE(events, entry, list) {
  1130. if (--row) {
  1131. continue;
  1132. }
  1133. if (!strcasecmp(args.field, "summary")) {
  1134. ast_copy_string(buf, entry->event->summary, len);
  1135. } else if (!strcasecmp(args.field, "description")) {
  1136. ast_copy_string(buf, entry->event->description, len);
  1137. } else if (!strcasecmp(args.field, "organizer")) {
  1138. ast_copy_string(buf, entry->event->organizer, len);
  1139. } else if (!strcasecmp(args.field, "location")) {
  1140. ast_copy_string(buf, entry->event->location, len);
  1141. } else if (!strcasecmp(args.field, "categories")) {
  1142. ast_copy_string(buf, entry->event->categories, len);
  1143. } else if (!strcasecmp(args.field, "priority")) {
  1144. snprintf(buf, len, "%d", entry->event->priority);
  1145. } else if (!strcasecmp(args.field, "calendar")) {
  1146. ast_copy_string(buf, entry->event->owner->name, len);
  1147. } else if (!strcasecmp(args.field, "uid")) {
  1148. ast_copy_string(buf, entry->event->uid, len);
  1149. } else if (!strcasecmp(args.field, "start")) {
  1150. snprintf(buf, len, "%ld", (long) entry->event->start);
  1151. } else if (!strcasecmp(args.field, "end")) {
  1152. snprintf(buf, len, "%ld", (long) entry->event->end);
  1153. } else if (!strcasecmp(args.field, "busystate")) {
  1154. snprintf(buf, len, "%u", entry->event->busy_state);
  1155. } else if (!strcasecmp(args.field, "attendees")) {
  1156. calendar_join_attendees(entry->event, buf, len);
  1157. } else {
  1158. ast_log(LOG_WARNING, "Unknown field '%s'\n", args.field);
  1159. }
  1160. break;
  1161. }
  1162. return 0;
  1163. }
  1164. static struct ast_custom_function calendar_query_result_function = {
  1165. .name = "CALENDAR_QUERY_RESULT",
  1166. .read = calendar_query_result_exec,
  1167. };
  1168. static int calendar_write_exec(struct ast_channel *chan, const char *cmd, char *data, const char *value)
  1169. {
  1170. int i, j, ret = -1;
  1171. char *val_dup = NULL;
  1172. struct ast_calendar *cal = NULL;
  1173. struct ast_calendar_event *event = NULL;
  1174. struct timeval tv = ast_tvnow();
  1175. AST_DECLARE_APP_ARGS(fields,
  1176. AST_APP_ARG(field)[10];
  1177. );
  1178. AST_DECLARE_APP_ARGS(values,
  1179. AST_APP_ARG(value)[10];
  1180. );
  1181. if (!(val_dup = ast_strdup(value))) {
  1182. ast_log(LOG_ERROR, "Could not allocate memory for values\n");
  1183. goto write_cleanup;
  1184. }
  1185. AST_STANDARD_APP_ARGS(fields, data);
  1186. AST_STANDARD_APP_ARGS(values, val_dup);
  1187. /* XXX Eventually we will support unnamed calendars, so if we don't find one, we parse
  1188. * for a calendar type and create it */
  1189. if (!(cal = find_calendar(fields.field[0]))) {
  1190. ast_log(LOG_WARNING, "Couldn't find calendar '%s'\n", fields.field[0]);
  1191. goto write_cleanup;
  1192. }
  1193. if (!(cal->tech->write_event)) {
  1194. ast_log(LOG_WARNING, "Calendar '%s' has no write function!\n", cal->name);
  1195. goto write_cleanup;
  1196. }
  1197. if (!(event = ast_calendar_event_alloc(cal))) {
  1198. goto write_cleanup;
  1199. }
  1200. if (ast_strlen_zero(fields.field[0])) {
  1201. ast_log(LOG_WARNING, "CALENDAR_WRITE requires a calendar name!\n");
  1202. goto write_cleanup;
  1203. }
  1204. if (fields.argc - 1 != values.argc) {
  1205. ast_log(LOG_WARNING, "CALENDAR_WRITE should have the same number of fields (%u) and values (%u)!\n", fields.argc - 1, values.argc);
  1206. goto write_cleanup;
  1207. }
  1208. event->owner = cal;
  1209. for (i = 1, j = 0; i < fields.argc; i++, j++) {
  1210. if (!strcasecmp(fields.field[i], "summary")) {
  1211. ast_string_field_set(event, summary, values.value[j]);
  1212. } else if (!strcasecmp(fields.field[i], "description")) {
  1213. ast_string_field_set(event, description, values.value[j]);
  1214. } else if (!strcasecmp(fields.field[i], "organizer")) {
  1215. ast_string_field_set(event, organizer, values.value[j]);
  1216. } else if (!strcasecmp(fields.field[i], "location")) {
  1217. ast_string_field_set(event, location, values.value[j]);
  1218. } else if (!strcasecmp(fields.field[i], "categories")) {
  1219. ast_string_field_set(event, categories, values.value[j]);
  1220. } else if (!strcasecmp(fields.field[i], "priority")) {
  1221. event->priority = atoi(values.value[j]);
  1222. } else if (!strcasecmp(fields.field[i], "uid")) {
  1223. ast_string_field_set(event, uid, values.value[j]);
  1224. } else if (!strcasecmp(fields.field[i], "start")) {
  1225. event->start = atoi(values.value[j]);
  1226. } else if (!strcasecmp(fields.field[i], "end")) {
  1227. event->end = atoi(values.value[j]);
  1228. } else if (!strcasecmp(fields.field[i], "busystate")) {
  1229. event->busy_state = atoi(values.value[j]);
  1230. } else {
  1231. ast_log(LOG_WARNING, "Unknown calendar event field '%s'\n", fields.field[i]);
  1232. }
  1233. }
  1234. if (!event->start) {
  1235. event->start = tv.tv_sec;
  1236. }
  1237. if (!event->end) {
  1238. event->end = tv.tv_sec;
  1239. }
  1240. if((ret = cal->tech->write_event(event))) {
  1241. ast_log(LOG_WARNING, "Writing event to calendar '%s' failed!\n", cal->name);
  1242. }
  1243. write_cleanup:
  1244. if (ret) {
  1245. pbx_builtin_setvar_helper(chan, "CALENDAR_SUCCESS", "0");
  1246. } else {
  1247. pbx_builtin_setvar_helper(chan, "CALENDAR_SUCCESS", "1");
  1248. }
  1249. if (cal) {
  1250. cal = unref_calendar(cal);
  1251. }
  1252. if (event) {
  1253. event = ast_calendar_unref_event(event);
  1254. }
  1255. if (val_dup) {
  1256. ast_free(val_dup);
  1257. }
  1258. return ret;
  1259. }
  1260. static struct ast_custom_function calendar_write_function = {
  1261. .name = "CALENDAR_WRITE",
  1262. .write = calendar_write_exec,
  1263. };
  1264. /*! \brief CLI command to list available calendars */
  1265. static char *handle_show_calendars(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  1266. {
  1267. #define FORMAT "%-20.20s %-10.10s %-6.6s\n"
  1268. struct ao2_iterator i;
  1269. struct ast_calendar *cal;
  1270. switch(cmd) {
  1271. case CLI_INIT:
  1272. e->command = "calendar show calendars";
  1273. e->usage =
  1274. "Usage: calendar show calendars\n"
  1275. " Lists all registered calendars.\n";
  1276. return NULL;
  1277. case CLI_GENERATE:
  1278. return NULL;
  1279. }
  1280. ast_cli(a->fd, FORMAT, "Calendar", "Type", "Status");
  1281. ast_cli(a->fd, FORMAT, "--------", "----", "------");
  1282. i = ao2_iterator_init(calendars, 0);
  1283. while ((cal = ao2_iterator_next(&i))) {
  1284. ast_cli(a->fd, FORMAT, cal->name, cal->tech->type, calendar_is_busy(cal) ? "busy" : "free");
  1285. cal = unref_calendar(cal);
  1286. }
  1287. ao2_iterator_destroy(&i);
  1288. return CLI_SUCCESS;
  1289. #undef FORMAT
  1290. }
  1291. /*! \brief CLI command to list of all calendars types currently loaded on the backend */
  1292. static char *handle_show_calendars_types(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  1293. {
  1294. #define FORMAT "%-10.10s %-30.30s\n"
  1295. struct ast_calendar_tech *iter;
  1296. switch(cmd) {
  1297. case CLI_INIT:
  1298. e->command = "calendar show types";
  1299. e->usage =
  1300. "Usage: calendar show types\n"
  1301. " Lists all registered calendars types.\n";
  1302. return NULL;
  1303. case CLI_GENERATE:
  1304. return NULL;
  1305. }
  1306. ast_cli(a->fd, FORMAT, "Type", "Description");
  1307. AST_LIST_LOCK(&techs);
  1308. AST_LIST_TRAVERSE(&techs, iter, list) {
  1309. ast_cli(a->fd, FORMAT, iter->type, iter->description);
  1310. }
  1311. AST_LIST_UNLOCK(&techs);
  1312. return CLI_SUCCESS;
  1313. #undef FORMAT
  1314. }
  1315. static char *epoch_to_string(char *buf, size_t buflen, time_t epoch)
  1316. {
  1317. struct ast_tm tm;
  1318. struct timeval tv = {
  1319. .tv_sec = epoch,
  1320. };
  1321. if (!epoch) {
  1322. *buf = '\0';
  1323. return buf;
  1324. }
  1325. ast_localtime(&tv, &tm, NULL);
  1326. ast_strftime(buf, buflen, "%F %r %z", &tm);
  1327. return buf;
  1328. }
  1329. static char *handle_show_calendar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  1330. {
  1331. #define FORMAT "%-18.18s : %-20.20s\n"
  1332. #define FORMAT2 "%-12.12s: %-40.60s\n"
  1333. struct ao2_iterator i;
  1334. struct ast_calendar *cal;
  1335. struct ast_calendar_event *event;
  1336. int which = 0;
  1337. char *ret = NULL;
  1338. switch(cmd) {
  1339. case CLI_INIT:
  1340. e->command = "calendar show calendar";
  1341. e->usage =
  1342. "Usage: calendar show calendar <calendar name>\n"
  1343. " Displays information about a calendar\n";
  1344. return NULL;
  1345. case CLI_GENERATE:
  1346. if (a->pos != 3) {
  1347. return NULL;
  1348. }
  1349. i = ao2_iterator_init(calendars, 0);
  1350. while ((cal = ao2_iterator_next(&i))) {
  1351. if (!strncasecmp(a->word, cal->name, strlen(a->word)) && ++which > a->n) {
  1352. ret = ast_strdup(cal->name);
  1353. cal = unref_calendar(cal);
  1354. break;
  1355. }
  1356. cal = unref_calendar(cal);
  1357. }
  1358. ao2_iterator_destroy(&i);
  1359. return ret;
  1360. }
  1361. if (a->argc != 4) {
  1362. return CLI_SHOWUSAGE;
  1363. }
  1364. if (!(cal = find_calendar(a->argv[3]))) {
  1365. return NULL;
  1366. }
  1367. ast_cli(a->fd, FORMAT, "Name", cal->name);
  1368. ast_cli(a->fd, FORMAT, "Notify channel", cal->notify_channel);
  1369. ast_cli(a->fd, FORMAT, "Notify context", cal->notify_context);
  1370. ast_cli(a->fd, FORMAT, "Notify extension", cal->notify_extension);
  1371. ast_cli(a->fd, FORMAT, "Notify application", cal->notify_app);
  1372. ast_cli(a->fd, FORMAT, "Notify appdata", cal->notify_appdata);
  1373. ast_cli(a->fd, "%-17.17s : %d\n", "Refresh time", cal->refresh);
  1374. ast_cli(a->fd, "%-17.17s : %d\n", "Timeframe", cal->timeframe);
  1375. if (cal->autoreminder) {
  1376. ast_cli(a->fd, "%-17.17s : %d minutes before event\n", "Autoreminder", cal->autoreminder);
  1377. } else {
  1378. ast_cli(a->fd, "%-17.17s : None\n", "Autoreminder");
  1379. }
  1380. ast_cli(a->fd, "%s\n", "Events");
  1381. ast_cli(a->fd, "%s\n", "------");
  1382. i = ao2_iterator_init(cal->events, 0);
  1383. while ((event = ao2_iterator_next(&i))) {
  1384. char buf[100];
  1385. ast_cli(a->fd, FORMAT2, "Summary", event->summary);
  1386. ast_cli(a->fd, FORMAT2, "Description", event->description);
  1387. ast_cli(a->fd, FORMAT2, "Organizer", event->organizer);
  1388. ast_cli(a->fd, FORMAT2, "Location", event->location);
  1389. ast_cli(a->fd, FORMAT2, "Categories", event->categories);
  1390. ast_cli(a->fd, "%-12.12s: %d\n", "Priority", event->priority);
  1391. ast_cli(a->fd, FORMAT2, "UID", event->uid);
  1392. ast_cli(a->fd, FORMAT2, "Start", epoch_to_string(buf, sizeof(buf), event->start));
  1393. ast_cli(a->fd, FORMAT2, "End", epoch_to_string(buf, sizeof(buf), event->end));
  1394. ast_cli(a->fd, FORMAT2, "Alarm", epoch_to_string(buf, sizeof(buf), event->alarm));
  1395. ast_cli(a->fd, "\n");
  1396. event = ast_calendar_unref_event(event);
  1397. }
  1398. ao2_iterator_destroy(&i);
  1399. cal = unref_calendar(cal);
  1400. return CLI_SUCCESS;
  1401. #undef FORMAT
  1402. #undef FORMAT2
  1403. }
  1404. static char *handle_dump_sched(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  1405. {
  1406. switch(cmd) {
  1407. case CLI_INIT:
  1408. e->command = "calendar dump sched";
  1409. e->usage =
  1410. "Usage: calendar dump sched\n"
  1411. " Dump the calendar sched context";
  1412. return NULL;
  1413. case CLI_GENERATE:
  1414. return NULL;
  1415. }
  1416. ast_sched_dump(sched);
  1417. return CLI_SUCCESS;
  1418. }
  1419. static struct ast_cli_entry calendar_cli[] = {
  1420. AST_CLI_DEFINE(handle_show_calendar, "Display information about a calendar"),
  1421. AST_CLI_DEFINE(handle_show_calendars, "Show registered calendars"),
  1422. AST_CLI_DEFINE(handle_dump_sched, "Dump calendar sched context"),
  1423. AST_CLI_DEFINE(handle_show_calendars_types, "Show all calendar types loaded"),
  1424. };
  1425. static int calendar_event_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
  1426. {
  1427. struct ast_datastore *datastore;
  1428. struct ast_calendar_event *event;
  1429. if (!chan) {
  1430. ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
  1431. return -1;
  1432. }
  1433. if (ast_strlen_zero(data)) {
  1434. ast_log(LOG_WARNING, "%s requires an argument\n", cmd);
  1435. return -1;
  1436. }
  1437. ast_channel_lock(chan);
  1438. if (!(datastore = ast_channel_datastore_find(chan, &event_notification_datastore, NULL))) {
  1439. ast_log(LOG_WARNING, "There is no event notification datastore on '%s'!\n", ast_channel_name(chan));
  1440. ast_channel_unlock(chan);
  1441. return -1;
  1442. }
  1443. ast_channel_unlock(chan);
  1444. if (!(event = datastore->data)) {
  1445. ast_log(LOG_WARNING, "The datastore contains no data!\n");
  1446. return -1;
  1447. }
  1448. if (!strcasecmp(data, "summary")) {
  1449. ast_copy_string(buf, event->summary, len);
  1450. } else if (!strcasecmp(data, "description")) {
  1451. ast_copy_string(buf, event->description, len);
  1452. } else if (!strcasecmp(data, "organizer")) {
  1453. ast_copy_string(buf, event->organizer, len);
  1454. } else if (!strcasecmp(data, "location")) {
  1455. ast_copy_string(buf, event->location, len);
  1456. } else if (!strcasecmp(data, "categories")) {
  1457. ast_copy_string(buf, event->categories, len);
  1458. } else if (!strcasecmp(data, "priority")) {
  1459. snprintf(buf, len, "%d", event->priority);
  1460. } else if (!strcasecmp(data, "calendar")) {
  1461. ast_copy_string(buf, event->owner->name, len);
  1462. } else if (!strcasecmp(data, "uid")) {
  1463. ast_copy_string(buf, event->uid, len);
  1464. } else if (!strcasecmp(data, "start")) {
  1465. snprintf(buf, len, "%ld", (long)event->start);
  1466. } else if (!strcasecmp(data, "end")) {
  1467. snprintf(buf, len, "%ld", (long)event->end);
  1468. } else if (!strcasecmp(data, "busystate")) {
  1469. snprintf(buf, len, "%u", event->busy_state);
  1470. } else if (!strcasecmp(data, "attendees")) {
  1471. calendar_join_attendees(event, buf, len);
  1472. }
  1473. return 0;
  1474. }
  1475. static struct ast_custom_function calendar_event_function = {
  1476. .name = "CALENDAR_EVENT",
  1477. .read = calendar_event_read,
  1478. };
  1479. static int reload(void)
  1480. {
  1481. struct ast_calendar_tech *iter;
  1482. ast_mutex_lock(&reloadlock);
  1483. /* Delete all of the calendars */
  1484. ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
  1485. /* Load configuration */
  1486. load_config(1);
  1487. AST_LIST_LOCK(&techs);
  1488. AST_LIST_TRAVERSE(&techs, iter, list) {
  1489. if (load_tech_calendars(iter)) {
  1490. ast_log(LOG_WARNING, "Failed to reload %s calendars, module disabled\n", iter->type);
  1491. }
  1492. }
  1493. AST_LIST_UNLOCK(&techs);
  1494. ast_mutex_unlock(&reloadlock);
  1495. return 0;
  1496. }
  1497. static void *do_refresh(void *data)
  1498. {
  1499. for (;;) {
  1500. struct timeval now = ast_tvnow();
  1501. struct timespec ts = {0,};
  1502. int wait;
  1503. ast_mutex_lock(&refreshlock);
  1504. while (!module_unloading) {
  1505. if ((wait = ast_sched_wait(sched)) < 0) {
  1506. wait = 1000;
  1507. }
  1508. ts.tv_sec = (now.tv_sec + wait / 1000) + 1;
  1509. if (ast_cond_timedwait(&refresh_condition, &refreshlock, &ts) == ETIMEDOUT) {
  1510. break;
  1511. }
  1512. }
  1513. ast_mutex_unlock(&refreshlock);
  1514. if (module_unloading) {
  1515. break;
  1516. }
  1517. ast_sched_runq(sched);
  1518. }
  1519. return NULL;
  1520. }
  1521. /* If I were to allow unloading it would look something like this */
  1522. static int unload_module(void)
  1523. {
  1524. struct ast_calendar_tech *tech;
  1525. ast_devstate_prov_del("calendar");
  1526. ast_custom_function_unregister(&calendar_busy_function);
  1527. ast_custom_function_unregister(&calendar_event_function);
  1528. ast_custom_function_unregister(&calendar_query_function);
  1529. ast_custom_function_unregister(&calendar_query_result_function);
  1530. ast_custom_function_unregister(&calendar_write_function);
  1531. ast_cli_unregister_multiple(calendar_cli, ARRAY_LEN(calendar_cli));
  1532. /* Remove all calendars */
  1533. ao2_callback(calendars, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
  1534. ao2_cleanup(calendars);
  1535. calendars = NULL;
  1536. ast_mutex_lock(&refreshlock);
  1537. module_unloading = 1;
  1538. ast_cond_signal(&refresh_condition);
  1539. ast_mutex_unlock(&refreshlock);
  1540. pthread_join(refresh_thread, NULL);
  1541. ast_sched_context_destroy(sched);
  1542. AST_LIST_LOCK(&techs);
  1543. AST_LIST_TRAVERSE_SAFE_BEGIN(&techs, tech, list) {
  1544. ast_unload_resource(tech->module, 0);
  1545. }
  1546. AST_LIST_TRAVERSE_SAFE_END;
  1547. AST_LIST_UNLOCK(&techs);
  1548. ast_config_destroy(calendar_config);
  1549. calendar_config = NULL;
  1550. return 0;
  1551. }
  1552. /*!
  1553. * \brief Load the module
  1554. *
  1555. * Module loading including tests for configuration or dependencies.
  1556. * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
  1557. * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
  1558. * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
  1559. * configuration file or other non-critical problem return
  1560. * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
  1561. */
  1562. static int load_module(void)
  1563. {
  1564. calendars = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, CALENDAR_BUCKETS,
  1565. calendar_hash_fn, NULL, calendar_cmp_fn);
  1566. if (!calendars) {
  1567. ast_log(LOG_ERROR, "Unable to allocate calendars container!\n");
  1568. return AST_MODULE_LOAD_DECLINE;
  1569. }
  1570. if (load_config(0)) {
  1571. /* We don't have calendar support enabled */
  1572. return AST_MODULE_LOAD_DECLINE;
  1573. }
  1574. ast_mutex_init(&refreshlock);
  1575. ast_cond_init(&refresh_condition, NULL);
  1576. ast_mutex_init(&reloadlock);
  1577. if (!(sched = ast_sched_context_create())) {
  1578. ast_log(LOG_ERROR, "Unable to create sched context\n");
  1579. ast_config_destroy(calendar_config);
  1580. calendar_config = NULL;
  1581. return AST_MODULE_LOAD_DECLINE;
  1582. }
  1583. if (ast_pthread_create_background(&refresh_thread, NULL, do_refresh, NULL) < 0) {
  1584. ast_log(LOG_ERROR, "Unable to start refresh thread--notifications disabled!\n");
  1585. }
  1586. ast_custom_function_register(&calendar_busy_function);
  1587. ast_custom_function_register(&calendar_event_function);
  1588. ast_custom_function_register(&calendar_query_function);
  1589. ast_custom_function_register(&calendar_query_result_function);
  1590. ast_custom_function_register(&calendar_write_function);
  1591. ast_cli_register_multiple(calendar_cli, ARRAY_LEN(calendar_cli));
  1592. ast_devstate_prov_add("Calendar", calendarstate);
  1593. return AST_MODULE_LOAD_SUCCESS;
  1594. }
  1595. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Asterisk Calendar integration",
  1596. .support_level = AST_MODULE_SUPPORT_CORE,
  1597. .load = load_module,
  1598. .unload = unload_module,
  1599. .reload = reload,
  1600. .load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
  1601. );