Fixed call parking, added separate paramater to allow/disallow call parking on
[asterisk/asterisk.git] / res / res_monitor.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <libgen.h>             //dirname()
8
9 #include <asterisk/lock.h>
10 #include <asterisk/channel.h>
11 #include <asterisk/logger.h>
12 #include <asterisk/file.h>
13 #include <asterisk/pbx.h>
14 #include <asterisk/module.h>
15 #include <asterisk/manager.h>
16 #include <asterisk/cli.h>
17 #include <asterisk/monitor.h>
18 #include <asterisk/app.h>
19 #include <asterisk/utils.h>
20 #include <asterisk/config.h>
21 #include "../asterisk.h"
22 #include "../astconf.h"
23
24 #define AST_MONITOR_DIR AST_SPOOL_DIR "/monitor"
25
26 AST_MUTEX_DEFINE_STATIC(monitorlock);
27
28 static unsigned long seq = 0;
29
30 static char *monitor_synopsis = "Monitor a channel";
31
32 static char *monitor_descrip = "Monitor([file_format[:urlbase]|[fname_base]|[options]]):\n"
33 "Used to start monitoring a channel. The channel's input and output\n"
34 "voice packets are logged to files until the channel hangs up or\n"
35 "monitoring is stopped by the StopMonitor application.\n"
36 "      file_format -- optional, if not set, defaults to \"wav\"\n"
37 "      fname_base -- if set, changes the filename used to the one specified.\n"
38 "      options:\n"
39 "              'm' - when the recording ends mix the two leg files into one and\n"
40 "                    delete the two leg files.  If MONITOR_EXEC is set, the\n"
41 "                    application refernced in it will be executed instead of\n"
42 "                    soxmix and the raw leg files will NOT be deleted automatically.\n"
43 "                    soxmix or MONITOR_EXEC is handed 3 arguments, the two leg files\n"
44 "                    and a target mixed file name which is the same as the leg file names\n"
45 "                    only without the in/out designator.\n"
46 "                    If MONITOR_EXEC_ARGS is set, the contents will be passed on as\n"
47 "                    additional arguements to MONITOR_EXEC\n"
48 "                    Both MONITOR_EXEC and the Mix flag can be set from the\n"
49 "                    administrator interface\n\n"
50 "\n"
51 "              'b' - Don't begin recording unless a call is bridged to another channel\n"
52 ;
53
54 static char *stopmonitor_synopsis = "Stop monitoring a channel";
55
56 static char *stopmonitor_descrip = "StopMonitor\n"
57         "Stops monitoring a channel. Has no effect if the channel is not monitored\n";
58
59 static char *changemonitor_synopsis = "Change monitoring filename of a channel";
60
61 static char *changemonitor_descrip = "ChangeMonitor\n"
62         "Changes monitoring filename of a channel. Has no effect if the channel is not monitored\n"
63         "The option string may contain the following:\n"
64         "       filename_base -- if set, changes the filename used to the one specified.\n";
65
66 /* Start monitoring a channel */
67 int ast_monitor_start(  struct ast_channel *chan, const char *format_spec,
68                                                 const char *fname_base, int need_lock)
69 {
70         int res = 0;
71         char tmp[256];
72
73         if (need_lock) {
74                 if (ast_mutex_lock(&chan->lock)) {
75                         ast_log(LOG_WARNING, "Unable to lock channel\n");
76                         return -1;
77                 }
78         }
79
80         if (!(chan->monitor)) {
81                 struct ast_channel_monitor *monitor;
82                 char *channel_name, *p;
83
84                 /* Create monitoring directory if needed */
85                 if (mkdir(AST_MONITOR_DIR, 0770) < 0) {
86                         if (errno != EEXIST) {
87                                 ast_log(LOG_WARNING, "Unable to create audio monitor directory: %s\n",
88                                                 strerror(errno));
89                         }
90                 }
91
92                 monitor = malloc(sizeof(struct ast_channel_monitor));
93                 if (!monitor) {
94                         if (need_lock) 
95                                 ast_mutex_unlock(&chan->lock);
96                         return -1;
97                 }
98                 memset(monitor, 0, sizeof(struct ast_channel_monitor));
99
100                 /* Determine file names */
101                 if (fname_base && !ast_strlen_zero(fname_base)) {
102                         int directory = strchr(fname_base, '/') ? 1 : 0;
103                         /* try creating the directory just in case it doesn't exist */
104                         if (directory) {
105                                 char *name = strdup(fname_base);
106                                 snprintf(tmp, sizeof(tmp), "mkdir -p \"%s\"",dirname(name));
107                                 free(name);
108                                 system(tmp);
109                         }
110                         snprintf(monitor->read_filename, FILENAME_MAX, "%s/%s-in",
111                                                 directory ? "" : AST_MONITOR_DIR, fname_base);
112                         snprintf(monitor->write_filename, FILENAME_MAX, "%s/%s-out",
113                                                 directory ? "" : AST_MONITOR_DIR, fname_base);
114                         strncpy(monitor->filename_base, fname_base, sizeof(monitor->filename_base) - 1);
115                 } else {
116                         ast_mutex_lock(&monitorlock);
117                         snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld",
118                                                 AST_MONITOR_DIR, seq);
119                         snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld",
120                                                 AST_MONITOR_DIR, seq);
121                         seq++;
122                         ast_mutex_unlock(&monitorlock);
123
124                         channel_name = strdup(chan->name);
125                         while((p = strchr(channel_name, '/'))) {
126                                 *p = '-';
127                         }
128                         snprintf(monitor->filename_base, FILENAME_MAX, "%s/%s",
129                                                 AST_MONITOR_DIR, channel_name);
130                         monitor->filename_changed = 1;
131                         free(channel_name);
132                 }
133
134                 monitor->stop = ast_monitor_stop;
135
136                 // Determine file format
137                 if (format_spec && !ast_strlen_zero(format_spec)) {
138                         monitor->format = strdup(format_spec);
139                 } else {
140                         monitor->format = strdup("wav");
141                 }
142                 
143                 // open files
144                 if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0) {
145                         ast_filedelete(monitor->read_filename, NULL);
146                 }
147                 if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
148                                                 monitor->format, NULL,
149                                                 O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) {
150                         ast_log(LOG_WARNING, "Could not create file %s\n",
151                                                 monitor->read_filename);
152                         free(monitor);
153                         ast_mutex_unlock(&chan->lock);
154                         return -1;
155                 }
156                 if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
157                         ast_filedelete(monitor->write_filename, NULL);
158                 }
159                 if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
160                                                 monitor->format, NULL,
161                                                 O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) {
162                         ast_log(LOG_WARNING, "Could not create file %s\n",
163                                                 monitor->write_filename);
164                         ast_closestream(monitor->read_stream);
165                         free(monitor);
166                         ast_mutex_unlock(&chan->lock);
167                         return -1;
168                 }
169                 chan->monitor = monitor;
170         } else {
171                 ast_log(LOG_DEBUG,"Cannot start monitoring %s, already monitored\n",
172                                         chan->name);
173                 res = -1;
174         }
175
176         if (need_lock) {
177                 ast_mutex_unlock(&chan->lock);
178         }
179         return res;
180 }
181
182 /* Stop monitoring a channel */
183 int ast_monitor_stop(struct ast_channel *chan, int need_lock)
184 {
185         char *execute, *execute_args;
186         int delfiles = 0;
187
188         if (need_lock) {
189                 if (ast_mutex_lock(&chan->lock)) {
190                         ast_log(LOG_WARNING, "Unable to lock channel\n");
191                         return -1;
192                 }
193         }
194
195         if (chan->monitor) {
196                 char filename[ FILENAME_MAX ];
197
198                 if (chan->monitor->read_stream) {
199                         ast_closestream(chan->monitor->read_stream);
200                 }
201                 if (chan->monitor->write_stream) {
202                         ast_closestream(chan->monitor->write_stream);
203                 }
204
205                 if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) {
206                         if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) {
207                                 snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base);
208                                 if (ast_fileexists(filename, NULL, NULL) > 0) {
209                                         ast_filedelete(filename, NULL);
210                                 }
211                                 ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format);
212                         } else {
213                                 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename);
214                         }
215
216                         if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) {
217                                 snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base);
218                                 if (ast_fileexists(filename, NULL, NULL) > 0) {
219                                         ast_filedelete(filename, NULL);
220                                 }
221                                 ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format);
222                         } else {
223                                 ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename);
224                         }
225                 }
226
227                 if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) {
228                         char tmp[1024];
229                         char tmp2[1024];
230                         char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
231                         char *name = chan->monitor->filename_base;
232                         int directory = strchr(name, '/') ? 1 : 0;
233                         char *dir = directory ? "" : AST_MONITOR_DIR;
234
235                         /* Set the execute application */
236                         execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
237                         if (!execute || ast_strlen_zero(execute)) { 
238                                 execute = "nice -n 19 soxmix"; 
239                                 delfiles = 1;
240                         } 
241                         execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
242                         if (!execute_args || ast_strlen_zero(execute_args)) {
243                                 execute_args = "";
244                         }
245                         
246                         snprintf(tmp, sizeof(tmp), "%s \"%s/%s-in.%s\" \"%s/%s-out.%s\" \"%s/%s.%s\" %s &", execute, dir, name, format, dir, name, format, dir, name, format,execute_args);
247                         if (delfiles) {
248                                 snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s\"/%s-* ) &",tmp, dir ,name); /* remove legs when done mixing */
249                                 strncpy(tmp, tmp2, sizeof(tmp) - 1);
250                         }
251                         ast_verbose("monitor executing %s\n",tmp);
252                         if (ast_safe_system(tmp) == -1)
253                                 ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
254                 }
255                 
256                 free(chan->monitor->format);
257                 free(chan->monitor);
258                 chan->monitor = NULL;
259         }
260
261         if (need_lock)
262                 ast_mutex_unlock(&chan->lock);
263         return 0;
264 }
265
266 /* Change monitoring filename of a channel */
267 int ast_monitor_change_fname(struct ast_channel *chan, const char *fname_base, int need_lock)
268 {
269         char tmp[256];
270         if ((!fname_base) || (ast_strlen_zero(fname_base))) {
271                 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null", chan->name);
272                 return -1;
273         }
274         
275         if (need_lock) {
276                 if (ast_mutex_lock(&chan->lock)) {
277                         ast_log(LOG_WARNING, "Unable to lock channel\n");
278                         return -1;
279                 }
280         }
281
282         if (chan->monitor) {
283                 int directory = strchr(fname_base, '/') ? 1 : 0;
284                 /* try creating the directory just in case it doesn't exist */
285                 if (directory) {
286                         char *name = strdup(fname_base);
287                         snprintf(tmp, sizeof(tmp), "mkdir -p %s",dirname(name));
288                         free(name);
289                         system(tmp);
290                 }
291
292                 snprintf(chan->monitor->filename_base, FILENAME_MAX, "%s/%s", directory ? "" : AST_MONITOR_DIR, fname_base);
293         } else {
294                 ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started", chan->name, fname_base);
295         }
296
297         if (need_lock)
298                 ast_mutex_unlock(&chan->lock);
299
300         return 0;
301 }
302
303 static int start_monitor_exec(struct ast_channel *chan, void *data)
304 {
305         char *arg = NULL;
306         char *format = NULL;
307         char *fname_base = NULL;
308         char *options = NULL;
309         char *delay = NULL;
310         char *urlprefix = NULL;
311         char tmp[256];
312         int joinfiles = 0;
313         int waitforbridge = 0;
314         int res = 0;
315         
316         /* Parse arguments. */
317         if (data && !ast_strlen_zero((char*)data)) {
318                 arg = ast_strdupa((char*)data);
319                 format = arg;
320                 arg = strchr(format,':');
321                 if (arg)
322                 {
323                         *arg++ = 0;
324                         urlprefix = arg;
325                 }
326                 else arg = format;
327                 fname_base = strchr(arg, '|');
328                 if (fname_base) {
329                         *fname_base = 0;
330                         fname_base++;
331                         if ((options = strchr(fname_base, '|'))) {
332                                 *options = 0;
333                                 options++;
334                                 if (strchr(options, 'm'))
335                                         joinfiles = 1;
336                                 if (strchr(options, 'b'))
337                                         waitforbridge = 1;
338                         }
339                 }
340         }
341         if (urlprefix)
342         {
343                 snprintf(tmp,sizeof(tmp) - 1,"%s/%s.%s",urlprefix,fname_base,
344                         ((strcmp(format,"gsm")) ? "wav" : "gsm"));
345                 if (!chan->cdr)
346                         chan->cdr = ast_cdr_alloc();
347                 ast_cdr_setuserfield(chan, tmp);
348         }
349         if (waitforbridge) {
350                 /* We must remove the "b" option if listed.  In principle none of
351                    the following could give NULL results, but we check just to
352                    be pedantic. Reconstructing with checks for 'm' option does not
353                    work if we end up adding more options than 'm' in the future. */
354                 delay = ast_strdupa((char*)data);
355                 if (delay) {
356                         options = strrchr(delay, '|');
357                         if (options) {
358                                 arg = strchr(options, 'b');
359                                 if (arg) {
360                                         *arg = 'X';
361                                         pbx_builtin_setvar_helper(chan,"AUTO_MONITOR",delay);
362                                 }
363                         }
364                 }
365                 return 0;
366         }
367
368         res = ast_monitor_start(chan, format, fname_base, 1);
369         if (res < 0)
370                 res = ast_monitor_change_fname(chan, fname_base, 1);
371         ast_monitor_setjoinfiles(chan, joinfiles);
372
373         return res;
374 }
375
376 static int stop_monitor_exec(struct ast_channel *chan, void *data)
377 {
378         return ast_monitor_stop(chan, 1);
379 }
380
381 static int change_monitor_exec(struct ast_channel *chan, void *data)
382 {
383         return ast_monitor_change_fname(chan, (const char*)data, 1);
384 }
385
386 static int start_monitor_action(struct mansession *s, struct message *m)
387 {
388         struct ast_channel *c = NULL;
389         char *name = astman_get_header(m, "Channel");
390         char *fname = astman_get_header(m, "File");
391         char *format = astman_get_header(m, "Format");
392         char *mix = astman_get_header(m, "Mix");
393         char *d;
394         
395         if ((!name) || (ast_strlen_zero(name))) {
396                 astman_send_error(s, m, "No channel specified");
397                 return 0;
398         }
399         c = ast_channel_walk_locked(NULL);
400         while (c) {
401                 if (!strcasecmp(c->name, name)) {
402                         break;
403                 }
404                 ast_mutex_unlock(&c->lock);
405                 c = ast_channel_walk_locked(c);
406         }
407         if (!c) {
408                 astman_send_error(s, m, "No such channel");
409                 return 0;
410         }
411
412         if ((!fname) || (ast_strlen_zero(fname))) {
413                 // No filename base specified, default to channel name as per CLI
414                 fname = malloc (FILENAME_MAX);
415                 if (!fname) {
416                         astman_send_error(s, m, "Could not start monitoring channel");
417                         ast_mutex_unlock(&c->lock);
418                         return 0;
419                 }
420                 memset(fname, 0, FILENAME_MAX);
421                 strncpy(fname, c->name, FILENAME_MAX-1);
422                 // Channels have the format technology/channel_name - have to replace that / 
423                 if ((d=strchr(fname, '/'))) *d='-';
424         }
425         
426         if (ast_monitor_start(c, format, fname, 1)) {
427                 if (ast_monitor_change_fname(c, fname, 1)) {
428                         astman_send_error(s, m, "Could not start monitoring channel");
429                         ast_mutex_unlock(&c->lock);
430                         return 0;
431                 }
432         }
433
434         if (ast_true(mix)) {
435                 ast_monitor_setjoinfiles(c, 1);
436         }
437
438         ast_mutex_unlock(&c->lock);
439         astman_send_ack(s, m, "Started monitoring channel");
440         return 0;
441 }
442
443 static int stop_monitor_action(struct mansession *s, struct message *m)
444 {
445         struct ast_channel *c = NULL;
446         char *name = astman_get_header(m, "Channel");
447         int res;
448         if ((!name) || (ast_strlen_zero(name))) {
449                 astman_send_error(s, m, "No channel specified");
450                 return 0;
451         }
452         c = ast_channel_walk_locked(NULL);
453         while(c) {
454                 if (!strcasecmp(c->name, name)) {
455                         break;
456                 }
457                 ast_mutex_unlock(&c->lock);
458                 c = ast_channel_walk_locked(c);
459         }
460         if (!c) {
461                 astman_send_error(s, m, "No such channel");
462                 return 0;
463         }
464         res = ast_monitor_stop(c, 1);
465         ast_mutex_unlock(&c->lock);
466         if (res) {
467                 astman_send_error(s, m, "Could not stop monitoring channel");
468                 return 0;
469         }
470         astman_send_ack(s, m, "Stopped monitoring channel");
471         return 0;
472 }
473
474 static int change_monitor_action(struct mansession *s, struct message *m)
475 {
476         struct ast_channel *c = NULL;
477         char *name = astman_get_header(m, "Channel");
478         char *fname = astman_get_header(m, "File");
479         if ((!name) || (ast_strlen_zero(name))) {
480                 astman_send_error(s, m, "No channel specified");
481                 return 0;
482         }
483         if ((!fname)||(ast_strlen_zero(fname))) {
484                 astman_send_error(s, m, "No filename specified");
485                 return 0;
486         }
487         c = ast_channel_walk_locked(NULL);
488         while(c) {
489                 if (!strcasecmp(c->name, name)) {
490                         break;
491                 }
492                 ast_mutex_unlock(&c->lock);
493                 c = ast_channel_walk_locked(c);
494         }
495         if (!c) {
496                 astman_send_error(s, m, "No such channel");
497                 return 0;
498         }
499         if (ast_monitor_change_fname(c, fname, 1)) {
500                 astman_send_error(s, m, "Could not change monitored filename of channel");
501                 ast_mutex_unlock(&c->lock);
502                 return 0;
503         }
504         ast_mutex_unlock(&c->lock);
505         astman_send_ack(s, m, "Stopped monitoring channel");
506         return 0;
507 }
508
509 void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon)
510 {
511         if (chan->monitor)
512                 chan->monitor->joinfiles = turnon;
513 }
514
515 int load_module(void)
516 {
517         ast_register_application("Monitor", start_monitor_exec, monitor_synopsis, monitor_descrip);
518         ast_register_application("StopMonitor", stop_monitor_exec, stopmonitor_synopsis, stopmonitor_descrip);
519         ast_register_application("ChangeMonitor", change_monitor_exec, changemonitor_synopsis, changemonitor_descrip);
520         ast_manager_register("Monitor", EVENT_FLAG_CALL, start_monitor_action, monitor_synopsis);
521         ast_manager_register("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action, stopmonitor_synopsis);
522         ast_manager_register("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action, changemonitor_synopsis);
523
524         return 0;
525 }
526
527 int unload_module(void)
528 {
529         ast_unregister_application("Monitor");
530         ast_unregister_application("StopMonitor");
531         return 0;
532 }
533
534 char *description(void)
535 {
536         return "Call Monitoring Resource";
537 }
538
539 int usecount(void)
540 {
541         /* Never allow monitor to be unloaded because it will
542            unresolve needed symbols in the channel */
543 #if 0
544         int res;
545         STANDARD_USECOUNT(res);
546         return res;
547 #else
548         return 1;
549 #endif
550 }
551
552 char *key()
553 {
554         return ASTERISK_GPL_KEY;
555 }