Asterisk - The Open Source Telephony Project  18.5.0
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 ([email protected])
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 <[email protected]>
26  * \author Joshua Colp <[email protected]>
27  * \author Russell Bryant <[email protected]>
28  *
29  * \ingroup applications
30  */
31 
32 /*** MODULEINFO
33  <support_level>core</support_level>
34  ***/
35 
36 #include "asterisk.h"
37 
38 #include <ctype.h>
39 #include <errno.h>
40 
41 #include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */
42 #include "asterisk/file.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/audiohook.h"
45 #include "asterisk/features.h"
46 #include "asterisk/app.h"
47 #include "asterisk/utils.h"
48 #include "asterisk/say.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/translate.h"
51 #include "asterisk/manager.h"
52 #include "asterisk/module.h"
53 #include "asterisk/lock.h"
54 #include "asterisk/options.h"
55 #include "asterisk/autochan.h"
57 #include "asterisk/json.h"
58 #include "asterisk/format_cache.h"
59 
60 #define AST_NAME_STRLEN 256
61 #define NUM_SPYGROUPS 128
62 
63 /*** DOCUMENTATION
64  <application name="ChanSpy" language="en_US">
65  <synopsis>
66  Listen to a channel, and optionally whisper into it.
67  </synopsis>
68  <syntax>
69  <parameter name="chanprefix" />
70  <parameter name="options">
71  <optionlist>
72  <option name="b">
73  <para>Only spy on channels involved in a bridged call.</para>
74  </option>
75  <option name="B">
76  <para>Instead of whispering on a single channel barge in on both
77  channels involved in the call.</para>
78  </option>
79  <option name="c">
80  <argument name="digit" required="true">
81  <para>Specify a DTMF digit that can be used to spy on the next available channel.</para>
82  </argument>
83  </option>
84  <option name="d">
85  <para>Override the typical numeric DTMF functionality and instead
86  use DTMF to switch between spy modes.</para>
87  <enumlist>
88  <enum name="4">
89  <para>spy mode</para>
90  </enum>
91  <enum name="5">
92  <para>whisper mode</para>
93  </enum>
94  <enum name="6">
95  <para>barge mode</para>
96  </enum>
97  </enumlist>
98  </option>
99  <option name="e">
100  <argument name="ext" required="true" />
101  <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
102  only monitor extensions whose name is in the <replaceable>ext</replaceable> : delimited
103  list.</para>
104  </option>
105  <option name="E">
106  <para>Exit when the spied-on channel hangs up.</para>
107  </option>
108  <option name="g">
109  <argument name="grp" required="true">
110  <para>Only spy on channels in which one or more of the groups
111  listed in <replaceable>grp</replaceable> matches one or more groups from the
112  <variable>SPYGROUP</variable> variable set on the channel to be spied upon.</para>
113  </argument>
114  <note><para>both <replaceable>grp</replaceable> and <variable>SPYGROUP</variable> can contain
115  either a single group or a colon-delimited list of groups, such
116  as <literal>sales:support:accounting</literal>.</para></note>
117  </option>
118  <option name="l">
119  <para>Allow usage of a long queue to store audio frames.</para>
120  <note><para>This may introduce some delay in the received audio feed, but will improve the audio quality.</para></note>
121  </option>
122  <option name="n" argsep="@">
123  <para>Say the name of the person being spied on if that person has recorded
124  his/her name. If a context is specified, then that voicemail context will
125  be searched when retrieving the name, otherwise the <literal>default</literal> context
126  be used when searching for the name (i.e. if SIP/1000 is the channel being
127  spied on and no mailbox is specified, then <literal>1000</literal> will be used when searching
128  for the name).</para>
129  <argument name="mailbox" />
130  <argument name="context" />
131  </option>
132  <option name="o">
133  <para>Only listen to audio coming from this channel.</para>
134  </option>
135  <option name="q">
136  <para>Don't play a beep when beginning to spy on a channel, or speak the
137  selected channel name.</para>
138  </option>
139  <option name="r">
140  <para>Record the session to the monitor spool directory. An optional base for the filename
141  may be specified. The default is <literal>chanspy</literal>.</para>
142  <argument name="basename" />
143  </option>
144  <option name="s">
145  <para>Skip the playback of the channel type (i.e. SIP, IAX, etc) when
146  speaking the selected channel name.</para>
147  </option>
148  <option name="S">
149  <para>Stop when no more channels are left to spy on.</para>
150  </option>
151  <option name="u">
152  <para>The <literal>chanprefix</literal> parameter is a channel uniqueid
153  or fully specified channel name.</para>
154  </option>
155  <option name="v">
156  <argument name="value" />
157  <para>Adjust the initial volume in the range from <literal>-4</literal>
158  to <literal>4</literal>. A negative value refers to a quieter setting.</para>
159  </option>
160  <option name="w">
161  <para>Enable <literal>whisper</literal> mode, so the spying channel can talk to
162  the spied-on channel.</para>
163  </option>
164  <option name="W">
165  <para>Enable <literal>private whisper</literal> mode, so the spying channel can
166  talk to the spied-on channel but cannot listen to that channel.</para>
167  </option>
168  <option name="x">
169  <argument name="digit" required="true">
170  <para>Specify a DTMF digit that can be used to exit the application while actively
171  spying on a channel. If there is no channel being spied on, the DTMF digit will be
172  ignored.</para>
173  </argument>
174  </option>
175  <option name="X">
176  <para>Allow the user to exit ChanSpy to a valid single digit
177  numeric extension in the current context or the context
178  specified by the <variable>SPY_EXIT_CONTEXT</variable> channel variable. The
179  name of the last channel that was spied on will be stored
180  in the <variable>SPY_CHANNEL</variable> variable.</para>
181  </option>
182  </optionlist>
183  </parameter>
184  </syntax>
185  <description>
186  <para>This application is used to listen to the audio from an Asterisk channel. This includes the audio
187  coming in and out of the channel being spied on. If the <literal>chanprefix</literal> parameter is specified,
188  only channels beginning with this string will be spied upon.</para>
189  <para>While spying, the following actions may be performed:</para>
190  <para> - Dialing <literal>#</literal> cycles the volume level.</para>
191  <para> - Dialing <literal>*</literal> will stop spying and look for another channel to spy on.</para>
192  <para> - Dialing a series of digits followed by <literal>#</literal> builds a channel name to append
193  to <literal>chanprefix</literal>. For example, executing ChanSpy(Agent) and then dialing the digits '1234#'
194  while spying will begin spying on the channel 'Agent/1234'. Note that this feature will be overridden
195  if the 'd' or 'u' options are used.</para>
196  <note><para>The <replaceable>X</replaceable> option supersedes the three features above in that if a valid
197  single digit extension exists in the correct context ChanSpy will exit to it.
198  This also disables choosing a channel based on <literal>chanprefix</literal> and a digit sequence.</para></note>
199  </description>
200  <see-also>
201  <ref type="application">ExtenSpy</ref>
202  <ref type="managerEvent">ChanSpyStart</ref>
203  <ref type="managerEvent">ChanSpyStop</ref>
204  </see-also>
205  </application>
206  <application name="ExtenSpy" language="en_US">
207  <synopsis>
208  Listen to a channel, and optionally whisper into it.
209  </synopsis>
210  <syntax>
211  <parameter name="exten" required="true" argsep="@">
212  <argument name="exten" required="true">
213  <para>Specify extension.</para>
214  </argument>
215  <argument name="context">
216  <para>Optionally specify a context, defaults to <literal>default</literal>.</para>
217  </argument>
218  </parameter>
219  <parameter name="options">
220  <optionlist>
221  <option name="b">
222  <para>Only spy on channels involved in a bridged call.</para>
223  </option>
224  <option name="B">
225  <para>Instead of whispering on a single channel barge in on both
226  channels involved in the call.</para>
227  </option>
228  <option name="c">
229  <argument name="digit" required="true">
230  <para>Specify a DTMF digit that can be used to spy on the next available channel.</para>
231  </argument>
232  </option>
233  <option name="d">
234  <para>Override the typical numeric DTMF functionality and instead
235  use DTMF to switch between spy modes.</para>
236  <enumlist>
237  <enum name="4">
238  <para>spy mode</para>
239  </enum>
240  <enum name="5">
241  <para>whisper mode</para>
242  </enum>
243  <enum name="6">
244  <para>barge mode</para>
245  </enum>
246  </enumlist>
247  </option>
248  <option name="e">
249  <argument name="ext" required="true" />
250  <para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
251  only monitor extensions whose name is in the <replaceable>ext</replaceable> : delimited
252  list.</para>
253  </option>
254  <option name="E">
255  <para>Exit when the spied-on channel hangs up.</para>
256  </option>
257  <option name="g">
258  <argument name="grp" required="true">
259  <para>Only spy on channels in which one or more of the groups
260  listed in <replaceable>grp</replaceable> matches one or more groups from the
261  <variable>SPYGROUP</variable> variable set on the channel to be spied upon.</para>
262  </argument>
263  <note><para>both <replaceable>grp</replaceable> and <variable>SPYGROUP</variable> can contain
264  either a single group or a colon-delimited list of groups, such
265  as <literal>sales:support:accounting</literal>.</para></note>
266  </option>
267  <option name="l">
268  <para>Allow usage of a long queue to store audio frames.</para>
269  <note><para>This may introduce some delay in the received audio feed, but will improve the audio quality.</para></note>
270  </option>
271  <option name="n" argsep="@">
272  <para>Say the name of the person being spied on if that person has recorded
273  his/her name. If a context is specified, then that voicemail context will
274  be searched when retrieving the name, otherwise the <literal>default</literal> context
275  be used when searching for the name (i.e. if SIP/1000 is the channel being
276  spied on and no mailbox is specified, then <literal>1000</literal> will be used when searching
277  for the name).</para>
278  <argument name="mailbox" />
279  <argument name="context" />
280  </option>
281  <option name="o">
282  <para>Only listen to audio coming from this channel.</para>
283  </option>
284  <option name="q">
285  <para>Don't play a beep when beginning to spy on a channel, or speak the
286  selected channel name.</para>
287  </option>
288  <option name="r">
289  <para>Record the session to the monitor spool directory. An optional base for the filename
290  may be specified. The default is <literal>chanspy</literal>.</para>
291  <argument name="basename" />
292  </option>
293  <option name="s">
294  <para>Skip the playback of the channel type (i.e. SIP, IAX, etc) when
295  speaking the selected channel name.</para>
296  </option>
297  <option name="S">
298  <para>Stop when there are no more extensions left to spy on.</para>
299  </option>
300  <option name="v">
301  <argument name="value" />
302  <para>Adjust the initial volume in the range from <literal>-4</literal>
303  to <literal>4</literal>. A negative value refers to a quieter setting.</para>
304  </option>
305  <option name="w">
306  <para>Enable <literal>whisper</literal> mode, so the spying channel can talk to
307  the spied-on channel.</para>
308  </option>
309  <option name="W">
310  <para>Enable <literal>private whisper</literal> mode, so the spying channel can
311  talk to the spied-on channel but cannot listen to that channel.</para>
312  </option>
313  <option name="x">
314  <argument name="digit" required="true">
315  <para>Specify a DTMF digit that can be used to exit the application while actively
316  spying on a channel. If there is no channel being spied on, the DTMF digit will be
317  ignored.</para>
318  </argument>
319  </option>
320  <option name="X">
321  <para>Allow the user to exit ChanSpy to a valid single digit
322  numeric extension in the current context or the context
323  specified by the <variable>SPY_EXIT_CONTEXT</variable> channel variable. The
324  name of the last channel that was spied on will be stored
325  in the <variable>SPY_CHANNEL</variable> variable.</para>
326  </option>
327  </optionlist>
328  </parameter>
329  </syntax>
330  <description>
331  <para>This application is used to listen to the audio from an Asterisk channel. This includes
332  the audio coming in and out of the channel being spied on. Only channels created by outgoing calls for the
333  specified extension will be selected for spying. If the optional context is not supplied,
334  the current channel's context will be used.</para>
335  <para>While spying, the following actions may be performed:</para>
336  <para> - Dialing <literal>#</literal> cycles the volume level.</para>
337  <para> - Dialing <literal>*</literal> will stop spying and look for another channel to spy on.</para>
338  <note><para>The <replaceable>X</replaceable> option supersedes the three features above in that if a valid
339  single digit extension exists in the correct context ChanSpy will exit to it.
340  This also disables choosing a channel based on <literal>chanprefix</literal> and a digit sequence.</para></note>
341  </description>
342  <see-also>
343  <ref type="application">ChanSpy</ref>
344  <ref type="managerEvent">ChanSpyStart</ref>
345  <ref type="managerEvent">ChanSpyStop</ref>
346  </see-also>
347  </application>
348  <application name="DAHDIScan" language="en_US">
349  <synopsis>
350  Scan DAHDI channels to monitor calls.
351  </synopsis>
352  <syntax>
353  <parameter name="group">
354  <para>Limit scanning to a channel <replaceable>group</replaceable> by setting this option.</para>
355  </parameter>
356  </syntax>
357  <description>
358  <para>Allows a call center manager to monitor DAHDI channels in a
359  convenient way. Use <literal>#</literal> to select the next channel and use <literal>*</literal> to exit.</para>
360  </description>
361  <see-also>
362  <ref type="managerEvent">ChanSpyStart</ref>
363  <ref type="managerEvent">ChanSpyStop</ref>
364  </see-also>
365  </application>
366  ***/
367 
368 static const char app_chan[] = "ChanSpy";
369 
370 static const char app_ext[] = "ExtenSpy";
371 
372 static const char app_dahdiscan[] = "DAHDIScan";
373 
374 enum {
375  OPTION_QUIET = (1 << 0), /* Quiet, no announcement */
376  OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */
377  OPTION_VOLUME = (1 << 2), /* Specify initial volume */
378  OPTION_GROUP = (1 << 3), /* Only look at channels in group */
379  OPTION_RECORD = (1 << 4),
380  OPTION_WHISPER = (1 << 5),
381  OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */
382  OPTION_READONLY = (1 << 7), /* Don't mix the two channels */
383  OPTION_EXIT = (1 << 8), /* Exit to a valid single digit extension */
384  OPTION_ENFORCED = (1 << 9), /* Enforced mode */
385  OPTION_NOTECH = (1 << 10), /* Skip technology name playback */
386  OPTION_BARGE = (1 << 11), /* Barge mode (whisper to both channels) */
387  OPTION_NAME = (1 << 12), /* Say the name of the person on whom we will spy */
388  OPTION_DTMF_SWITCH_MODES = (1 << 13), /* Allow numeric DTMF to switch between chanspy modes */
389  OPTION_DTMF_EXIT = (1 << 14), /* Set DTMF to exit, added for DAHDIScan integration */
390  OPTION_DTMF_CYCLE = (1 << 15), /* Custom DTMF for cycling next available channel, (default is '*') */
391  OPTION_DAHDI_SCAN = (1 << 16), /* Scan groups in DAHDIScan mode */
392  OPTION_STOP = (1 << 17),
393  OPTION_EXITONHANGUP = (1 << 18), /* Hang up when the spied-on channel hangs up. */
394  OPTION_UNIQUEID = (1 << 19), /* The chanprefix is a channel uniqueid or fully specified channel name. */
395  OPTION_LONG_QUEUE = (1 << 20), /* Allow usage of a long queue to store audio frames. */
396 };
397 
398 enum {
407 };
408 
430 });
431 
433  /* spy data */
437  int fd;
439  struct ast_flags flags;
440 };
441 
443  char exit;
444  char cycle;
445  char volume;
446 };
447 
448 static void *spy_alloc(struct ast_channel *chan, void *data)
449 {
450  /* just store the data pointer in the channel structure */
451  return data;
452 }
453 
454 static void spy_release(struct ast_channel *chan, void *data)
455 {
456  /* nothing to do */
457 }
458 
459 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
460 {
461  struct chanspy_translation_helper *csth = data;
462  struct ast_frame *f, *cur;
463 
466  /* Channel is already gone more than likely */
468  return -1;
469  }
470 
471  if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
472  /* Option 'o' was set, so don't mix channel audio */
474  } else {
476  }
477 
479 
480  if (!f)
481  return 0;
482 
483  for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
484  if (ast_write(chan, cur)) {
485  ast_frfree(f);
486  return -1;
487  }
488 
489  if (csth->fd) {
490  if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) {
491  ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
492  }
493  }
494  }
495 
496  ast_frfree(f);
497 
498  return 0;
499 }
500 
501 static struct ast_generator spygen = {
502  .alloc = spy_alloc,
503  .release = spy_release,
504  .generate = spy_generate,
505 };
506 
507 static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
508 {
509  int res;
510 
511  ast_autochan_channel_lock(autochan);
512  ast_verb(3, "Attaching spy channel %s to %s\n",
513  spychan_name, ast_channel_name(autochan->chan));
514 
515  if (ast_test_flag(flags, OPTION_READONLY)) {
517  } else {
519  }
520  if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
521  ast_debug(9, "Using a long queue to store audio frames in spy audiohook\n");
522  } else {
524  }
525  res = ast_audiohook_attach(autochan->chan, audiohook);
526  ast_autochan_channel_unlock(autochan);
527  return res;
528 }
529 
530 static void change_spy_mode(const char digit, struct ast_flags *flags)
531 {
532  if (digit == '4') {
535  } else if (digit == '5') {
538  } else if (digit == '6') {
540  ast_set_flag(flags, OPTION_BARGE);
541  }
542 }
543 
544 static int pack_channel_into_message(struct ast_channel *chan, const char *role,
545  struct ast_multi_channel_blob *payload)
546 {
547  RAII_VAR(struct ast_channel_snapshot *, snapshot,
549  ao2_cleanup);
550 
551  if (!snapshot) {
552  return -1;
553  }
554  ast_multi_channel_blob_add_channel(payload, role, snapshot);
555  return 0;
556 }
557 
558 /*! \internal
559  * \brief Publish the chanspy message over Stasis-Core
560  * \param spyer The channel doing the spying
561  * \param spyee Who is being spied upon
562  * \start start If non-zero, the spying is starting. Otherwise, the spyer is
563  * finishing
564  */
565 static void publish_chanspy_message(struct ast_channel *spyer,
566  struct ast_channel *spyee,
567  int start)
568 {
569  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
570  RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
573 
574  if (!spyer) {
575  ast_log(AST_LOG_WARNING, "Attempt to publish ChanSpy message for NULL spyer channel\n");
576  return;
577  }
578  blob = ast_json_null();
579  if (!blob || !type) {
580  return;
581  }
582 
583  payload = ast_multi_channel_blob_create(blob);
584  if (!payload) {
585  return;
586  }
587 
588  if (pack_channel_into_message(spyer, "spyer_channel", payload)) {
589  return;
590  }
591 
592  if (spyee) {
593  if (pack_channel_into_message(spyee, "spyee_channel", payload)) {
594  return;
595  }
596  }
597 
598  message = stasis_message_create(type, payload);
599  if (!message) {
600  return;
601  }
603 }
604 
605 static int attach_barge(struct ast_autochan *spyee_autochan,
606  struct ast_autochan **spyee_bridge_autochan, struct ast_audiohook *bridge_whisper_audiohook,
607  const char *spyer_name, const char *name, struct ast_flags *flags)
608 {
609  int retval = 0;
610  struct ast_autochan *internal_bridge_autochan;
611  struct ast_channel *spyee_chan;
612  RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup);
613 
614  ast_autochan_channel_lock(spyee_autochan);
615  spyee_chan = ast_channel_ref(spyee_autochan->chan);
616  ast_autochan_channel_unlock(spyee_autochan);
617  bridged = ast_channel_bridge_peer(spyee_chan);
618  ast_channel_unref(spyee_chan);
619  if (!bridged) {
620  return -1;
621  }
622 
623  ast_audiohook_init(bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy", 0);
624 
625  internal_bridge_autochan = ast_autochan_setup(bridged);
626  if (!internal_bridge_autochan) {
627  return -1;
628  }
629 
630  if (start_spying(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook, flags)) {
631  ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
632  retval = -1;
633  }
634 
635  *spyee_bridge_autochan = internal_bridge_autochan;
636 
637  return retval;
638 }
639 
640 static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
641  int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
642  char *exitcontext)
643 {
644  struct chanspy_translation_helper csth;
645  int running = 0, bridge_connected = 0, res, x = 0;
646  char inp[24] = {0};
647  char *name;
648  struct ast_frame *f;
649  struct ast_silence_generator *silgen = NULL;
650  struct ast_autochan *spyee_bridge_autochan = NULL;
651  const char *spyer_name;
652 
653  ast_channel_lock(chan);
654  if (ast_check_hangup(chan)) {
655  ast_channel_unlock(chan);
656  return 0;
657  }
658  spyer_name = ast_strdupa(ast_channel_name(chan));
659  ast_channel_unlock(chan);
660 
661  ast_autochan_channel_lock(spyee_autochan);
662  if (ast_check_hangup(spyee_autochan->chan)
663  || ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) {
664  ast_autochan_channel_unlock(spyee_autochan);
665  return 0;
666  }
667  name = ast_strdupa(ast_channel_name(spyee_autochan->chan));
668 
669  ast_verb(2, "Spying on channel %s\n", name);
670  publish_chanspy_message(chan, spyee_autochan->chan, 1);
671  ast_autochan_channel_unlock(spyee_autochan);
672 
673  memset(&csth, 0, sizeof(csth));
674  ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
675 
676  /* This is the audiohook which gives us the audio off the channel we are
677  spying on.
678  */
680 
681  if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook, flags)) {
683  return 0;
684  }
685 
687  /* This audiohook will let us inject audio from our channel into the
688  channel we are currently spying on.
689  */
691 
692  if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook, flags)) {
693  ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
694  }
695  }
696 
698 
699  csth.volfactor = *volfactor;
700 
701  if (csth.volfactor) {
704  }
705 
706  csth.fd = fd;
707 
708  if (ast_test_flag(flags, OPTION_PRIVATE))
710  else
711  ast_activate_generator(chan, &spygen, &csth);
712 
713  /* We can no longer rely on 'spyee' being an actual channel;
714  it can be hung up and freed out from under us. However, the
715  channel destructor will put NULL into our csth.spy.chan
716  field when that happens, so that is our signal that the spyee
717  channel has gone away.
718  */
719 
720  /* Note: it is very important that the ast_waitfor() be the first
721  condition in this expression, so that if we wait for some period
722  of time before receiving a frame from our spying channel, we check
723  for hangup on the spied-on channel _after_ knowing that a frame
724  has arrived, since the spied-on channel could have gone away while
725  we were waiting
726  */
727  while (ast_waitfor(chan, -1) > -1 && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
728  if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
729  running = -1;
730  if (f) {
731  ast_frfree(f);
732  }
733  break;
734  }
735 
736  if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
737  /* This hook lets us inject audio into the channel that the spyee is currently
738  * bridged with. If the spyee isn't bridged with anything yet, nothing will
739  * be attached and we'll need to continue attempting to attach the barge
740  * audio hook. */
741  if (!bridge_connected && attach_barge(spyee_autochan, &spyee_bridge_autochan,
742  &csth.bridge_whisper_audiohook, spyer_name, name, flags) == 0) {
743  bridge_connected = 1;
744  }
745 
749 
750  if (bridge_connected) {
754  }
755 
756  ast_frfree(f);
757  continue;
758  } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
762  ast_frfree(f);
763  continue;
764  }
765 
766  res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
767  ast_frfree(f);
768  if (!res)
769  continue;
770 
771  if (x == sizeof(inp))
772  x = 0;
773 
774  if (res < 0) {
775  running = -1;
776  break;
777  }
778 
779  if (ast_test_flag(flags, OPTION_EXIT)) {
780  char tmp[2];
781  tmp[0] = res;
782  tmp[1] = '\0';
783  if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
784  ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
785  pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
786  running = -2;
787  break;
788  } else {
789  ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
790  }
791  } else if (res >= '0' && res <= '9') {
793  change_spy_mode(res, flags);
794  } else {
795  inp[x++] = res;
796  }
797  }
798 
799  if (res == user_options->cycle) {
800  running = 0;
801  break;
802  } else if (res == user_options->exit) {
803  running = -2;
804  break;
805  } else if (res == user_options->volume) {
806  if (!ast_strlen_zero(inp)) {
807  running = atoi(inp);
808  break;
809  }
810 
811  (*volfactor)++;
812  if (*volfactor > 4)
813  *volfactor = -4;
814  ast_verb(3, "Setting spy volume on %s to %d\n", ast_channel_name(chan), *volfactor);
815 
816  csth.volfactor = *volfactor;
819  }
820  }
821 
822  if (ast_test_flag(flags, OPTION_PRIVATE))
824  else
826 
828 
834  }
835 
841  }
842 
847 
848  ast_verb(2, "Done Spying on channel %s\n", name);
849  publish_chanspy_message(chan, spyee_autochan->chan, 0);
850 
851  if (spyee_bridge_autochan) {
852  ast_autochan_destroy(spyee_bridge_autochan);
853  }
854 
855  return running;
856 }
857 
858 static struct ast_autochan *next_channel(struct ast_channel_iterator *iter,
859  struct ast_channel *chan)
860 {
861  struct ast_channel *next;
862  struct ast_autochan *autochan_store;
863  const size_t pseudo_len = strlen("DAHDI/pseudo");
864 
865  if (!iter) {
866  return NULL;
867  }
868 
869  for (; (next = ast_channel_iterator_next(iter)); ast_channel_unref(next)) {
870  if (!strncmp(ast_channel_name(next), "DAHDI/pseudo", pseudo_len)
871  || next == chan) {
872  continue;
873  }
874 
875  autochan_store = ast_autochan_setup(next);
876  ast_channel_unref(next);
877 
878  return autochan_store;
879  }
880  return NULL;
881 }
882 
883 static int spy_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
884 {
885  char *mailbox_id;
886 
887  mailbox_id = ast_alloca(strlen(mailbox) + strlen(context) + 2);
888  sprintf(mailbox_id, "%s@%s", mailbox, context); /* Safe */
889  return ast_app_sayname(chan, mailbox_id);
890 }
891 
892 static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
893  int volfactor, const int fd, struct spy_dtmf_options *user_options,
894  const char *mygroup, const char *myenforced, const char *spec, const char *exten,
895  const char *context, const char *mailbox, const char *name_context)
896 {
897  char nameprefix[AST_NAME_STRLEN];
898  char exitcontext[AST_MAX_CONTEXT] = "";
899  signed char zero_volume = 0;
900  int waitms;
901  int res;
902  int num_spyed_upon = 1;
903  struct ast_channel_iterator *iter = NULL;
904 
905  if (ast_test_flag(flags, OPTION_EXIT)) {
906  const char *c;
907  ast_channel_lock(chan);
908  if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
909  ast_copy_string(exitcontext, c, sizeof(exitcontext));
910  } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))) {
911  ast_copy_string(exitcontext, ast_channel_macrocontext(chan), sizeof(exitcontext));
912  } else {
913  ast_copy_string(exitcontext, ast_channel_context(chan), sizeof(exitcontext));
914  }
915  ast_channel_unlock(chan);
916  }
917 
918  if (ast_channel_state(chan) != AST_STATE_UP)
919  ast_answer(chan);
920 
922 
923  waitms = 100;
924 
925  for (;;) {
926  struct ast_autochan *autochan = NULL, *next_autochan = NULL;
927  struct ast_channel *prev = NULL;
928 
929  if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
930  res = ast_streamfile(chan, "beep", ast_channel_language(chan));
931  if (!res)
932  res = ast_waitstream(chan, "");
933  else if (res < 0) {
935  break;
936  }
937  if (!ast_strlen_zero(exitcontext)) {
938  char tmp[2];
939  tmp[0] = res;
940  tmp[1] = '\0';
941  if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
942  goto exit;
943  else
944  ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
945  }
946  }
947 
948  /* Set up the iterator we'll be using during this call */
949  if (!ast_strlen_zero(spec)) {
950  if (ast_test_flag(flags, OPTION_UNIQUEID)) {
951  struct ast_channel *unique_chan;
952 
953  unique_chan = ast_channel_get_by_name(spec);
954  if (!unique_chan) {
955  res = -1;
956  goto exit;
957  }
958  iter = ast_channel_iterator_by_name_new(ast_channel_name(unique_chan), 0);
959  ast_channel_unref(unique_chan);
960  } else {
961  iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
962  }
963  } else if (!ast_strlen_zero(exten)) {
964  iter = ast_channel_iterator_by_exten_new(exten, context);
965  } else {
967  }
968 
969  if (!iter) {
970  res = -1;
971  goto exit;
972  }
973 
974  res = ast_waitfordigit(chan, waitms);
975  if (res < 0) {
976  iter = ast_channel_iterator_destroy(iter);
978  break;
979  }
980  if (!ast_strlen_zero(exitcontext)) {
981  char tmp[2];
982  tmp[0] = res;
983  tmp[1] = '\0';
984  if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
985  iter = ast_channel_iterator_destroy(iter);
986  goto exit;
987  } else {
988  ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
989  }
990  }
991 
992  /* reset for the next loop around, unless overridden later */
993  waitms = 100;
994  num_spyed_upon = 0;
995 
996  for (autochan = next_channel(iter, chan);
997  autochan;
998  prev = autochan->chan,
999  ast_autochan_destroy(autochan),
1000  autochan = next_autochan ?: next_channel(iter, chan),
1001  next_autochan = NULL) {
1002  int igrp = !mygroup;
1003  int ienf = !myenforced;
1004 
1005  if (autochan->chan == prev) {
1006  ast_autochan_destroy(autochan);
1007  break;
1008  }
1009 
1010  if (ast_check_hangup(chan)) {
1011  ast_autochan_destroy(autochan);
1012  break;
1013  }
1014 
1015  ast_autochan_channel_lock(autochan);
1016  if (ast_test_flag(flags, OPTION_BRIDGED)
1017  && !ast_channel_is_bridged(autochan->chan)) {
1018  ast_autochan_channel_unlock(autochan);
1019  continue;
1020  }
1021 
1022  if (ast_check_hangup(autochan->chan)
1024  ast_autochan_channel_unlock(autochan);
1025  continue;
1026  }
1027  ast_autochan_channel_unlock(autochan);
1028 
1029  if (mygroup) {
1030  int num_groups = 0;
1031  int num_mygroups = 0;
1032  char dup_group[512];
1033  char dup_mygroup[512];
1034  char *groups[NUM_SPYGROUPS];
1035  char *mygroups[NUM_SPYGROUPS];
1036  const char *group = NULL;
1037  int x;
1038  int y;
1039  ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
1040  num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
1041  ARRAY_LEN(mygroups));
1042 
1043  /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable
1044  * rather than "SPYGROUP", this check is done to preserve expected behavior */
1045  ast_autochan_channel_lock(autochan);
1046  if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
1047  group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
1048  } else {
1049  group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
1050  }
1051  ast_autochan_channel_unlock(autochan);
1052 
1053  if (!ast_strlen_zero(group)) {
1054  ast_copy_string(dup_group, group, sizeof(dup_group));
1055  num_groups = ast_app_separate_args(dup_group, ':', groups,
1056  ARRAY_LEN(groups));
1057  }
1058 
1059  for (y = 0; y < num_mygroups; y++) {
1060  for (x = 0; x < num_groups; x++) {
1061  if (!strcmp(mygroups[y], groups[x])) {
1062  igrp = 1;
1063  break;
1064  }
1065  }
1066  }
1067  }
1068 
1069  if (!igrp) {
1070  continue;
1071  }
1072  if (myenforced) {
1073  char ext[AST_CHANNEL_NAME + 3];
1074  char buffer[512];
1075  char *end;
1076 
1077  snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
1078 
1079  ast_autochan_channel_lock(autochan);
1080  ast_copy_string(ext + 1, ast_channel_name(autochan->chan), sizeof(ext) - 1);
1081  ast_autochan_channel_unlock(autochan);
1082  if ((end = strchr(ext, '-'))) {
1083  *end++ = ':';
1084  *end = '\0';
1085  }
1086 
1087  ext[0] = ':';
1088 
1089  if (strcasestr(buffer, ext)) {
1090  ienf = 1;
1091  }
1092  }
1093 
1094  if (!ienf) {
1095  continue;
1096  }
1097 
1098  if (!ast_test_flag(flags, OPTION_QUIET)) {
1099  char peer_name[AST_NAME_STRLEN + 5];
1100  char *ptr, *s;
1101 
1102  strcpy(peer_name, "spy-");
1103  ast_autochan_channel_lock(autochan);
1104  strncat(peer_name, ast_channel_name(autochan->chan), AST_NAME_STRLEN - 4 - 1);
1105  ast_autochan_channel_unlock(autochan);
1106  if ((ptr = strchr(peer_name, '/'))) {
1107  *ptr++ = '\0';
1108  for (s = peer_name; s < ptr; s++) {
1109  *s = tolower(*s);
1110  }
1111  if ((s = strchr(ptr, '-'))) {
1112  *s = '\0';
1113  }
1114  }
1115 
1116  if (ast_test_flag(flags, OPTION_NAME)) {
1117  const char *local_context = S_OR(name_context, "default");
1118  const char *local_mailbox = S_OR(mailbox, ptr);
1119 
1120  if (local_mailbox) {
1121  res = spy_sayname(chan, local_mailbox, local_context);
1122  } else {
1123  res = -1;
1124  }
1125  }
1126  if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
1127  int num;
1128  if (!ast_test_flag(flags, OPTION_NOTECH)) {
1129  if (ast_fileexists(peer_name, NULL, NULL) > 0) {
1130  res = ast_streamfile(chan, peer_name, ast_channel_language(chan));
1131  if (!res) {
1132  res = ast_waitstream(chan, "");
1133  }
1134  if (res) {
1135  ast_autochan_destroy(autochan);
1136  break;
1137  }
1138  } else {
1139  res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan), AST_SAY_CASE_NONE);
1140  }
1141  }
1142  if (ptr && (num = atoi(ptr))) {
1143  ast_say_digits(chan, num, "", ast_channel_language(chan));
1144  }
1145  }
1146  }
1147 
1148  res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
1149  num_spyed_upon++;
1150 
1151  if (res == -1) {
1152  ast_autochan_destroy(autochan);
1153  iter = ast_channel_iterator_destroy(iter);
1154  goto exit;
1155  } else if (res == -2) {
1156  res = 0;
1157  ast_autochan_destroy(autochan);
1158  iter = ast_channel_iterator_destroy(iter);
1159  goto exit;
1160  } else if (res > 1 && spec && !ast_test_flag(flags, OPTION_UNIQUEID)) {
1161  struct ast_channel *next;
1162 
1163  snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
1164 
1165  if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
1166  next_autochan = ast_autochan_setup(next);
1167  next = ast_channel_unref(next);
1168  } else {
1169  /* stay on this channel, if it is still valid */
1170  ast_autochan_channel_lock(autochan);
1171  if (!ast_check_hangup(autochan->chan)) {
1172  next_autochan = ast_autochan_setup(autochan->chan);
1173  } else {
1174  /* the channel is gone */
1175  next_autochan = NULL;
1176  }
1177  ast_autochan_channel_unlock(autochan);
1178  }
1179  } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
1180  ast_autochan_destroy(autochan);
1181  iter = ast_channel_iterator_destroy(iter);
1182  goto exit;
1183  }
1184  }
1185 
1186  iter = ast_channel_iterator_destroy(iter);
1187 
1188  if (res == -1 || ast_check_hangup(chan))
1189  break;
1190  if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
1191  break;
1192  }
1193  }
1194 exit:
1195 
1197 
1198  ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
1199 
1200  return res;
1201 }
1202 
1203 static int chanspy_exec(struct ast_channel *chan, const char *data)
1204 {
1205  char *myenforced = NULL;
1206  char *mygroup = NULL;
1207  char *recbase = NULL;
1208  int fd = 0;
1209  struct ast_flags flags;
1210  struct spy_dtmf_options user_options = {
1211  .cycle = '*',
1212  .volume = '#',
1213  .exit = '\0',
1214  };
1215  RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
1216  int volfactor = 0;
1217  int res;
1218  char *mailbox = NULL;
1219  char *name_context = NULL;
1221  AST_APP_ARG(spec);
1223  );
1224  char *opts[OPT_ARG_ARRAY_SIZE];
1225  char *parse = ast_strdupa(data);
1226 
1227  AST_STANDARD_APP_ARGS(args, parse);
1228 
1229  if (args.spec && !strcmp(args.spec, "all"))
1230  args.spec = NULL;
1231 
1232  if (args.options) {
1233  char tmp;
1234  ast_app_parse_options(spy_opts, &flags, opts, args.options);
1235  if (ast_test_flag(&flags, OPTION_GROUP))
1236  mygroup = opts[OPT_ARG_GROUP];
1237 
1238  if (ast_test_flag(&flags, OPTION_RECORD) &&
1239  !(recbase = opts[OPT_ARG_RECORD]))
1240  recbase = "chanspy";
1241 
1242  if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1243  tmp = opts[OPT_ARG_EXIT][0];
1244  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1245  user_options.exit = tmp;
1246  } else {
1247  ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1248  }
1249  }
1250 
1251  if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1252  tmp = opts[OPT_ARG_CYCLE][0];
1253  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1254  user_options.cycle = tmp;
1255  } else {
1256  ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1257  }
1258  }
1259 
1260  if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1261  int vol;
1262 
1263  if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1264  ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1265  else
1266  volfactor = vol;
1267  }
1268 
1269  if (ast_test_flag(&flags, OPTION_PRIVATE))
1270  ast_set_flag(&flags, OPTION_WHISPER);
1271 
1272  if (ast_test_flag(&flags, OPTION_ENFORCED))
1273  myenforced = opts[OPT_ARG_ENFORCED];
1274 
1275  if (ast_test_flag(&flags, OPTION_NAME)) {
1276  if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1277  char *delimiter;
1278  if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1279  mailbox = opts[OPT_ARG_NAME];
1280  *delimiter++ = '\0';
1281  name_context = delimiter;
1282  } else {
1283  mailbox = opts[OPT_ARG_NAME];
1284  }
1285  }
1286  }
1287  } else {
1288  ast_clear_flag(&flags, AST_FLAGS_ALL);
1289  }
1290 
1291  oldwf = ao2_bump(ast_channel_writeformat(chan));
1292  if (ast_set_write_format(chan, ast_format_slin) < 0) {
1293  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1294  return -1;
1295  }
1296 
1297  if (recbase) {
1298  char filename[PATH_MAX];
1299 
1300  snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1301  if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1302  ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1303  fd = 0;
1304  }
1305  }
1306 
1307  res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
1308 
1309  if (fd)
1310  close(fd);
1311 
1312  if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1313  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1314 
1315  if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) {
1316  ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n");
1317  }
1318 
1319  return res;
1320 }
1321 
1322 static int extenspy_exec(struct ast_channel *chan, const char *data)
1323 {
1324  char *ptr, *exten = NULL;
1325  char *mygroup = NULL;
1326  char *recbase = NULL;
1327  int fd = 0;
1328  struct ast_flags flags;
1329  struct spy_dtmf_options user_options = {
1330  .cycle = '*',
1331  .volume = '#',
1332  .exit = '\0',
1333  };
1334  RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
1335  int volfactor = 0;
1336  int res;
1337  char *mailbox = NULL;
1338  char *name_context = NULL;
1342  );
1343  char *parse = ast_strdupa(data);
1344 
1345  AST_STANDARD_APP_ARGS(args, parse);
1346 
1347  if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
1348  exten = args.context;
1349  *ptr++ = '\0';
1350  args.context = ptr;
1351  }
1352  if (ast_strlen_zero(args.context))
1353  args.context = ast_strdupa(ast_channel_context(chan));
1354 
1355  if (args.options) {
1356  char *opts[OPT_ARG_ARRAY_SIZE];
1357  char tmp;
1358 
1359  ast_app_parse_options(spy_opts, &flags, opts, args.options);
1360  if (ast_test_flag(&flags, OPTION_GROUP))
1361  mygroup = opts[OPT_ARG_GROUP];
1362 
1363  if (ast_test_flag(&flags, OPTION_RECORD) &&
1364  !(recbase = opts[OPT_ARG_RECORD]))
1365  recbase = "chanspy";
1366 
1367  if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1368  tmp = opts[OPT_ARG_EXIT][0];
1369  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1370  user_options.exit = tmp;
1371  } else {
1372  ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1373  }
1374  }
1375 
1376  if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1377  tmp = opts[OPT_ARG_CYCLE][0];
1378  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1379  user_options.cycle = tmp;
1380  } else {
1381  ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1382  }
1383  }
1384 
1385  if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1386  int vol;
1387 
1388  if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1389  ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1390  else
1391  volfactor = vol;
1392  }
1393 
1394  if (ast_test_flag(&flags, OPTION_PRIVATE))
1395  ast_set_flag(&flags, OPTION_WHISPER);
1396 
1397  if (ast_test_flag(&flags, OPTION_NAME)) {
1398  if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1399  char *delimiter;
1400  if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1401  mailbox = opts[OPT_ARG_NAME];
1402  *delimiter++ = '\0';
1403  name_context = delimiter;
1404  } else {
1405  mailbox = opts[OPT_ARG_NAME];
1406  }
1407  }
1408  }
1409 
1410  } else {
1411  /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1412  ast_clear_flag(&flags, AST_FLAGS_ALL);
1413  }
1414 
1415  oldwf = ao2_bump(ast_channel_writeformat(chan));
1416  if (ast_set_write_format(chan, ast_format_slin) < 0) {
1417  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1418  return -1;
1419  }
1420 
1421  if (recbase) {
1422  char filename[PATH_MAX];
1423 
1424  snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1425  if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1426  ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1427  fd = 0;
1428  }
1429  }
1430 
1431 
1432  res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
1433 
1434  if (fd)
1435  close(fd);
1436 
1437  if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1438  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1439 
1440  return res;
1441 }
1442 
1443 static int dahdiscan_exec(struct ast_channel *chan, const char *data)
1444 {
1445  const char *spec = "DAHDI";
1446  struct ast_flags flags = {0};
1447  struct spy_dtmf_options user_options = {
1448  .cycle = '#',
1449  .volume = '\0',
1450  .exit = '*',
1451  };
1452  struct ast_format *oldwf;
1453  int res;
1454  char *mygroup = NULL;
1455 
1456  /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1457  ast_clear_flag(&flags, AST_FLAGS_ALL);
1458 
1459  if (!ast_strlen_zero(data)) {
1460  mygroup = ast_strdupa(data);
1461  }
1462  ast_set_flag(&flags, OPTION_DTMF_EXIT);
1465 
1466  oldwf = ao2_bump(ast_channel_writeformat(chan));
1467  if (ast_set_write_format(chan, ast_format_slin) < 0) {
1468  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1469  ao2_cleanup(oldwf);
1470  return -1;
1471  }
1472 
1473  res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
1474 
1475  if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1476  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1477  ao2_cleanup(oldwf);
1478 
1479  return res;
1480 }
1481 
1482 static int unload_module(void)
1483 {
1484  int res = 0;
1485 
1489 
1490  return res;
1491 }
1492 
1493 static int load_module(void)
1494 {
1495  int res = 0;
1496 
1500 
1501  return res;
1502 }
1503 
1504 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");
static struct ast_autochan * next_channel(struct ast_channel_iterator *iter, struct ast_channel *chan)
Definition: app_chanspy.c:858
static const char type[]
Definition: chan_ooh323.c:109
char digit
#define ast_channel_lock(chan)
Definition: channel.h:2945
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
Main Channel structure associated with a channel.
#define NUM_SPYGROUPS
Definition: app_chanspy.c:61
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1250
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:1422
Asterisk main include file. File version handling, generic pbx functions.
#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:170
#define AST_OPTION_TXGAIN
#define ast_autochan_channel_lock(autochan)
Lock the autochan&#39;s channel lock.
Definition: autochan.h:75
struct ast_flags flags
Definition: app_chanspy.c:439
static int dahdiscan_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1443
void *(* alloc)(struct ast_channel *chan, void *params)
Definition: channel.h:227
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
int ast_app_sayname(struct ast_channel *chan, const char *mailbox_id)
Play a recorded user name for the mailbox to the specified channel.
Definition: main/app.c:710
#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:2960
Support for translation of data formats. translate.c.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
static const char app_chan[]
Definition: app_chanspy.c:368
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
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:640
Audiohooks Architecture.
struct ast_audiohook spy_audiohook
Definition: app_chanspy.c:434
static int tmp()
Definition: bt_open.c:389
#define AST_LOG_WARNING
Definition: logger.h:279
Structure representing a snapshot of channel state.
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Definition: channel.c:11235
#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:4302
ast_channel_state
ast_channel states
Definition: channelstate.h:35
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition: channel.c:8349
Definition of a media format.
Definition: format.c:43
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:501
static int spy_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
Definition: app_chanspy.c:883
struct ast_channel * chan
Definition: autochan.h:33
static struct test_val c
#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 * args
struct stasis_message_type * ast_channel_chanspy_start_type(void)
Message type for when a channel starts spying on another channel.
#define NULL
Definition: resample.c:96
const char * data
char * end
Definition: eagi_proxy.c:73
struct ast_audiohook bridge_whisper_audiohook
Definition: app_chanspy.c:436
#define AST_FRAME_DTMF
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:7522
const char * ext
Definition: http.c:147
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:133
#define AST_FILE_MODE
Definition: asterisk.h:32
#define ast_verb(level,...)
Definition: logger.h:463
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
struct ast_frame_subclass subclass
Utility functions.
static int attach_barge(struct ast_autochan *spyee_autochan, struct ast_autochan **spyee_bridge_autochan, struct ast_audiohook *bridge_whisper_audiohook, const char *spyer_name, const char *name, struct ast_flags *flags)
Definition: app_chanspy.c:605
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:1434
#define ast_strlen_zero(foo)
Definition: strings.h:52
static const char app_ext[]
Definition: app_chanspy.c:370
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
static int extenspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1322
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition: json.c:248
#define ao2_bump(obj)
Definition: astobj2.h:491
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags flags)
Initialize an audiohook structure.
Definition: audiohook.c:108
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:300
static char mailbox[AST_MAX_MAILBOX_UNIQUEID]
Definition: chan_mgcp.c:204
static char exitcontext[AST_MAX_CONTEXT]
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define AST_NAME_STRLEN
Definition: app_chanspy.c:60
static void * spy_alloc(struct ast_channel *chan, void *data)
Definition: app_chanspy.c:448
General Asterisk PBX channel definitions.
Asterisk JSON abstraction layer.
Asterisk file paths, configured in asterisk.conf.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
Definition: app_chanspy.c:459
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.
static const char app_dahdiscan[]
Definition: app_chanspy.c:372
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:2992
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5890
int ast_say_character_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity)
function to pronounce character and phonetic strings
Definition: channel.c:8367
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: main/app.c:2906
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:445
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
const char * ast_channel_uniqueid(const struct ast_channel *chan)
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8266
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
"smart" channels that update automatically if a channel is masqueraded
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:579
static struct ast_generator spygen
Definition: app_chanspy.c:501
#define LOG_ERROR
Definition: logger.h:285
static void publish_chanspy_message(struct ast_channel *spyer, struct ast_channel *spyee, int start)
Definition: app_chanspy.c:565
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag)
Set a flag on a channel.
Definition: channel.c:11228
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int errno
static int load_module(void)
Definition: app_chanspy.c:1493
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:1368
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
Definition: app_chanspy.c:507
#define LOG_NOTICE
Definition: logger.h:263
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8793
char * strcasestr(const char *, const char *)
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10746
#define ast_channel_unlock(chan)
Definition: channel.h:2946
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:8312
static int unload_module(void)
Definition: app_chanspy.c:1482
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1511
#define AST_MAX_CONTEXT
Definition: channel.h:136
static const char name[]
Definition: cdr_mysql.c:74
const char * ast_config_AST_MONITOR_DIR
Definition: options.c:155
#define AST_CHANNEL_NAME
Definition: channel.h:172
#define AST_FLAGS_ALL
Definition: utils.h:196
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:5189
Structure used to handle boolean flags.
Definition: utils.h:199
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:1388
#define ast_clear_flag(p, flag)
Definition: utils.h:77
static int pack_channel_into_message(struct ast_channel *chan, const char *role, struct ast_multi_channel_blob *payload)
Definition: app_chanspy.c:544
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition: autochan.c:64
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...
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3184
static void spy_release(struct ast_channel *chan, void *data)
Definition: app_chanspy.c:454
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition: autochan.c:38
static const struct ast_app_option spy_opts[128]
Definition: app_chanspy.c:430
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2902
struct ast_audiohook_options options
Definition: audiohook.h:118
static void change_spy_mode(const char digit, struct ast_flags *flags)
Definition: app_chanspy.c:530
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2970
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3171
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object...
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
struct ast_channel * ast_channel_bridge_peer(struct ast_channel *chan)
Get the channel&#39;s bridge peer only if the bridge is two-party.
Definition: channel.c:10765
const char * ast_channel_name(const struct ast_channel *chan)
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1776
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1086
A multi channel blob data structure for multi_channel_blob stasis messages.
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition: channel.c:1360
static ENTRY retval
Definition: hsearch.c:50
#define ast_frfree(fr)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2814
Data structure associated with a single frame of data.
const char * ast_channel_language(const struct ast_channel *chan)
Abstract JSON element (object, array, string, int, ...).
Options provided by main asterisk program.
const char * ast_channel_context(const struct ast_channel *chan)
enum ast_audiohook_status status
Definition: audiohook.h:107
union ast_frame::@263 data
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:892
enum ast_frame_type frametype
#define PATH_MAX
Definition: asterisk.h:40
#define ast_autochan_channel_unlock(autochan)
Definition: autochan.h:84
char x
Definition: extconf.c:81
static struct test_options options
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
Call Parking and Pickup API Includes code and algorithms from the Zapata library. ...
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
struct ast_channel_iterator * ast_channel_iterator_all_new(void)
Create a new channel iterator.
Definition: channel.c:1408
const char * ast_channel_macrocontext(const struct ast_channel *chan)
Say numbers and dates (maybe words one day too)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:295
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
Asterisk module definitions.
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
struct ast_frame * ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format)
Reads a frame in from the audiohook structure.
Definition: audiohook.c:449
static int chanspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1203
struct ast_audiohook whisper_audiohook
Definition: app_chanspy.c:435
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.
struct stasis_message_type * ast_channel_chanspy_stop_type(void)
Message type for when a channel stops spying on another channel.
#define ast_app_separate_args(a, b, c, d)
Media Format Cache API.
#define AST_APP_ARG(name)
Define an application argument.