Add an announcement option to music-on-hold - plays sound when put on hold/between...
[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 || !chan->music_state) {
264                 return;
265         }
266
267         state = chan->music_state;
268
269         if (chan->stream) {
270                 ast_closestream(chan->stream);
271                 chan->stream = 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 = chan->music_state;
290         int tries;
291
292         /* Discontinue a stream if it is running already */
293         if (chan->stream) {
294                 ast_closestream(chan->stream);
295                 chan->stream = 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, chan->language, 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], chan->language, 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(chan->stream, 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(chan->stream);
364                 if (state->samples > loc && loc) {
365                         /* seek one sample from the end for one guaranteed valid read */
366                         ast_seekstream(chan->stream, 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 (!(chan->stream && (f = ast_readframe(chan->stream)))) {
378                 if (!ast_moh_files_next(chan))
379                         f = ast_readframe(chan->stream);
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 = chan->music_state;
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, &chan->writeformat);
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 = chan->music_state;
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 (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) {
447                 chan->music_state = state;
448                 ast_module_ref(ast_module_info->self);
449         } else {
450                 state = chan->music_state;
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, &chan->writeformat);
474         ast_format_copy(&state->mohwfmt, &chan->writeformat);
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 chan->music_state;
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_string_field_set(chan,musicclass,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_string_field_set(chan, musicclass, 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, "get_mohbyname", (char *) file, lineno, funcname);
893 #else
894         moh = __ao2_find(mohclasses, &tmp_class, flags);
895 #endif
896
897         if (!moh && warn) {
898                 ast_debug(1, "Music on Hold class '%s' not found in memory\n", name);
899         }
900
901         return moh;
902 }
903
904 static struct mohdata *mohalloc(struct mohclass *cl)
905 {
906         struct mohdata *moh;
907         long flags;
908
909         if (!(moh = ast_calloc(1, sizeof(*moh))))
910                 return NULL;
911
912         if (pipe(moh->pipe)) {
913                 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
914                 ast_free(moh);
915                 return NULL;
916         }
917
918         /* Make entirely non-blocking */
919         flags = fcntl(moh->pipe[0], F_GETFL);
920         fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
921         flags = fcntl(moh->pipe[1], F_GETFL);
922         fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
923
924         moh->f.frametype = AST_FRAME_VOICE;
925         ast_format_copy(&moh->f.subclass.format, &cl->format);
926         moh->f.offset = AST_FRIENDLY_OFFSET;
927
928         moh->parent = mohclass_ref(cl, "Reffing music class for mohdata parent");
929
930         ao2_lock(cl);
931         AST_LIST_INSERT_HEAD(&cl->members, moh, list);
932         ao2_unlock(cl);
933         
934         return moh;
935 }
936
937 static void moh_release(struct ast_channel *chan, void *data)
938 {
939         struct mohdata *moh = data;
940         struct mohclass *class = moh->parent;
941         struct ast_format oldwfmt;
942
943         ao2_lock(class);
944         AST_LIST_REMOVE(&moh->parent->members, moh, list);      
945         ao2_unlock(class);
946         
947         close(moh->pipe[0]);
948         close(moh->pipe[1]);
949
950         ast_format_copy(&oldwfmt, &moh->origwfmt);
951
952         moh->parent = class = mohclass_unref(class, "unreffing moh->parent upon deactivation of generator");
953
954         ast_free(moh);
955
956         if (chan) {
957                 struct moh_files_state *state;
958
959                 state = chan->music_state;
960                 if (state && state->class) {
961                         state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator");
962                 }
963                 if (oldwfmt.id && ast_set_write_format(chan, &oldwfmt)) {
964                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n",
965                                         ast_channel_name(chan), ast_getformatname(&oldwfmt));
966                 }
967
968                 ast_verb(3, "Stopped music on hold on %s\n", ast_channel_name(chan));
969         }
970 }
971
972 static void *moh_alloc(struct ast_channel *chan, void *params)
973 {
974         struct mohdata *res;
975         struct mohclass *class = params;
976         struct moh_files_state *state;
977
978         /* Initiating music_state for current channel. Channel should know name of moh class */
979         if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) {
980                 chan->music_state = state;
981                 ast_module_ref(ast_module_info->self);
982         } else {
983                 state = chan->music_state;
984                 if (!state) {
985                         return NULL;
986                 }
987                 if (state->class) {
988                         mohclass_unref(state->class, "Uh Oh. Restarting MOH with an active class");
989                         ast_log(LOG_WARNING, "Uh Oh. Restarting MOH with an active class\n");
990                 }
991                 memset(state, 0, sizeof(*state));
992         }
993
994         if ((res = mohalloc(class))) {
995                 ast_format_copy(&res->origwfmt, &chan->writeformat);
996                 if (ast_set_write_format(chan, &class->format)) {
997                         ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", ast_channel_name(chan), ast_codec2str(&class->format));
998                         moh_release(NULL, res);
999                         res = NULL;
1000                 } else {
1001                         state->class = mohclass_ref(class, "Placing reference into state container");
1002                 }
1003                 ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n", class->name, ast_channel_name(chan));
1004         }
1005         return res;
1006 }
1007
1008 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
1009 {
1010         struct mohdata *moh = data;
1011         short buf[1280 + AST_FRIENDLY_OFFSET / 2];
1012         int res;
1013
1014         len = ast_codec_get_len(&moh->parent->format, samples);
1015
1016         if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
1017                 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, ast_channel_name(chan));
1018                 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
1019         }
1020         res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
1021         if (res <= 0)
1022                 return 0;
1023
1024         moh->f.datalen = res;
1025         moh->f.data.ptr = buf + AST_FRIENDLY_OFFSET / 2;
1026         moh->f.samples = ast_codec_get_samples(&moh->f);
1027
1028         if (ast_write(chan, &moh->f) < 0) {
1029                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
1030                 return -1;
1031         }
1032
1033         return 0;
1034 }
1035
1036 static struct ast_generator mohgen = {
1037         .alloc    = moh_alloc,
1038         .release  = moh_release,
1039         .generate = moh_generate,
1040         .digit    = moh_handle_digit,
1041 };
1042
1043 static int moh_add_file(struct mohclass *class, const char *filepath)
1044 {
1045         if (!class->allowed_files) {
1046                 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray))))
1047                         return -1;
1048                 class->allowed_files = INITIAL_NUM_FILES;
1049         } else if (class->total_files == class->allowed_files) {
1050                 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) {
1051                         class->allowed_files = 0;
1052                         class->total_files = 0;
1053                         return -1;
1054                 }
1055                 class->allowed_files *= 2;
1056         }
1057
1058         if (!(class->filearray[class->total_files] = ast_strdup(filepath)))
1059                 return -1;
1060
1061         class->total_files++;
1062
1063         return 0;
1064 }
1065
1066 static int moh_sort_compare(const void *i1, const void *i2)
1067 {
1068         char *s1, *s2;
1069
1070         s1 = ((char **)i1)[0];
1071         s2 = ((char **)i2)[0];
1072
1073         return strcasecmp(s1, s2);
1074 }
1075
1076 static int moh_scan_files(struct mohclass *class) {
1077
1078         DIR *files_DIR;
1079         struct dirent *files_dirent;
1080         char dir_path[PATH_MAX];
1081         char path[PATH_MAX];
1082         char filepath[PATH_MAX];
1083         char *ext;
1084         struct stat statbuf;
1085         int i;
1086
1087         if (class->dir[0] != '/') {
1088                 ast_copy_string(dir_path, ast_config_AST_DATA_DIR, sizeof(dir_path));
1089                 strncat(dir_path, "/", sizeof(dir_path) - 1);
1090                 strncat(dir_path, class->dir, sizeof(dir_path) - 1);
1091         } else {
1092                 ast_copy_string(dir_path, class->dir, sizeof(dir_path));
1093         }
1094         ast_debug(4, "Scanning '%s' for files for class '%s'\n", dir_path, class->name);
1095         files_DIR = opendir(dir_path);
1096         if (!files_DIR) {
1097                 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", dir_path);
1098                 return -1;
1099         }
1100
1101         for (i = 0; i < class->total_files; i++)
1102                 ast_free(class->filearray[i]);
1103
1104         class->total_files = 0;
1105         if (!getcwd(path, sizeof(path))) {
1106                 ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno));
1107                 return -1;
1108         }
1109         if (chdir(dir_path) < 0) {
1110                 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
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 #if 0
1175         /* XXX This isn't correct.  Args is an application for custom mode. XXX */
1176         if (strchr(class->args, 'r')) {
1177                 ast_set_flag(class, MOH_RANDOMIZE);
1178         }
1179 #endif
1180
1181         return 0;
1182 }
1183
1184 static void moh_rescan_files(void) {
1185         struct ao2_iterator i;
1186         struct mohclass *c;
1187
1188         i = ao2_iterator_init(mohclasses, 0);
1189
1190         while ((c = ao2_iterator_next(&i))) {
1191                 if (!strcasecmp(c->mode, "files")) {
1192                         moh_scan_files(c);
1193                 }
1194                 ao2_ref(c, -1);
1195         }
1196
1197         ao2_iterator_destroy(&i);
1198 }
1199
1200 static int moh_diff(struct mohclass *old, struct mohclass *new)
1201 {
1202         if (!old || !new) {
1203                 return -1;
1204         }
1205
1206         if (strcmp(old->dir, new->dir)) {
1207                 return -1;
1208         } else if (strcmp(old->mode, new->mode)) {
1209                 return -1;
1210         } else if (strcmp(old->args, new->args)) {
1211                 return -1;
1212         } else if (old->flags != new->flags) {
1213                 return -1;
1214         }
1215
1216         return 0;
1217 }
1218
1219 static int init_app_class(struct mohclass *class)
1220 {
1221         if (!strcasecmp(class->mode, "custom")) {
1222                 ast_set_flag(class, MOH_CUSTOM);
1223         } else if (!strcasecmp(class->mode, "mp3nb")) {
1224                 ast_set_flag(class, MOH_SINGLE);
1225         } else if (!strcasecmp(class->mode, "quietmp3nb")) {
1226                 ast_set_flag(class, MOH_SINGLE | MOH_QUIET);
1227         } else if (!strcasecmp(class->mode, "quietmp3")) {
1228                 ast_set_flag(class, MOH_QUIET);
1229         }
1230
1231         class->srcfd = -1;
1232
1233         if (!(class->timer = ast_timer_open())) {
1234                 ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
1235                 return -1;
1236         }
1237         if (class->timer && ast_timer_set_rate(class->timer, 25)) {
1238                 ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
1239                 ast_timer_close(class->timer);
1240                 class->timer = NULL;
1241         }
1242
1243         if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) {
1244                 ast_log(LOG_WARNING, "Unable to create moh thread...\n");
1245                 if (class->timer) {
1246                         ast_timer_close(class->timer);
1247                         class->timer = NULL;
1248                 }
1249                 return -1;
1250         }
1251
1252         return 0;
1253 }
1254
1255 /*!
1256  * \note This function owns the reference it gets to moh if unref is true
1257  */
1258 #define moh_register(a,b,c)     _moh_register(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__)
1259 static int _moh_register(struct mohclass *moh, int reload, int unref, const char *file, int line, const char *funcname)
1260 {
1261         struct mohclass *mohclass = NULL;
1262
1263         mohclass = _get_mohbyname(moh->name, 0, MOH_NOTDELETED, file, line, funcname);
1264
1265         if (mohclass && !moh_diff(mohclass, moh)) {
1266                 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
1267                 mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name");
1268                 if (unref) {
1269                         moh = mohclass_unref(moh, "unreffing potential new moh class (it is a duplicate)");
1270                 }
1271                 return -1;
1272         } else if (mohclass) {
1273                 /* Found a class, but it's different from the one being registered */
1274                 mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name");
1275         }
1276
1277         time(&moh->start);
1278         moh->start -= respawn_time;
1279
1280         if (!strcasecmp(moh->mode, "files")) {
1281                 if (init_files_class(moh)) {
1282                         if (unref) {
1283                                 moh = mohclass_unref(moh, "unreffing potential new moh class (init_files_class failed)");
1284                         }
1285                         return -1;
1286                 }
1287         } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || 
1288                         !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || 
1289                         !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) {
1290                 if (init_app_class(moh)) {
1291                         if (unref) {
1292                                 moh = mohclass_unref(moh, "unreffing potential new moh class (init_app_class_failed)");
1293                         }
1294                         return -1;
1295                 }
1296         } else {
1297                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
1298                 if (unref) {
1299                         moh = mohclass_unref(moh, "unreffing potential new moh class (unknown mode)");
1300                 }
1301                 return -1;
1302         }
1303
1304         ao2_t_link(mohclasses, moh, "Adding class to container");
1305
1306         if (unref) {
1307                 moh = mohclass_unref(moh, "Unreffing new moh class because we just added it to the container");
1308         }
1309
1310         return 0;
1311 }
1312
1313 static void local_ast_moh_cleanup(struct ast_channel *chan)
1314 {
1315         struct moh_files_state *state = chan->music_state;
1316
1317         if (state) {
1318                 if (state->class) {
1319                         /* This should never happen.  We likely just leaked some resource. */
1320                         state->class =
1321                                 mohclass_unref(state->class, "Uh Oh. Cleaning up MOH with an active class");
1322                         ast_log(LOG_WARNING, "Uh Oh. Cleaning up MOH with an active class\n");
1323                 }
1324                 ast_free(chan->music_state);
1325                 chan->music_state = NULL;
1326                 /* Only held a module reference if we had a music state */
1327                 ast_module_unref(ast_module_info->self);
1328         }
1329 }
1330
1331 static void moh_class_destructor(void *obj);
1332
1333 #define moh_class_malloc()      _moh_class_malloc(__FILE__,__LINE__,__PRETTY_FUNCTION__)
1334
1335 static struct mohclass *_moh_class_malloc(const char *file, int line, const char *funcname)
1336 {
1337         struct mohclass *class;
1338
1339         if ((class =
1340 #ifdef REF_DEBUG
1341                         __ao2_alloc_debug(sizeof(*class), moh_class_destructor, "Allocating new moh class", file, line, funcname, 1)
1342 #elif defined(__AST_DEBUG_MALLOC)
1343                         __ao2_alloc_debug(sizeof(*class), moh_class_destructor, "Allocating new moh class", file, line, funcname, 0)
1344 #else
1345                         ao2_alloc(sizeof(*class), moh_class_destructor)
1346 #endif
1347                 )) {
1348                 ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0);
1349                 class->srcfd = -1;
1350         }
1351
1352         return class;
1353 }
1354
1355 static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
1356 {
1357         struct mohclass *mohclass = NULL;
1358         struct moh_files_state *state = chan->music_state;
1359         struct ast_variable *var = NULL;
1360         int res;
1361         int realtime_possible = ast_check_realtime("musiconhold");
1362
1363         /* The following is the order of preference for which class to use:
1364          * 1) The channels explicitly set musicclass, which should *only* be
1365          *    set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
1366          * 2) The mclass argument. If a channel is calling ast_moh_start() as the
1367          *    result of receiving a HOLD control frame, this should be the
1368          *    payload that came with the frame.
1369          * 3) The interpclass argument. This would be from the mohinterpret
1370          *    option from channel drivers. This is the same as the old musicclass
1371          *    option.
1372          * 4) The default class.
1373          */
1374         if (!ast_strlen_zero(chan->musicclass)) {
1375                 mohclass = get_mohbyname(chan->musicclass, 1, 0);
1376                 if (!mohclass && realtime_possible) {
1377                         var = ast_load_realtime("musiconhold", "name", chan->musicclass, SENTINEL);
1378                 }
1379         }
1380         if (!mohclass && !var && !ast_strlen_zero(mclass)) {
1381                 mohclass = get_mohbyname(mclass, 1, 0);
1382                 if (!mohclass && realtime_possible) {
1383                         var = ast_load_realtime("musiconhold", "name", mclass, SENTINEL);
1384                 }
1385         }
1386         if (!mohclass && !var && !ast_strlen_zero(interpclass)) {
1387                 mohclass = get_mohbyname(interpclass, 1, 0);
1388                 if (!mohclass && realtime_possible) {
1389                         var = ast_load_realtime("musiconhold", "name", interpclass, SENTINEL);
1390                 }
1391         }
1392
1393         if (!mohclass && !var) {
1394                 mohclass = get_mohbyname("default", 1, 0);
1395                 if (!mohclass && realtime_possible) {
1396                         var = ast_load_realtime("musiconhold", "name", "default", SENTINEL);
1397                 }
1398         }
1399
1400         /* If no moh class found in memory, then check RT. Note that the logic used
1401          * above guarantees that if var is non-NULL, then mohclass must be NULL.
1402          */
1403         if (var) {
1404                 struct ast_variable *tmp = NULL;
1405
1406                 if ((mohclass = moh_class_malloc())) {
1407                         mohclass->realtime = 1;
1408                         for (tmp = var; tmp; tmp = tmp->next) {
1409                                 if (!strcasecmp(tmp->name, "name"))
1410                                         ast_copy_string(mohclass->name, tmp->value, sizeof(mohclass->name));
1411                                 else if (!strcasecmp(tmp->name, "mode"))
1412                                         ast_copy_string(mohclass->mode, tmp->value, sizeof(mohclass->mode)); 
1413                                 else if (!strcasecmp(tmp->name, "directory"))
1414                                         ast_copy_string(mohclass->dir, tmp->value, sizeof(mohclass->dir));
1415                                 else if (!strcasecmp(tmp->name, "application"))
1416                                         ast_copy_string(mohclass->args, tmp->value, sizeof(mohclass->args));
1417                                 else if (!strcasecmp(tmp->name, "digit") && (isdigit(*tmp->value) || strchr("*#", *tmp->value)))
1418                                         mohclass->digit = *tmp->value;
1419                                 else if (!strcasecmp(tmp->name, "random"))
1420                                         ast_set2_flag(mohclass, ast_true(tmp->value), MOH_RANDOMIZE);
1421                                 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "random"))
1422                                         ast_set_flag(mohclass, MOH_RANDOMIZE);
1423                                 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha")) 
1424                                         ast_set_flag(mohclass, MOH_SORTALPHA);
1425                                 else if (!strcasecmp(tmp->name, "format")) {
1426                                         ast_getformatbyname(tmp->value, &mohclass->format);
1427                                         if (!mohclass->format.id) {
1428                                                 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value);
1429                                                 ast_format_set(&mohclass->format, AST_FORMAT_SLINEAR, 0);
1430                                         }
1431                                 }
1432                         }
1433                         ast_variables_destroy(var);
1434                         if (ast_strlen_zero(mohclass->dir)) {
1435                                 if (!strcasecmp(mohclass->mode, "custom")) {
1436                                         strcpy(mohclass->dir, "nodir");
1437                                 } else {
1438                                         ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name);
1439                                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no directory specified)");
1440                                         return -1;
1441                                 }
1442                         }
1443                         if (ast_strlen_zero(mohclass->mode)) {
1444                                 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", mohclass->name);
1445                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no mode specified)");
1446                                 return -1;
1447                         }
1448                         if (ast_strlen_zero(mohclass->args) && !strcasecmp(mohclass->mode, "custom")) {
1449                                 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", mohclass->name);
1450                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no app specified for custom mode");
1451                                 return -1;
1452                         }
1453
1454                         if (ast_test_flag(global_flags, MOH_CACHERTCLASSES)) {
1455                                 /* CACHERTCLASSES enabled, let's add this class to default tree */
1456                                 if (state && state->class) {
1457                                         /* Class already exist for this channel */
1458                                         ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1459                                         if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) {
1460                                                 /* we found RT class with the same name, seems like we should continue playing existing one */
1461                                                 /* XXX This code is impossible to reach */
1462                                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has a class)");
1463                                                 mohclass = state->class;
1464                                         }
1465                                 }
1466                                 /* We don't want moh_register to unref the mohclass because we do it at the end of this function as well.
1467                                  * If we allowed moh_register to unref the mohclass,too, then the count would be off by one. The result would
1468                                  * be that the destructor would be called when the generator on the channel is deactivated. The container then
1469                                  * has a pointer to a freed mohclass, so any operations involving the mohclass container would result in reading
1470                                  * invalid memory.
1471                                  */
1472                                 if (moh_register(mohclass, 0, DONT_UNREF) == -1) {
1473                                         mohclass = mohclass_unref(mohclass, "unreffing mohclass failed to register");
1474                                         return -1;
1475                                 }
1476                         } else {
1477                                 /* We don't register RT moh class, so let's init it manualy */
1478
1479                                 time(&mohclass->start);
1480                                 mohclass->start -= respawn_time;
1481
1482                                 if (!strcasecmp(mohclass->mode, "files")) {
1483                                         if (!moh_scan_files(mohclass)) {
1484                                                 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
1485                                                 return -1;
1486                                         }
1487                                         if (strchr(mohclass->args, 'r'))
1488                                                 ast_set_flag(mohclass, MOH_RANDOMIZE);
1489                                 } 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")) {
1490
1491                                         if (!strcasecmp(mohclass->mode, "custom"))
1492                                                 ast_set_flag(mohclass, MOH_CUSTOM);
1493                                         else if (!strcasecmp(mohclass->mode, "mp3nb"))
1494                                                 ast_set_flag(mohclass, MOH_SINGLE);
1495                                         else if (!strcasecmp(mohclass->mode, "quietmp3nb"))
1496                                                 ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET);
1497                                         else if (!strcasecmp(mohclass->mode, "quietmp3"))
1498                                                 ast_set_flag(mohclass, MOH_QUIET);
1499
1500                                         mohclass->srcfd = -1;
1501                                         if (!(mohclass->timer = ast_timer_open())) {
1502                                                 ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
1503                                         }
1504                                         if (mohclass->timer && ast_timer_set_rate(mohclass->timer, 25)) {
1505                                                 ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
1506                                                 ast_timer_close(mohclass->timer);
1507                                                 mohclass->timer = NULL;
1508                                         }
1509
1510                                         /* Let's check if this channel already had a moh class before */
1511                                         if (state && state->class) {
1512                                                 /* Class already exist for this channel */
1513                                                 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1514                                                 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) {
1515                                                         /* we found RT class with the same name, seems like we should continue playing existing one */
1516                                                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has one)");
1517                                                         mohclass = state->class;
1518                                                 }
1519                                         } else {
1520                                                 if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) {
1521                                                         ast_log(LOG_WARNING, "Unable to create moh...\n");
1522                                                         if (mohclass->timer) {
1523                                                                 ast_timer_close(mohclass->timer);
1524                                                                 mohclass->timer = NULL;
1525                                                         }
1526                                                         mohclass = mohclass_unref(mohclass, "Unreffing potential mohclass (failed to create background thread)");
1527                                                         return -1;
1528                                                 }
1529                                         }
1530                                 } else {
1531                                         ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mohclass->mode);
1532                                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (unknown mode)");
1533                                         return -1;
1534                                 }
1535                         }
1536                 } else {
1537                         ast_variables_destroy(var);
1538                         var = NULL;
1539                 }
1540         }
1541
1542         if (!mohclass) {
1543                 return -1;
1544         }
1545
1546         /* If we are using a cached realtime class with files, re-scan the files */
1547         if (!var && ast_test_flag(global_flags, MOH_CACHERTCLASSES) && mohclass->realtime && !strcasecmp(mohclass->mode, "files")) {
1548                 if (!moh_scan_files(mohclass)) {
1549                         mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
1550                         return -1;
1551                 }
1552         }
1553
1554         ast_manager_event(chan, EVENT_FLAG_CALL, "MusicOnHold",
1555                 "State: Start\r\n"
1556                 "Channel: %s\r\n"
1557                 "UniqueID: %s\r\n"
1558                 "Class: %s\r\n",
1559                 ast_channel_name(chan), chan->uniqueid,
1560                 mohclass->name);
1561
1562         ast_set_flag(chan, AST_FLAG_MOH);
1563
1564         if (mohclass->total_files) {
1565                 res = ast_activate_generator(chan, &moh_file_stream, mohclass);
1566         } else {
1567                 res = ast_activate_generator(chan, &mohgen, mohclass);
1568         }
1569
1570         mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start");
1571
1572         return res;
1573 }
1574
1575 static void local_ast_moh_stop(struct ast_channel *chan)
1576 {
1577         ast_clear_flag(chan, AST_FLAG_MOH);
1578         ast_deactivate_generator(chan);
1579
1580         ast_channel_lock(chan);
1581         if (chan->music_state) {
1582                 if (chan->stream) {
1583                         ast_closestream(chan->stream);
1584                         chan->stream = NULL;
1585                 }
1586         }
1587
1588         ast_manager_event(chan, EVENT_FLAG_CALL, "MusicOnHold",
1589                 "State: Stop\r\n"
1590                 "Channel: %s\r\n"
1591                 "UniqueID: %s\r\n",
1592                 ast_channel_name(chan), chan->uniqueid);
1593         ast_channel_unlock(chan);
1594 }
1595
1596 static void moh_class_destructor(void *obj)
1597 {
1598         struct mohclass *class = obj;
1599         struct mohdata *member;
1600         pthread_t tid = 0;
1601
1602         ast_debug(1, "Destroying MOH class '%s'\n", class->name);
1603
1604         ao2_lock(class);
1605         while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) {
1606                 free(member);
1607         }
1608         ao2_unlock(class);
1609
1610         /* Kill the thread first, so it cannot restart the child process while the
1611          * class is being destroyed */
1612         if (class->thread != AST_PTHREADT_NULL && class->thread != 0) {
1613                 tid = class->thread;
1614                 class->thread = AST_PTHREADT_NULL;
1615                 pthread_cancel(tid);
1616                 /* We'll collect the exit status later, after we ensure all the readers
1617                  * are dead. */
1618         }
1619
1620         if (class->pid > 1) {
1621                 char buff[8192];
1622                 int bytes, tbytes = 0, stime = 0, pid = 0;
1623
1624                 ast_debug(1, "killing %d!\n", class->pid);
1625
1626                 stime = time(NULL) + 2;
1627                 pid = class->pid;
1628                 class->pid = 0;
1629
1630                 /* Back when this was just mpg123, SIGKILL was fine.  Now we need
1631                  * to give the process a reason and time enough to kill off its
1632                  * children. */
1633                 do {
1634                         if (killpg(pid, SIGHUP) < 0) {
1635                                 ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno));
1636                         }
1637                         usleep(100000);
1638                         if (killpg(pid, SIGTERM) < 0) {
1639                                 if (errno == ESRCH) {
1640                                         break;
1641                                 }
1642                                 ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno));
1643                         }
1644                         usleep(100000);
1645                         if (killpg(pid, SIGKILL) < 0) {
1646                                 if (errno == ESRCH) {
1647                                         break;
1648                                 }
1649                                 ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno));
1650                         }
1651                 } while (0);
1652
1653                 while ((ast_wait_for_input(class->srcfd, 100) > 0) && 
1654                                 (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) {
1655                         tbytes = tbytes + bytes;
1656                 }
1657
1658                 ast_debug(1, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1659
1660                 close(class->srcfd);
1661                 class->srcfd = -1;
1662         }
1663
1664         if (class->filearray) {
1665                 int i;
1666                 for (i = 0; i < class->total_files; i++) {
1667                         free(class->filearray[i]);
1668                 }
1669                 free(class->filearray);
1670                 class->filearray = NULL;
1671         }
1672
1673         if (class->timer) {
1674                 ast_timer_close(class->timer);
1675                 class->timer = NULL;
1676         }
1677
1678         /* Finally, collect the exit status of the monitor thread */
1679         if (tid > 0) {
1680                 pthread_join(tid, NULL);
1681         }
1682
1683 }
1684
1685 static int moh_class_mark(void *obj, void *arg, int flags)
1686 {
1687         struct mohclass *class = obj;
1688
1689         class->delete = 1;
1690
1691         return 0;
1692 }
1693
1694 static int moh_classes_delete_marked(void *obj, void *arg, int flags)
1695 {
1696         struct mohclass *class = obj;
1697
1698         return class->delete ? CMP_MATCH : 0;
1699 }
1700
1701 static int load_moh_classes(int reload)
1702 {
1703         struct ast_config *cfg;
1704         struct ast_variable *var;
1705         struct mohclass *class; 
1706         char *cat;
1707         int numclasses = 0;
1708         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1709
1710         cfg = ast_config_load("musiconhold.conf", config_flags);
1711
1712         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
1713                 if (ast_check_realtime("musiconhold") && reload) {
1714                         ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1715                         ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, moh_classes_delete_marked, NULL, "Purge marked classes");
1716                 }
1717                 return 0;
1718         }
1719         if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1720                 moh_rescan_files();
1721                 return 0;
1722         }
1723
1724         if (reload) {
1725                 ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1726         }
1727
1728         ast_clear_flag(global_flags, AST_FLAGS_ALL);
1729
1730         cat = ast_category_browse(cfg, NULL);
1731         for (; cat; cat = ast_category_browse(cfg, cat)) {
1732                 /* Setup common options from [general] section */
1733                 if (!strcasecmp(cat, "general")) {
1734                         for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1735                                 if (!strcasecmp(var->name, "cachertclasses")) {
1736                                         ast_set2_flag(global_flags, ast_true(var->value), MOH_CACHERTCLASSES);
1737                                 } else {
1738                                         ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name);
1739                                 }
1740                         }
1741                 }
1742                 /* These names were deprecated in 1.4 and should not be used until after the next major release. */
1743                 if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files") || 
1744                                 !strcasecmp(cat, "general")) {
1745                         continue;
1746                 }
1747
1748                 if (!(class = moh_class_malloc())) {
1749                         break;
1750                 }
1751
1752                 ast_copy_string(class->name, cat, sizeof(class->name));
1753                 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1754                         if (!strcasecmp(var->name, "mode")) {
1755                                 ast_copy_string(class->mode, var->value, sizeof(class->mode));
1756                         } else if (!strcasecmp(var->name, "directory")) {
1757                                 ast_copy_string(class->dir, var->value, sizeof(class->dir));
1758                         } else if (!strcasecmp(var->name, "application")) {
1759                                 ast_copy_string(class->args, var->value, sizeof(class->args));
1760                         } else if (!strcasecmp(var->name, "announcement")) {
1761                                 ast_copy_string(class->announcement, var->value, sizeof(class->announcement));
1762                                 ast_set_flag(class, MOH_ANNOUNCEMENT);
1763                         } else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value))) {
1764                                 class->digit = *var->value;
1765                         } else if (!strcasecmp(var->name, "random")) {
1766                                 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
1767                         } else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random")) {
1768                                 ast_set_flag(class, MOH_RANDOMIZE);
1769                         } else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) {
1770                                 ast_set_flag(class, MOH_SORTALPHA);
1771                         } else if (!strcasecmp(var->name, "format")) {
1772                                 ast_getformatbyname(var->value, &class->format);
1773                                 if (!class->format.id) {
1774                                         ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
1775                                         ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0);
1776                                 }
1777                         }
1778                 }
1779
1780                 if (ast_strlen_zero(class->dir)) {
1781                         if (!strcasecmp(class->mode, "custom")) {
1782                                 strcpy(class->dir, "nodir");
1783                         } else {
1784                                 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
1785                                 class = mohclass_unref(class, "unreffing potential mohclass (no directory)");
1786                                 continue;
1787                         }
1788                 }
1789                 if (ast_strlen_zero(class->mode)) {
1790                         ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
1791                         class = mohclass_unref(class, "unreffing potential mohclass (no mode)");
1792                         continue;
1793                 }
1794                 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
1795                         ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
1796                         class = mohclass_unref(class, "unreffing potential mohclass (no app for custom mode)");
1797                         continue;
1798                 }
1799
1800                 /* Don't leak a class when it's already registered */
1801                 if (!moh_register(class, reload, HANDLE_REF)) {
1802                         numclasses++;
1803                 }
1804         }
1805
1806         ast_config_destroy(cfg);
1807
1808         ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, 
1809                         moh_classes_delete_marked, NULL, "Purge marked classes");
1810
1811         return numclasses;
1812 }
1813
1814 static void ast_moh_destroy(void)
1815 {
1816         ast_verb(2, "Destroying musiconhold processes\n");
1817         ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Destroy callback");
1818 }
1819
1820 static char *handle_cli_moh_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1821 {
1822         switch (cmd) {
1823         case CLI_INIT:
1824                 e->command = "moh reload";
1825                 e->usage =
1826                         "Usage: moh reload\n"
1827                         "       Reloads the MusicOnHold module.\n"
1828                         "       Alias for 'module reload res_musiconhold.so'\n";
1829                 return NULL;
1830         case CLI_GENERATE:
1831                 return NULL;
1832         }
1833
1834         if (a->argc != e->args)
1835                 return CLI_SHOWUSAGE;
1836
1837         reload();
1838
1839         return CLI_SUCCESS;
1840 }
1841
1842 static char *handle_cli_moh_show_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1843 {
1844         struct mohclass *class;
1845         struct ao2_iterator i;
1846
1847         switch (cmd) {
1848         case CLI_INIT:
1849                 e->command = "moh show files";
1850                 e->usage =
1851                         "Usage: moh show files\n"
1852                         "       Lists all loaded file-based MusicOnHold classes and their\n"
1853                         "       files.\n";
1854                 return NULL;
1855         case CLI_GENERATE:
1856                 return NULL;
1857         }
1858
1859         if (a->argc != e->args)
1860                 return CLI_SHOWUSAGE;
1861
1862         i = ao2_iterator_init(mohclasses, 0);
1863         for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) {
1864                 int x;
1865
1866                 if (!class->total_files) {
1867                         continue;
1868                 }
1869
1870                 ast_cli(a->fd, "Class: %s\n", class->name);
1871                 for (x = 0; x < class->total_files; x++) {
1872                         ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]);
1873                 }
1874         }
1875         ao2_iterator_destroy(&i);
1876
1877         return CLI_SUCCESS;
1878 }
1879
1880 static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1881 {
1882         struct mohclass *class;
1883         struct ao2_iterator i;
1884
1885         switch (cmd) {
1886         case CLI_INIT:
1887                 e->command = "moh show classes";
1888                 e->usage =
1889                         "Usage: moh show classes\n"
1890                         "       Lists all MusicOnHold classes.\n";
1891                 return NULL;
1892         case CLI_GENERATE:
1893                 return NULL;
1894         }
1895
1896         if (a->argc != e->args)
1897                 return CLI_SHOWUSAGE;
1898
1899         i = ao2_iterator_init(mohclasses, 0);
1900         for (; (class = ao2_t_iterator_next(&i, "Show classes iterator")); mohclass_unref(class, "Unref iterator in moh show classes")) {
1901                 ast_cli(a->fd, "Class: %s\n", class->name);
1902                 ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
1903                 ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
1904                 if (ast_test_flag(class, MOH_CUSTOM)) {
1905                         ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
1906                 }
1907                 if (strcasecmp(class->mode, "files")) {
1908                         ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(&class->format));
1909                 }
1910         }
1911         ao2_iterator_destroy(&i);
1912
1913         return CLI_SUCCESS;
1914 }
1915
1916 static struct ast_cli_entry cli_moh[] = {
1917         AST_CLI_DEFINE(handle_cli_moh_reload,       "Reload MusicOnHold"),
1918         AST_CLI_DEFINE(handle_cli_moh_show_classes, "List MusicOnHold classes"),
1919         AST_CLI_DEFINE(handle_cli_moh_show_files,   "List MusicOnHold file-based classes")
1920 };
1921
1922 static int moh_class_hash(const void *obj, const int flags)
1923 {
1924         const struct mohclass *class = obj;
1925
1926         return ast_str_case_hash(class->name);
1927 }
1928
1929 static int moh_class_cmp(void *obj, void *arg, int flags)
1930 {
1931         struct mohclass *class = obj, *class2 = arg;
1932
1933         return strcasecmp(class->name, class2->name) ? 0 :
1934                 (flags & MOH_NOTDELETED) && (class->delete || class2->delete) ? 0 :
1935                 CMP_MATCH | CMP_STOP;
1936 }
1937
1938 static int load_module(void)
1939 {
1940         int res;
1941
1942         if (!(mohclasses = ao2_t_container_alloc(53, moh_class_hash, moh_class_cmp, "Moh class container"))) {
1943                 return AST_MODULE_LOAD_DECLINE;
1944         }
1945
1946         if (!load_moh_classes(0) && ast_check_realtime("musiconhold") == 0) {   /* No music classes configured, so skip it */
1947                 ast_log(LOG_WARNING, "No music on hold classes configured, "
1948                                 "disabling music on hold.\n");
1949         } else {
1950                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop,
1951                                 local_ast_moh_cleanup);
1952         }
1953
1954         res = ast_register_application_xml(play_moh, play_moh_exec);
1955         ast_register_atexit(ast_moh_destroy);
1956         ast_cli_register_multiple(cli_moh, ARRAY_LEN(cli_moh));
1957         if (!res)
1958                 res = ast_register_application_xml(wait_moh, wait_moh_exec);
1959         if (!res)
1960                 res = ast_register_application_xml(set_moh, set_moh_exec);
1961         if (!res)
1962                 res = ast_register_application_xml(start_moh, start_moh_exec);
1963         if (!res)
1964                 res = ast_register_application_xml(stop_moh, stop_moh_exec);
1965
1966         return AST_MODULE_LOAD_SUCCESS;
1967 }
1968
1969 static int reload(void)
1970 {
1971         if (load_moh_classes(1)) {
1972                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop,
1973                                 local_ast_moh_cleanup);
1974         }
1975
1976         return AST_MODULE_LOAD_SUCCESS;
1977 }
1978
1979 static int moh_class_inuse(void *obj, void *arg, int flags)
1980 {
1981         struct mohclass *class = obj;
1982
1983         return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP;
1984 }
1985
1986 static int unload_module(void)
1987 {
1988         int res = 0;
1989         struct mohclass *class = NULL;
1990
1991         /* XXX This check shouldn't be required if module ref counting was being used
1992          * properly ... */
1993         if ((class = ao2_t_callback(mohclasses, 0, moh_class_inuse, NULL, "Module unload callback"))) {
1994                 class = mohclass_unref(class, "unref of class from module unload callback");
1995                 res = -1;
1996         }
1997
1998         if (res < 0) {
1999                 ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n");
2000                 return res;
2001         }
2002
2003         ast_uninstall_music_functions();
2004
2005         ast_moh_destroy();
2006         res = ast_unregister_application(play_moh);
2007         res |= ast_unregister_application(wait_moh);
2008         res |= ast_unregister_application(set_moh);
2009         res |= ast_unregister_application(start_moh);
2010         res |= ast_unregister_application(stop_moh);
2011         ast_cli_unregister_multiple(cli_moh, ARRAY_LEN(cli_moh));
2012         ast_unregister_atexit(ast_moh_destroy);
2013
2014         return res;
2015 }
2016
2017 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Music On Hold Resource",
2018         .load = load_module,
2019         .unload = unload_module,
2020         .reload = reload,
2021         .load_pri = AST_MODPRI_CHANNEL_DEPEND,
2022 );