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