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