Add some asserts that were handy when looking for a stasis cache problem.
[asterisk/asterisk.git] / res / res_musiconhold.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2010, Digium, Inc.
5  *
6  * Mark Spencer <markster@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  *
21  * \brief Routines implementing music on hold
22  * 
23  * \author Mark Spencer <markster@digium.com>
24  */
25
26 /*! \li \ref res_musiconhold.c uses the configuration file \ref musiconhold.conf
27  * \addtogroup configuration_file Configuration Files
28  */
29
30 /*! 
31  * \page musiconhold.conf musiconhold.conf
32  * \verbinclude musiconhold.conf.sample
33  */
34
35 /*** MODULEINFO
36         <conflict>win32</conflict>
37         <support_level>core</support_level>
38  ***/
39
40 #include "asterisk.h"
41
42 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
43
44 #include <ctype.h>
45 #include <signal.h>
46 #include <sys/time.h>
47 #include <sys/signal.h>
48 #include <netinet/in.h>
49 #include <sys/stat.h>
50 #include <dirent.h>
51
52 #ifdef SOLARIS
53 #include <thread.h>
54 #endif
55
56 #include "asterisk/lock.h"
57 #include "asterisk/file.h"
58 #include "asterisk/channel.h"
59 #include "asterisk/pbx.h"
60 #include "asterisk/app.h"
61 #include "asterisk/module.h"
62 #include "asterisk/translate.h"
63 #include "asterisk/say.h"
64 #include "asterisk/musiconhold.h"
65 #include "asterisk/config.h"
66 #include "asterisk/utils.h"
67 #include "asterisk/cli.h"
68 #include "asterisk/stringfields.h"
69 #include "asterisk/linkedlists.h"
70 #include "asterisk/stasis.h"
71 #include "asterisk/stasis_channels.h"
72 #include "asterisk/paths.h"
73 #include "asterisk/astobj2.h"
74 #include "asterisk/timing.h"
75 #include "asterisk/time.h"
76 #include "asterisk/poll-compat.h"
77
78 #define INITIAL_NUM_FILES   8
79 #define HANDLE_REF      1
80 #define DONT_UNREF      0
81
82 /*** DOCUMENTATION
83         <application name="MusicOnHold" language="en_US">
84                 <synopsis>
85                         Play Music On Hold indefinitely.
86                 </synopsis>
87                 <syntax>
88                         <parameter name="class" required="true" />
89                         <parameter name="duration" />
90                 </syntax>
91                 <description>
92                         <para>Plays hold music specified by class. If omitted, the default music
93                         source for the channel will be used. Change the default class with
94                         Set(CHANNEL(musicclass)=...). If duration is given, hold music will be played
95                         specified number of seconds. If duration is ommited, music plays indefinitely.
96                         Returns <literal>0</literal> when done, <literal>-1</literal> on hangup.</para>
97                         <para>This application does not automatically answer and should be preceeded by
98                         an application such as Answer() or Progress().</para>
99                 </description>
100         </application>
101         <application name="WaitMusicOnHold" language="en_US">
102                 <synopsis>
103                         Wait, playing Music On Hold.
104                 </synopsis>
105                 <syntax>
106                         <parameter name="delay" required="true" />
107                 </syntax>
108                 <description>
109                         <para> !!! DEPRECATED. Use MusicOnHold instead !!!</para>
110                         <para>Plays hold music specified number of seconds. Returns <literal>0</literal> when done,
111                         or <literal>-1</literal> on hangup. If no hold music is available, the delay will still occur
112                         with no sound.</para>
113                         <para> !!! DEPRECATED. Use MusicOnHold instead !!!</para>
114                 </description>
115         </application>
116         <application name="SetMusicOnHold" language="en_US">
117                 <synopsis>
118                         Set default Music On Hold class.
119                 </synopsis>
120                 <syntax>
121                         <parameter name="class" required="yes" />
122                 </syntax>
123                 <description>
124                         <para>!!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!</para>
125                         <para>Sets the default class for music on hold for a given channel.
126                         When music on hold is activated, this class will be used to select which
127                         music is played.</para>
128                         <para>!!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!</para>
129                 </description>
130         </application>
131         <application name="StartMusicOnHold" language="en_US">
132                 <synopsis>
133                         Play Music On Hold.
134                 </synopsis>
135                 <syntax>
136                         <parameter name="class" required="true" />
137                 </syntax>
138                 <description>
139                         <para>Starts playing music on hold, uses default music class for channel.
140                         Starts playing music specified by class. If omitted, the default music
141                         source for the channel will be used. Always returns <literal>0</literal>.</para>
142                 </description>
143         </application>
144         <application name="StopMusicOnHold" language="en_US">
145                 <synopsis>
146                         Stop playing Music On Hold.
147                 </synopsis>
148                 <syntax />
149                 <description>
150                         <para>Stops playing music on hold.</para>
151                 </description>
152         </application>
153  ***/
154
155 static const char play_moh[] = "MusicOnHold";
156 static const char wait_moh[] = "WaitMusicOnHold";
157 static const char set_moh[] = "SetMusicOnHold";
158 static const char start_moh[] = "StartMusicOnHold";
159 static const char stop_moh[] = "StopMusicOnHold";
160
161 static int respawn_time = 20;
162
163 struct moh_files_state {
164         /*! Holds a reference to the MOH class. */
165         struct mohclass *class;
166         char name[MAX_MUSICCLASS];
167         struct ast_format origwfmt;
168         struct ast_format mohwfmt;
169         int announcement;
170         int samples;
171         int sample_queue;
172         int pos;
173         int save_pos;
174         int save_total;
175         char save_pos_filename[PATH_MAX];
176 };
177
178 #define MOH_QUIET               (1 << 0)
179 #define MOH_SINGLE              (1 << 1)
180 #define MOH_CUSTOM              (1 << 2)
181 #define MOH_RANDOMIZE           (1 << 3)
182 #define MOH_SORTALPHA           (1 << 4)
183
184 #define MOH_CACHERTCLASSES      (1 << 5)        /*!< Should we use a separate instance of MOH for each user or not */
185 #define MOH_ANNOUNCEMENT        (1 << 6)                        /*!< Do we play announcement files between songs on this channel? */
186
187 /* Custom astobj2 flag */
188 #define MOH_NOTDELETED          (1 << 30)       /*!< Find only records that aren't deleted? */
189
190 static struct ast_flags global_flags[1] = {{0}};        /*!< global MOH_ flags */
191
192 struct mohclass {
193         char name[MAX_MUSICCLASS];
194         char dir[256];
195         char args[256];
196         char announcement[256];
197         char mode[80];
198         char digit;
199         /*! A dynamically sized array to hold the list of filenames in "files" mode */
200         char **filearray;
201         /*! The current size of the filearray */
202         int allowed_files;
203         /*! The current number of files loaded into the filearray */
204         int total_files;
205         unsigned int flags;
206         /*! The format from the MOH source, not applicable to "files" mode */
207         struct ast_format format;
208         /*! The pid of the external application delivering MOH */
209         int pid;
210         time_t start;
211         pthread_t thread;
212         /*! Source of audio */
213         int srcfd;
214         /*! Generic timer */
215         struct ast_timer *timer;
216         /*! Created on the fly, from RT engine */
217         unsigned int realtime:1;
218         unsigned int delete:1;
219         AST_LIST_HEAD_NOLOCK(, mohdata) members;
220         AST_LIST_ENTRY(mohclass) list;
221 };
222
223 struct mohdata {
224         int pipe[2];
225         struct ast_format origwfmt;
226         struct mohclass *parent;
227         struct ast_frame f;
228         AST_LIST_ENTRY(mohdata) list;
229 };
230
231 static struct ao2_container *mohclasses;
232
233 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
234 #define MPG_123 "/usr/bin/mpg123"
235 #define MAX_MP3S 256
236
237 static int reload(void);
238
239 #define mohclass_ref(class,string)   (ao2_t_ref((class), +1, (string)), class)
240
241 #ifndef REF_DEBUG
242 #define mohclass_unref(class,string) (ao2_t_ref((class), -1, (string)), (struct mohclass *) NULL)
243 #else
244 #define mohclass_unref(class,string) _mohclass_unref(class, string, __FILE__,__LINE__,__PRETTY_FUNCTION__)
245 static struct mohclass *_mohclass_unref(struct mohclass *class, const char *tag, const char *file, int line, const char *funcname)
246 {
247         struct mohclass *dup;
248         if ((dup = ao2_find(mohclasses, class, OBJ_POINTER))) {
249                 if (__ao2_ref_debug(dup, -1, (char *) tag, (char *) file, line, funcname) == 2) {
250                         FILE *ref = fopen("/tmp/refs", "a");
251                         if (ref) {
252                                 fprintf(ref, "%p =1   %s:%d:%s (%s) BAD ATTEMPT!\n", class, file, line, funcname, tag);
253                                 fclose(ref);
254                         }
255                         ast_log(LOG_WARNING, "Attempt to unref mohclass %p (%s) when only 1 ref remained, and class is still in a container! (at %s:%d (%s))\n",
256                                 class, class->name, file, line, funcname);
257                 } else {
258                         ao2_ref(class, -1);
259                 }
260         } else {
261                 ao2_t_ref(class, -1, (char *) tag);
262         }
263         return NULL;
264 }
265 #endif
266
267 static void moh_post_start(struct ast_channel *chan, const char *moh_class_name)
268 {
269         struct stasis_message *message;
270         struct ast_json *json_object;
271
272         ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n",
273                 moh_class_name, ast_channel_name(chan));
274
275         json_object = ast_json_pack("{s: s}", "class", moh_class_name);
276         if (!json_object) {
277                 return;
278         }
279
280         message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
281                 ast_channel_moh_start_type(), json_object);
282         if (message) {
283                 /* A channel snapshot must have been in the cache. */
284                 ast_assert(((struct ast_channel_blob *) stasis_message_data(message))->snapshot != NULL);
285
286                 stasis_publish(ast_channel_topic(chan), message);
287         }
288         ao2_cleanup(message);
289         ast_json_unref(json_object);
290 }
291
292 static void moh_post_stop(struct ast_channel *chan)
293 {
294         struct stasis_message *message;
295
296         ast_verb(3, "Stopped music on hold on %s\n", ast_channel_name(chan));
297
298         message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
299                 ast_channel_moh_stop_type(), NULL);
300         if (message) {
301                 /* A channel snapshot must have been in the cache. */
302                 ast_assert(((struct ast_channel_blob *) stasis_message_data(message))->snapshot != NULL);
303
304                 stasis_publish(ast_channel_topic(chan), message);
305         }
306         ao2_cleanup(message);
307 }
308
309 static void moh_files_release(struct ast_channel *chan, void *data)
310 {
311         struct moh_files_state *state;
312
313         if (!chan || !ast_channel_music_state(chan)) {
314                 return;
315         }
316
317         state = ast_channel_music_state(chan);
318
319         if (ast_channel_stream(chan)) {
320                 ast_closestream(ast_channel_stream(chan));
321                 ast_channel_stream_set(chan, NULL);
322         }
323
324         moh_post_stop(chan);
325
326         ast_format_clear(&state->mohwfmt); /* make sure to clear this format before restoring the original format. */
327         if (state->origwfmt.id && ast_set_write_format(chan, &state->origwfmt)) {
328                 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%s'\n", ast_channel_name(chan), ast_getformatname(&state->origwfmt));
329         }
330
331         state->save_pos = state->pos;
332         state->announcement = 0;
333
334         state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator");
335 }
336
337 static int ast_moh_files_next(struct ast_channel *chan) 
338 {
339         struct moh_files_state *state = ast_channel_music_state(chan);
340         int tries;
341
342         /* Discontinue a stream if it is running already */
343         if (ast_channel_stream(chan)) {
344                 ast_closestream(ast_channel_stream(chan));
345                 ast_channel_stream_set(chan, NULL);
346         }
347
348         if (ast_test_flag(state->class, MOH_ANNOUNCEMENT) && state->announcement == 0) {
349                 state->announcement = 1;
350                 if (ast_openstream_full(chan, state->class->announcement, ast_channel_language(chan), 1)) {
351                         ast_debug(1, "%s Opened announcement '%s'\n", ast_channel_name(chan), state->class->announcement);
352                         return 0;
353                 }
354         } else {
355                 state->announcement = 0;
356         }
357
358         if (!state->class->total_files) {
359                 ast_log(LOG_WARNING, "No files available for class '%s'\n", state->class->name);
360                 return -1;
361         }
362
363         if (state->pos == 0 && ast_strlen_zero(state->save_pos_filename)) {
364                 /* First time so lets play the file. */
365                 state->save_pos = -1;
366         } else if (state->save_pos >= 0 && state->save_pos < state->class->total_files && !strcmp(state->class->filearray[state->save_pos], state->save_pos_filename)) {
367                 /* If a specific file has been saved confirm it still exists and that it is still valid */
368                 state->pos = state->save_pos;
369                 state->save_pos = -1;
370         } else if (ast_test_flag(state->class, MOH_RANDOMIZE)) {
371                 /* Get a random file and ensure we can open it */
372                 for (tries = 0; tries < 20; tries++) {
373                         state->pos = ast_random() % state->class->total_files;
374                         if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0) {
375                                 break;
376                         }
377                 }
378                 state->save_pos = -1;
379                 state->samples = 0;
380         } else {
381                 /* This is easy, just increment our position and make sure we don't exceed the total file count */
382                 state->pos++;
383                 state->pos %= state->class->total_files;
384                 state->save_pos = -1;
385                 state->samples = 0;
386         }
387
388         for (tries = 0; tries < state->class->total_files; ++tries) {
389                 if (ast_openstream_full(chan, state->class->filearray[state->pos], ast_channel_language(chan), 1)) {
390                         break;
391                 }
392
393                 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
394                 state->pos++;
395                 state->pos %= state->class->total_files;
396         }
397
398         if (tries == state->class->total_files) {
399                 return -1;
400         }
401
402         /* Record the pointer to the filename for position resuming later */
403         ast_copy_string(state->save_pos_filename, state->class->filearray[state->pos], sizeof(state->save_pos_filename));
404
405         ast_debug(1, "%s Opened file %d '%s'\n", ast_channel_name(chan), state->pos, state->class->filearray[state->pos]);
406
407         if (state->samples) {
408                 size_t loc;
409                 /* seek *SHOULD* be good since it's from a known location */
410                 ast_seekstream(ast_channel_stream(chan), state->samples, SEEK_SET);
411                 /* if the seek failed then recover because if there is not a valid read,
412                  * moh_files_generate will return -1 and MOH will stop */
413                 loc = ast_tellstream(ast_channel_stream(chan));
414                 if (state->samples > loc && loc) {
415                         /* seek one sample from the end for one guaranteed valid read */
416                         ast_seekstream(ast_channel_stream(chan), 1, SEEK_END);
417                 }
418         }
419
420         return 0;
421 }
422
423 static struct ast_frame *moh_files_readframe(struct ast_channel *chan)
424 {
425         struct ast_frame *f = NULL;
426
427         if (!(ast_channel_stream(chan) && (f = ast_readframe(ast_channel_stream(chan))))) {
428                 if (!ast_moh_files_next(chan))
429                         f = ast_readframe(ast_channel_stream(chan));
430         }
431
432         return f;
433 }
434
435 static void moh_files_write_format_change(struct ast_channel *chan, void *data)
436 {
437         struct moh_files_state *state = ast_channel_music_state(chan);
438
439         /* In order to prevent a recursive call to this function as a result
440          * of setting the moh write format back on the channel. Clear
441          * the moh write format before setting the write format on the channel.*/
442         if (&state->origwfmt.id) {
443                 struct ast_format tmp;
444
445                 ast_format_copy(&tmp, ast_channel_writeformat(chan));
446                 if (state->mohwfmt.id) {
447                         ast_format_clear(&state->origwfmt);
448                         ast_set_write_format(chan, &state->mohwfmt);
449                 }
450                 ast_format_copy(&state->origwfmt, &tmp);
451         }
452 }
453
454 static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples)
455 {
456         struct moh_files_state *state = ast_channel_music_state(chan);
457         struct ast_frame *f = NULL;
458         int res = 0;
459
460         state->sample_queue += samples;
461
462         while (state->sample_queue > 0) {
463                 ast_channel_lock(chan);
464                 if ((f = moh_files_readframe(chan))) {
465                         /* We need to be sure that we unlock
466                          * the channel prior to calling
467                          * ast_write. Otherwise, the recursive locking
468                          * that occurs can cause deadlocks when using
469                          * indirect channels, like local channels
470                          */
471                         ast_channel_unlock(chan);
472                         state->samples += f->samples;
473                         state->sample_queue -= f->samples;
474                         if (ast_format_cmp(&f->subclass.format, &state->mohwfmt) == AST_FORMAT_CMP_NOT_EQUAL) {
475                                 ast_format_copy(&state->mohwfmt, &f->subclass.format);
476                         }
477                         res = ast_write(chan, f);
478                         ast_frfree(f);
479                         if (res < 0) {
480                                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
481                                 return -1;
482                         }
483                 } else {
484                         ast_channel_unlock(chan);
485                         return -1;      
486                 }
487         }
488         return res;
489 }
490
491 static void *moh_files_alloc(struct ast_channel *chan, void *params)
492 {
493         struct moh_files_state *state;
494         struct mohclass *class = params;
495
496         state = ast_channel_music_state(chan);
497         if (!state && (state = ast_calloc(1, sizeof(*state)))) {
498                 ast_channel_music_state_set(chan, state);
499                 ast_module_ref(ast_module_info->self);
500         } else {
501                 if (!state) {
502                         return NULL;
503                 }
504                 if (state->class) {
505                         mohclass_unref(state->class, "Uh Oh. Restarting MOH with an active class");
506                         ast_log(LOG_WARNING, "Uh Oh. Restarting MOH with an active class\n");
507                 }
508         }
509
510         /* LOGIC: Comparing an unrefcounted pointer is a really bad idea, because
511          * malloc may allocate a different class to the same memory block.  This
512          * might only happen when two reloads are generated in a short period of
513          * time, but it's still important to protect against.
514          * PROG: Compare the quick operation first, to save CPU. */
515         if (state->save_total != class->total_files || strcmp(state->name, class->name) != 0) {
516                 memset(state, 0, sizeof(*state));
517                 if (ast_test_flag(class, MOH_RANDOMIZE) && class->total_files) {
518                         state->pos = ast_random() % class->total_files;
519                 }
520         }
521
522         state->class = mohclass_ref(class, "Reffing music class for channel");
523         ast_format_copy(&state->origwfmt, ast_channel_writeformat(chan));
524         ast_format_copy(&state->mohwfmt, ast_channel_writeformat(chan));
525
526         /* For comparison on restart of MOH (see above) */
527         ast_copy_string(state->name, class->name, sizeof(state->name));
528         state->save_total = class->total_files;
529
530         moh_post_start(chan, class->name);
531
532         return state;
533 }
534
535 static int moh_digit_match(void *obj, void *arg, int flags)
536 {
537         char *digit = arg;
538         struct mohclass *class = obj;
539
540         return (*digit == class->digit) ? CMP_MATCH | CMP_STOP : 0;
541 }
542
543 /*! \note This function should be called with the mohclasses list locked */
544 static struct mohclass *get_mohbydigit(char digit)
545 {
546         return ao2_t_callback(mohclasses, 0, moh_digit_match, &digit, "digit callback");
547 }
548
549 static void moh_handle_digit(struct ast_channel *chan, char digit)
550 {
551         struct mohclass *class;
552         const char *classname = NULL;
553
554         if ((class = get_mohbydigit(digit))) {
555                 classname = ast_strdupa(class->name);
556                 class = mohclass_unref(class, "Unreffing ao2_find from finding by digit");
557                 ast_channel_musicclass_set(chan, classname);
558                 ast_moh_stop(chan);
559                 ast_moh_start(chan, classname, NULL);
560         }
561 }
562
563 static struct ast_generator moh_file_stream = {
564         .alloc    = moh_files_alloc,
565         .release  = moh_files_release,
566         .generate = moh_files_generator,
567         .digit    = moh_handle_digit,
568         .write_format_change = moh_files_write_format_change,
569 };
570
571 static int spawn_mp3(struct mohclass *class)
572 {
573         int fds[2];
574         int files = 0;
575         char fns[MAX_MP3S][80];
576         char *argv[MAX_MP3S + 50];
577         char xargs[256];
578         char *argptr;
579         int argc = 0;
580         DIR *dir = NULL;
581         struct dirent *de;
582
583         
584         if (!strcasecmp(class->dir, "nodir")) {
585                 files = 1;
586         } else {
587                 dir = opendir(class->dir);
588                 if (!dir && strncasecmp(class->dir, "http://", 7)) {
589                         ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
590                         return -1;
591                 }
592         }
593
594         if (!ast_test_flag(class, MOH_CUSTOM)) {
595                 argv[argc++] = "mpg123";
596                 argv[argc++] = "-q";
597                 argv[argc++] = "-s";
598                 argv[argc++] = "--mono";
599                 argv[argc++] = "-r";
600                 argv[argc++] = "8000";
601                 
602                 if (!ast_test_flag(class, MOH_SINGLE)) {
603                         argv[argc++] = "-b";
604                         argv[argc++] = "2048";
605                 }
606                 
607                 argv[argc++] = "-f";
608                 
609                 if (ast_test_flag(class, MOH_QUIET))
610                         argv[argc++] = "4096";
611                 else
612                         argv[argc++] = "8192";
613                 
614                 /* Look for extra arguments and add them to the list */
615                 ast_copy_string(xargs, class->args, sizeof(xargs));
616                 argptr = xargs;
617                 while (!ast_strlen_zero(argptr)) {
618                         argv[argc++] = argptr;
619                         strsep(&argptr, ",");
620                 }
621         } else  {
622                 /* Format arguments for argv vector */
623                 ast_copy_string(xargs, class->args, sizeof(xargs));
624                 argptr = xargs;
625                 while (!ast_strlen_zero(argptr)) {
626                         argv[argc++] = argptr;
627                         strsep(&argptr, " ");
628                 }
629         }
630
631         if (!strncasecmp(class->dir, "http://", 7)) {
632                 ast_copy_string(fns[files], class->dir, sizeof(fns[files]));
633                 argv[argc++] = fns[files];
634                 files++;
635         } else if (dir) {
636                 while ((de = readdir(dir)) && (files < MAX_MP3S)) {
637                         if ((strlen(de->d_name) > 3) && 
638                             ((ast_test_flag(class, MOH_CUSTOM) && 
639                               (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 
640                                !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
641                              !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
642                                 ast_copy_string(fns[files], de->d_name, sizeof(fns[files]));
643                                 argv[argc++] = fns[files];
644                                 files++;
645                         }
646                 }
647         }
648         argv[argc] = NULL;
649         if (dir) {
650                 closedir(dir);
651         }
652         if (pipe(fds)) {        
653                 ast_log(LOG_WARNING, "Pipe failed\n");
654                 return -1;
655         }
656         if (!files) {
657                 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
658                 close(fds[0]);
659                 close(fds[1]);
660                 return -1;
661         }
662         if (!strncasecmp(class->dir, "http://", 7) && time(NULL) - class->start < respawn_time) {
663                 sleep(respawn_time - (time(NULL) - class->start));
664         }
665
666         time(&class->start);
667         class->pid = ast_safe_fork(0);
668         if (class->pid < 0) {
669                 close(fds[0]);
670                 close(fds[1]);
671                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
672                 return -1;
673         }
674         if (!class->pid) {
675                 if (ast_opt_high_priority)
676                         ast_set_priority(0);
677
678                 close(fds[0]);
679                 /* Stdout goes to pipe */
680                 dup2(fds[1], STDOUT_FILENO);
681
682                 /* Close everything else */
683                 ast_close_fds_above_n(STDERR_FILENO);
684
685                 /* Child */
686                 if (strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir") && chdir(class->dir) < 0) {
687                         ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
688                         _exit(1);
689                 }
690                 setpgid(0, getpid());
691                 if (ast_test_flag(class, MOH_CUSTOM)) {
692                         execv(argv[0], argv);
693                 } else {
694                         /* Default install is /usr/local/bin */
695                         execv(LOCAL_MPG_123, argv);
696                         /* Many places have it in /usr/bin */
697                         execv(MPG_123, argv);
698                         /* Check PATH as a last-ditch effort */
699                         execvp("mpg123", argv);
700                 }
701                 /* Can't use logger, since log FDs are closed */
702                 fprintf(stderr, "MOH: exec failed: %s\n", strerror(errno));
703                 close(fds[1]);
704                 _exit(1);
705         } else {
706                 /* Parent */
707                 close(fds[1]);
708         }
709         return fds[0];
710 }
711
712 static void *monmp3thread(void *data)
713 {
714 #define MOH_MS_INTERVAL         100
715
716         struct mohclass *class = data;
717         struct mohdata *moh;
718         short sbuf[8192];
719         int res = 0, res2;
720         int len;
721         struct timeval deadline, tv_tmp;
722
723         deadline.tv_sec = 0;
724         deadline.tv_usec = 0;
725         for(;/* ever */;) {
726                 pthread_testcancel();
727                 /* Spawn mp3 player if it's not there */
728                 if (class->srcfd < 0) {
729                         if ((class->srcfd = spawn_mp3(class)) < 0) {
730                                 ast_log(LOG_WARNING, "Unable to spawn mp3player\n");
731                                 /* Try again later */
732                                 sleep(500);
733                                 continue;
734                         }
735                 }
736                 if (class->timer) {
737                         struct pollfd pfd = { .fd = ast_timer_fd(class->timer), .events = POLLIN | POLLPRI, };
738
739 #ifdef SOLARIS
740                         thr_yield();
741 #endif
742                         /* Pause some amount of time */
743                         if (ast_poll(&pfd, 1, -1) > 0) {
744                                 if (ast_timer_ack(class->timer, 1) < 0) {
745                                         ast_log(LOG_ERROR, "Failed to acknowledge timer for mp3player\n");
746                                         return NULL;
747                                 }
748                                 /* 25 samples per second => 40ms framerate => 320 samples */
749                                 res = 320; /* 320/40 = 8 samples/ms */
750                         } else {
751                                 ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno));
752                                 res = 0;
753                         }
754                         pthread_testcancel();
755                 } else {
756                         long delta;
757                         /* Reliable sleep */
758                         tv_tmp = ast_tvnow();
759                         if (ast_tvzero(deadline))
760                                 deadline = tv_tmp;
761                         delta = ast_tvdiff_ms(tv_tmp, deadline);
762                         if (delta < MOH_MS_INTERVAL) {  /* too early */
763                                 deadline = ast_tvadd(deadline, ast_samp2tv(MOH_MS_INTERVAL, 1000));     /* next deadline */
764                                 usleep(1000 * (MOH_MS_INTERVAL - delta));
765                                 pthread_testcancel();
766                         } else {
767                                 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
768                                 deadline = tv_tmp;
769                         }
770                         /* 10 samples per second (MOH_MS_INTERVAL) => 100ms framerate => 800 samples */
771                         res = 8 * MOH_MS_INTERVAL; /* 800/100 = 8 samples/ms */
772                 }
773                 /* For non-8000Hz formats, we need to alter the resolution */
774                 res = res * ast_format_rate(&class->format) / 8000;
775
776                 if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members))
777                         continue;
778                 /* Read mp3 audio */
779                 len = ast_codec_get_len(&class->format, res);
780
781                 if ((res2 = read(class->srcfd, sbuf, len)) != len) {
782                         if (!res2) {
783                                 close(class->srcfd);
784                                 class->srcfd = -1;
785                                 pthread_testcancel();
786                                 if (class->pid > 1) {
787                                         do {
788                                                 if (killpg(class->pid, SIGHUP) < 0) {
789                                                         if (errno == ESRCH) {
790                                                                 break;
791                                                         }
792                                                         ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno));
793                                                 }
794                                                 usleep(100000);
795                                                 if (killpg(class->pid, SIGTERM) < 0) {
796                                                         if (errno == ESRCH) {
797                                                                 break;
798                                                         }
799                                                         ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno));
800                                                 }
801                                                 usleep(100000);
802                                                 if (killpg(class->pid, SIGKILL) < 0) {
803                                                         if (errno == ESRCH) {
804                                                                 break;
805                                                         }
806                                                         ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno));
807                                                 }
808                                         } while (0);
809                                         class->pid = 0;
810                                 }
811                         } else {
812                                 ast_debug(1, "Read %d bytes of audio while expecting %d\n", res2, len);
813                         }
814                         continue;
815                 }
816
817                 pthread_testcancel();
818
819                 ao2_lock(class);
820                 AST_LIST_TRAVERSE(&class->members, moh, list) {
821                         /* Write data */
822                         if ((res = write(moh->pipe[1], sbuf, res2)) != res2) {
823                                 ast_debug(1, "Only wrote %d of %d bytes to pipe\n", res, res2);
824                         }
825                 }
826                 ao2_unlock(class);
827         }
828         return NULL;
829 }
830
831 static int play_moh_exec(struct ast_channel *chan, const char *data)
832 {
833         char *parse;
834         char *class;
835         int timeout = -1;
836         int res;
837         AST_DECLARE_APP_ARGS(args,
838                 AST_APP_ARG(class);
839                 AST_APP_ARG(duration);
840         );
841
842         parse = ast_strdupa(data);
843
844         AST_STANDARD_APP_ARGS(args, parse);
845
846         if (!ast_strlen_zero(args.duration)) {
847                 if (sscanf(args.duration, "%30d", &timeout) == 1) {
848                         timeout *= 1000;
849                 } else {
850                         ast_log(LOG_WARNING, "Invalid MusicOnHold duration '%s'. Will wait indefinitely.\n", args.duration);
851                 }
852         }
853
854         class = S_OR(args.class, NULL);
855         if (ast_moh_start(chan, class, NULL)) {
856                 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, ast_channel_name(chan));
857                 return 0;
858         }
859
860         if (timeout > 0)
861                 res = ast_safe_sleep(chan, timeout);
862         else {
863                 while (!(res = ast_safe_sleep(chan, 10000)));
864         }
865
866         ast_moh_stop(chan);
867
868         return res;
869 }
870
871 static int wait_moh_exec(struct ast_channel *chan, const char *data)
872 {
873         static int deprecation_warning = 0;
874         int res;
875
876         if (!deprecation_warning) {
877                 deprecation_warning = 1;
878                 ast_log(LOG_WARNING, "WaitMusicOnHold application is deprecated and will be removed. Use MusicOnHold with duration parameter instead\n");
879         }
880
881         if (!data || !atoi(data)) {
882                 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
883                 return -1;
884         }
885         if (ast_moh_start(chan, NULL, NULL)) {
886                 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), ast_channel_name(chan));
887                 return 0;
888         }
889         res = ast_safe_sleep(chan, atoi(data) * 1000);
890         ast_moh_stop(chan);
891         return res;
892 }
893
894 static int set_moh_exec(struct ast_channel *chan, const char *data)
895 {
896         static int deprecation_warning = 0;
897
898         if (!deprecation_warning) {
899                 deprecation_warning = 1;
900                 ast_log(LOG_WARNING, "SetMusicOnHold application is deprecated and will be removed. Use Set(CHANNEL(musicclass)=...) instead\n");
901         }
902
903         if (ast_strlen_zero(data)) {
904                 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
905                 return -1;
906         }
907         ast_channel_musicclass_set(chan, data);
908         return 0;
909 }
910
911 static int start_moh_exec(struct ast_channel *chan, const char *data)
912 {
913         char *parse;
914         char *class;
915         AST_DECLARE_APP_ARGS(args,
916                 AST_APP_ARG(class);
917         );
918
919         parse = ast_strdupa(data);
920
921         AST_STANDARD_APP_ARGS(args, parse);
922
923         class = S_OR(args.class, NULL);
924         if (ast_moh_start(chan, class, NULL)) 
925                 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, ast_channel_name(chan));
926
927         return 0;
928 }
929
930 static int stop_moh_exec(struct ast_channel *chan, const char *data)
931 {
932         ast_moh_stop(chan);
933
934         return 0;
935 }
936
937 #define get_mohbyname(a,b,c)    _get_mohbyname(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__)
938
939 static struct mohclass *_get_mohbyname(const char *name, int warn, int flags, const char *file, int lineno, const char *funcname)
940 {
941         struct mohclass *moh = NULL;
942         struct mohclass tmp_class = {
943                 .flags = 0,
944         };
945
946         ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name));
947
948 #ifdef REF_DEBUG
949         moh = __ao2_find_debug(mohclasses, &tmp_class, flags,
950                 "get_mohbyname", file, lineno, funcname);
951 #else
952         moh = __ao2_find(mohclasses, &tmp_class, flags);
953 #endif
954
955         if (!moh && warn) {
956                 ast_debug(1, "Music on Hold class '%s' not found in memory\n", name);
957         }
958
959         return moh;
960 }
961
962 static struct mohdata *mohalloc(struct mohclass *cl)
963 {
964         struct mohdata *moh;
965         long flags;
966
967         if (!(moh = ast_calloc(1, sizeof(*moh))))
968                 return NULL;
969
970         if (pipe(moh->pipe)) {
971                 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
972                 ast_free(moh);
973                 return NULL;
974         }
975
976         /* Make entirely non-blocking */
977         flags = fcntl(moh->pipe[0], F_GETFL);
978         fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
979         flags = fcntl(moh->pipe[1], F_GETFL);
980         fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
981
982         moh->f.frametype = AST_FRAME_VOICE;
983         ast_format_copy(&moh->f.subclass.format, &cl->format);
984         moh->f.offset = AST_FRIENDLY_OFFSET;
985
986         moh->parent = mohclass_ref(cl, "Reffing music class for mohdata parent");
987
988         ao2_lock(cl);
989         AST_LIST_INSERT_HEAD(&cl->members, moh, list);
990         ao2_unlock(cl);
991         
992         return moh;
993 }
994
995 static void moh_release(struct ast_channel *chan, void *data)
996 {
997         struct mohdata *moh = data;
998         struct mohclass *class = moh->parent;
999         struct ast_format oldwfmt;
1000
1001         ao2_lock(class);
1002         AST_LIST_REMOVE(&moh->parent->members, moh, list);      
1003         ao2_unlock(class);
1004         
1005         close(moh->pipe[0]);
1006         close(moh->pipe[1]);
1007
1008         ast_format_copy(&oldwfmt, &moh->origwfmt);
1009
1010         moh->parent = class = mohclass_unref(class, "unreffing moh->parent upon deactivation of generator");
1011
1012         ast_free(moh);
1013
1014         if (chan) {
1015                 struct moh_files_state *state;
1016
1017                 state = ast_channel_music_state(chan);
1018                 if (state && state->class) {
1019                         state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator");
1020                 }
1021                 if (oldwfmt.id && ast_set_write_format(chan, &oldwfmt)) {
1022                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n",
1023                                         ast_channel_name(chan), ast_getformatname(&oldwfmt));
1024                 }
1025
1026                 moh_post_stop(chan);
1027         }
1028 }
1029
1030 static void *moh_alloc(struct ast_channel *chan, void *params)
1031 {
1032         struct mohdata *res;
1033         struct mohclass *class = params;
1034         struct moh_files_state *state;
1035
1036         /* Initiating music_state for current channel. Channel should know name of moh class */
1037         state = ast_channel_music_state(chan);
1038         if (!state && (state = ast_calloc(1, sizeof(*state)))) {
1039                 ast_channel_music_state_set(chan, state);
1040                 ast_module_ref(ast_module_info->self);
1041         } else {
1042                 if (!state) {
1043                         return NULL;
1044                 }
1045                 if (state->class) {
1046                         mohclass_unref(state->class, "Uh Oh. Restarting MOH with an active class");
1047                         ast_log(LOG_WARNING, "Uh Oh. Restarting MOH with an active class\n");
1048                 }
1049                 memset(state, 0, sizeof(*state));
1050         }
1051
1052         if ((res = mohalloc(class))) {
1053                 ast_format_copy(&res->origwfmt, ast_channel_writeformat(chan));
1054                 if (ast_set_write_format(chan, &class->format)) {
1055                         ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", ast_channel_name(chan), ast_codec2str(&class->format));
1056                         moh_release(NULL, res);
1057                         res = NULL;
1058                 } else {
1059                         state->class = mohclass_ref(class, "Placing reference into state container");
1060                         moh_post_start(chan, class->name);
1061                 }
1062         }
1063         return res;
1064 }
1065
1066 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
1067 {
1068         struct mohdata *moh = data;
1069         short buf[1280 + AST_FRIENDLY_OFFSET / 2];
1070         int res;
1071
1072         len = ast_codec_get_len(&moh->parent->format, samples);
1073
1074         if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
1075                 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, ast_channel_name(chan));
1076                 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
1077         }
1078         res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
1079         if (res <= 0)
1080                 return 0;
1081
1082         moh->f.datalen = res;
1083         moh->f.data.ptr = buf + AST_FRIENDLY_OFFSET / 2;
1084         moh->f.samples = ast_codec_get_samples(&moh->f);
1085
1086         if (ast_write(chan, &moh->f) < 0) {
1087                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
1088                 return -1;
1089         }
1090
1091         return 0;
1092 }
1093
1094 static struct ast_generator mohgen = {
1095         .alloc    = moh_alloc,
1096         .release  = moh_release,
1097         .generate = moh_generate,
1098         .digit    = moh_handle_digit,
1099 };
1100
1101 static int moh_add_file(struct mohclass *class, const char *filepath)
1102 {
1103         if (!class->allowed_files) {
1104                 class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray));
1105                 if (!class->filearray) {
1106                         return -1;
1107                 }
1108                 class->allowed_files = INITIAL_NUM_FILES;
1109         } else if (class->total_files == class->allowed_files) {
1110                 char **new_array;
1111
1112                 new_array = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2);
1113                 if (!new_array) {
1114                         return -1;
1115                 }
1116                 class->filearray = new_array;
1117                 class->allowed_files *= 2;
1118         }
1119
1120         class->filearray[class->total_files] = ast_strdup(filepath);
1121         if (!class->filearray[class->total_files]) {
1122                 return -1;
1123         }
1124
1125         class->total_files++;
1126
1127         return 0;
1128 }
1129
1130 static int moh_sort_compare(const void *i1, const void *i2)
1131 {
1132         char *s1, *s2;
1133
1134         s1 = ((char **)i1)[0];
1135         s2 = ((char **)i2)[0];
1136
1137         return strcasecmp(s1, s2);
1138 }
1139
1140 static int moh_scan_files(struct mohclass *class) {
1141
1142         DIR *files_DIR;
1143         struct dirent *files_dirent;
1144         char dir_path[PATH_MAX];
1145         char path[PATH_MAX];
1146         char filepath[PATH_MAX];
1147         char *ext;
1148         struct stat statbuf;
1149         int i;
1150
1151         if (class->dir[0] != '/') {
1152                 ast_copy_string(dir_path, ast_config_AST_DATA_DIR, sizeof(dir_path));
1153                 strncat(dir_path, "/", sizeof(dir_path) - 1);
1154                 strncat(dir_path, class->dir, sizeof(dir_path) - 1);
1155         } else {
1156                 ast_copy_string(dir_path, class->dir, sizeof(dir_path));
1157         }
1158         ast_debug(4, "Scanning '%s' for files for class '%s'\n", dir_path, class->name);
1159         files_DIR = opendir(dir_path);
1160         if (!files_DIR) {
1161                 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", dir_path);
1162                 return -1;
1163         }
1164
1165         for (i = 0; i < class->total_files; i++) {
1166                 ast_free(class->filearray[i]);
1167         }
1168         class->total_files = 0;
1169
1170         if (!getcwd(path, sizeof(path))) {
1171                 ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno));
1172                 closedir(files_DIR);
1173                 return -1;
1174         }
1175         if (chdir(dir_path) < 0) {
1176                 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
1177                 closedir(files_DIR);
1178                 return -1;
1179         }
1180         while ((files_dirent = readdir(files_DIR))) {
1181                 /* The file name must be at least long enough to have the file type extension */
1182                 if ((strlen(files_dirent->d_name) < 4))
1183                         continue;
1184
1185                 /* Skip files that starts with a dot */
1186                 if (files_dirent->d_name[0] == '.')
1187                         continue;
1188
1189                 /* Skip files without extensions... they are not audio */
1190                 if (!strchr(files_dirent->d_name, '.'))
1191                         continue;
1192
1193                 snprintf(filepath, sizeof(filepath), "%s/%s", dir_path, files_dirent->d_name);
1194
1195                 if (stat(filepath, &statbuf))
1196                         continue;
1197
1198                 if (!S_ISREG(statbuf.st_mode))
1199                         continue;
1200
1201                 if ((ext = strrchr(filepath, '.')))
1202                         *ext = '\0';
1203
1204                 /* if the file is present in multiple formats, ensure we only put it into the list once */
1205                 for (i = 0; i < class->total_files; i++)
1206                         if (!strcmp(filepath, class->filearray[i]))
1207                                 break;
1208
1209                 if (i == class->total_files) {
1210                         if (moh_add_file(class, filepath))
1211                                 break;
1212                 }
1213         }
1214
1215         closedir(files_DIR);
1216         if (chdir(path) < 0) {
1217                 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
1218                 return -1;
1219         }
1220         if (ast_test_flag(class, MOH_SORTALPHA))
1221                 qsort(&class->filearray[0], class->total_files, sizeof(char *), moh_sort_compare);
1222         return class->total_files;
1223 }
1224
1225 static int init_files_class(struct mohclass *class)
1226 {
1227         int res;
1228
1229         res = moh_scan_files(class);
1230
1231         if (res < 0) {
1232                 return -1;
1233         }
1234
1235         if (!res) {
1236                 ast_verb(3, "Files not found in %s for moh class:%s\n",
1237                         class->dir, class->name);
1238                 return -1;
1239         }
1240
1241 #if 0
1242         /* XXX This isn't correct.  Args is an application for custom mode. XXX */
1243         if (strchr(class->args, 'r')) {
1244                 ast_set_flag(class, MOH_RANDOMIZE);
1245         }
1246 #endif
1247
1248         return 0;
1249 }
1250
1251 static void moh_rescan_files(void) {
1252         struct ao2_iterator i;
1253         struct mohclass *c;
1254
1255         i = ao2_iterator_init(mohclasses, 0);
1256
1257         while ((c = ao2_iterator_next(&i))) {
1258                 if (!strcasecmp(c->mode, "files")) {
1259                         moh_scan_files(c);
1260                 }
1261                 ao2_ref(c, -1);
1262         }
1263
1264         ao2_iterator_destroy(&i);
1265 }
1266
1267 static int moh_diff(struct mohclass *old, struct mohclass *new)
1268 {
1269         if (!old || !new) {
1270                 return -1;
1271         }
1272
1273         if (strcmp(old->dir, new->dir)) {
1274                 return -1;
1275         } else if (strcmp(old->mode, new->mode)) {
1276                 return -1;
1277         } else if (strcmp(old->args, new->args)) {
1278                 return -1;
1279         } else if (old->flags != new->flags) {
1280                 return -1;
1281         }
1282
1283         return 0;
1284 }
1285
1286 static int init_app_class(struct mohclass *class)
1287 {
1288         if (!strcasecmp(class->mode, "custom")) {
1289                 ast_set_flag(class, MOH_CUSTOM);
1290         } else if (!strcasecmp(class->mode, "mp3nb")) {
1291                 ast_set_flag(class, MOH_SINGLE);
1292         } else if (!strcasecmp(class->mode, "quietmp3nb")) {
1293                 ast_set_flag(class, MOH_SINGLE | MOH_QUIET);
1294         } else if (!strcasecmp(class->mode, "quietmp3")) {
1295                 ast_set_flag(class, MOH_QUIET);
1296         }
1297
1298         class->srcfd = -1;
1299
1300         if (!(class->timer = ast_timer_open())) {
1301                 ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
1302                 return -1;
1303         }
1304         if (class->timer && ast_timer_set_rate(class->timer, 25)) {
1305                 ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
1306                 ast_timer_close(class->timer);
1307                 class->timer = NULL;
1308         }
1309
1310         if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) {
1311                 ast_log(LOG_WARNING, "Unable to create moh thread...\n");
1312                 if (class->timer) {
1313                         ast_timer_close(class->timer);
1314                         class->timer = NULL;
1315                 }
1316                 return -1;
1317         }
1318
1319         return 0;
1320 }
1321
1322 /*!
1323  * \note This function owns the reference it gets to moh if unref is true
1324  */
1325 #define moh_register(moh, reload, unref) _moh_register(moh, reload, unref, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1326 static int _moh_register(struct mohclass *moh, int reload, int unref, const char *file, int line, const char *funcname)
1327 {
1328         struct mohclass *mohclass = NULL;
1329
1330         mohclass = _get_mohbyname(moh->name, 0, MOH_NOTDELETED, file, line, funcname);
1331
1332         if (mohclass && !moh_diff(mohclass, moh)) {
1333                 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
1334                 mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name");
1335                 if (unref) {
1336                         moh = mohclass_unref(moh, "unreffing potential new moh class (it is a duplicate)");
1337                 }
1338                 return -1;
1339         } else if (mohclass) {
1340                 /* Found a class, but it's different from the one being registered */
1341                 mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name");
1342         }
1343
1344         time(&moh->start);
1345         moh->start -= respawn_time;
1346
1347         if (!strcasecmp(moh->mode, "files")) {
1348                 if (init_files_class(moh)) {
1349                         if (unref) {
1350                                 moh = mohclass_unref(moh, "unreffing potential new moh class (init_files_class failed)");
1351                         }
1352                         return -1;
1353                 }
1354         } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || 
1355                         !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || 
1356                         !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) {
1357                 if (init_app_class(moh)) {
1358                         if (unref) {
1359                                 moh = mohclass_unref(moh, "unreffing potential new moh class (init_app_class_failed)");
1360                         }
1361                         return -1;
1362                 }
1363         } else {
1364                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
1365                 if (unref) {
1366                         moh = mohclass_unref(moh, "unreffing potential new moh class (unknown mode)");
1367                 }
1368                 return -1;
1369         }
1370
1371         ao2_t_link(mohclasses, moh, "Adding class to container");
1372
1373         if (unref) {
1374                 moh = mohclass_unref(moh, "Unreffing new moh class because we just added it to the container");
1375         }
1376
1377         return 0;
1378 }
1379
1380 static void local_ast_moh_cleanup(struct ast_channel *chan)
1381 {
1382         struct moh_files_state *state = ast_channel_music_state(chan);
1383
1384         if (state) {
1385                 if (state->class) {
1386                         /* This should never happen.  We likely just leaked some resource. */
1387                         state->class =
1388                                 mohclass_unref(state->class, "Uh Oh. Cleaning up MOH with an active class");
1389                         ast_log(LOG_WARNING, "Uh Oh. Cleaning up MOH with an active class\n");
1390                 }
1391                 ast_free(ast_channel_music_state(chan));
1392                 ast_channel_music_state_set(chan, NULL);
1393                 /* Only held a module reference if we had a music state */
1394                 ast_module_unref(ast_module_info->self);
1395         }
1396 }
1397
1398 static void moh_class_destructor(void *obj);
1399
1400 #define moh_class_malloc()      _moh_class_malloc(__FILE__,__LINE__,__PRETTY_FUNCTION__)
1401
1402 static struct mohclass *_moh_class_malloc(const char *file, int line, const char *funcname)
1403 {
1404         struct mohclass *class;
1405
1406         if ((class =
1407 #ifdef REF_DEBUG
1408                         __ao2_alloc_debug(sizeof(*class), moh_class_destructor,
1409                                 AO2_ALLOC_OPT_LOCK_MUTEX, "Allocating new moh class", file, line, funcname, 1)
1410 #elif defined(__AST_DEBUG_MALLOC)
1411                         __ao2_alloc_debug(sizeof(*class), moh_class_destructor,
1412                                 AO2_ALLOC_OPT_LOCK_MUTEX, "Allocating new moh class", file, line, funcname, 0)
1413 #else
1414                         ao2_alloc(sizeof(*class), moh_class_destructor)
1415 #endif
1416                 )) {
1417                 ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0);
1418                 class->srcfd = -1;
1419         }
1420
1421         return class;
1422 }
1423
1424 static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
1425 {
1426         struct mohclass *mohclass = NULL;
1427         struct moh_files_state *state = ast_channel_music_state(chan);
1428         struct ast_variable *var = NULL;
1429         int res;
1430         int realtime_possible = ast_check_realtime("musiconhold");
1431
1432         /* The following is the order of preference for which class to use:
1433          * 1) The channels explicitly set musicclass, which should *only* be
1434          *    set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
1435          * 2) The mclass argument. If a channel is calling ast_moh_start() as the
1436          *    result of receiving a HOLD control frame, this should be the
1437          *    payload that came with the frame.
1438          * 3) The interpclass argument. This would be from the mohinterpret
1439          *    option from channel drivers. This is the same as the old musicclass
1440          *    option.
1441          * 4) The default class.
1442          */
1443         if (!ast_strlen_zero(ast_channel_musicclass(chan))) {
1444                 mohclass = get_mohbyname(ast_channel_musicclass(chan), 1, 0);
1445                 if (!mohclass && realtime_possible) {
1446                         var = ast_load_realtime("musiconhold", "name", ast_channel_musicclass(chan), SENTINEL);
1447                 }
1448         }
1449         if (!mohclass && !var && !ast_strlen_zero(mclass)) {
1450                 mohclass = get_mohbyname(mclass, 1, 0);
1451                 if (!mohclass && realtime_possible) {
1452                         var = ast_load_realtime("musiconhold", "name", mclass, SENTINEL);
1453                 }
1454         }
1455         if (!mohclass && !var && !ast_strlen_zero(interpclass)) {
1456                 mohclass = get_mohbyname(interpclass, 1, 0);
1457                 if (!mohclass && realtime_possible) {
1458                         var = ast_load_realtime("musiconhold", "name", interpclass, SENTINEL);
1459                 }
1460         }
1461
1462         if (!mohclass && !var) {
1463                 mohclass = get_mohbyname("default", 1, 0);
1464                 if (!mohclass && realtime_possible) {
1465                         var = ast_load_realtime("musiconhold", "name", "default", SENTINEL);
1466                 }
1467         }
1468
1469         /* If no moh class found in memory, then check RT. Note that the logic used
1470          * above guarantees that if var is non-NULL, then mohclass must be NULL.
1471          */
1472         if (var) {
1473                 struct ast_variable *tmp = NULL;
1474
1475                 if ((mohclass = moh_class_malloc())) {
1476                         mohclass->realtime = 1;
1477                         for (tmp = var; tmp; tmp = tmp->next) {
1478                                 if (!strcasecmp(tmp->name, "name"))
1479                                         ast_copy_string(mohclass->name, tmp->value, sizeof(mohclass->name));
1480                                 else if (!strcasecmp(tmp->name, "mode"))
1481                                         ast_copy_string(mohclass->mode, tmp->value, sizeof(mohclass->mode)); 
1482                                 else if (!strcasecmp(tmp->name, "directory"))
1483                                         ast_copy_string(mohclass->dir, tmp->value, sizeof(mohclass->dir));
1484                                 else if (!strcasecmp(tmp->name, "application"))
1485                                         ast_copy_string(mohclass->args, tmp->value, sizeof(mohclass->args));
1486                                 else if (!strcasecmp(tmp->name, "digit") && (isdigit(*tmp->value) || strchr("*#", *tmp->value)))
1487                                         mohclass->digit = *tmp->value;
1488                                 else if (!strcasecmp(tmp->name, "random"))
1489                                         ast_set2_flag(mohclass, ast_true(tmp->value), MOH_RANDOMIZE);
1490                                 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "random"))
1491                                         ast_set_flag(mohclass, MOH_RANDOMIZE);
1492                                 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha")) 
1493                                         ast_set_flag(mohclass, MOH_SORTALPHA);
1494                                 else if (!strcasecmp(tmp->name, "format")) {
1495                                         ast_getformatbyname(tmp->value, &mohclass->format);
1496                                         if (!mohclass->format.id) {
1497                                                 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value);
1498                                                 ast_format_set(&mohclass->format, AST_FORMAT_SLINEAR, 0);
1499                                         }
1500                                 }
1501                         }
1502                         ast_variables_destroy(var);
1503                         if (ast_strlen_zero(mohclass->dir)) {
1504                                 if (!strcasecmp(mohclass->mode, "custom")) {
1505                                         strcpy(mohclass->dir, "nodir");
1506                                 } else {
1507                                         ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name);
1508                                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no directory specified)");
1509                                         return -1;
1510                                 }
1511                         }
1512                         if (ast_strlen_zero(mohclass->mode)) {
1513                                 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", mohclass->name);
1514                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no mode specified)");
1515                                 return -1;
1516                         }
1517                         if (ast_strlen_zero(mohclass->args) && !strcasecmp(mohclass->mode, "custom")) {
1518                                 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", mohclass->name);
1519                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no app specified for custom mode");
1520                                 return -1;
1521                         }
1522
1523                         if (ast_test_flag(global_flags, MOH_CACHERTCLASSES)) {
1524                                 /* CACHERTCLASSES enabled, let's add this class to default tree */
1525                                 if (state && state->class) {
1526                                         /* Class already exist for this channel */
1527                                         ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1528                                 }
1529                                 /* We don't want moh_register to unref the mohclass because we do it at the end of this function as well.
1530                                  * If we allowed moh_register to unref the mohclass,too, then the count would be off by one. The result would
1531                                  * be that the destructor would be called when the generator on the channel is deactivated. The container then
1532                                  * has a pointer to a freed mohclass, so any operations involving the mohclass container would result in reading
1533                                  * invalid memory.
1534                                  */
1535                                 if (moh_register(mohclass, 0, DONT_UNREF) == -1) {
1536                                         mohclass = mohclass_unref(mohclass, "unreffing mohclass failed to register");
1537                                         return -1;
1538                                 }
1539                         } else {
1540                                 /* We don't register RT moh class, so let's init it manualy */
1541
1542                                 time(&mohclass->start);
1543                                 mohclass->start -= respawn_time;
1544
1545                                 if (!strcasecmp(mohclass->mode, "files")) {
1546                                         if (!moh_scan_files(mohclass)) {
1547                                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
1548                                                 return -1;
1549                                         }
1550                                         if (strchr(mohclass->args, 'r'))
1551                                                 ast_set_flag(mohclass, MOH_RANDOMIZE);
1552                                 } else if (!strcasecmp(mohclass->mode, "mp3") || !strcasecmp(mohclass->mode, "mp3nb") || !strcasecmp(mohclass->mode, "quietmp3") || !strcasecmp(mohclass->mode, "quietmp3nb") || !strcasecmp(mohclass->mode, "httpmp3") || !strcasecmp(mohclass->mode, "custom")) {
1553
1554                                         if (!strcasecmp(mohclass->mode, "custom"))
1555                                                 ast_set_flag(mohclass, MOH_CUSTOM);
1556                                         else if (!strcasecmp(mohclass->mode, "mp3nb"))
1557                                                 ast_set_flag(mohclass, MOH_SINGLE);
1558                                         else if (!strcasecmp(mohclass->mode, "quietmp3nb"))
1559                                                 ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET);
1560                                         else if (!strcasecmp(mohclass->mode, "quietmp3"))
1561                                                 ast_set_flag(mohclass, MOH_QUIET);
1562
1563                                         mohclass->srcfd = -1;
1564                                         if (!(mohclass->timer = ast_timer_open())) {
1565                                                 ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
1566                                         }
1567                                         if (mohclass->timer && ast_timer_set_rate(mohclass->timer, 25)) {
1568                                                 ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
1569                                                 ast_timer_close(mohclass->timer);
1570                                                 mohclass->timer = NULL;
1571                                         }
1572
1573                                         /* Let's check if this channel already had a moh class before */
1574                                         if (state && state->class) {
1575                                                 /* Class already exist for this channel */
1576                                                 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1577                                                 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) {
1578                                                         /* we found RT class with the same name, seems like we should continue playing existing one */
1579                                                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has one)");
1580                                                         mohclass = mohclass_ref(state->class, "using existing class from state");
1581                                                 }
1582                                         } else {
1583                                                 if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) {
1584                                                         ast_log(LOG_WARNING, "Unable to create moh...\n");
1585                                                         if (mohclass->timer) {
1586                                                                 ast_timer_close(mohclass->timer);
1587                                                                 mohclass->timer = NULL;
1588                                                         }
1589                                                         mohclass = mohclass_unref(mohclass, "Unreffing potential mohclass (failed to create background thread)");
1590                                                         return -1;
1591                                                 }
1592                                         }
1593                                 } else {
1594                                         ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mohclass->mode);
1595                                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (unknown mode)");
1596                                         return -1;
1597                                 }
1598                         }
1599                 } else {
1600                         ast_variables_destroy(var);
1601                         var = NULL;
1602                 }
1603         }
1604
1605         if (!mohclass) {
1606                 return -1;
1607         }
1608
1609         /* If we are using a cached realtime class with files, re-scan the files */
1610         if (!var && ast_test_flag(global_flags, MOH_CACHERTCLASSES) && mohclass->realtime && !strcasecmp(mohclass->mode, "files")) {
1611                 if (!moh_scan_files(mohclass)) {
1612                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
1613                         return -1;
1614                 }
1615         }
1616
1617         if (mohclass->total_files) {
1618                 res = ast_activate_generator(chan, &moh_file_stream, mohclass);
1619         } else {
1620                 res = ast_activate_generator(chan, &mohgen, mohclass);
1621         }
1622         if (!res) {
1623                 ast_channel_latest_musicclass_set(chan, mohclass->name);
1624                 ast_set_flag(ast_channel_flags(chan), AST_FLAG_MOH);
1625         }
1626
1627         mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start");
1628
1629         return res;
1630 }
1631
1632 static void local_ast_moh_stop(struct ast_channel *chan)
1633 {
1634         ast_clear_flag(ast_channel_flags(chan), AST_FLAG_MOH);
1635         ast_deactivate_generator(chan);
1636
1637         ast_channel_lock(chan);
1638         if (ast_channel_music_state(chan)) {
1639                 if (ast_channel_stream(chan)) {
1640                         ast_closestream(ast_channel_stream(chan));
1641                         ast_channel_stream_set(chan, NULL);
1642                 }
1643         }
1644         ast_channel_unlock(chan);
1645 }
1646
1647 static void moh_class_destructor(void *obj)
1648 {
1649         struct mohclass *class = obj;
1650         struct mohdata *member;
1651         pthread_t tid = 0;
1652
1653         ast_debug(1, "Destroying MOH class '%s'\n", class->name);
1654
1655         ao2_lock(class);
1656         while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) {
1657                 free(member);
1658         }
1659         ao2_unlock(class);
1660
1661         /* Kill the thread first, so it cannot restart the child process while the
1662          * class is being destroyed */
1663         if (class->thread != AST_PTHREADT_NULL && class->thread != 0) {
1664                 tid = class->thread;
1665                 class->thread = AST_PTHREADT_NULL;
1666                 pthread_cancel(tid);
1667                 /* We'll collect the exit status later, after we ensure all the readers
1668                  * are dead. */
1669         }
1670
1671         if (class->pid > 1) {
1672                 char buff[8192];
1673                 int bytes, tbytes = 0, stime = 0, pid = 0;
1674
1675                 ast_debug(1, "killing %d!\n", class->pid);
1676
1677                 stime = time(NULL) + 2;
1678                 pid = class->pid;
1679                 class->pid = 0;
1680
1681                 /* Back when this was just mpg123, SIGKILL was fine.  Now we need
1682                  * to give the process a reason and time enough to kill off its
1683                  * children. */
1684                 do {
1685                         if (killpg(pid, SIGHUP) < 0) {
1686                                 ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno));
1687                         }
1688                         usleep(100000);
1689                         if (killpg(pid, SIGTERM) < 0) {
1690                                 if (errno == ESRCH) {
1691                                         break;
1692                                 }
1693                                 ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno));
1694                         }
1695                         usleep(100000);
1696                         if (killpg(pid, SIGKILL) < 0) {
1697                                 if (errno == ESRCH) {
1698                                         break;
1699                                 }
1700                                 ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno));
1701                         }
1702                 } while (0);
1703
1704                 while ((ast_wait_for_input(class->srcfd, 100) > 0) && 
1705                                 (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) {
1706                         tbytes = tbytes + bytes;
1707                 }
1708
1709                 ast_debug(1, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1710
1711                 close(class->srcfd);
1712                 class->srcfd = -1;
1713         }
1714
1715         if (class->filearray) {
1716                 int i;
1717                 for (i = 0; i < class->total_files; i++) {
1718                         free(class->filearray[i]);
1719                 }
1720                 free(class->filearray);
1721                 class->filearray = NULL;
1722         }
1723
1724         if (class->timer) {
1725                 ast_timer_close(class->timer);
1726                 class->timer = NULL;
1727         }
1728
1729         /* Finally, collect the exit status of the monitor thread */
1730         if (tid > 0) {
1731                 pthread_join(tid, NULL);
1732         }
1733
1734 }
1735
1736 static int moh_class_mark(void *obj, void *arg, int flags)
1737 {
1738         struct mohclass *class = obj;
1739
1740         class->delete = 1;
1741
1742         return 0;
1743 }
1744
1745 static int moh_classes_delete_marked(void *obj, void *arg, int flags)
1746 {
1747         struct mohclass *class = obj;
1748
1749         return class->delete ? CMP_MATCH : 0;
1750 }
1751
1752 static int load_moh_classes(int reload)
1753 {
1754         struct ast_config *cfg;
1755         struct ast_variable *var;
1756         struct mohclass *class; 
1757         char *cat;
1758         int numclasses = 0;
1759         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1760
1761         cfg = ast_config_load("musiconhold.conf", config_flags);
1762
1763         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
1764                 if (ast_check_realtime("musiconhold") && reload) {
1765                         ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1766                         ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, moh_classes_delete_marked, NULL, "Purge marked classes");
1767                 }
1768                 return 0;
1769         }
1770         if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1771                 moh_rescan_files();
1772                 return 0;
1773         }
1774
1775         if (reload) {
1776                 ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1777         }
1778
1779         ast_clear_flag(global_flags, AST_FLAGS_ALL);
1780
1781         cat = ast_category_browse(cfg, NULL);
1782         for (; cat; cat = ast_category_browse(cfg, cat)) {
1783                 /* Setup common options from [general] section */
1784                 if (!strcasecmp(cat, "general")) {
1785                         for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1786                                 if (!strcasecmp(var->name, "cachertclasses")) {
1787                                         ast_set2_flag(global_flags, ast_true(var->value), MOH_CACHERTCLASSES);
1788                                 } else {
1789                                         ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name);
1790                                 }
1791                         }
1792                 }
1793                 /* These names were deprecated in 1.4 and should not be used until after the next major release. */
1794                 if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files") || 
1795                                 !strcasecmp(cat, "general")) {
1796                         continue;
1797                 }
1798
1799                 if (!(class = moh_class_malloc())) {
1800                         break;
1801                 }
1802
1803                 ast_copy_string(class->name, cat, sizeof(class->name));
1804                 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1805                         if (!strcasecmp(var->name, "mode")) {
1806                                 ast_copy_string(class->mode, var->value, sizeof(class->mode));
1807                         } else if (!strcasecmp(var->name, "directory")) {
1808                                 ast_copy_string(class->dir, var->value, sizeof(class->dir));
1809                         } else if (!strcasecmp(var->name, "application")) {
1810                                 ast_copy_string(class->args, var->value, sizeof(class->args));
1811                         } else if (!strcasecmp(var->name, "announcement")) {
1812                                 ast_copy_string(class->announcement, var->value, sizeof(class->announcement));
1813                                 ast_set_flag(class, MOH_ANNOUNCEMENT);
1814                         } else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value))) {
1815                                 class->digit = *var->value;
1816                         } else if (!strcasecmp(var->name, "random")) {
1817                                 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
1818                         } else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random")) {
1819                                 ast_set_flag(class, MOH_RANDOMIZE);
1820                         } else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) {
1821                                 ast_set_flag(class, MOH_SORTALPHA);
1822                         } else if (!strcasecmp(var->name, "format")) {
1823                                 ast_getformatbyname(var->value, &class->format);
1824                                 if (!class->format.id) {
1825                                         ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
1826                                         ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0);
1827                                 }
1828                         }
1829                 }
1830
1831                 if (ast_strlen_zero(class->dir)) {
1832                         if (!strcasecmp(class->mode, "custom")) {
1833                                 strcpy(class->dir, "nodir");
1834                         } else {
1835                                 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
1836                                 class = mohclass_unref(class, "unreffing potential mohclass (no directory)");
1837                                 continue;
1838                         }
1839                 }
1840                 if (ast_strlen_zero(class->mode)) {
1841                         ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
1842                         class = mohclass_unref(class, "unreffing potential mohclass (no mode)");
1843                         continue;
1844                 }
1845                 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
1846                         ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
1847                         class = mohclass_unref(class, "unreffing potential mohclass (no app for custom mode)");
1848                         continue;
1849                 }
1850
1851                 /* Don't leak a class when it's already registered */
1852                 if (!moh_register(class, reload, HANDLE_REF)) {
1853                         numclasses++;
1854                 }
1855         }
1856
1857         ast_config_destroy(cfg);
1858
1859         ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, 
1860                         moh_classes_delete_marked, NULL, "Purge marked classes");
1861
1862         return numclasses;
1863 }
1864
1865 static void ast_moh_destroy(void)
1866 {
1867         ast_verb(2, "Destroying musiconhold processes\n");
1868         if (mohclasses) {
1869                 ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Destroy callback");
1870                 ao2_ref(mohclasses, -1);
1871                 mohclasses = NULL;
1872         }
1873 }
1874
1875 static char *handle_cli_moh_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1876 {
1877         switch (cmd) {
1878         case CLI_INIT:
1879                 e->command = "moh reload";
1880                 e->usage =
1881                         "Usage: moh reload\n"
1882                         "       Reloads the MusicOnHold module.\n"
1883                         "       Alias for 'module reload res_musiconhold.so'\n";
1884                 return NULL;
1885         case CLI_GENERATE:
1886                 return NULL;
1887         }
1888
1889         if (a->argc != e->args)
1890                 return CLI_SHOWUSAGE;
1891
1892         reload();
1893
1894         return CLI_SUCCESS;
1895 }
1896
1897 static char *handle_cli_moh_show_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1898 {
1899         struct mohclass *class;
1900         struct ao2_iterator i;
1901
1902         switch (cmd) {
1903         case CLI_INIT:
1904                 e->command = "moh show files";
1905                 e->usage =
1906                         "Usage: moh show files\n"
1907                         "       Lists all loaded file-based MusicOnHold classes and their\n"
1908                         "       files.\n";
1909                 return NULL;
1910         case CLI_GENERATE:
1911                 return NULL;
1912         }
1913
1914         if (a->argc != e->args)
1915                 return CLI_SHOWUSAGE;
1916
1917         i = ao2_iterator_init(mohclasses, 0);
1918         for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) {
1919                 int x;
1920
1921                 if (!class->total_files) {
1922                         continue;
1923                 }
1924
1925                 ast_cli(a->fd, "Class: %s\n", class->name);
1926                 for (x = 0; x < class->total_files; x++) {
1927                         ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]);
1928                 }
1929         }
1930         ao2_iterator_destroy(&i);
1931
1932         return CLI_SUCCESS;
1933 }
1934
1935 static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1936 {
1937         struct mohclass *class;
1938         struct ao2_iterator i;
1939
1940         switch (cmd) {
1941         case CLI_INIT:
1942                 e->command = "moh show classes";
1943                 e->usage =
1944                         "Usage: moh show classes\n"
1945                         "       Lists all MusicOnHold classes.\n";
1946                 return NULL;
1947         case CLI_GENERATE:
1948                 return NULL;
1949         }
1950
1951         if (a->argc != e->args)
1952                 return CLI_SHOWUSAGE;
1953
1954         i = ao2_iterator_init(mohclasses, 0);
1955         for (; (class = ao2_t_iterator_next(&i, "Show classes iterator")); mohclass_unref(class, "Unref iterator in moh show classes")) {
1956                 ast_cli(a->fd, "Class: %s\n", class->name);
1957                 ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
1958                 ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
1959                 if (ast_test_flag(class, MOH_CUSTOM)) {
1960                         ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
1961                 }
1962                 if (strcasecmp(class->mode, "files")) {
1963                         ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(&class->format));
1964                 }
1965         }
1966         ao2_iterator_destroy(&i);
1967
1968         return CLI_SUCCESS;
1969 }
1970
1971 static struct ast_cli_entry cli_moh[] = {
1972         AST_CLI_DEFINE(handle_cli_moh_reload,       "Reload MusicOnHold"),
1973         AST_CLI_DEFINE(handle_cli_moh_show_classes, "List MusicOnHold classes"),
1974         AST_CLI_DEFINE(handle_cli_moh_show_files,   "List MusicOnHold file-based classes")
1975 };
1976
1977 static int moh_class_hash(const void *obj, const int flags)
1978 {
1979         const struct mohclass *class = obj;
1980
1981         return ast_str_case_hash(class->name);
1982 }
1983
1984 static int moh_class_cmp(void *obj, void *arg, int flags)
1985 {
1986         struct mohclass *class = obj, *class2 = arg;
1987
1988         return strcasecmp(class->name, class2->name) ? 0 :
1989                 (flags & MOH_NOTDELETED) && (class->delete || class2->delete) ? 0 :
1990                 CMP_MATCH | CMP_STOP;
1991 }
1992
1993 /*!
1994  * \brief Load the module
1995  *
1996  * Module loading including tests for configuration or dependencies.
1997  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
1998  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
1999  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
2000  * configuration file or other non-critical problem return 
2001  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
2002  */
2003 static int load_module(void)
2004 {
2005         int res;
2006
2007         if (!(mohclasses = ao2_t_container_alloc(53, moh_class_hash, moh_class_cmp, "Moh class container"))) {
2008                 return AST_MODULE_LOAD_DECLINE;
2009         }
2010
2011         if (!load_moh_classes(0) && ast_check_realtime("musiconhold") == 0) {   /* No music classes configured, so skip it */
2012                 ast_log(LOG_WARNING, "No music on hold classes configured, "
2013                                 "disabling music on hold.\n");
2014         } else {
2015                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop,
2016                                 local_ast_moh_cleanup);
2017         }
2018
2019         res = ast_register_application_xml(play_moh, play_moh_exec);
2020         ast_register_atexit(ast_moh_destroy);
2021         ast_cli_register_multiple(cli_moh, ARRAY_LEN(cli_moh));
2022         if (!res)
2023                 res = ast_register_application_xml(wait_moh, wait_moh_exec);
2024         if (!res)
2025                 res = ast_register_application_xml(set_moh, set_moh_exec);
2026         if (!res)
2027                 res = ast_register_application_xml(start_moh, start_moh_exec);
2028         if (!res)
2029                 res = ast_register_application_xml(stop_moh, stop_moh_exec);
2030
2031         return AST_MODULE_LOAD_SUCCESS;
2032 }
2033
2034 static int reload(void)
2035 {
2036         if (load_moh_classes(1)) {
2037                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop,
2038                                 local_ast_moh_cleanup);
2039         }
2040
2041         return AST_MODULE_LOAD_SUCCESS;
2042 }
2043
2044 static int moh_class_inuse(void *obj, void *arg, int flags)
2045 {
2046         struct mohclass *class = obj;
2047
2048         return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP;
2049 }
2050
2051 static int unload_module(void)
2052 {
2053         int res = 0;
2054         struct mohclass *class = NULL;
2055
2056         /* XXX This check shouldn't be required if module ref counting was being used
2057          * properly ... */
2058         if ((class = ao2_t_callback(mohclasses, 0, moh_class_inuse, NULL, "Module unload callback"))) {
2059                 class = mohclass_unref(class, "unref of class from module unload callback");
2060                 res = -1;
2061         }
2062
2063         if (res < 0) {
2064                 ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n");
2065                 return res;
2066         }
2067
2068         ast_uninstall_music_functions();
2069
2070         ast_moh_destroy();
2071         res = ast_unregister_application(play_moh);
2072         res |= ast_unregister_application(wait_moh);
2073         res |= ast_unregister_application(set_moh);
2074         res |= ast_unregister_application(start_moh);
2075         res |= ast_unregister_application(stop_moh);
2076         ast_cli_unregister_multiple(cli_moh, ARRAY_LEN(cli_moh));
2077         ast_unregister_atexit(ast_moh_destroy);
2078
2079         return res;
2080 }
2081
2082 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Music On Hold Resource",
2083         .load = load_module,
2084         .unload = unload_module,
2085         .reload = reload,
2086         .load_pri = AST_MODPRI_CHANNEL_DEPEND,
2087 );