Wed Jan 8 2020 09:49:39

Asterisk developer's documentation


app_chanspy.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2005 Anthony Minessale II (anthmct@yahoo.com)
5  * Copyright (C) 2005 - 2008, Digium, Inc.
6  *
7  * A license has been granted to Digium (via disclaimer) for the use of
8  * this code.
9  *
10  * See http://www.asterisk.org for more information about
11  * the Asterisk project. Please do not directly contact
12  * any of the maintainers of this project for assistance;
13  * the project provides a web site, mailing lists and IRC
14  * channels for your use.
15  *
16  * This program is free software, distributed under the terms of
17  * the GNU General Public License Version 2. See the LICENSE file
18  * at the top of the source tree.
19  */
20 
21 /*! \file
22  *
23  * \brief ChanSpy: Listen in on any channel.
24  *
25  * \author Anthony Minessale II <anthmct@yahoo.com>
26  * \author Joshua Colp <jcolp@digium.com>
27  * \author Russell Bryant <russell@digium.com>
28  *
29  * \ingroup applications
30  */
31 
32 /*** MODULEINFO
33  <support_level>core</support_level>
34  ***/
35 
36 #include "asterisk.h"
37 
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 408536 $")
39 
40 #include <ctype.h>
41 #include <errno.h>
42 
43 #include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */
44 #include "asterisk/file.h"
45 #include "asterisk/channel.h"
46 #include "asterisk/audiohook.h"
47 #include "asterisk/features.h"
48 #include "asterisk/app.h"
49 #include "asterisk/utils.h"
50 #include "asterisk/say.h"
51 #include "asterisk/pbx.h"
52 #include "asterisk/translate.h"
53 #include "asterisk/manager.h"
54 #include "asterisk/module.h"
55 #include "asterisk/lock.h"
56 #include "asterisk/options.h"
57 #include "asterisk/autochan.h"
58 
59 #define AST_NAME_STRLEN 256
60 #define NUM_SPYGROUPS 128
61 
62 /*** DOCUMENTATION
63  <application name="ChanSpy" language="en_US">
64  <synopsis>
65  Listen to a channel, and optionally whisper into it.
66  </synopsis>
67  <syntax>
68  <parameter name="chanprefix" />
69  <parameter name="options">
70  <optionlist>
71  <option name="b">
72  <para>Only spy on channels involved in a bridged call.</para>
73  </option>
74  <option name="B">
75  <para>Instead of whispering on a single channel barge in on both
76  channels involved in the call.</para>
77  </option>
78  <option name="c">
79  <argument name="digit" required="true">
80  <para>Specify a DTMF digit that can be used to spy on the next available channel.</para>
81  </argument>
82  </option>
83  <option name="d">
84  <para>Override the typical numeric DTMF functionality and instead
85  use DTMF to switch between spy modes.</para>
86  <enumlist>
87  <enum name="4">
88  <para>spy mode</para>
89  </enum>
90  <enum name="5">
91  <para>whisper mode</para>
92  </enum>
93  <enum name="6">
94  <para>barge mode</para>
95  </enum>
96  </enumlist>
97  </option>
98  <option name="e">
99  <argument name="ext" required="true" />
100  <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
101  only monitor extensions whose name is in the <replaceable>ext</replaceable> : delimited
102  list.</para>
103  </option>
104  <option name="E">
105  <para>Exit when the spied-on channel hangs up.</para>
106  </option>
107  <option name="g">
108  <argument name="grp" required="true">
109  <para>Only spy on channels in which one or more of the groups
110  listed in <replaceable>grp</replaceable> matches one or more groups from the
111  <variable>SPYGROUP</variable> variable set on the channel to be spied upon.</para>
112  </argument>
113  <note><para>both <replaceable>grp</replaceable> and <variable>SPYGROUP</variable> can contain
114  either a single group or a colon-delimited list of groups, such
115  as <literal>sales:support:accounting</literal>.</para></note>
116  </option>
117  <option name="n" argsep="@">
118  <para>Say the name of the person being spied on if that person has recorded
119  his/her name. If a context is specified, then that voicemail context will
120  be searched when retrieving the name, otherwise the <literal>default</literal> context
121  be used when searching for the name (i.e. if SIP/1000 is the channel being
122  spied on and no mailbox is specified, then <literal>1000</literal> will be used when searching
123  for the name).</para>
124  <argument name="mailbox" />
125  <argument name="context" />
126  </option>
127  <option name="o">
128  <para>Only listen to audio coming from this channel.</para>
129  </option>
130  <option name="q">
131  <para>Don't play a beep when beginning to spy on a channel, or speak the
132  selected channel name.</para>
133  </option>
134  <option name="r">
135  <para>Record the session to the monitor spool directory. An optional base for the filename
136  may be specified. The default is <literal>chanspy</literal>.</para>
137  <argument name="basename" />
138  </option>
139  <option name="s">
140  <para>Skip the playback of the channel type (i.e. SIP, IAX, etc) when
141  speaking the selected channel name.</para>
142  </option>
143  <option name="S">
144  <para>Stop when no more channels are left to spy on.</para>
145  </option>
146  <option name="v">
147  <argument name="value" />
148  <para>Adjust the initial volume in the range from <literal>-4</literal>
149  to <literal>4</literal>. A negative value refers to a quieter setting.</para>
150  </option>
151  <option name="w">
152  <para>Enable <literal>whisper</literal> mode, so the spying channel can talk to
153  the spied-on channel.</para>
154  </option>
155  <option name="W">
156  <para>Enable <literal>private whisper</literal> mode, so the spying channel can
157  talk to the spied-on channel but cannot listen to that channel.</para>
158  </option>
159  <option name="x">
160  <argument name="digit" required="true">
161  <para>Specify a DTMF digit that can be used to exit the application while actively
162  spying on a channel. If there is no channel being spied on, the DTMF digit will be
163  ignored.</para>
164  </argument>
165  </option>
166  <option name="X">
167  <para>Allow the user to exit ChanSpy to a valid single digit
168  numeric extension in the current context or the context
169  specified by the <variable>SPY_EXIT_CONTEXT</variable> channel variable. The
170  name of the last channel that was spied on will be stored
171  in the <variable>SPY_CHANNEL</variable> variable.</para>
172  </option>
173  </optionlist>
174  </parameter>
175  </syntax>
176  <description>
177  <para>This application is used to listen to the audio from an Asterisk channel. This includes the audio
178  coming in and out of the channel being spied on. If the <literal>chanprefix</literal> parameter is specified,
179  only channels beginning with this string will be spied upon.</para>
180  <para>While spying, the following actions may be performed:</para>
181  <para> - Dialing <literal>#</literal> cycles the volume level.</para>
182  <para> - Dialing <literal>*</literal> will stop spying and look for another channel to spy on.</para>
183  <para> - Dialing a series of digits followed by <literal>#</literal> builds a channel name to append
184  to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing the digits '1234#'
185  while spying will begin spying on the channel 'Agent/1234'. Note that this feature will be overridden if the 'd' option
186  is used</para>
187  <note><para>The <replaceable>X</replaceable> option supersedes the three features above in that if a valid
188  single digit extension exists in the correct context ChanSpy will exit to it.
189  This also disables choosing a channel based on <literal>chanprefix</literal> and a digit sequence.</para></note>
190  </description>
191  <see-also>
192  <ref type="application">ExtenSpy</ref>
193  </see-also>
194  </application>
195  <application name="ExtenSpy" language="en_US">
196  <synopsis>
197  Listen to a channel, and optionally whisper into it.
198  </synopsis>
199  <syntax>
200  <parameter name="exten" required="true" argsep="@">
201  <argument name="exten" required="true">
202  <para>Specify extension.</para>
203  </argument>
204  <argument name="context">
205  <para>Optionally specify a context, defaults to <literal>default</literal>.</para>
206  </argument>
207  </parameter>
208  <parameter name="options">
209  <optionlist>
210  <option name="b">
211  <para>Only spy on channels involved in a bridged call.</para>
212  </option>
213  <option name="B">
214  <para>Instead of whispering on a single channel barge in on both
215  channels involved in the call.</para>
216  </option>
217  <option name="c">
218  <argument name="digit" required="true">
219  <para>Specify a DTMF digit that can be used to spy on the next available channel.</para>
220  </argument>
221  </option>
222  <option name="d">
223  <para>Override the typical numeric DTMF functionality and instead
224  use DTMF to switch between spy modes.</para>
225  <enumlist>
226  <enum name="4">
227  <para>spy mode</para>
228  </enum>
229  <enum name="5">
230  <para>whisper mode</para>
231  </enum>
232  <enum name="6">
233  <para>barge mode</para>
234  </enum>
235  </enumlist>
236  </option>
237  <option name="e">
238  <argument name="ext" required="true" />
239  <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
240  only monitor extensions whose name is in the <replaceable>ext</replaceable> : delimited
241  list.</para>
242  </option>
243  <option name="E">
244  <para>Exit when the spied-on channel hangs up.</para>
245  </option>
246  <option name="g">
247  <argument name="grp" required="true">
248  <para>Only spy on channels in which one or more of the groups
249  listed in <replaceable>grp</replaceable> matches one or more groups from the
250  <variable>SPYGROUP</variable> variable set on the channel to be spied upon.</para>
251  </argument>
252  <note><para>both <replaceable>grp</replaceable> and <variable>SPYGROUP</variable> can contain
253  either a single group or a colon-delimited list of groups, such
254  as <literal>sales:support:accounting</literal>.</para></note>
255  </option>
256  <option name="n" argsep="@">
257  <para>Say the name of the person being spied on if that person has recorded
258  his/her name. If a context is specified, then that voicemail context will
259  be searched when retrieving the name, otherwise the <literal>default</literal> context
260  be used when searching for the name (i.e. if SIP/1000 is the channel being
261  spied on and no mailbox is specified, then <literal>1000</literal> will be used when searching
262  for the name).</para>
263  <argument name="mailbox" />
264  <argument name="context" />
265  </option>
266  <option name="o">
267  <para>Only listen to audio coming from this channel.</para>
268  </option>
269  <option name="q">
270  <para>Don't play a beep when beginning to spy on a channel, or speak the
271  selected channel name.</para>
272  </option>
273  <option name="r">
274  <para>Record the session to the monitor spool directory. An optional base for the filename
275  may be specified. The default is <literal>chanspy</literal>.</para>
276  <argument name="basename" />
277  </option>
278  <option name="s">
279  <para>Skip the playback of the channel type (i.e. SIP, IAX, etc) when
280  speaking the selected channel name.</para>
281  </option>
282  <option name="S">
283  <para>Stop when there are no more extensions left to spy on.</para>
284  </option>
285  <option name="v">
286  <argument name="value" />
287  <para>Adjust the initial volume in the range from <literal>-4</literal>
288  to <literal>4</literal>. A negative value refers to a quieter setting.</para>
289  </option>
290  <option name="w">
291  <para>Enable <literal>whisper</literal> mode, so the spying channel can talk to
292  the spied-on channel.</para>
293  </option>
294  <option name="W">
295  <para>Enable <literal>private whisper</literal> mode, so the spying channel can
296  talk to the spied-on channel but cannot listen to that channel.</para>
297  </option>
298  <option name="x">
299  <argument name="digit" required="true">
300  <para>Specify a DTMF digit that can be used to exit the application while actively
301  spying on a channel. If there is no channel being spied on, the DTMF digit will be
302  ignored.</para>
303  </argument>
304  </option>
305  <option name="X">
306  <para>Allow the user to exit ChanSpy to a valid single digit
307  numeric extension in the current context or the context
308  specified by the <variable>SPY_EXIT_CONTEXT</variable> channel variable. The
309  name of the last channel that was spied on will be stored
310  in the <variable>SPY_CHANNEL</variable> variable.</para>
311  </option>
312  </optionlist>
313  </parameter>
314  </syntax>
315  <description>
316  <para>This application is used to listen to the audio from an Asterisk channel. This includes
317  the audio coming in and out of the channel being spied on. Only channels created by outgoing calls for the
318  specified extension will be selected for spying. If the optional context is not supplied,
319  the current channel's context will be used.</para>
320  <para>While spying, the following actions may be performed:</para>
321  <para> - Dialing <literal>#</literal> cycles the volume level.</para>
322  <para> - Dialing <literal>*</literal> will stop spying and look for another channel to spy on.</para>
323  <note><para>The <replaceable>X</replaceable> option supersedes the three features above in that if a valid
324  single digit extension exists in the correct context ChanSpy will exit to it.
325  This also disables choosing a channel based on <literal>chanprefix</literal> and a digit sequence.</para></note>
326  </description>
327  <see-also>
328  <ref type="application">ChanSpy</ref>
329  </see-also>
330  </application>
331 
332  <application name="DAHDIScan" language="en_US">
333  <synopsis>
334  Scan DAHDI channels to monitor calls.
335  </synopsis>
336  <syntax>
337  <parameter name="group">
338  <para>Limit scanning to a channel <replaceable>group</replaceable> by setting this option.</para>
339  </parameter>
340  </syntax>
341  <description>
342  <para>Allows a call center manager to monitor DAHDI channels in a
343  convenient way. Use <literal>#</literal> to select the next channel and use <literal>*</literal> to exit.</para>
344  </description>
345  </application>
346  ***/
347 
348 static const char app_chan[] = "ChanSpy";
349 
350 static const char app_ext[] = "ExtenSpy";
351 
352 static const char app_dahdiscan[] = "DAHDIScan";
353 
354 enum {
355  OPTION_QUIET = (1 << 0), /* Quiet, no announcement */
356  OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */
357  OPTION_VOLUME = (1 << 2), /* Specify initial volume */
358  OPTION_GROUP = (1 << 3), /* Only look at channels in group */
359  OPTION_RECORD = (1 << 4),
360  OPTION_WHISPER = (1 << 5),
361  OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */
362  OPTION_READONLY = (1 << 7), /* Don't mix the two channels */
363  OPTION_EXIT = (1 << 8), /* Exit to a valid single digit extension */
364  OPTION_ENFORCED = (1 << 9), /* Enforced mode */
365  OPTION_NOTECH = (1 << 10), /* Skip technology name playback */
366  OPTION_BARGE = (1 << 11), /* Barge mode (whisper to both channels) */
367  OPTION_NAME = (1 << 12), /* Say the name of the person on whom we will spy */
368  OPTION_DTMF_SWITCH_MODES = (1 << 13), /* Allow numeric DTMF to switch between chanspy modes */
369  OPTION_DTMF_EXIT = (1 << 14), /* Set DTMF to exit, added for DAHDIScan integration */
370  OPTION_DTMF_CYCLE = (1 << 15), /* Custom DTMF for cycling next available channel, (default is '*') */
371  OPTION_DAHDI_SCAN = (1 << 16), /* Scan groups in DAHDIScan mode */
372  OPTION_STOP = (1 << 17),
373  OPTION_EXITONHANGUP = (1 << 18), /* Hang up when the spied-on channel hangs up. */
374 };
375 
376 enum {
385 };
386 
406 });
407 
409  /* spy data */
413  int fd;
415  struct ast_flags flags;
416 };
417 
419  char exit;
420  char cycle;
421  char volume;
422 };
423 
424 static void *spy_alloc(struct ast_channel *chan, void *data)
425 {
426  /* just store the data pointer in the channel structure */
427  return data;
428 }
429 
430 static void spy_release(struct ast_channel *chan, void *data)
431 {
432  /* nothing to do */
433 }
434 
435 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
436 {
437  struct chanspy_translation_helper *csth = data;
438  struct ast_frame *f, *cur;
439 
442  /* Channel is already gone more than likely */
444  return -1;
445  }
446 
447  if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
448  /* Option 'o' was set, so don't mix channel audio */
450  } else {
452  }
453 
455 
456  if (!f)
457  return 0;
458 
459  for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
460  if (ast_write(chan, cur)) {
461  ast_frfree(f);
462  return -1;
463  }
464 
465  if (csth->fd) {
466  if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) {
467  ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
468  }
469  }
470  }
471 
472  ast_frfree(f);
473 
474  return 0;
475 }
476 
477 static struct ast_generator spygen = {
478  .alloc = spy_alloc,
479  .release = spy_release,
480  .generate = spy_generate,
481 };
482 
483 static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook)
484 {
485  int res = 0;
486  struct ast_channel *peer = NULL;
487 
488  ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, autochan->chan->name);
489 
491  res = ast_audiohook_attach(autochan->chan, audiohook);
492 
493  if (!res && ast_test_flag(autochan->chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(autochan->chan))) {
495  }
496  return res;
497 }
498 
499 static void change_spy_mode(const char digit, struct ast_flags *flags)
500 {
501  if (digit == '4') {
504  } else if (digit == '5') {
507  } else if (digit == '6') {
509  ast_set_flag(flags, OPTION_BARGE);
510  }
511 }
512 
513 static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
514  int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
515  char *exitcontext)
516 {
517  struct chanspy_translation_helper csth;
518  int running = 0, res, x = 0;
519  char inp[24] = {0};
520  char *name;
521  struct ast_frame *f;
522  struct ast_silence_generator *silgen = NULL;
523  struct ast_autochan *spyee_bridge_autochan = NULL;
524  const char *spyer_name;
525  struct ast_channel *chans[] = { chan, spyee_autochan->chan };
526 
527  ast_channel_lock(chan);
528  spyer_name = ast_strdupa(chan->name);
529  ast_channel_unlock(chan);
530 
531  /* We now hold the channel lock on spyee */
532 
533  if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan) ||
534  ast_test_flag(spyee_autochan->chan, AST_FLAG_ZOMBIE)) {
535  return 0;
536  }
537 
538  ast_channel_lock(spyee_autochan->chan);
539  name = ast_strdupa(spyee_autochan->chan->name);
540  ast_channel_unlock(spyee_autochan->chan);
541 
542  ast_verb(2, "Spying on channel %s\n", name);
543  ast_manager_event_multichan(EVENT_FLAG_CALL, "ChanSpyStart", 2, chans,
544  "SpyerChannel: %s\r\n"
545  "SpyeeChannel: %s\r\n",
546  spyer_name, name);
547 
548  memset(&csth, 0, sizeof(csth));
549  ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
550 
551  /* This is the audiohook which gives us the audio off the channel we are
552  spying on.
553  */
555 
556  if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
558  return 0;
559  }
560 
562  /* This audiohook will let us inject audio from our channel into the
563  channel we are currently spying on.
564  */
566 
567  if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
568  ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
569  }
570  }
571 
573  /* And this hook lets us inject audio into the channel that the spied on
574  channel is currently bridged with.
575  */
577 
578  if ((spyee_bridge_autochan = ast_autochan_setup(ast_bridged_channel(spyee_autochan->chan)))) {
579  ast_channel_lock(spyee_bridge_autochan->chan);
580  if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
581  ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
582  }
583  ast_channel_unlock(spyee_bridge_autochan->chan);
584  }
585  }
586 
587  ast_channel_lock(chan);
589  ast_channel_unlock(chan);
590 
591  csth.volfactor = *volfactor;
592 
593  if (csth.volfactor) {
596  }
597 
598  csth.fd = fd;
599 
600  if (ast_test_flag(flags, OPTION_PRIVATE))
602  else
603  ast_activate_generator(chan, &spygen, &csth);
604 
605  /* We can no longer rely on 'spyee' being an actual channel;
606  it can be hung up and freed out from under us. However, the
607  channel destructor will put NULL into our csth.spy.chan
608  field when that happens, so that is our signal that the spyee
609  channel has gone away.
610  */
611 
612  /* Note: it is very important that the ast_waitfor() be the first
613  condition in this expression, so that if we wait for some period
614  of time before receiving a frame from our spying channel, we check
615  for hangup on the spied-on channel _after_ knowing that a frame
616  has arrived, since the spied-on channel could have gone away while
617  we were waiting
618  */
619  while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
620  if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
621  running = -1;
622  break;
623  }
624 
625  if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
632  ast_frfree(f);
633  continue;
634  } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
638  ast_frfree(f);
639  continue;
640  }
641 
642  res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
643  ast_frfree(f);
644  if (!res)
645  continue;
646 
647  if (x == sizeof(inp))
648  x = 0;
649 
650  if (res < 0) {
651  running = -1;
652  break;
653  }
654 
655  if (ast_test_flag(flags, OPTION_EXIT)) {
656  char tmp[2];
657  tmp[0] = res;
658  tmp[1] = '\0';
659  if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
660  ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
661  pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
662  running = -2;
663  break;
664  } else {
665  ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
666  }
667  } else if (res >= '0' && res <= '9') {
669  change_spy_mode(res, flags);
670  } else {
671  inp[x++] = res;
672  }
673  }
674 
675  if (res == user_options->cycle) {
676  running = 0;
677  break;
678  } else if (res == user_options->exit) {
679  running = -2;
680  break;
681  } else if (res == user_options->volume) {
682  if (!ast_strlen_zero(inp)) {
683  running = atoi(inp);
684  break;
685  }
686 
687  (*volfactor)++;
688  if (*volfactor > 4)
689  *volfactor = -4;
690  ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);
691 
692  csth.volfactor = *volfactor;
695  }
696  }
697 
698  if (ast_test_flag(flags, OPTION_PRIVATE))
700  else
702 
703  ast_channel_lock(chan);
705  ast_channel_unlock(chan);
706 
712  }
713 
719  }
720 
725 
726  if (spyee_bridge_autochan) {
727  ast_autochan_destroy(spyee_bridge_autochan);
728  }
729 
730  ast_verb(2, "Done Spying on channel %s\n", name);
731  ast_manager_event(chan, EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);
732 
733  return running;
734 }
735 
736 static struct ast_autochan *next_channel(struct ast_channel_iterator *iter,
737  struct ast_autochan *autochan, struct ast_channel *chan)
738 {
739  struct ast_channel *next;
740  struct ast_autochan *autochan_store;
741  const size_t pseudo_len = strlen("DAHDI/pseudo");
742 
743  if (!iter) {
744  return NULL;
745  }
746 
747 redo:
748  if (!(next = ast_channel_iterator_next(iter))) {
749  return NULL;
750  }
751 
752  if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) {
753  ast_channel_unref(next);
754  goto redo;
755  } else if (next == chan) {
756  ast_channel_unref(next);
757  goto redo;
758  }
759 
760  autochan_store = ast_autochan_setup(next);
761  ast_channel_unref(next);
762 
763  return autochan_store;
764 }
765 
766 static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
767  int volfactor, const int fd, struct spy_dtmf_options *user_options,
768  const char *mygroup, const char *myenforced, const char *spec, const char *exten,
769  const char *context, const char *mailbox, const char *name_context)
770 {
771  char nameprefix[AST_NAME_STRLEN];
772  char exitcontext[AST_MAX_CONTEXT] = "";
773  signed char zero_volume = 0;
774  int waitms;
775  int res;
776  int num_spyed_upon = 1;
777  struct ast_channel_iterator *iter = NULL;
778 
779  if (ast_test_flag(flags, OPTION_EXIT)) {
780  const char *c;
781  ast_channel_lock(chan);
782  if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
783  ast_copy_string(exitcontext, c, sizeof(exitcontext));
784  } else if (!ast_strlen_zero(chan->macrocontext)) {
785  ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
786  } else {
787  ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
788  }
789  ast_channel_unlock(chan);
790  }
791 
792  if (chan->_state != AST_STATE_UP)
793  ast_answer(chan);
794 
795  ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
796 
797  waitms = 100;
798 
799  for (;;) {
800  struct ast_autochan *autochan = NULL, *next_autochan = NULL;
801  struct ast_channel *prev = NULL;
802 
803  if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
804  res = ast_streamfile(chan, "beep", chan->language);
805  if (!res)
806  res = ast_waitstream(chan, "");
807  else if (res < 0) {
809  break;
810  }
811  if (!ast_strlen_zero(exitcontext)) {
812  char tmp[2];
813  tmp[0] = res;
814  tmp[1] = '\0';
815  if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
816  goto exit;
817  else
818  ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
819  }
820  }
821 
822  /* Set up the iterator we'll be using during this call */
823  if (!ast_strlen_zero(spec)) {
824  iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
825  } else if (!ast_strlen_zero(exten)) {
826  iter = ast_channel_iterator_by_exten_new(exten, context);
827  } else {
829  }
830 
831  if (!iter) {
832  res = -1;
833  goto exit;
834  }
835 
836  res = ast_waitfordigit(chan, waitms);
837  if (res < 0) {
838  iter = ast_channel_iterator_destroy(iter);
840  break;
841  }
842  if (!ast_strlen_zero(exitcontext)) {
843  char tmp[2];
844  tmp[0] = res;
845  tmp[1] = '\0';
846  if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
847  iter = ast_channel_iterator_destroy(iter);
848  goto exit;
849  } else {
850  ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
851  }
852  }
853 
854  /* reset for the next loop around, unless overridden later */
855  waitms = 100;
856  num_spyed_upon = 0;
857 
858  for (autochan = next_channel(iter, autochan, chan);
859  autochan;
860  prev = autochan->chan, ast_autochan_destroy(autochan),
861  autochan = next_autochan ? next_autochan :
862  next_channel(iter, autochan, chan), next_autochan = NULL) {
863  int igrp = !mygroup;
864  int ienf = !myenforced;
865 
866  if (autochan->chan == prev) {
867  ast_autochan_destroy(autochan);
868  break;
869  }
870 
871  if (ast_check_hangup(chan)) {
872  ast_autochan_destroy(autochan);
873  break;
874  }
875 
876  if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) {
877  continue;
878  }
879 
880  if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) {
881  continue;
882  }
883 
884  if (mygroup) {
885  int num_groups = 0;
886  int num_mygroups = 0;
887  char dup_group[512];
888  char dup_mygroup[512];
889  char *groups[NUM_SPYGROUPS];
890  char *mygroups[NUM_SPYGROUPS];
891  const char *group = NULL;
892  int x;
893  int y;
894  ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
895  num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
896  ARRAY_LEN(mygroups));
897 
898  /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable
899  * rather than "SPYGROUP", this check is done to preserve expected behavior */
900  if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
901  group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
902  } else {
903  group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
904  }
905 
906  if (!ast_strlen_zero(group)) {
907  ast_copy_string(dup_group, group, sizeof(dup_group));
908  num_groups = ast_app_separate_args(dup_group, ':', groups,
909  ARRAY_LEN(groups));
910  }
911 
912  for (y = 0; y < num_mygroups; y++) {
913  for (x = 0; x < num_groups; x++) {
914  if (!strcmp(mygroups[y], groups[x])) {
915  igrp = 1;
916  break;
917  }
918  }
919  }
920  }
921 
922  if (!igrp) {
923  continue;
924  }
925  if (myenforced) {
926  char ext[AST_CHANNEL_NAME + 3];
927  char buffer[512];
928  char *end;
929 
930  snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
931 
932  ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1);
933  if ((end = strchr(ext, '-'))) {
934  *end++ = ':';
935  *end = '\0';
936  }
937 
938  ext[0] = ':';
939 
940  if (strcasestr(buffer, ext)) {
941  ienf = 1;
942  }
943  }
944 
945  if (!ienf) {
946  continue;
947  }
948 
949 
950  if (!ast_test_flag(flags, OPTION_QUIET)) {
951  char peer_name[AST_NAME_STRLEN + 5];
952  char *ptr, *s;
953 
954  strcpy(peer_name, "spy-");
955  strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1);
956  if ((ptr = strchr(peer_name, '/'))) {
957  *ptr++ = '\0';
958  for (s = peer_name; s < ptr; s++) {
959  *s = tolower(*s);
960  }
961  if ((s = strchr(ptr, '-'))) {
962  *s = '\0';
963  }
964  }
965 
966  if (ast_test_flag(flags, OPTION_NAME)) {
967  const char *local_context = S_OR(name_context, "default");
968  const char *local_mailbox = S_OR(mailbox, ptr);
969  if (local_mailbox) {
970  res = ast_app_sayname(chan, local_mailbox, local_context);
971  } else {
972  res = -1;
973  }
974  }
975  if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
976  int num;
977  if (!ast_test_flag(flags, OPTION_NOTECH)) {
978  if (ast_fileexists(peer_name, NULL, NULL) > 0) {
979  res = ast_streamfile(chan, peer_name, chan->language);
980  if (!res) {
981  res = ast_waitstream(chan, "");
982  }
983  if (res) {
984  ast_autochan_destroy(autochan);
985  break;
986  }
987  } else {
988  res = ast_say_character_str(chan, peer_name, "", chan->language);
989  }
990  }
991  if (ptr && (num = atoi(ptr))) {
992  ast_say_digits(chan, num, "", chan->language);
993  }
994  }
995  }
996 
997  res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
998  num_spyed_upon++;
999 
1000  if (res == -1) {
1001  ast_autochan_destroy(autochan);
1002  iter = ast_channel_iterator_destroy(iter);
1003  goto exit;
1004  } else if (res == -2) {
1005  res = 0;
1006  ast_autochan_destroy(autochan);
1007  iter = ast_channel_iterator_destroy(iter);
1008  goto exit;
1009  } else if (res > 1 && spec) {
1010  struct ast_channel *next;
1011 
1012  snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
1013 
1014  if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
1015  next_autochan = ast_autochan_setup(next);
1016  next = ast_channel_unref(next);
1017  } else {
1018  /* stay on this channel, if it is still valid */
1019  if (!ast_check_hangup(autochan->chan)) {
1020  next_autochan = ast_autochan_setup(autochan->chan);
1021  } else {
1022  /* the channel is gone */
1023  next_autochan = NULL;
1024  }
1025  }
1026  } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
1027  ast_autochan_destroy(autochan);
1028  iter = ast_channel_iterator_destroy(iter);
1029  goto exit;
1030  }
1031  }
1032 
1033  iter = ast_channel_iterator_destroy(iter);
1034 
1035  if (res == -1 || ast_check_hangup(chan))
1036  break;
1037  if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
1038  break;
1039  }
1040  }
1041 exit:
1042 
1044 
1045  ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
1046 
1047  return res;
1048 }
1049 
1050 static int chanspy_exec(struct ast_channel *chan, const char *data)
1051 {
1052  char *myenforced = NULL;
1053  char *mygroup = NULL;
1054  char *recbase = NULL;
1055  int fd = 0;
1056  struct ast_flags flags;
1057  struct spy_dtmf_options user_options = {
1058  .cycle = '*',
1059  .volume = '#',
1060  .exit = '\0',
1061  };
1062  int oldwf = 0;
1063  int volfactor = 0;
1064  int res;
1065  char *mailbox = NULL;
1066  char *name_context = NULL;
1068  AST_APP_ARG(spec);
1069  AST_APP_ARG(options);
1070  );
1071  char *opts[OPT_ARG_ARRAY_SIZE];
1072  char *parse = ast_strdupa(data);
1073 
1074  AST_STANDARD_APP_ARGS(args, parse);
1075 
1076  if (args.spec && !strcmp(args.spec, "all"))
1077  args.spec = NULL;
1078 
1079  if (args.options) {
1080  char tmp;
1081  ast_app_parse_options(spy_opts, &flags, opts, args.options);
1082  if (ast_test_flag(&flags, OPTION_GROUP))
1083  mygroup = opts[OPT_ARG_GROUP];
1084 
1085  if (ast_test_flag(&flags, OPTION_RECORD) &&
1086  !(recbase = opts[OPT_ARG_RECORD]))
1087  recbase = "chanspy";
1088 
1089  if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1090  tmp = opts[OPT_ARG_EXIT][0];
1091  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1092  user_options.exit = tmp;
1093  } else {
1094  ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1095  }
1096  }
1097 
1098  if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1099  tmp = opts[OPT_ARG_CYCLE][0];
1100  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1101  user_options.cycle = tmp;
1102  } else {
1103  ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1104  }
1105  }
1106 
1107  if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1108  int vol;
1109 
1110  if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1111  ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1112  else
1113  volfactor = vol;
1114  }
1115 
1116  if (ast_test_flag(&flags, OPTION_PRIVATE))
1117  ast_set_flag(&flags, OPTION_WHISPER);
1118 
1119  if (ast_test_flag(&flags, OPTION_ENFORCED))
1120  myenforced = opts[OPT_ARG_ENFORCED];
1121 
1122  if (ast_test_flag(&flags, OPTION_NAME)) {
1123  if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1124  char *delimiter;
1125  if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1126  mailbox = opts[OPT_ARG_NAME];
1127  *delimiter++ = '\0';
1128  name_context = delimiter;
1129  } else {
1130  mailbox = opts[OPT_ARG_NAME];
1131  }
1132  }
1133  }
1134  } else {
1135  ast_clear_flag(&flags, AST_FLAGS_ALL);
1136  }
1137 
1138  oldwf = chan->writeformat;
1139  if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1140  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1141  return -1;
1142  }
1143 
1144  if (recbase) {
1145  char filename[PATH_MAX];
1146 
1147  snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1148  if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1149  ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1150  fd = 0;
1151  }
1152  }
1153 
1154  res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
1155 
1156  if (fd)
1157  close(fd);
1158 
1159  if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1160  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1161 
1162  if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) {
1163  ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n");
1164  }
1165 
1166  return res;
1167 }
1168 
1169 static int extenspy_exec(struct ast_channel *chan, const char *data)
1170 {
1171  char *ptr, *exten = NULL;
1172  char *mygroup = NULL;
1173  char *recbase = NULL;
1174  int fd = 0;
1175  struct ast_flags flags;
1176  struct spy_dtmf_options user_options = {
1177  .cycle = '*',
1178  .volume = '#',
1179  .exit = '\0',
1180  };
1181  int oldwf = 0;
1182  int volfactor = 0;
1183  int res;
1184  char *mailbox = NULL;
1185  char *name_context = NULL;
1188  AST_APP_ARG(options);
1189  );
1190  char *parse = ast_strdupa(data);
1191 
1192  AST_STANDARD_APP_ARGS(args, parse);
1193  if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
1194  exten = args.context;
1195  *ptr++ = '\0';
1196  args.context = ptr;
1197  }
1198 
1199  if (ast_strlen_zero(args.context))
1200  args.context = ast_strdupa(chan->context);
1201 
1202  if (args.options) {
1203  char *opts[OPT_ARG_ARRAY_SIZE];
1204  char tmp;
1205 
1206  ast_app_parse_options(spy_opts, &flags, opts, args.options);
1207  if (ast_test_flag(&flags, OPTION_GROUP))
1208  mygroup = opts[OPT_ARG_GROUP];
1209 
1210  if (ast_test_flag(&flags, OPTION_RECORD) &&
1211  !(recbase = opts[OPT_ARG_RECORD]))
1212  recbase = "chanspy";
1213 
1214  if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1215  tmp = opts[OPT_ARG_EXIT][0];
1216  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1217  user_options.exit = tmp;
1218  } else {
1219  ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1220  }
1221  }
1222 
1223  if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1224  tmp = opts[OPT_ARG_CYCLE][0];
1225  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1226  user_options.cycle = tmp;
1227  } else {
1228  ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1229  }
1230  }
1231 
1232  if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1233  int vol;
1234 
1235  if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1236  ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1237  else
1238  volfactor = vol;
1239  }
1240 
1241  if (ast_test_flag(&flags, OPTION_PRIVATE))
1242  ast_set_flag(&flags, OPTION_WHISPER);
1243 
1244  if (ast_test_flag(&flags, OPTION_NAME)) {
1245  if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1246  char *delimiter;
1247  if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1248  mailbox = opts[OPT_ARG_NAME];
1249  *delimiter++ = '\0';
1250  name_context = delimiter;
1251  } else {
1252  mailbox = opts[OPT_ARG_NAME];
1253  }
1254  }
1255  }
1256 
1257  } else {
1258  /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1259  ast_clear_flag(&flags, AST_FLAGS_ALL);
1260  }
1261 
1262  oldwf = chan->writeformat;
1263  if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1264  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1265  return -1;
1266  }
1267 
1268  if (recbase) {
1269  char filename[PATH_MAX];
1270 
1271  snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1272  if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1273  ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1274  fd = 0;
1275  }
1276  }
1277 
1278 
1279  res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
1280 
1281  if (fd)
1282  close(fd);
1283 
1284  if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1285  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1286 
1287  return res;
1288 }
1289 
1290 static int dahdiscan_exec(struct ast_channel *chan, const char *data)
1291 {
1292  const char *spec = "DAHDI";
1293  struct ast_flags flags;
1294  struct spy_dtmf_options user_options = {
1295  .cycle = '#',
1296  .volume = '\0',
1297  .exit = '*',
1298  };
1299  int oldwf = 0;
1300  int res;
1301  char *mygroup = NULL;
1302 
1303  /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1304  ast_clear_flag(&flags, AST_FLAGS_ALL);
1305 
1306  if (!ast_strlen_zero(data)) {
1307  mygroup = ast_strdupa(data);
1308  }
1309  ast_set_flag(&flags, OPTION_DTMF_EXIT);
1312 
1313  oldwf = chan->writeformat;
1314  if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1315  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1316  return -1;
1317  }
1318 
1319  res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
1320 
1321  if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1322  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1323 
1324  return res;
1325 }
1326 
1327 static int unload_module(void)
1328 {
1329  int res = 0;
1330 
1331  res |= ast_unregister_application(app_chan);
1332  res |= ast_unregister_application(app_ext);
1333  res |= ast_unregister_application(app_dahdiscan);
1334 
1335  return res;
1336 }
1337 
1338 static int load_module(void)
1339 {
1340  int res = 0;
1341 
1342  res |= ast_register_application_xml(app_chan, chanspy_exec);
1344  res |= ast_register_application_xml(app_dahdiscan, dahdiscan_exec);
1345 
1346  return res;
1347 }
1348 
1349 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");
union ast_frame_subclass subclass
Definition: frame.h:146
#define ast_channel_lock(chan)
Definition: channel.h:2466
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:109
Main Channel structure associated with a channel.
Definition: channel.h:742
#define NUM_SPYGROUPS
Definition: app_chanspy.c:60
Definition: app.c:104
struct ast_frame * ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, format_t format)
Reads a frame in from the audiohook structure.
Definition: audiohook.c:313
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:396
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
Definition: app.h:732
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:946
Asterisk locking-related definitions:
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition: channel.c:1715
Asterisk main include file. File version handling, generic pbx functions.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
Definition: app.h:712
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction, struct ast_frame *frame)
Writes a frame into the audiohook structure.
Definition: audiohook.c:127
struct ast_flags flags
Definition: app_chanspy.c:415
format_t writeformat
Definition: channel.h:854
static int dahdiscan_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1290
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2502
#define ast_test_flag(p, flag)
Definition: utils.h:63
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition: channel.c:3148
Support for translation of data formats. translate.c.
void * ptr
Definition: frame.h:160
static const char app_chan[]
Definition: app_chanspy.c:348
char context[AST_MAX_CONTEXT]
Definition: channel.h:868
#define ast_set_flag(p, flag)
Definition: utils.h:70
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source)
Initialize an audiohook structure.
Definition: audiohook.c:64
#define LOG_WARNING
Definition: logger.h:144
static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan, int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags, char *exitcontext)
Definition: app_chanspy.c:513
Audiohooks Architecture.
struct ast_audiohook spy_audiohook
Definition: app_chanspy.c:410
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: app.c:2101
#define AST_FRAME_DTMF
Definition: frame.h:128
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4383
#define EVENT_FLAG_CALL
Definition: manager.h:72
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition: channel.c:8409
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:348
struct ast_channel * chan
Definition: autochan.h:33
#define ast_copy_flags(dest, src, flagz)
Definition: utils.h:84
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
const char * data
Definition: channel.h:755
struct ast_audiohook bridge_whisper_audiohook
Definition: app_chanspy.c:412
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7795
const char * ext
Definition: http.c:112
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:96
#define AST_FILE_MODE
Definition: asterisk.h:36
#define ast_verb(level,...)
Definition: logger.h:243
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
Definition: pbx.c:10475
Utility functions.
struct ast_channel * ast_channel_get_by_name_prefix(const char *name, size_t name_len)
Find a channel by a name prefix.
Definition: channel.c:1808
static const char app_ext[]
Definition: app_chanspy.c:350
#define ast_manager_event(chan, category, event, contents,...)
Definition: manager.h:221
static int extenspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1169
unsigned int flags
Definition: channel.h:850
int ast_set_write_format(struct ast_channel *chan, format_t format)
Sets write format on channel chan Set write format for channel to whichever component of &quot;format&quot; is ...
Definition: channel.c:5307
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:272
static char exitcontext[AST_MAX_CONTEXT]
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define AST_NAME_STRLEN
Definition: app_chanspy.c:59
static void * spy_alloc(struct ast_channel *chan, void *data)
Definition: app_chanspy.c:424
General Asterisk PBX channel definitions.
Asterisk file paths, configured in asterisk.conf.
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
Definition: app_chanspy.c:435
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
int datalen
Definition: frame.h:148
static const char app_dahdiscan[]
Definition: app_chanspy.c:352
static struct ast_app_option spy_opts[128]
Definition: app_chanspy.c:406
int ast_softhangup(struct ast_channel *chan, int reason)
Softly hangup up a channel.
Definition: channel.c:2746
int ast_app_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
Given a mailbox and context, play that mailbox owner&#39;s name to the channel specified.
Definition: app.c:478
Core PBX routines and definitions.
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:806
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8309
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
&quot;smart&quot; channels that update automatically if a channel is masqueraded
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:401
static struct ast_generator spygen
Definition: app_chanspy.c:477
#define LOG_ERROR
Definition: logger.h:155
static struct @350 args
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
enum ast_channel_state _state
Definition: channel.h:839
struct ast_channel * ast_bridged_channel(struct ast_channel *chan)
Find bridged channel.
Definition: channel.c:7160
static int load_module(void)
Definition: app_chanspy.c:1338
struct ast_channel_iterator * ast_channel_iterator_by_exten_new(const char *exten, const char *context)
Create a new channel iterator based on extension.
Definition: channel.c:1691
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:11261
#define ast_channel_unlock(chan)
Definition: channel.h:2467
void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state)
Stops a previously-started silence generator on the given channel.
Definition: channel.c:8355
void *(* alloc)(struct ast_channel *chan, void *params)
Definition: channel.h:180
int errno
static int unload_module(void)
Definition: app_chanspy.c:1327
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1858
#define AST_MAX_CONTEXT
Definition: channel.h:136
static const char name[]
const char * ast_config_AST_MONITOR_DIR
Definition: asterisk.c:260
char macrocontext[AST_MAX_CONTEXT]
Definition: channel.h:870
#define AST_CHANNEL_NAME
Definition: channel.h:137
#define AST_FLAGS_ALL
Definition: utils.h:196
int ast_say_character_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang)
Definition: channel.c:8421
static struct ast_format f[]
Definition: format_g726.c:181
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition: channel.c:4916
Structure used to handle boolean flags.
Definition: utils.h:200
struct ast_channel_iterator * ast_channel_iterator_by_name_new(const char *name, size_t name_len)
Create a new channel iterator based on name.
Definition: channel.c:1696
#define ast_clear_flag(p, flag)
Definition: utils.h:77
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition: autochan.c:63
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
Definition: pbx.c:10546
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3552
static void spy_release(struct ast_channel *chan, void *data)
Definition: app_chanspy.c:430
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition: autochan.c:40
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:3107
struct ast_audiohook_options options
Definition: audiohook.h:117
static void change_spy_mode(const char digit, struct ast_flags *flags)
Definition: app_chanspy.c:499
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook)
Definition: app_chanspy.c:483
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3539
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1343
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:919
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition: channel.c:1649
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:3086
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
Data structure associated with a single frame of data.
Definition: frame.h:142
#define ast_manager_event_multichan(category, event, nchans, chans, contents,...)
Definition: manager.h:226
Options provided by main asterisk program.
unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
Definition: app.c:1453
enum ast_audiohook_status status
Definition: audiohook.h:107
static int common_exec(struct ast_channel *chan, struct ast_flags *flags, int volfactor, const int fd, struct spy_dtmf_options *user_options, const char *mygroup, const char *myenforced, const char *spec, const char *exten, const char *context, const char *mailbox, const char *name_context)
Definition: app_chanspy.c:766
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
enum ast_frame_type frametype
Definition: frame.h:144
#define ast_frfree(fr)
Definition: frame.h:583
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
Call Parking and Pickup API Includes code and algorithms from the Zapata library. ...
struct ast_channel_iterator * ast_channel_iterator_all_new(void)
Create a new channel iterator.
Definition: channel.c:1701
Say numbers and dates (maybe words one day too)
static struct ast_autochan * next_channel(struct ast_channel_iterator *iter, struct ast_autochan *autochan, struct ast_channel *chan)
Definition: app_chanspy.c:736
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:267
Asterisk module definitions.
char * strcasestr(const char *, const char *)
union ast_frame::@172 data
static int chanspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1050
const ast_string_field language
Definition: channel.h:787
struct ast_audiohook whisper_audiohook
Definition: app_chanspy.c:411
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
static char mailbox[AST_MAX_EXTENSION]
Definition: chan_mgcp.c:197
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
#define AST_OPTION_TXGAIN
Definition: frame.h:458
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
Definition: app.h:721