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