Asterisk - The Open Source Telephony Project  18.5.0
app_meetme.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2007, Digium, Inc.
5  *
6  * Mark Spencer <[email protected]>
7  *
8  * SLA Implementation by:
9  * Russell Bryant <[email protected]>
10  *
11  * See http://www.asterisk.org for more information about
12  * the Asterisk project. Please do not directly contact
13  * any of the maintainers of this project for assistance;
14  * the project provides a web site, mailing lists and IRC
15  * channels for your use.
16  *
17  * This program is free software, distributed under the terms of
18  * the GNU General Public License Version 2. See the LICENSE file
19  * at the top of the source tree.
20  */
21 
22 /*! \file
23  *
24  * \brief Meet me conference bridge and Shared Line Appearances
25  *
26  * \author Mark Spencer <[email protected]>
27  * \author (SLA) Russell Bryant <[email protected]>
28  *
29  * \ingroup applications
30  */
31 
32 /*! \li \ref app_meetme.c uses configuration file \ref meetme.conf
33  * \addtogroup configuration_file Configuration Files
34  */
35 
36 /*!
37  * \page meetme.conf meetme.conf
38  * \verbinclude meetme.conf.sample
39  */
40 
41 /*** MODULEINFO
42  <depend>dahdi</depend>
43  <defaultenabled>no</defaultenabled>
44  <support_level>extended</support_level>
45  <replacement>app_confbridge</replacement>
46  ***/
47 
48 #include "asterisk.h"
49 
50 #include <dahdi/user.h>
51 
52 #include "asterisk/lock.h"
53 #include "asterisk/file.h"
54 #include "asterisk/channel.h"
55 #include "asterisk/pbx.h"
56 #include "asterisk/module.h"
57 #include "asterisk/config.h"
58 #include "asterisk/app.h"
59 #include "asterisk/dsp.h"
60 #include "asterisk/musiconhold.h"
61 #include "asterisk/manager.h"
62 #include "asterisk/cli.h"
63 #include "asterisk/say.h"
64 #include "asterisk/utils.h"
65 #include "asterisk/translate.h"
66 #include "asterisk/ulaw.h"
67 #include "asterisk/astobj2.h"
68 #include "asterisk/devicestate.h"
69 #include "asterisk/dial.h"
70 #include "asterisk/causes.h"
71 #include "asterisk/paths.h"
72 #include "asterisk/test.h"
73 #include "asterisk/stasis.h"
76 #include "asterisk/json.h"
78 
79 #include "enter.h"
80 #include "leave.h"
81 
82 /*** DOCUMENTATION
83  <application name="MeetMe" language="en_US">
84  <synopsis>
85  MeetMe conference bridge.
86  </synopsis>
87  <syntax>
88  <parameter name="confno">
89  <para>The conference number</para>
90  </parameter>
91  <parameter name="options">
92  <optionlist>
93  <option name="a">
94  <para>Set admin mode.</para>
95  </option>
96  <option name="A">
97  <para>Set marked mode.</para>
98  </option>
99  <option name="b">
100  <para>Run AGI script specified in <variable>MEETME_AGI_BACKGROUND</variable>
101  Default: <literal>conf-background.agi</literal>.</para>
102  <note><para>This does not work with non-DAHDI channels in the same
103  conference).</para></note>
104  </option>
105  <option name="c">
106  <para>Announce user(s) count on joining a conference.</para>
107  </option>
108  <option name="C">
109  <para>Continue in dialplan when kicked out of conference.</para>
110  </option>
111  <option name="d">
112  <para>Dynamically add conference.</para>
113  </option>
114  <option name="D">
115  <para>Dynamically add conference, prompting for a PIN.</para>
116  </option>
117  <option name="e">
118  <para>Select an empty conference.</para>
119  </option>
120  <option name="E">
121  <para>Select an empty pinless conference.</para>
122  </option>
123  <option name="F">
124  <para>Pass DTMF through the conference.</para>
125  </option>
126  <option name="G">
127  <argument name="x" required="true">
128  <para>The file to playback</para>
129  </argument>
130  <para>Play an intro announcement in conference.</para>
131  </option>
132  <option name="i">
133  <para>Announce user join/leave with review.</para>
134  </option>
135  <option name="I">
136  <para>Announce user join/leave without review.</para>
137  </option>
138  <option name="k">
139  <para>Close the conference if there's only one active participant left at exit.</para>
140  </option>
141  <option name="l">
142  <para>Set listen only mode (Listen only, no talking).</para>
143  </option>
144  <option name="m">
145  <para>Set initially muted.</para>
146  </option>
147  <option name="M" hasparams="optional">
148  <para>Enable music on hold when the conference has a single caller. Optionally,
149  specify a musiconhold class to use. If one is not provided, it will use the
150  channel's currently set music class, or <literal>default</literal>.</para>
151  <argument name="class" required="true" />
152  </option>
153  <option name="n">
154  <para>Disable the denoiser. By default, if <literal>func_speex</literal> is loaded, Asterisk
155  will apply a denoiser to channels in the MeetMe conference. However, channel
156  drivers that present audio with a varying rate will experience degraded
157  performance with a denoiser attached. This parameter allows a channel joining
158  the conference to choose not to have a denoiser attached without having to
159  unload <literal>func_speex</literal>.</para>
160  </option>
161  <option name="o">
162  <para>Set talker optimization - treats talkers who aren't speaking as
163  being muted, meaning (a) No encode is done on transmission and (b)
164  Received audio that is not registered as talking is omitted causing no
165  buildup in background noise.</para>
166  </option>
167  <option name="p" hasparams="optional">
168  <para>Allow user to exit the conference by pressing <literal>#</literal> (default)
169  or any of the defined keys. Dial plan execution will continue at the next
170  priority following MeetMe. The key used is set to channel variable
171  <variable>MEETME_EXIT_KEY</variable>.</para>
172  <argument name="keys" required="true" />
173  <note>
174  <para>Option <literal>s</literal> has priority for <literal>*</literal>
175  since it cannot change its activation code.</para>
176  </note>
177  </option>
178  <option name="P">
179  <para>Always prompt for the pin even if it is specified.</para>
180  </option>
181  <option name="q">
182  <para>Quiet mode (don't play enter/leave sounds).</para>
183  </option>
184  <option name="r">
185  <para>Record conference (records as <variable>MEETME_RECORDINGFILE</variable>
186  using format <variable>MEETME_RECORDINGFORMAT</variable>. Default filename is
187  <literal>meetme-conf-rec-${CONFNO}-${UNIQUEID}</literal> and the default format is
188  wav.</para>
189  </option>
190  <option name="s">
191  <para>Present menu (user or admin) when <literal>*</literal> is received
192  (send to menu).</para>
193  </option>
194  <option name="t">
195  <para>Set talk only mode. (Talk only, no listening).</para>
196  </option>
197  <option name="T">
198  <para>Set talker detection (sent to manager interface and meetme list).</para>
199  </option>
200  <option name="v" hasparams="optional">
201  <para>Announce when a user is joining or leaving the conference. Use the voicemail greeting as the announcement.
202  If the i or I options are set, the application will fall back to them if no voicemail greeting can be found.</para>
203  <argument name="mailbox@[context]" required="true">
204  <para>The mailbox and voicemail context to play from. If no context provided, assumed context is default.</para>
205  </argument>
206  </option>
207  <option name="w" hasparams="optional">
208  <para>Wait until the marked user enters the conference.</para>
209  <argument name="secs" required="true" />
210  </option>
211  <option name="x">
212  <para>Leave the conference when the last marked user leaves.</para>
213  </option>
214  <option name="X">
215  <para>Allow user to exit the conference by entering a valid single digit
216  extension <variable>MEETME_EXIT_CONTEXT</variable> or the current context
217  if that variable is not defined.</para>
218  <note>
219  <para>Option <literal>s</literal> has priority for <literal>*</literal>
220  since it cannot change its activation code.</para>
221  </note>
222  </option>
223  <option name="1">
224  <para>Do not play message when first person enters</para>
225  </option>
226  <option name="S">
227  <para>Kick the user <replaceable>x</replaceable> seconds <emphasis>after</emphasis> he entered into
228  the conference.</para>
229  <argument name="x" required="true" />
230  </option>
231  <option name="L" argsep=":">
232  <para>Limit the conference to <replaceable>x</replaceable> ms. Play a warning when
233  <replaceable>y</replaceable> ms are left. Repeat the warning every <replaceable>z</replaceable> ms.
234  The following special variables can be used with this option:</para>
235  <variablelist>
236  <variable name="CONF_LIMIT_TIMEOUT_FILE">
237  <para>File to play when time is up.</para>
238  </variable>
239  <variable name="CONF_LIMIT_WARNING_FILE">
240  <para>File to play as warning if <replaceable>y</replaceable> is defined. The
241  default is to say the time remaining.</para>
242  </variable>
243  </variablelist>
244  <argument name="x" />
245  <argument name="y" />
246  <argument name="z" />
247  </option>
248  </optionlist>
249  </parameter>
250  <parameter name="pin" />
251  </syntax>
252  <description>
253  <para>Enters the user into a specified MeetMe conference. If the <replaceable>confno</replaceable>
254  is omitted, the user will be prompted to enter one. User can exit the conference by hangup, or
255  if the <literal>p</literal> option is specified, by pressing <literal>#</literal>.</para>
256  <note><para>The DAHDI kernel modules and a functional DAHDI timing source (see dahdi_test)
257  must be present for conferencing to operate properly. In addition, the chan_dahdi channel driver
258  must be loaded for the <literal>i</literal> and <literal>r</literal> options to operate at
259  all.</para></note>
260  </description>
261  <see-also>
262  <ref type="application">MeetMeCount</ref>
263  <ref type="application">MeetMeAdmin</ref>
264  <ref type="application">MeetMeChannelAdmin</ref>
265  </see-also>
266  </application>
267  <application name="MeetMeCount" language="en_US">
268  <synopsis>
269  MeetMe participant count.
270  </synopsis>
271  <syntax>
272  <parameter name="confno" required="true">
273  <para>Conference number.</para>
274  </parameter>
275  <parameter name="var" />
276  </syntax>
277  <description>
278  <para>Plays back the number of users in the specified MeetMe conference.
279  If <replaceable>var</replaceable> is specified, playback will be skipped and the value
280  will be returned in the variable. Upon application completion, MeetMeCount will hangup
281  the channel, unless priority <literal>n+1</literal> exists, in which case priority progress will
282  continue.</para>
283  </description>
284  <see-also>
285  <ref type="application">MeetMe</ref>
286  </see-also>
287  </application>
288  <application name="MeetMeAdmin" language="en_US">
289  <synopsis>
290  MeetMe conference administration.
291  </synopsis>
292  <syntax>
293  <parameter name="confno" required="true" />
294  <parameter name="command" required="true">
295  <optionlist>
296  <option name="e">
297  <para>Eject last user that joined.</para>
298  </option>
299  <option name="E">
300  <para>Extend conference end time, if scheduled.</para>
301  </option>
302  <option name="k">
303  <para>Kick one user out of conference.</para>
304  </option>
305  <option name="K">
306  <para>Kick all users out of conference.</para>
307  </option>
308  <option name="l">
309  <para>Unlock conference.</para>
310  </option>
311  <option name="L">
312  <para>Lock conference.</para>
313  </option>
314  <option name="m">
315  <para>Unmute one user.</para>
316  </option>
317  <option name="M">
318  <para>Mute one user.</para>
319  </option>
320  <option name="n">
321  <para>Unmute all users in the conference.</para>
322  </option>
323  <option name="N">
324  <para>Mute all non-admin users in the conference.</para>
325  </option>
326  <option name="r">
327  <para>Reset one user's volume settings.</para>
328  </option>
329  <option name="R">
330  <para>Reset all users volume settings.</para>
331  </option>
332  <option name="s">
333  <para>Lower entire conference speaking volume.</para>
334  </option>
335  <option name="S">
336  <para>Raise entire conference speaking volume.</para>
337  </option>
338  <option name="t">
339  <para>Lower one user's talk volume.</para>
340  </option>
341  <option name="T">
342  <para>Raise one user's talk volume.</para>
343  </option>
344  <option name="u">
345  <para>Lower one user's listen volume.</para>
346  </option>
347  <option name="U">
348  <para>Raise one user's listen volume.</para>
349  </option>
350  <option name="v">
351  <para>Lower entire conference listening volume.</para>
352  </option>
353  <option name="V">
354  <para>Raise entire conference listening volume.</para>
355  </option>
356  </optionlist>
357  </parameter>
358  <parameter name="user" />
359  </syntax>
360  <description>
361  <para>Run admin <replaceable>command</replaceable> for conference <replaceable>confno</replaceable>.</para>
362  <para>Will additionally set the variable <variable>MEETMEADMINSTATUS</variable> with one of
363  the following values:</para>
364  <variablelist>
365  <variable name="MEETMEADMINSTATUS">
366  <value name="NOPARSE">
367  Invalid arguments.
368  </value>
369  <value name="NOTFOUND">
370  User specified was not found.
371  </value>
372  <value name="FAILED">
373  Another failure occurred.
374  </value>
375  <value name="OK">
376  The operation was completed successfully.
377  </value>
378  </variable>
379  </variablelist>
380  </description>
381  <see-also>
382  <ref type="application">MeetMe</ref>
383  </see-also>
384  </application>
385  <application name="MeetMeChannelAdmin" language="en_US">
386  <synopsis>
387  MeetMe conference Administration (channel specific).
388  </synopsis>
389  <syntax>
390  <parameter name="channel" required="true" />
391  <parameter name="command" required="true">
392  <optionlist>
393  <option name="k">
394  <para>Kick the specified user out of the conference he is in.</para>
395  </option>
396  <option name="m">
397  <para>Unmute the specified user.</para>
398  </option>
399  <option name="M">
400  <para>Mute the specified user.</para>
401  </option>
402  </optionlist>
403  </parameter>
404  </syntax>
405  <description>
406  <para>Run admin <replaceable>command</replaceable> for a specific
407  <replaceable>channel</replaceable> in any conference.</para>
408  </description>
409  </application>
410  <application name="SLAStation" language="en_US">
411  <synopsis>
412  Shared Line Appearance Station.
413  </synopsis>
414  <syntax>
415  <parameter name="station" required="true">
416  <para>Station name</para>
417  </parameter>
418  </syntax>
419  <description>
420  <para>This application should be executed by an SLA station. The argument depends
421  on how the call was initiated. If the phone was just taken off hook, then the argument
422  <replaceable>station</replaceable> should be just the station name. If the call was
423  initiated by pressing a line key, then the station name should be preceded by an underscore
424  and the trunk name associated with that line button.</para>
425  <para>For example: <literal>station1_line1</literal></para>
426  <para>On exit, this application will set the variable <variable>SLASTATION_STATUS</variable> to
427  one of the following values:</para>
428  <variablelist>
429  <variable name="SLASTATION_STATUS">
430  <value name="FAILURE" />
431  <value name="CONGESTION" />
432  <value name="SUCCESS" />
433  </variable>
434  </variablelist>
435  </description>
436  </application>
437  <application name="SLATrunk" language="en_US">
438  <synopsis>
439  Shared Line Appearance Trunk.
440  </synopsis>
441  <syntax>
442  <parameter name="trunk" required="true">
443  <para>Trunk name</para>
444  </parameter>
445  <parameter name="options">
446  <optionlist>
447  <option name="M" hasparams="optional">
448  <para>Play back the specified MOH <replaceable>class</replaceable>
449  instead of ringing</para>
450  <argument name="class" required="true" />
451  </option>
452  </optionlist>
453  </parameter>
454  </syntax>
455  <description>
456  <para>This application should be executed by an SLA trunk on an inbound call. The channel calling
457  this application should correspond to the SLA trunk with the name <replaceable>trunk</replaceable>
458  that is being passed as an argument.</para>
459  <para>On exit, this application will set the variable <variable>SLATRUNK_STATUS</variable> to
460  one of the following values:</para>
461  <variablelist>
462  <variable name="SLATRUNK_STATUS">
463  <value name="FAILURE" />
464  <value name="SUCCESS" />
465  <value name="UNANSWERED" />
466  <value name="RINGTIMEOUT" />
467  </variable>
468  </variablelist>
469  </description>
470  </application>
471  <function name="MEETME_INFO" language="en_US">
472  <synopsis>
473  Query a given conference of various properties.
474  </synopsis>
475  <syntax>
476  <parameter name="keyword" required="true">
477  <para>Options:</para>
478  <enumlist>
479  <enum name="lock">
480  <para>Boolean of whether the corresponding conference is locked.</para>
481  </enum>
482  <enum name="parties">
483  <para>Number of parties in a given conference</para>
484  </enum>
485  <enum name="activity">
486  <para>Duration of conference in seconds.</para>
487  </enum>
488  <enum name="dynamic">
489  <para>Boolean of whether the corresponding conference is dynamic.</para>
490  </enum>
491  </enumlist>
492  </parameter>
493  <parameter name="confno" required="true">
494  <para>Conference number to retrieve information from.</para>
495  </parameter>
496  </syntax>
497  <description />
498  <see-also>
499  <ref type="application">MeetMe</ref>
500  <ref type="application">MeetMeCount</ref>
501  <ref type="application">MeetMeAdmin</ref>
502  <ref type="application">MeetMeChannelAdmin</ref>
503  </see-also>
504  </function>
505  <manager name="MeetmeMute" language="en_US">
506  <synopsis>
507  Mute a Meetme user.
508  </synopsis>
509  <syntax>
510  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
511  <parameter name="Meetme" required="true" />
512  <parameter name="Usernum" required="true" />
513  </syntax>
514  <description>
515  </description>
516  </manager>
517  <manager name="MeetmeUnmute" language="en_US">
518  <synopsis>
519  Unmute a Meetme user.
520  </synopsis>
521  <syntax>
522  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
523  <parameter name="Meetme" required="true" />
524  <parameter name="Usernum" required="true" />
525  </syntax>
526  <description>
527  </description>
528  </manager>
529  <manager name="MeetmeList" language="en_US">
530  <synopsis>
531  List participants in a conference.
532  </synopsis>
533  <syntax>
534  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
535  <parameter name="Conference" required="false">
536  <para>Conference number.</para>
537  </parameter>
538  </syntax>
539  <description>
540  <para>Lists all users in a particular MeetMe conference.
541  MeetmeList will follow as separate events, followed by a final event called
542  MeetmeListComplete.</para>
543  </description>
544  </manager>
545  <manager name="MeetmeListRooms" language="en_US">
546  <synopsis>
547  List active conferences.
548  </synopsis>
549  <syntax>
550  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
551  </syntax>
552  <description>
553  <para>Lists data about all active conferences.
554  MeetmeListRooms will follow as separate events, followed by a final event called
555  MeetmeListRoomsComplete.</para>
556  </description>
557  </manager>
558  <managerEvent language="en_US" name="MeetmeJoin">
559  <managerEventInstance class="EVENT_FLAG_CALL">
560  <synopsis>Raised when a user joins a MeetMe conference.</synopsis>
561  <syntax>
562  <parameter name="Meetme">
563  <para>The identifier for the MeetMe conference.</para>
564  </parameter>
565  <parameter name="User">
566  <para>The identifier of the MeetMe user who joined.</para>
567  </parameter>
568  <channel_snapshot/>
569  </syntax>
570  <see-also>
571  <ref type="managerEvent">MeetmeLeave</ref>
572  <ref type="application">MeetMe</ref>
573  </see-also>
574  </managerEventInstance>
575  </managerEvent>
576  <managerEvent language="en_US" name="MeetmeLeave">
577  <managerEventInstance class="EVENT_FLAG_CALL">
578  <synopsis>Raised when a user leaves a MeetMe conference.</synopsis>
579  <syntax>
580  <xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
581  <channel_snapshot/>
582  <parameter name="Duration">
583  <para>The length of time in seconds that the Meetme user was in the conference.</para>
584  </parameter>
585  </syntax>
586  <see-also>
587  <ref type="managerEvent">MeetmeJoin</ref>
588  </see-also>
589  </managerEventInstance>
590  </managerEvent>
591  <managerEvent language="en_US" name="MeetmeEnd">
592  <managerEventInstance class="EVENT_FLAG_CALL">
593  <synopsis>Raised when a MeetMe conference ends.</synopsis>
594  <syntax>
595  <xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter[@name='Meetme'])" />
596  </syntax>
597  <see-also>
598  <ref type="managerEvent">MeetmeJoin</ref>
599  </see-also>
600  </managerEventInstance>
601  </managerEvent>
602  <managerEvent language="en_US" name="MeetmeTalkRequest">
603  <managerEventInstance class="EVENT_FLAG_CALL">
604  <synopsis>Raised when a MeetMe user has started talking.</synopsis>
605  <syntax>
606  <xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
607  <channel_snapshot/>
608  <parameter name="Duration">
609  <para>The length of time in seconds that the Meetme user has been in the conference at the time of this event.</para>
610  </parameter>
611  <parameter name="Status">
612  <enumlist>
613  <enum name="on"/>
614  <enum name="off"/>
615  </enumlist>
616  </parameter>
617  </syntax>
618  </managerEventInstance>
619  </managerEvent>
620  <managerEvent language="en_US" name="MeetmeTalking">
621  <managerEventInstance class="EVENT_FLAG_CALL">
622  <synopsis>Raised when a MeetMe user begins or ends talking.</synopsis>
623  <syntax>
624  <xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
625  <channel_snapshot/>
626  <xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeTalkRequest']/managerEventInstance/syntax/parameter)" />
627  </syntax>
628  </managerEventInstance>
629  </managerEvent>
630  <managerEvent language="en_US" name="MeetmeMute">
631  <managerEventInstance class="EVENT_FLAG_CALL">
632  <synopsis>Raised when a MeetMe user is muted or unmuted.</synopsis>
633  <syntax>
634  <xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeJoin']/managerEventInstance/syntax/parameter)" />
635  <channel_snapshot/>
636  <xi:include xpointer="xpointer(/docs/managerEvent[@name='MeetmeTalkRequest']/managerEventInstance/syntax/parameter)" />
637  </syntax>
638  </managerEventInstance>
639  </managerEvent>
640  ***/
641 
642 #define CONFIG_FILE_NAME "meetme.conf"
643 #define SLA_CONFIG_FILE "sla.conf"
644 #define STR_CONCISE "concise"
645 
646 /*! each buffer is 20ms, so this is 640ms total */
647 #define DEFAULT_AUDIO_BUFFERS 32
648 
649 /*! String format for scheduled conferences */
650 #define DATE_FORMAT "%Y-%m-%d %H:%M:%S"
651 
652 enum {
653  ADMINFLAG_MUTED = (1 << 1), /*!< User is muted */
654  ADMINFLAG_SELFMUTED = (1 << 2), /*!< User muted self */
655  ADMINFLAG_KICKME = (1 << 3), /*!< User has been kicked */
656  /*! User has requested to speak */
658  ADMINFLAG_HANGUP = (1 << 5), /*!< User will be leaving the conference */
659 };
660 
661 #define MEETME_DELAYDETECTTALK 300
662 #define MEETME_DELAYDETECTENDTALK 1000
663 
664 #define AST_FRAME_BITS 32
665 
669 };
670 
674 };
675 
681 };
682 
683 #define CONF_SIZE 320
684 
685 enum {
686  /*! user has admin access on the conference */
687  CONFFLAG_ADMIN = (1 << 0),
688  /*! If set the user can only receive audio from the conference */
689  CONFFLAG_MONITOR = (1 << 1),
690  /*! If set asterisk will exit conference when key defined in p() option is pressed */
691  CONFFLAG_KEYEXIT = (1 << 2),
692  /*! If set asterisk will provide a menu to the user when '*' is pressed */
693  CONFFLAG_STARMENU = (1 << 3),
694  /*! If set the use can only send audio to the conference */
695  CONFFLAG_TALKER = (1 << 4),
696  /*! If set there will be no enter or leave sounds */
697  CONFFLAG_QUIET = (1 << 5),
698  /*! If set, when user joins the conference, they will be told the number
699  * of users that are already in */
701  /*! Set to run AGI Script in Background */
702  CONFFLAG_AGI = (1 << 7),
703  /*! Set to have music on hold when user is alone in conference */
704  CONFFLAG_MOH = (1 << 8),
705  /*! If set, the channel will leave the conference if all marked users leave */
707  /*! If set, the MeetMe will wait until a marked user enters */
708  CONFFLAG_WAITMARKED = (1 << 10),
709  /*! If set, the MeetMe will exit to the specified context */
711  /*! If set, the user will be marked */
712  CONFFLAG_MARKEDUSER = (1 << 12),
713  /*! If set, user will be ask record name on entry of conference */
714  CONFFLAG_INTROUSER = (1 << 13),
715  /*! If set, the MeetMe will be recorded */
717  /*! If set, the user will be monitored if the user is talking or not */
719  CONFFLAG_DYNAMIC = (1 << 16),
720  CONFFLAG_DYNAMICPIN = (1 << 17),
721  CONFFLAG_EMPTY = (1 << 18),
722  CONFFLAG_EMPTYNOPIN = (1 << 19),
724  /*! If set, treat talking users as muted users */
726  /*! If set, won't speak the extra prompt when the first person
727  * enters the conference */
729  /*! If set, user will be asked to record name on entry of conference
730  * without review */
732  /*! If set, the user will be initially self-muted */
733  CONFFLAG_STARTMUTED = (1 << 24),
734  /*! Pass DTMF through the conference */
735  CONFFLAG_PASS_DTMF = (1 << 25),
736  CONFFLAG_SLA_STATION = (1 << 26),
737  CONFFLAG_SLA_TRUNK = (1 << 27),
738  /*! If set, the user should continue in the dialplan if kicked out */
742 };
743 
744 /* These flags are defined separately because we ran out of bits that an enum can be used to represent.
745  If you add new flags, be sure to do it in the same way that these are. */
746 /*! Do not write any audio to this channel until the state is up. */
747 #define CONFFLAG_NO_AUDIO_UNTIL_UP (1ULL << 31)
748 #define CONFFLAG_INTROMSG (1ULL << 32) /*!< If set play an intro announcement at start of conference */
749 #define CONFFLAG_INTROUSER_VMREC (1ULL << 33)
750 /*! If there's only one person left in a conference when someone leaves, kill the conference */
751 #define CONFFLAG_KILL_LAST_MAN_STANDING (1ULL << 34)
752 /*! If set, don't enable a denoiser for the channel */
753 #define CONFFLAG_DONT_DENOISE (1ULL << 35)
754 
755 enum {
764 };
765 
801 
802 static const char * const app = "MeetMe";
803 static const char * const app2 = "MeetMeCount";
804 static const char * const app3 = "MeetMeAdmin";
805 static const char * const app4 = "MeetMeChannelAdmin";
806 static const char * const slastation_app = "SLAStation";
807 static const char * const slatrunk_app = "SLATrunk";
808 
809 /* Lookup RealTime conferences based on confno and current time */
810 static int rt_schedule;
811 static int fuzzystart;
812 static int earlyalert;
813 static int endalert;
814 static int extendby;
815 
816 /*! Log participant count to the RealTime backend */
817 static int rt_log_members;
818 
819 #define MAX_CONFNUM 80
820 #define MAX_PIN 80
821 #define OPTIONS_LEN 100
822 
823 /* Enough space for "<conference #>,<pin>,<admin pin>" followed by a 0 byte. */
824 #define MAX_SETTINGS (MAX_CONFNUM + MAX_PIN + MAX_PIN + 3)
825 
829 };
830 
833  char namerecloc[PATH_MAX]; /*!< Name Recorded file Location */
837  int vmrec;
839 };
840 
841 /*! \brief The MeetMe Conference object */
843  ast_mutex_t playlock; /*!< Conference specific lock (players) */
844  ast_mutex_t listenlock; /*!< Conference specific lock (listeners) */
845  char confno[MAX_CONFNUM]; /*!< Conference */
846  struct ast_channel *chan; /*!< Announcements channel */
847  struct ast_channel *lchan; /*!< Listen/Record channel */
848  int fd; /*!< Announcements fd */
849  int dahdiconf; /*!< DAHDI Conf # */
850  int users; /*!< Number of active users */
851  int markedusers; /*!< Number of marked users */
852  int maxusers; /*!< Participant limit if scheduled */
853  int endalert; /*!< When to play conf ending message */
854  time_t start; /*!< Start time (s) */
855  int refcount; /*!< reference count of usage */
856  enum recording_state recording:2; /*!< recording status */
857  unsigned int isdynamic:1; /*!< Created on the fly? */
858  unsigned int locked:1; /*!< Is the conference locked? */
859  unsigned int gmuted:1; /*!< Is the conference globally muted? (all non-admins) */
860  pthread_t recordthread; /*!< thread for recording */
861  ast_mutex_t recordthreadlock; /*!< control threads trying to start recordthread */
862  pthread_attr_t attr; /*!< thread attribute */
863  char *recordingfilename; /*!< Filename to record the Conference into */
864  char *recordingformat; /*!< Format to record the Conference in */
865  char pin[MAX_PIN]; /*!< If protected by a PIN */
866  char pinadmin[MAX_PIN]; /*!< If protected by a admin PIN */
867  char uniqueid[32];
868  long endtime; /*!< When to end the conf if scheduled */
869  const char *useropts; /*!< RealTime user flags */
870  const char *adminopts; /*!< RealTime moderator flags */
871  const char *bookid; /*!< RealTime conference id */
872  struct ast_frame *transframe[32];
874  struct ast_trans_pvt *transpath[32];
877  /* announce_thread related data */
878  pthread_t announcethread;
880  unsigned int announcethread_stop:1;
884 };
885 
887 
888 static unsigned int conf_map[1024] = {0, };
889 
890 struct volume {
891  int desired; /*!< Desired volume adjustment */
892  int actual; /*!< Actual volume adjustment (for channels that can't adjust) */
893 };
894 
895 /*! \brief The MeetMe User object */
897  int user_no; /*!< User Number */
898  struct ast_flags64 userflags; /*!< Flags as set in the conference */
899  int adminflags; /*!< Flags set by the Admin */
900  struct ast_channel *chan; /*!< Connected channel */
901  int talking; /*!< Is user talking */
902  int dahdichannel; /*!< Is a DAHDI channel */
903  char usrvalue[50]; /*!< Custom User Value */
904  char namerecloc[PATH_MAX]; /*!< Name Recorded file Location */
905  time_t jointime; /*!< Time the user joined the conference */
906  time_t kicktime; /*!< Time the user will be kicked from the conference */
907  struct timeval start_time; /*!< Time the user entered into the conference */
908  long timelimit; /*!< Time limit for the user to be in the conference L(x:y:z) */
909  long play_warning; /*!< Play a warning when 'y' ms are left */
910  long warning_freq; /*!< Repeat the warning every 'z' ms */
911  const char *warning_sound; /*!< File to play as warning if 'y' is defined */
912  const char *end_sound; /*!< File to play when time is up. */
913  struct volume talk;
914  struct volume listen;
916 };
917 
921 };
922 
929 };
930 
932  /*! This means that any station can put it on hold, and any station
933  * can retrieve the call from hold. */
935  /*! This means that only the station that put the call on hold may
936  * retrieve it from hold. */
938 };
939 
940 struct sla_trunk_ref;
941 
942 struct sla_station {
946  AST_STRING_FIELD(device);
947  AST_STRING_FIELD(autocontext);
948  );
950  struct ast_dial *dial;
951  /*! Ring timeout for this station, for any trunk. If a ring timeout
952  * is set for a specific trunk on this station, that will take
953  * priority over this value. */
954  unsigned int ring_timeout;
955  /*! Ring delay for this station, for any trunk. If a ring delay
956  * is set for a specific trunk on this station, that will take
957  * priority over this value. */
958  unsigned int ring_delay;
959  /*! This option uses the values in the sla_hold_access enum and sets the
960  * access control type for hold on this station. */
961  unsigned int hold_access:1;
962  /*! Mark used during reload processing */
963  unsigned int mark:1;
964 };
965 
966 /*!
967  * \brief A reference to a station
968  *
969  * This struct looks near useless at first glance. However, its existence
970  * in the list of stations in sla_trunk means that this station references
971  * that trunk. We use the mark to keep track of whether it needs to be
972  * removed from the sla_trunk's list of stations during a reload.
973  */
977  /*! Mark used during reload processing */
978  unsigned int mark:1;
979 };
980 
981 struct sla_trunk {
984  AST_STRING_FIELD(device);
985  AST_STRING_FIELD(autocontext);
986  );
988  /*! Number of stations that use this trunk */
989  unsigned int num_stations;
990  /*! Number of stations currently on a call with this trunk */
991  unsigned int active_stations;
992  /*! Number of stations that have this trunk on hold. */
993  unsigned int hold_stations;
994  struct ast_channel *chan;
995  unsigned int ring_timeout;
996  /*! If set to 1, no station will be able to join an active call with
997  * this trunk. */
998  unsigned int barge_disabled:1;
999  /*! This option uses the values in the sla_hold_access enum and sets the
1000  * access control type for hold on this trunk. */
1001  unsigned int hold_access:1;
1002  /*! Whether this trunk is currently on hold, meaning that once a station
1003  * connects to it, the trunk channel needs to have UNHOLD indicated to it. */
1004  unsigned int on_hold:1;
1005  /*! Mark used during reload processing */
1006  unsigned int mark:1;
1007 };
1008 
1009 /*!
1010  * \brief A station's reference to a trunk
1011  *
1012  * An sla_station keeps a list of trunk_refs. This holds metadata about the
1013  * stations usage of the trunk.
1014  */
1017  struct sla_trunk *trunk;
1020  /*! Ring timeout to use when this trunk is ringing on this specific
1021  * station. This takes higher priority than a ring timeout set at
1022  * the station level. */
1023  unsigned int ring_timeout;
1024  /*! Ring delay to use when this trunk is ringing on this specific
1025  * station. This takes higher priority than a ring delay set at
1026  * the station level. */
1027  unsigned int ring_delay;
1028  /*! Mark used during reload processing */
1029  unsigned int mark:1;
1030 };
1031 
1033 static struct ao2_container *sla_trunks;
1034 
1035 static const char sla_registrar[] = "SLA";
1036 
1037 /*! \brief Event types that can be queued up for the SLA thread */
1039  /*! A station has put the call on hold */
1041  /*! The state of a dial has changed */
1043  /*! The state of a ringing trunk has changed */
1045 };
1046 
1047 struct sla_event {
1052 };
1053 
1054 /*! \brief A station that failed to be dialed
1055  * \note Only used by the SLA thread. */
1058  struct timeval last_try;
1060 };
1061 
1062 /*! \brief A trunk that is ringing */
1064  struct sla_trunk *trunk;
1065  /*! The time that this trunk started ringing */
1066  struct timeval ring_begin;
1067  AST_LIST_HEAD_NOLOCK(, sla_station_ref) timed_out_stations;
1069 };
1070 
1074 };
1075 
1076 /*! \brief A station that is ringing */
1079  /*! The time that this station started ringing */
1080  struct timeval ring_begin;
1082 };
1083 
1084 /*!
1085  * \brief A structure for data used by the sla thread
1086  */
1087 static struct {
1088  /*! The SLA thread ID */
1089  pthread_t thread;
1096  unsigned int stop:1;
1097  /*! Attempt to handle CallerID, even though it is known not to work
1098  * properly in some situations. */
1099  unsigned int attempt_callerid:1;
1100 } sla = {
1101  .thread = AST_PTHREADT_NULL,
1102 };
1103 
1104 /*! \brief The number of audio buffers to be allocated on pseudo channels
1105  * when in a conference */
1106 static int audio_buffers;
1107 
1108 /*! \brief Map 'volume' levels from -5 through +5 into decibel (dB)
1109  * settings for channel drivers.
1110  *
1111  * \note these are not a straight linear-to-dB
1112  * conversion... the numbers have been modified
1113  * to give the user a better level of adjustability.
1114  */
1115 static const char gain_map[] = {
1116  -15,
1117  -13,
1118  -10,
1119  -6,
1120  0,
1121  0,
1122  0,
1123  6,
1124  10,
1125  13,
1126  15,
1127 };
1128 
1129 /* Routes the various meetme message types to the meetme stasis callback function to turn them into events */
1131 
1132 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_join_type);
1133 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_leave_type);
1134 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_end_type);
1135 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_mute_type);
1136 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_talking_type);
1137 STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_talk_request_type);
1138 
1139 static void meetme_stasis_cb(void *data, struct stasis_subscription *sub,
1140  struct stasis_message *message);
1141 
1142 static void meetme_stasis_cleanup(void)
1143 {
1144  if (meetme_event_message_router) {
1145  stasis_message_router_unsubscribe(meetme_event_message_router);
1146  meetme_event_message_router = NULL;
1147  }
1148 
1149  STASIS_MESSAGE_TYPE_CLEANUP(meetme_join_type);
1150  STASIS_MESSAGE_TYPE_CLEANUP(meetme_leave_type);
1151  STASIS_MESSAGE_TYPE_CLEANUP(meetme_end_type);
1152  STASIS_MESSAGE_TYPE_CLEANUP(meetme_mute_type);
1153  STASIS_MESSAGE_TYPE_CLEANUP(meetme_talking_type);
1154  STASIS_MESSAGE_TYPE_CLEANUP(meetme_talk_request_type);
1155 }
1156 
1157 static int meetme_stasis_init(void)
1158 {
1159 
1160  STASIS_MESSAGE_TYPE_INIT(meetme_join_type);
1161  STASIS_MESSAGE_TYPE_INIT(meetme_leave_type);
1162  STASIS_MESSAGE_TYPE_INIT(meetme_end_type);
1163  STASIS_MESSAGE_TYPE_INIT(meetme_mute_type);
1164  STASIS_MESSAGE_TYPE_INIT(meetme_talking_type);
1165  STASIS_MESSAGE_TYPE_INIT(meetme_talk_request_type);
1166 
1167  meetme_event_message_router = stasis_message_router_create(
1169 
1170  if (!meetme_event_message_router) {
1172  return -1;
1173  }
1174 
1175  if (stasis_message_router_add(meetme_event_message_router,
1176  meetme_join_type(),
1178  NULL)) {
1180  return -1;
1181  }
1182 
1183  if (stasis_message_router_add(meetme_event_message_router,
1184  meetme_leave_type(),
1186  NULL)) {
1188  return -1;
1189  }
1190 
1191  if (stasis_message_router_add(meetme_event_message_router,
1192  meetme_end_type(),
1194  NULL)) {
1196  return -1;
1197  }
1198 
1199  if (stasis_message_router_add(meetme_event_message_router,
1200  meetme_mute_type(),
1202  NULL)) {
1204  return -1;
1205  }
1206 
1207  if (stasis_message_router_add(meetme_event_message_router,
1208  meetme_talking_type(),
1210  NULL)) {
1212  return -1;
1213  }
1214 
1215  if (stasis_message_router_add(meetme_event_message_router,
1216  meetme_talk_request_type(),
1218  NULL)) {
1220  return -1;
1221  }
1222 
1223  return 0;
1224 }
1225 
1226 static void meetme_stasis_cb(void *data, struct stasis_subscription *sub,
1227  struct stasis_message *message)
1228 {
1229  struct ast_channel_blob *channel_blob = stasis_message_data(message);
1230  struct stasis_message_type *message_type;
1231  const char *event;
1232  const char *conference_num;
1233  const char *status;
1234  struct ast_json *json_cur;
1235  RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
1236  RAII_VAR(struct ast_str *, extra_text, NULL, ast_free);
1237 
1238  if (!channel_blob) {
1239  ast_assert(0);
1240  return;
1241  }
1242 
1243  message_type = stasis_message_type(message);
1244 
1245  if (!message_type) {
1246  ast_assert(0);
1247  return;
1248  }
1249 
1250  if (message_type == meetme_join_type()) {
1251  event = "MeetmeJoin";
1252  } else if (message_type == meetme_leave_type()) {
1253  event = "MeetmeLeave";
1254  } else if (message_type == meetme_end_type()) {
1255  event = "MeetmeEnd";
1256  } else if (message_type == meetme_mute_type()) {
1257  event = "MeetmeMute";
1258  } else if (message_type == meetme_talking_type()) {
1259  event = "MeetmeTalking";
1260  } else if (message_type == meetme_talk_request_type()) {
1261  event = "MeetmeTalkRequest";
1262  } else {
1263  ast_assert(0);
1264  return;
1265  }
1266 
1267  if (!event) {
1268  ast_assert(0);
1269  return;
1270  }
1271 
1272  conference_num = ast_json_string_get(ast_json_object_get(channel_blob->blob, "Meetme"));
1273  if (!conference_num) {
1274  ast_assert(0);
1275  return;
1276  }
1277 
1278  status = ast_json_string_get(ast_json_object_get(channel_blob->blob, "status"));
1279  if (status) {
1280  ast_str_append_event_header(&extra_text, "Status", status);
1281  }
1282 
1283  if (channel_blob->snapshot) {
1284  channel_text = ast_manager_build_channel_state_string(channel_blob->snapshot);
1285  }
1286 
1287  if ((json_cur = ast_json_object_get(channel_blob->blob, "user"))) {
1288  int user_number = ast_json_integer_get(json_cur);
1289  RAII_VAR(struct ast_str *, user_prop_str, ast_str_create(32), ast_free);
1290  if (!user_prop_str) {
1291  return;
1292  }
1293 
1294  ast_str_set(&user_prop_str, 0, "%d", user_number);
1295  ast_str_append_event_header(&extra_text, "User", ast_str_buffer(user_prop_str));
1296 
1297  if ((json_cur = ast_json_object_get(channel_blob->blob, "duration"))) {
1298  int duration = ast_json_integer_get(json_cur);
1299  ast_str_set(&user_prop_str, 0, "%d", duration);
1300  ast_str_append_event_header(&extra_text, "Duration", ast_str_buffer(user_prop_str));
1301  }
1302 
1303  json_cur = NULL;
1304  }
1305 
1307  "Meetme: %s\r\n"
1308  "%s"
1309  "%s",
1310  conference_num,
1311  channel_text ? ast_str_buffer(channel_text) : "",
1312  extra_text ? ast_str_buffer(extra_text) : "");
1313 }
1314 
1315 /*!
1316  * \internal
1317  * \brief Build a json object from a status value for inclusion in json extras for meetme_stasis_generate_msg
1318  * \since 12.0.0
1319  *
1320  * \param on if true, then status is on. Otherwise status is off
1321  * \retval NULL on failure to allocate the JSON blob.
1322  * \retval pointer to the JSON blob if successful.
1323  */
1324 static struct ast_json *status_to_json(int on)
1325 {
1326  struct ast_json *json_object = ast_json_pack("{s: s}",
1327  "status", on ? "on" : "off");
1328 
1329  return json_object;
1330 }
1331 
1332 /*!
1333  * \internal
1334  * \brief Generate a stasis message associated with a meetme event
1335  * \since 12.0.0
1336  *
1337  * \param meetme_confere The conference responsible for generating this message
1338  * \param chan The channel involved in the message (NULL allowed)
1339  * \param user The conference user involved in the message (NULL allowed)
1340  * \param message_type the type the stasis message being generated
1341  * \param extras Additional json fields desired for inclusion
1342  */
1343 static void meetme_stasis_generate_msg(struct ast_conference *meetme_conference, struct ast_channel *chan,
1344  struct ast_conf_user *user, struct stasis_message_type *message_type, struct ast_json *extras)
1345 {
1346  RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
1347  RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1348 
1349  json_object = ast_json_pack("{s: s}",
1350  "Meetme", meetme_conference->confno);
1351 
1352  if (!json_object) {
1353  return;
1354  }
1355 
1356  if (extras) {
1357  ast_json_object_update(json_object, extras);
1358  }
1359 
1360  if (user) {
1361  struct timeval now = ast_tvnow();
1362  long duration = (long)(now.tv_sec - user->jointime);
1363  struct ast_json *json_user;
1364  struct ast_json *json_user_duration;
1365 
1366  json_user = ast_json_integer_create(user->user_no);
1367  if (!json_user || ast_json_object_set(json_object, "user", json_user)) {
1368  return;
1369  }
1370 
1371  if (duration > 0) {
1372  json_user_duration = ast_json_integer_create(duration);
1373  if (!json_user_duration
1374  || ast_json_object_set(json_object, "duration", json_user_duration)) {
1375  return;
1376  }
1377  }
1378  }
1379 
1380  if (chan) {
1381  ast_channel_lock(chan);
1382  }
1383  msg = ast_channel_blob_create(chan, message_type, json_object);
1384  if (chan) {
1385  ast_channel_unlock(chan);
1386  }
1387 
1388  if (!msg) {
1389  return;
1390  }
1391 
1392  stasis_publish(ast_channel_topic(chan), msg);
1393 }
1394 
1395 static int admin_exec(struct ast_channel *chan, const char *data);
1396 static void *recordthread(void *args);
1397 
1398 static const char *istalking(int x)
1399 {
1400  if (x > 0)
1401  return "(talking)";
1402  else if (x < 0)
1403  return "(unmonitored)";
1404  else
1405  return "(not talking)";
1406 }
1407 
1408 static int careful_write(int fd, unsigned char *data, int len, int block)
1409 {
1410  int res;
1411  int x;
1412 
1413  while (len) {
1414  if (block) {
1415  x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
1416  res = ioctl(fd, DAHDI_IOMUX, &x);
1417  } else
1418  res = 0;
1419  if (res >= 0)
1420  res = write(fd, data, len);
1421  if (res < 1) {
1422  if (errno != EAGAIN) {
1423  ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
1424  return -1;
1425  } else
1426  return 0;
1427  }
1428  len -= res;
1429  data += res;
1430  }
1431 
1432  return 0;
1433 }
1434 
1435 static int set_talk_volume(struct ast_conf_user *user, int volume)
1436 {
1437  char gain_adjust;
1438 
1439  /* attempt to make the adjustment in the channel driver;
1440  if successful, don't adjust in the frame reading routine
1441  */
1442  gain_adjust = gain_map[volume + 5];
1443 
1444  return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
1445 }
1446 
1447 static int set_listen_volume(struct ast_conf_user *user, int volume)
1448 {
1449  char gain_adjust;
1450 
1451  /* attempt to make the adjustment in the channel driver;
1452  if successful, don't adjust in the frame reading routine
1453  */
1454  gain_adjust = gain_map[volume + 5];
1455 
1456  return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
1457 }
1458 
1459 static void tweak_volume(struct volume *vol, enum volume_action action)
1460 {
1461  switch (action) {
1462  case VOL_UP:
1463  switch (vol->desired) {
1464  case 5:
1465  break;
1466  case 0:
1467  vol->desired = 2;
1468  break;
1469  case -2:
1470  vol->desired = 0;
1471  break;
1472  default:
1473  vol->desired++;
1474  break;
1475  }
1476  break;
1477  case VOL_DOWN:
1478  switch (vol->desired) {
1479  case -5:
1480  break;
1481  case 2:
1482  vol->desired = 0;
1483  break;
1484  case 0:
1485  vol->desired = -2;
1486  break;
1487  default:
1488  vol->desired--;
1489  break;
1490  }
1491  }
1492 }
1493 
1494 static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
1495 {
1496  tweak_volume(&user->talk, action);
1497  /* attempt to make the adjustment in the channel driver;
1498  if successful, don't adjust in the frame reading routine
1499  */
1500  if (!set_talk_volume(user, user->talk.desired))
1501  user->talk.actual = 0;
1502  else
1503  user->talk.actual = user->talk.desired;
1504 }
1505 
1506 static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
1507 {
1508  tweak_volume(&user->listen, action);
1509  /* attempt to make the adjustment in the channel driver;
1510  if successful, don't adjust in the frame reading routine
1511  */
1512  if (!set_listen_volume(user, user->listen.desired))
1513  user->listen.actual = 0;
1514  else
1515  user->listen.actual = user->listen.desired;
1516 }
1517 
1518 static void reset_volumes(struct ast_conf_user *user)
1519 {
1520  signed char zero_volume = 0;
1521 
1522  ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
1523  ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
1524 }
1525 
1526 static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
1527 {
1528  unsigned char *data;
1529  int len;
1530  int res = -1;
1531 
1532  ast_test_suite_event_notify("CONFPLAY", "Channel: %s\r\n"
1533  "Conference: %s\r\n"
1534  "Marked: %d",
1535  ast_channel_name(chan),
1536  conf->confno,
1537  conf->markedusers);
1538 
1539  if (!ast_check_hangup(chan))
1540  res = ast_autoservice_start(chan);
1541 
1542  AST_LIST_LOCK(&confs);
1543 
1544  switch(sound) {
1545  case ENTER:
1546  data = enter;
1547  len = sizeof(enter);
1548  break;
1549  case LEAVE:
1550  data = leave;
1551  len = sizeof(leave);
1552  break;
1553  default:
1554  data = NULL;
1555  len = 0;
1556  }
1557  if (data) {
1558  careful_write(conf->fd, data, len, 1);
1559  }
1560 
1562 
1563  if (!res)
1564  ast_autoservice_stop(chan);
1565 }
1566 
1567 static int user_no_cmp(void *obj, void *arg, int flags)
1568 {
1569  struct ast_conf_user *user = obj;
1570  int *user_no = arg;
1571 
1572  if (user->user_no == *user_no) {
1573  return (CMP_MATCH | CMP_STOP);
1574  }
1575 
1576  return 0;
1577 }
1578 
1579 static int user_max_cmp(void *obj, void *arg, int flags)
1580 {
1581  struct ast_conf_user *user = obj;
1582  int *max_no = arg;
1583 
1584  if (user->user_no > *max_no) {
1585  *max_no = user->user_no;
1586  }
1587 
1588  return 0;
1589 }
1590 
1591 /*!
1592  * \brief Find or create a conference
1593  *
1594  * \param confno The conference name/number
1595  * \param pin The regular user pin
1596  * \param pinadmin The admin pin
1597  * \param make Make the conf if it doesn't exist
1598  * \param dynamic Mark the newly created conference as dynamic
1599  * \param refcount How many references to mark on the conference
1600  * \param chan The asterisk channel
1601  * \param test
1602  *
1603  * \return A pointer to the conference struct, or NULL if it wasn't found and
1604  * make or dynamic were not set.
1605  */
1606 static struct ast_conference *build_conf(const char *confno, const char *pin,
1607  const char *pinadmin, int make, int dynamic, int refcount,
1608  const struct ast_channel *chan, struct ast_test *test)
1609 {
1610  struct ast_conference *cnf;
1611  struct dahdi_confinfo dahdic = { 0, };
1612  int confno_int = 0;
1614 
1615  AST_LIST_LOCK(&confs);
1616 
1617  AST_LIST_TRAVERSE(&confs, cnf, list) {
1618  if (!strcmp(confno, cnf->confno))
1619  break;
1620  }
1621 
1622  if (cnf || (!make && !dynamic) || !cap_slin)
1623  goto cnfout;
1624 
1625  ast_format_cap_append(cap_slin, ast_format_slin, 0);
1626  /* Make a new one */
1627  cnf = ast_calloc(1, sizeof(*cnf));
1628  if (!cnf) {
1629  goto cnfout;
1630  }
1631 
1633  NULL, user_no_cmp);
1634  if (!cnf->usercontainer) {
1635  goto cnfout;
1636  }
1637 
1638  ast_mutex_init(&cnf->playlock);
1639  ast_mutex_init(&cnf->listenlock);
1644  ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
1645  ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
1646  ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
1647  ast_copy_string(cnf->uniqueid, ast_channel_uniqueid(chan), sizeof(cnf->uniqueid));
1648 
1649  /* Setup a new dahdi conference */
1650  dahdic.confno = -1;
1651  dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1652  cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
1653  if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
1654  if (test) {
1655  /* if we are creating a conference for a unit test, it is not neccesary
1656  * to open a pseudo channel, so, if we fail continue creating
1657  * the conference. */
1658  ast_test_status_update(test, "Unable to open DAHDI pseudo device\n");
1659  } else {
1660  ast_log(LOG_WARNING, "Unable to open DAHDI pseudo device\n");
1661  if (cnf->fd >= 0)
1662  close(cnf->fd);
1663  ao2_ref(cnf->usercontainer, -1);
1664  ast_mutex_destroy(&cnf->playlock);
1668  ast_free(cnf);
1669  cnf = NULL;
1670  goto cnfout;
1671  }
1672  }
1673 
1674  cnf->dahdiconf = dahdic.confno;
1675 
1676  /* Setup a new channel for playback of audio files */
1677  cnf->chan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL);
1678  if (cnf->chan) {
1681  dahdic.chan = 0;
1682  dahdic.confno = cnf->dahdiconf;
1683  dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
1684  if (ioctl(ast_channel_fd(cnf->chan, 0), DAHDI_SETCONF, &dahdic)) {
1685  if (test) {
1686  ast_test_status_update(test, "Error setting conference on pseudo channel\n");
1687  }
1688  ast_log(LOG_WARNING, "Error setting conference\n");
1689  if (cnf->chan)
1690  ast_hangup(cnf->chan);
1691  else
1692  close(cnf->fd);
1693  ao2_ref(cnf->usercontainer, -1);
1694  ast_mutex_destroy(&cnf->playlock);
1698  ast_free(cnf);
1699  cnf = NULL;
1700  goto cnfout;
1701  }
1702  }
1703 
1704  /* Fill the conference struct */
1705  cnf->start = time(NULL);
1706  cnf->maxusers = 0x7fffffff;
1707  cnf->isdynamic = dynamic ? 1 : 0;
1708  ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
1709  AST_LIST_INSERT_HEAD(&confs, cnf, list);
1710 
1711  /* Reserve conference number in map */
1712  if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
1713  conf_map[confno_int] = 1;
1714 
1715 cnfout:
1716  ao2_cleanup(cap_slin);
1717  if (cnf)
1718  ast_atomic_fetchadd_int(&cnf->refcount, refcount);
1719 
1721 
1722  return cnf;
1723 }
1724 
1725 static char *complete_confno(const char *word, int state)
1726 {
1727  struct ast_conference *cnf;
1728  char *ret = NULL;
1729  int which = 0;
1730  int len = strlen(word);
1731 
1732  AST_LIST_LOCK(&confs);
1733  AST_LIST_TRAVERSE(&confs, cnf, list) {
1734  if (!strncmp(word, cnf->confno, len) && ++which > state) {
1735  /* dup before releasing the lock */
1736  ret = ast_strdup(cnf->confno);
1737  break;
1738  }
1739  }
1741  return ret;
1742 }
1743 
1744 static char *complete_userno(struct ast_conference *cnf, const char *word, int state)
1745 {
1746  char usrno[50];
1747  struct ao2_iterator iter;
1748  struct ast_conf_user *usr;
1749  char *ret = NULL;
1750  int which = 0;
1751  int len = strlen(word);
1752 
1753  iter = ao2_iterator_init(cnf->usercontainer, 0);
1754  for (; (usr = ao2_iterator_next(&iter)); ao2_ref(usr, -1)) {
1755  snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
1756  if (!strncmp(word, usrno, len) && ++which > state) {
1757  ao2_ref(usr, -1);
1758  ret = ast_strdup(usrno);
1759  break;
1760  }
1761  }
1762  ao2_iterator_destroy(&iter);
1763  return ret;
1764 }
1765 
1766 static char *complete_meetmecmd_mute_kick(const char *line, const char *word, int pos, int state)
1767 {
1768  if (pos == 2) {
1769  return complete_confno(word, state);
1770  }
1771  if (pos == 3) {
1772  int len = strlen(word);
1773  char *ret = NULL;
1774  char *saved = NULL;
1775  char *myline;
1776  char *confno;
1777  struct ast_conference *cnf;
1778 
1779  if (!strncasecmp(word, "all", len)) {
1780  if (state == 0) {
1781  return ast_strdup("all");
1782  }
1783  --state;
1784  }
1785 
1786  /* Extract the confno from the command line. */
1787  myline = ast_strdupa(line);
1788  strtok_r(myline, " ", &saved);
1789  strtok_r(NULL, " ", &saved);
1790  confno = strtok_r(NULL, " ", &saved);
1791 
1792  AST_LIST_LOCK(&confs);
1793  AST_LIST_TRAVERSE(&confs, cnf, list) {
1794  if (!strcmp(confno, cnf->confno)) {
1795  ret = complete_userno(cnf, word, state);
1796  break;
1797  }
1798  }
1800 
1801  return ret;
1802  }
1803  return NULL;
1804 }
1805 
1806 static char *complete_meetmecmd_lock(const char *word, int pos, int state)
1807 {
1808  if (pos == 2) {
1809  return complete_confno(word, state);
1810  }
1811  return NULL;
1812 }
1813 
1814 static char *complete_meetmecmd_list(const char *line, const char *word, int pos, int state)
1815 {
1816  int len;
1817 
1818  if (pos == 2) {
1819  len = strlen(word);
1820  if (!strncasecmp(word, STR_CONCISE, len)) {
1821  if (state == 0) {
1822  return ast_strdup(STR_CONCISE);
1823  }
1824  --state;
1825  }
1826 
1827  return complete_confno(word, state);
1828  }
1829  if (pos == 3 && state == 0) {
1830  char *saved = NULL;
1831  char *myline;
1832  char *confno;
1833 
1834  /* Extract the confno from the command line. */
1835  myline = ast_strdupa(line);
1836  strtok_r(myline, " ", &saved);
1837  strtok_r(NULL, " ", &saved);
1838  confno = strtok_r(NULL, " ", &saved);
1839 
1840  if (!strcasecmp(confno, STR_CONCISE)) {
1841  /* There is nothing valid in this position now. */
1842  return NULL;
1843  }
1844 
1845  len = strlen(word);
1846  if (!strncasecmp(word, STR_CONCISE, len)) {
1847  return ast_strdup(STR_CONCISE);
1848  }
1849  }
1850  return NULL;
1851 }
1852 
1853 static char *meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1854 {
1855  /* Process the command */
1856  struct ast_conf_user *user;
1857  struct ast_conference *cnf;
1858  int hr, min, sec;
1859  int total = 0;
1860  time_t now;
1861 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s %-8s %-6s\n"
1862 #define MC_DATA_FORMAT "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"
1863 
1864  switch (cmd) {
1865  case CLI_INIT:
1866  e->command = "meetme list";
1867  e->usage =
1868  "Usage: meetme list [<confno>] [" STR_CONCISE "]\n"
1869  " List all conferences or a specific conference.\n";
1870  return NULL;
1871  case CLI_GENERATE:
1872  return complete_meetmecmd_list(a->line, a->word, a->pos, a->n);
1873  }
1874 
1875  if (a->argc == 2 || (a->argc == 3 && !strcasecmp(a->argv[2], STR_CONCISE))) {
1876  /* List all the conferences */
1877  int concise = (a->argc == 3);
1878  struct ast_str *marked_users;
1879 
1880  if (!(marked_users = ast_str_create(30))) {
1881  return CLI_FAILURE;
1882  }
1883 
1884  now = time(NULL);
1885  AST_LIST_LOCK(&confs);
1886  if (AST_LIST_EMPTY(&confs)) {
1887  if (!concise) {
1888  ast_cli(a->fd, "No active MeetMe conferences.\n");
1889  }
1891  ast_free(marked_users);
1892  return CLI_SUCCESS;
1893  }
1894  if (!concise) {
1895  ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
1896  }
1897  AST_LIST_TRAVERSE(&confs, cnf, list) {
1898  hr = (now - cnf->start) / 3600;
1899  min = ((now - cnf->start) % 3600) / 60;
1900  sec = (now - cnf->start) % 60;
1901  if (!concise) {
1902  if (cnf->markedusers == 0) {
1903  ast_str_set(&marked_users, 0, "N/A ");
1904  } else {
1905  ast_str_set(&marked_users, 0, "%4.4d", cnf->markedusers);
1906  }
1907  ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users,
1908  ast_str_buffer(marked_users), hr, min, sec,
1909  cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
1910  } else {
1911  ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
1912  cnf->confno,
1913  cnf->users,
1914  cnf->markedusers,
1915  hr, min, sec,
1916  cnf->isdynamic,
1917  cnf->locked);
1918  }
1919 
1920  total += cnf->users;
1921  }
1923  if (!concise) {
1924  ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
1925  }
1926  ast_free(marked_users);
1927  return CLI_SUCCESS;
1928  }
1929  if (a->argc == 3 || (a->argc == 4 && !strcasecmp(a->argv[3], STR_CONCISE))) {
1930  struct ao2_iterator user_iter;
1931  int concise = (a->argc == 4);
1932 
1933  /* List all the users in a conference */
1934  if (AST_LIST_EMPTY(&confs)) {
1935  if (!concise) {
1936  ast_cli(a->fd, "No active MeetMe conferences.\n");
1937  }
1938  return CLI_SUCCESS;
1939  }
1940  /* Find the right conference */
1941  AST_LIST_LOCK(&confs);
1942  AST_LIST_TRAVERSE(&confs, cnf, list) {
1943  if (strcmp(cnf->confno, a->argv[2]) == 0) {
1944  break;
1945  }
1946  }
1947  if (!cnf) {
1948  if (!concise)
1949  ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
1951  return CLI_SUCCESS;
1952  }
1953  /* Show all the users */
1954  time(&now);
1955  user_iter = ao2_iterator_init(cnf->usercontainer, 0);
1956  while((user = ao2_iterator_next(&user_iter))) {
1957  hr = (now - user->jointime) / 3600;
1958  min = ((now - user->jointime) % 3600) / 60;
1959  sec = (now - user->jointime) % 60;
1960  if (!concise) {
1961  ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
1962  user->user_no,
1963  S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
1964  S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
1965  ast_channel_name(user->chan),
1966  ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "(Admin)" : "",
1967  ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "(Listen only)" : "",
1968  user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
1969  user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
1970  istalking(user->talking), hr, min, sec);
1971  } else {
1972  ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
1973  user->user_no,
1976  ast_channel_name(user->chan),
1977  ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "1" : "",
1978  ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "1" : "",
1979  user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
1980  user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
1981  user->talking, hr, min, sec);
1982  }
1983  ao2_ref(user, -1);
1984  }
1985  ao2_iterator_destroy(&user_iter);
1986  if (!concise) {
1987  ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
1988  }
1990  return CLI_SUCCESS;
1991  }
1992  return CLI_SHOWUSAGE;
1993 }
1994 
1995 
1996 static char *meetme_cmd_helper(struct ast_cli_args *a)
1997 {
1998  /* Process the command */
1999  struct ast_str *cmdline;
2000 
2001  /* Max confno length */
2002  if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
2003  return CLI_FAILURE;
2004  }
2005 
2006  ast_str_set(&cmdline, 0, "%s", a->argv[2]); /* Argv 2: conference number */
2007  if (strcasestr(a->argv[1], "lock")) {
2008  if (strcasecmp(a->argv[1], "lock") == 0) {
2009  /* Lock */
2010  ast_str_append(&cmdline, 0, ",L");
2011  } else {
2012  /* Unlock */
2013  ast_str_append(&cmdline, 0, ",l");
2014  }
2015  } else if (strcasestr(a->argv[1], "mute")) {
2016  if (strcasecmp(a->argv[1], "mute") == 0) {
2017  /* Mute */
2018  if (strcasecmp(a->argv[3], "all") == 0) {
2019  ast_str_append(&cmdline, 0, ",N");
2020  } else {
2021  ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);
2022  }
2023  } else {
2024  /* Unmute */
2025  if (strcasecmp(a->argv[3], "all") == 0) {
2026  ast_str_append(&cmdline, 0, ",n");
2027  } else {
2028  ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
2029  }
2030  }
2031  } else if (strcasecmp(a->argv[1], "kick") == 0) {
2032  if (strcasecmp(a->argv[3], "all") == 0) {
2033  /* Kick all */
2034  ast_str_append(&cmdline, 0, ",K");
2035  } else {
2036  /* Kick a single user */
2037  ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
2038  }
2039  } else {
2040  /*
2041  * Should never get here because it is already filtered by the
2042  * callers.
2043  */
2044  ast_free(cmdline);
2045  return CLI_SHOWUSAGE;
2046  }
2047 
2048  ast_debug(1, "Cmdline: %s\n", ast_str_buffer(cmdline));
2049 
2050  admin_exec(NULL, ast_str_buffer(cmdline));
2051  ast_free(cmdline);
2052 
2053  return CLI_SUCCESS;
2054 }
2055 
2056 static char *meetme_lock_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2057 {
2058  switch (cmd) {
2059  case CLI_INIT:
2060  e->command = "meetme {lock|unlock}";
2061  e->usage =
2062  "Usage: meetme lock|unlock <confno>\n"
2063  " Lock or unlock a conference to new users.\n";
2064  return NULL;
2065  case CLI_GENERATE:
2066  return complete_meetmecmd_lock(a->word, a->pos, a->n);
2067  }
2068 
2069  if (a->argc != 3) {
2070  return CLI_SHOWUSAGE;
2071  }
2072 
2073  return meetme_cmd_helper(a);
2074 }
2075 
2076 static char *meetme_kick_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2077 {
2078  switch (cmd) {
2079  case CLI_INIT:
2080  e->command = "meetme kick";
2081  e->usage =
2082  "Usage: meetme kick <confno> all|<userno>\n"
2083  " Kick a conference or a user in a conference.\n";
2084  return NULL;
2085  case CLI_GENERATE:
2086  return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
2087  }
2088 
2089  if (a->argc != 4) {
2090  return CLI_SHOWUSAGE;
2091  }
2092 
2093  return meetme_cmd_helper(a);
2094 }
2095 
2096 static char *meetme_mute_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2097 {
2098  switch (cmd) {
2099  case CLI_INIT:
2100  e->command = "meetme {mute|unmute}";
2101  e->usage =
2102  "Usage: meetme mute|unmute <confno> all|<userno>\n"
2103  " Mute or unmute a conference or a user in a conference.\n";
2104  return NULL;
2105  case CLI_GENERATE:
2106  return complete_meetmecmd_mute_kick(a->line, a->word, a->pos, a->n);
2107  }
2108 
2109  if (a->argc != 4) {
2110  return CLI_SHOWUSAGE;
2111  }
2112 
2113  return meetme_cmd_helper(a);
2114 }
2115 
2116 static const char *sla_hold_str(unsigned int hold_access)
2117 {
2118  const char *hold = "Unknown";
2119 
2120  switch (hold_access) {
2121  case SLA_HOLD_OPEN:
2122  hold = "Open";
2123  break;
2124  case SLA_HOLD_PRIVATE:
2125  hold = "Private";
2126  default:
2127  break;
2128  }
2129 
2130  return hold;
2131 }
2132 
2133 static char *sla_show_trunks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2134 {
2135  struct ao2_iterator i;
2136  struct sla_trunk *trunk;
2137 
2138  switch (cmd) {
2139  case CLI_INIT:
2140  e->command = "sla show trunks";
2141  e->usage =
2142  "Usage: sla show trunks\n"
2143  " This will list all trunks defined in sla.conf\n";
2144  return NULL;
2145  case CLI_GENERATE:
2146  return NULL;
2147  }
2148 
2149  ast_cli(a->fd, "\n"
2150  "=============================================================\n"
2151  "=== Configured SLA Trunks ===================================\n"
2152  "=============================================================\n"
2153  "===\n");
2154  i = ao2_iterator_init(sla_trunks, 0);
2155  for (; (trunk = ao2_iterator_next(&i)); ao2_ref(trunk, -1)) {
2156  struct sla_station_ref *station_ref;
2157  char ring_timeout[16] = "(none)";
2158 
2159  ao2_lock(trunk);
2160 
2161  if (trunk->ring_timeout) {
2162  snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
2163  }
2164 
2165  ast_cli(a->fd, "=== ---------------------------------------------------------\n"
2166  "=== Trunk Name: %s\n"
2167  "=== ==> Device: %s\n"
2168  "=== ==> AutoContext: %s\n"
2169  "=== ==> RingTimeout: %s\n"
2170  "=== ==> BargeAllowed: %s\n"
2171  "=== ==> HoldAccess: %s\n"
2172  "=== ==> Stations ...\n",
2173  trunk->name, trunk->device,
2174  S_OR(trunk->autocontext, "(none)"),
2175  ring_timeout,
2176  trunk->barge_disabled ? "No" : "Yes",
2177  sla_hold_str(trunk->hold_access));
2178 
2179  AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
2180  ast_cli(a->fd, "=== ==> Station name: %s\n", station_ref->station->name);
2181  }
2182 
2183  ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
2184 
2185  ao2_unlock(trunk);
2186  }
2188  ast_cli(a->fd, "=============================================================\n\n");
2189 
2190  return CLI_SUCCESS;
2191 }
2192 
2193 static const char *trunkstate2str(enum sla_trunk_state state)
2194 {
2195 #define S(e) case e: return # e;
2196  switch (state) {
2202  }
2203  return "Uknown State";
2204 #undef S
2205 }
2206 
2207 static char *sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2208 {
2209  struct ao2_iterator i;
2210  struct sla_station *station;
2211 
2212  switch (cmd) {
2213  case CLI_INIT:
2214  e->command = "sla show stations";
2215  e->usage =
2216  "Usage: sla show stations\n"
2217  " This will list all stations defined in sla.conf\n";
2218  return NULL;
2219  case CLI_GENERATE:
2220  return NULL;
2221  }
2222 
2223  ast_cli(a->fd, "\n"
2224  "=============================================================\n"
2225  "=== Configured SLA Stations =================================\n"
2226  "=============================================================\n"
2227  "===\n");
2228  i = ao2_iterator_init(sla_stations, 0);
2229  for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
2230  struct sla_trunk_ref *trunk_ref;
2231  char ring_timeout[16] = "(none)";
2232  char ring_delay[16] = "(none)";
2233 
2234  ao2_lock(station);
2235 
2236  if (station->ring_timeout) {
2237  snprintf(ring_timeout, sizeof(ring_timeout),
2238  "%u", station->ring_timeout);
2239  }
2240  if (station->ring_delay) {
2241  snprintf(ring_delay, sizeof(ring_delay),
2242  "%u", station->ring_delay);
2243  }
2244  ast_cli(a->fd, "=== ---------------------------------------------------------\n"
2245  "=== Station Name: %s\n"
2246  "=== ==> Device: %s\n"
2247  "=== ==> AutoContext: %s\n"
2248  "=== ==> RingTimeout: %s\n"
2249  "=== ==> RingDelay: %s\n"
2250  "=== ==> HoldAccess: %s\n"
2251  "=== ==> Trunks ...\n",
2252  station->name, station->device,
2253  S_OR(station->autocontext, "(none)"),
2254  ring_timeout, ring_delay,
2255  sla_hold_str(station->hold_access));
2256  AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
2257  if (trunk_ref->ring_timeout) {
2258  snprintf(ring_timeout, sizeof(ring_timeout),
2259  "%u", trunk_ref->ring_timeout);
2260  } else {
2261  strcpy(ring_timeout, "(none)");
2262  }
2263  if (trunk_ref->ring_delay) {
2264  snprintf(ring_delay, sizeof(ring_delay),
2265  "%u", trunk_ref->ring_delay);
2266  } else {
2267  strcpy(ring_delay, "(none)");
2268  }
2269 
2270  ast_cli(a->fd, "=== ==> Trunk Name: %s\n"
2271  "=== ==> State: %s\n"
2272  "=== ==> RingTimeout: %s\n"
2273  "=== ==> RingDelay: %s\n",
2274  trunk_ref->trunk->name,
2275  trunkstate2str(trunk_ref->state),
2276  ring_timeout, ring_delay);
2277  }
2278  ast_cli(a->fd, "=== ---------------------------------------------------------\n"
2279  "===\n");
2280 
2281  ao2_unlock(station);
2282  }
2284  ast_cli(a->fd, "============================================================\n"
2285  "\n");
2286 
2287  return CLI_SUCCESS;
2288 }
2289 
2290 static struct ast_cli_entry cli_meetme[] = {
2291  AST_CLI_DEFINE(meetme_kick_cmd, "Kick a conference or a user in a conference."),
2292  AST_CLI_DEFINE(meetme_show_cmd, "List all conferences or a specific conference."),
2293  AST_CLI_DEFINE(meetme_lock_cmd, "Lock or unlock a conference to new users."),
2294  AST_CLI_DEFINE(meetme_mute_cmd, "Mute or unmute a conference or a user in a conference."),
2295  AST_CLI_DEFINE(sla_show_trunks, "Show SLA Trunks"),
2296  AST_CLI_DEFINE(sla_show_stations, "Show SLA Stations"),
2297 };
2298 
2299 static void conf_flush(int fd, struct ast_channel *chan)
2300 {
2301  int x;
2302 
2303  /* read any frames that may be waiting on the channel
2304  and throw them away
2305  */
2306  if (chan) {
2307  struct ast_frame *f;
2308 
2309  /* when no frames are available, this will wait
2310  for 1 millisecond maximum
2311  */
2312  while (ast_waitfor(chan, 1) > 0) {
2313  f = ast_read(chan);
2314  if (f)
2315  ast_frfree(f);
2316  else /* channel was hung up or something else happened */
2317  break;
2318  }
2319  }
2320 
2321  /* flush any data sitting in the pseudo channel */
2322  x = DAHDI_FLUSH_ALL;
2323  if (ioctl(fd, DAHDI_FLUSH, &x))
2324  ast_log(LOG_WARNING, "Error flushing channel\n");
2325 
2326 }
2327 
2328 /*! \brief Remove the conference from the list and free it.
2329 
2330  We assume that this was called while holding conflock. */
2331 static int conf_free(struct ast_conference *conf)
2332 {
2333  int x;
2334  struct announce_listitem *item;
2335 
2336  AST_LIST_REMOVE(&confs, conf, list);
2337 
2338  meetme_stasis_generate_msg(conf, NULL, NULL, meetme_end_type(), NULL);
2339 
2340  if (conf->recording == MEETME_RECORD_ACTIVE) {
2343  while (1) {
2344  usleep(1);
2345  AST_LIST_LOCK(&confs);
2346  if (conf->recording == MEETME_RECORD_OFF)
2347  break;
2349  }
2350  }
2351 
2352  for (x = 0; x < AST_FRAME_BITS; x++) {
2353  if (conf->transframe[x])
2354  ast_frfree(conf->transframe[x]);
2355  if (conf->transpath[x])
2357  }
2358  if (conf->announcethread != AST_PTHREADT_NULL) {
2360  conf->announcethread_stop = 1;
2364  pthread_join(conf->announcethread, NULL);
2365 
2366  while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
2367  /* If it's a voicemail greeting file we don't want to remove it */
2368  if (!item->vmrec){
2369  ast_filedelete(item->namerecloc, NULL);
2370  }
2371  ao2_ref(item, -1);
2372  }
2374  }
2375 
2376  if (conf->origframe)
2377  ast_frfree(conf->origframe);
2378  ast_hangup(conf->lchan);
2379  ast_hangup(conf->chan);
2380  if (conf->fd >= 0)
2381  close(conf->fd);
2382  if (conf->recordingfilename) {
2383  ast_free(conf->recordingfilename);
2384  }
2385  if (conf->usercontainer) {
2386  ao2_ref(conf->usercontainer, -1);
2387  }
2388  if (conf->recordingformat) {
2389  ast_free(conf->recordingformat);
2390  }
2391  ast_mutex_destroy(&conf->playlock);
2392  ast_mutex_destroy(&conf->listenlock);
2395  ast_free(conf);
2396 
2397  return 0;
2398 }
2399 
2400 static void conf_queue_dtmf(const struct ast_conference *conf,
2401  const struct ast_conf_user *sender, struct ast_frame *f)
2402 {
2403  struct ast_conf_user *user;
2404  struct ao2_iterator user_iter;
2405 
2406  user_iter = ao2_iterator_init(conf->usercontainer, 0);
2407  while ((user = ao2_iterator_next(&user_iter))) {
2408  if (user == sender) {
2409  ao2_ref(user, -1);
2410  continue;
2411  }
2412  if (ast_write(user->chan, f) < 0)
2413  ast_log(LOG_WARNING, "Error writing frame to channel %s\n", ast_channel_name(user->chan));
2414  ao2_ref(user, -1);
2415  }
2416  ao2_iterator_destroy(&user_iter);
2417 }
2418 
2420  struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
2421 {
2422  struct sla_event *event;
2423 
2424  if (sla.thread == AST_PTHREADT_NULL) {
2425  ao2_ref(station, -1);
2426  ao2_ref(trunk_ref, -1);
2427  return;
2428  }
2429 
2430  if (!(event = ast_calloc(1, sizeof(*event)))) {
2431  ao2_ref(station, -1);
2432  ao2_ref(trunk_ref, -1);
2433  return;
2434  }
2435 
2436  event->type = type;
2437  event->trunk_ref = trunk_ref;
2438  event->station = station;
2439 
2440  if (!lock) {
2441  AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
2442  return;
2443  }
2444 
2445  ast_mutex_lock(&sla.lock);
2446  AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
2447  ast_cond_signal(&sla.cond);
2448  ast_mutex_unlock(&sla.lock);
2449 }
2450 
2452 {
2453  sla_queue_event_full(type, NULL, NULL, 0);
2454 }
2455 
2457 {
2458  sla_queue_event_full(type, NULL, NULL, 1);
2459 }
2460 
2461 /*! \brief Queue a SLA event from the conference */
2462 static void sla_queue_event_conf(enum sla_event_type type, struct ast_channel *chan,
2463  struct ast_conference *conf)
2464 {
2465  struct sla_station *station;
2466  struct sla_trunk_ref *trunk_ref = NULL;
2467  char *trunk_name;
2468  struct ao2_iterator i;
2469 
2470  trunk_name = ast_strdupa(conf->confno);
2471  strsep(&trunk_name, "_");
2472  if (ast_strlen_zero(trunk_name)) {
2473  ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
2474  return;
2475  }
2476 
2477  i = ao2_iterator_init(sla_stations, 0);
2478  while ((station = ao2_iterator_next(&i))) {
2479  ao2_lock(station);
2480  AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
2481  if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name)) {
2482  ao2_ref(trunk_ref, 1);
2483  break;
2484  }
2485  }
2486  ao2_unlock(station);
2487  if (trunk_ref) {
2488  /* station reference given to sla_queue_event_full() */
2489  break;
2490  }
2491  ao2_ref(station, -1);
2492  }
2494 
2495  if (!trunk_ref) {
2496  ast_debug(1, "Trunk not found for event!\n");
2497  return;
2498  }
2499 
2500  sla_queue_event_full(type, trunk_ref, station, 1);
2501 }
2502 
2503 /*! \brief Decrement reference counts, as incremented by find_conf() */
2504 static int dispose_conf(struct ast_conference *conf)
2505 {
2506  int res = 0;
2507  int confno_int = 0;
2508 
2509  AST_LIST_LOCK(&confs);
2510  if (ast_atomic_dec_and_test(&conf->refcount)) {
2511  /* Take the conference room number out of an inuse state */
2512  if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024)) {
2513  conf_map[confno_int] = 0;
2514  }
2515  conf_free(conf);
2516  res = 1;
2517  }
2519 
2520  return res;
2521 }
2522 
2523 static int rt_extend_conf(const char *confno)
2524 {
2525  char currenttime[32];
2526  char endtime[32];
2527  struct timeval now;
2528  struct ast_tm tm;
2529  struct ast_variable *var, *orig_var;
2530  char bookid[51];
2531 
2532  if (!extendby) {
2533  return 0;
2534  }
2535 
2536  now = ast_tvnow();
2537 
2538  ast_localtime(&now, &tm, NULL);
2539  ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
2540 
2541  var = ast_load_realtime("meetme", "confno",
2542  confno, "startTime<= ", currenttime,
2543  "endtime>= ", currenttime, NULL);
2544 
2545  orig_var = var;
2546 
2547  /* Identify the specific RealTime conference */
2548  while (var) {
2549  if (!strcasecmp(var->name, "bookid")) {
2550  ast_copy_string(bookid, var->value, sizeof(bookid));
2551  }
2552  if (!strcasecmp(var->name, "endtime")) {
2553  ast_copy_string(endtime, var->value, sizeof(endtime));
2554  }
2555 
2556  var = var->next;
2557  }
2558  ast_variables_destroy(orig_var);
2559 
2560  ast_strptime(endtime, DATE_FORMAT, &tm);
2561  now = ast_mktime(&tm, NULL);
2562 
2563  now.tv_sec += extendby;
2564 
2565  ast_localtime(&now, &tm, NULL);
2566  ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
2567  strcat(currenttime, "0"); /* Seconds needs to be 00 */
2568 
2569  var = ast_load_realtime("meetme", "confno",
2570  confno, "startTime<= ", currenttime,
2571  "endtime>= ", currenttime, NULL);
2572 
2573  /* If there is no conflict with extending the conference, update the DB */
2574  if (!var) {
2575  ast_debug(3, "Trying to update the endtime of Conference %s to %s\n", confno, currenttime);
2576  ast_update_realtime("meetme", "bookid", bookid, "endtime", currenttime, NULL);
2577  return 0;
2578 
2579  }
2580 
2581  ast_variables_destroy(var);
2582  return -1;
2583 }
2584 
2585 static void conf_start_moh(struct ast_channel *chan, const char *musicclass)
2586 {
2587  char *original_moh;
2588 
2589  ast_channel_lock(chan);
2590  original_moh = ast_strdupa(ast_channel_musicclass(chan));
2591  ast_channel_musicclass_set(chan, musicclass);
2592  ast_channel_unlock(chan);
2593 
2594  ast_moh_start(chan, original_moh, NULL);
2595 
2596  ast_channel_lock(chan);
2597  ast_channel_musicclass_set(chan, original_moh);
2598  ast_channel_unlock(chan);
2599 }
2600 
2601 static const char *get_announce_filename(enum announcetypes type)
2602 {
2603  switch (type) {
2604  case CONF_HASLEFT:
2605  return "conf-hasleft";
2606  break;
2607  case CONF_HASJOIN:
2608  return "conf-hasjoin";
2609  break;
2610  default:
2611  return "";
2612  }
2613 }
2614 
2615 static void *announce_thread(void *data)
2616 {
2617  struct announce_listitem *current;
2618  struct ast_conference *conf = data;
2619  int res;
2620  char filename[PATH_MAX] = "";
2622  AST_LIST_HEAD_INIT_NOLOCK(&local_list);
2623 
2624  while (!conf->announcethread_stop) {
2626  if (conf->announcethread_stop) {
2628  break;
2629  }
2630  if (AST_LIST_EMPTY(&conf->announcelist))
2632 
2633  AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
2635 
2637  if (conf->announcethread_stop) {
2638  break;
2639  }
2640 
2641  for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
2642  ast_debug(1, "About to play %s\n", current->namerecloc);
2643  if (!ast_fileexists(current->namerecloc, NULL, NULL))
2644  continue;
2645  if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
2646  if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
2647  res = ast_waitstream(current->confchan, "");
2648  if (!res) {
2649  ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
2650  if (!ast_streamfile(current->confchan, filename, current->language))
2651  ast_waitstream(current->confchan, "");
2652  }
2653  }
2654  if (current->announcetype == CONF_HASLEFT && current->announcetype && !current->vmrec) {
2655  /* only remove it if it isn't a VM recording file */
2656  ast_filedelete(current->namerecloc, NULL);
2657  }
2658  }
2659  }
2660 
2661  /* thread marked to stop, clean up */
2662  while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
2663  /* only delete if it's a vm rec */
2664  if (!current->vmrec) {
2665  ast_filedelete(current->namerecloc, NULL);
2666  }
2667  ao2_ref(current, -1);
2668  }
2669  return NULL;
2670 }
2671 
2672 static int can_write(struct ast_channel *chan, struct ast_flags64 *confflags)
2673 {
2674  if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
2675  return 1;
2676  }
2677 
2678  return (ast_channel_state(chan) == AST_STATE_UP);
2679 }
2680 
2681 static void send_talking_event(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
2682 {
2683  RAII_VAR(struct ast_json *, status_blob, status_to_json(talking), ast_json_unref);
2684  meetme_stasis_generate_msg(conf, chan, user, meetme_talking_type(), status_blob);
2685 }
2686 
2687 static void set_user_talking(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
2688 {
2689  int last_talking = user->talking;
2690  if (last_talking == talking)
2691  return;
2692 
2693  user->talking = talking;
2694 
2695  if (monitor) {
2696  /* Check if talking state changed. Take care of -1 which means unmonitored */
2697  int was_talking = (last_talking > 0);
2698  int now_talking = (talking > 0);
2699  if (was_talking != now_talking) {
2700  send_talking_event(chan, conf, user, now_talking);
2701  }
2702  }
2703 }
2704 
2705 static int user_set_hangup_cb(void *obj, void *check_admin_arg, int flags)
2706 {
2707  struct ast_conf_user *user = obj;
2708  /* actual pointer contents of check_admin_arg is irrelevant */
2709 
2710  if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
2711  user->adminflags |= ADMINFLAG_HANGUP;
2712  }
2713  return 0;
2714 }
2715 
2716 static int user_set_kickme_cb(void *obj, void *check_admin_arg, int flags)
2717 {
2718  struct ast_conf_user *user = obj;
2719  /* actual pointer contents of check_admin_arg is irrelevant */
2720 
2721  if (!check_admin_arg || (check_admin_arg && !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN))) {
2722  user->adminflags |= ADMINFLAG_KICKME;
2723  }
2724  return 0;
2725 }
2726 
2727 static int user_set_unmuted_cb(void *obj, void *check_admin_arg, int flags)
2728 {
2729  struct ast_conf_user *user = obj;
2730  /* actual pointer contents of check_admin_arg is irrelevant */
2731 
2732  if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
2734  }
2735  return 0;
2736 }
2737 
2738 static int user_set_muted_cb(void *obj, void *check_admin_arg, int flags)
2739 {
2740  struct ast_conf_user *user = obj;
2741  /* actual pointer contents of check_admin_arg is irrelevant */
2742 
2743  if (!check_admin_arg || !ast_test_flag64(&user->userflags, CONFFLAG_ADMIN)) {
2744  user->adminflags |= ADMINFLAG_MUTED;
2745  }
2746  return 0;
2747 }
2748 
2754 };
2755 
2756 /*! \internal
2757  * \brief Processes menu options for the standard menu (accessible through the 's' option for app_meetme)
2758  *
2759  * \param menu_mode a pointer to the currently active menu_mode.
2760  * \param dtmf a pointer to the dtmf value currently being processed against the menu.
2761  * \param conf the active conference for which the user has called the menu from.
2762  * \param confflags flags used by conf for various options
2763  * \param chan ast_channel belonging to the user who called the menu
2764  * \param user which meetme conference user invoked the menu
2765  */
2766 static void meetme_menu_normal(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
2767 {
2768  switch (*dtmf) {
2769  case '1': /* Un/Mute */
2770  *menu_mode = MENU_DISABLED;
2771 
2772  /* user can only toggle the self-muted state */
2774 
2775  /* they can't override the admin mute state */
2777  if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
2778  ast_waitstream(chan, "");
2779  }
2780  } else {
2781  if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
2782  ast_waitstream(chan, "");
2783  }
2784  }
2785  break;
2786 
2787  case '2':
2788  *menu_mode = MENU_DISABLED;
2791  }
2792 
2793  if (user->adminflags & ADMINFLAG_T_REQUEST) {
2794  if (!ast_streamfile(chan, "beep", ast_channel_language(chan))) {
2795  ast_waitstream(chan, "");
2796  }
2797  }
2798  break;
2799 
2800  case '4':
2802  break;
2803  case '5':
2804  /* Extend RT conference */
2805  if (rt_schedule) {
2806  rt_extend_conf(conf->confno);
2807  }
2808  *menu_mode = MENU_DISABLED;
2809  break;
2810 
2811  case '6':
2812  tweak_listen_volume(user, VOL_UP);
2813  break;
2814 
2815  case '7':
2816  tweak_talk_volume(user, VOL_DOWN);
2817  break;
2818 
2819  case '8':
2820  *menu_mode = MENU_DISABLED;
2821  break;
2822 
2823  case '9':
2824  tweak_talk_volume(user, VOL_UP);
2825  break;
2826 
2827  default:
2828  *menu_mode = MENU_DISABLED;
2829  if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
2830  ast_waitstream(chan, "");
2831  }
2832  break;
2833  }
2834 }
2835 
2836 /*! \internal
2837  * \brief Processes menu options for the adminstrator menu (accessible through the 's' option for app_meetme)
2838  *
2839  * \param menu_mode a pointer to the currently active menu_mode.
2840  * \param dtmf a pointer to the dtmf value currently being processed against the menu.
2841  * \param conf the active conference for which the user has called the menu from.
2842  * \param confflags flags used by conf for various options
2843  * \param chan ast_channel belonging to the user who called the menu
2844  * \param user which meetme conference user invoked the menu
2845  */
2846 static void meetme_menu_admin(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
2847 {
2848  switch(*dtmf) {
2849  case '1': /* Un/Mute */
2850  *menu_mode = MENU_DISABLED;
2851  /* for admin, change both admin and use flags */
2854  } else {
2856  }
2857 
2859  if (!ast_streamfile(chan, "conf-muted", ast_channel_language(chan))) {
2860  ast_waitstream(chan, "");
2861  }
2862  } else {
2863  if (!ast_streamfile(chan, "conf-unmuted", ast_channel_language(chan))) {
2864  ast_waitstream(chan, "");
2865  }
2866  }
2867  break;
2868 
2869  case '2': /* Un/Lock the Conference */
2870  *menu_mode = MENU_DISABLED;
2871  if (conf->locked) {
2872  conf->locked = 0;
2873  if (!ast_streamfile(chan, "conf-unlockednow", ast_channel_language(chan))) {
2874  ast_waitstream(chan, "");
2875  }
2876  } else {
2877  conf->locked = 1;
2878  if (!ast_streamfile(chan, "conf-lockednow", ast_channel_language(chan))) {
2879  ast_waitstream(chan, "");
2880  }
2881  }
2882  break;
2883 
2884  case '3': /* Eject last user */
2885  {
2886  struct ast_conf_user *usr = NULL;
2887  int max_no = 0;
2889  *menu_mode = MENU_DISABLED;
2890  usr = ao2_find(conf->usercontainer, &max_no, 0);
2892  if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
2893  ast_waitstream(chan, "");
2894  }
2895  } else {
2896  usr->adminflags |= ADMINFLAG_KICKME;
2897  }
2898  ao2_ref(usr, -1);
2899  ast_stopstream(chan);
2900  break;
2901  }
2902 
2903  case '4':
2905  break;
2906 
2907  case '5':
2908  /* Extend RT conference */
2909  if (rt_schedule) {
2910  if (!rt_extend_conf(conf->confno)) {
2911  if (!ast_streamfile(chan, "conf-extended", ast_channel_language(chan))) {
2912  ast_waitstream(chan, "");
2913  }
2914  } else {
2915  if (!ast_streamfile(chan, "conf-nonextended", ast_channel_language(chan))) {
2916  ast_waitstream(chan, "");
2917  }
2918  }
2919  ast_stopstream(chan);
2920  }
2921  *menu_mode = MENU_DISABLED;
2922  break;
2923 
2924  case '6':
2925  tweak_listen_volume(user, VOL_UP);
2926  break;
2927 
2928  case '7':
2929  tweak_talk_volume(user, VOL_DOWN);
2930  break;
2931 
2932  case '8':
2933  if (!ast_streamfile(chan, "conf-adminmenu-menu8", ast_channel_language(chan))) {
2934  /* If the user provides DTMF while playing the sound, we want to drop right into the extended menu function with new DTMF once we get out of here. */
2935  *dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
2936  ast_stopstream(chan);
2937  }
2938  *menu_mode = MENU_ADMIN_EXTENDED;
2939  break;
2940 
2941  case '9':
2942  tweak_talk_volume(user, VOL_UP);
2943  break;
2944  default:
2945  *menu_mode = MENU_DISABLED;
2946  /* Play an error message! */
2947  if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
2948  ast_waitstream(chan, "");
2949  }
2950  break;
2951  }
2952 
2953 }
2954 
2955 /*! \internal
2956  * \brief Processes menu options for the extended administrator menu (accessible through option 8 on the administrator menu)
2957  *
2958  * \param menu_mode a pointer to the currently active menu_mode.
2959  * \param dtmf a pointer to the dtmf value currently being processed against the menu.
2960  * \param conf the active conference for which the user has called the menu from.
2961  * \param confflags flags used by conf for various options
2962  * \param chan ast_channel belonging to the user who called the menu
2963  * \param user which meetme conference user invoked the menu
2964  * \param recordingtmp character buffer which may hold the name of the conference recording file
2965  */
2966 static void meetme_menu_admin_extended(enum menu_modes *menu_mode, int *dtmf,
2967  struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan,
2968  struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size,
2969  struct ast_format_cap *cap_slin)
2970 {
2971  int keepplaying;
2972  int playednamerec;
2973  int res;
2974  struct ao2_iterator user_iter;
2975  struct ast_conf_user *usr = NULL;
2976 
2977  switch(*dtmf) {
2978  case '1': /* *81 Roll call */
2979  keepplaying = 1;
2980  playednamerec = 0;
2981  if (conf->users == 1) {
2982  if (keepplaying && !ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
2983  res = ast_waitstream(chan, AST_DIGIT_ANY);
2984  ast_stopstream(chan);
2985  if (res > 0) {
2986  keepplaying = 0;
2987  }
2988  }
2989  } else if (conf->users == 2) {
2990  if (keepplaying && !ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
2991  res = ast_waitstream(chan, AST_DIGIT_ANY);
2992  ast_stopstream(chan);
2993  if (res > 0) {
2994  keepplaying = 0;
2995  }
2996  }
2997  } else {
2998  if (keepplaying && !ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
2999  res = ast_waitstream(chan, AST_DIGIT_ANY);
3000  ast_stopstream(chan);
3001  if (res > 0) {
3002  keepplaying = 0;
3003  }
3004  }
3005  if (keepplaying) {
3006  res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3007  ast_stopstream(chan);
3008  if (res > 0) {
3009  keepplaying = 0;
3010  }
3011  }
3012  if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
3013  res = ast_waitstream(chan, AST_DIGIT_ANY);
3014  ast_stopstream(chan);
3015  if (res > 0) {
3016  keepplaying = 0;
3017  }
3018  }
3019  }
3020  user_iter = ao2_iterator_init(conf->usercontainer, 0);
3021  while((usr = ao2_iterator_next(&user_iter))) {
3022  if (ast_fileexists(usr->namerecloc, NULL, NULL)) {
3023  if (keepplaying && !ast_streamfile(chan, usr->namerecloc, ast_channel_language(chan))) {
3024  res = ast_waitstream(chan, AST_DIGIT_ANY);
3025  ast_stopstream(chan);
3026  if (res > 0) {
3027  keepplaying = 0;
3028  }
3029  }
3030  playednamerec = 1;
3031  }
3032  ao2_ref(usr, -1);
3033  }
3034  ao2_iterator_destroy(&user_iter);
3035  if (keepplaying && playednamerec && !ast_streamfile(chan, "conf-roll-callcomplete", ast_channel_language(chan))) {
3036  res = ast_waitstream(chan, AST_DIGIT_ANY);
3037  ast_stopstream(chan);
3038  if (res > 0) {
3039  keepplaying = 0;
3040  }
3041  }
3042 
3043  *menu_mode = MENU_DISABLED;
3044  break;
3045 
3046  case '2': /* *82 Eject all non-admins */
3047  if (conf->users == 1) {
3048  if(!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
3049  ast_waitstream(chan, "");
3050  }
3051  } else {
3053  }
3054  ast_stopstream(chan);
3055  *menu_mode = MENU_DISABLED;
3056  break;
3057 
3058  case '3': /* *83 (Admin) mute/unmute all non-admins */
3059  if(conf->gmuted) {
3060  conf->gmuted = 0;
3062  if (!ast_streamfile(chan, "conf-now-unmuted", ast_channel_language(chan))) {
3063  ast_waitstream(chan, "");
3064  }
3065  } else {
3066  conf->gmuted = 1;
3068  if (!ast_streamfile(chan, "conf-now-muted", ast_channel_language(chan))) {
3069  ast_waitstream(chan, "");
3070  }
3071  }
3072  ast_stopstream(chan);
3073  *menu_mode = MENU_DISABLED;
3074  break;
3075 
3076  case '4': /* *84 Record conference */
3077  if (conf->recording != MEETME_RECORD_ACTIVE) {
3078  ast_set_flag64(confflags, CONFFLAG_RECORDCONF);
3079  if (!conf->recordingfilename) {
3080  const char *var;
3081  ast_channel_lock(chan);
3082  if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
3083  conf->recordingfilename = ast_strdup(var);
3084  }
3085  if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
3086  conf->recordingformat = ast_strdup(var);
3087  }
3088  ast_channel_unlock(chan);
3089  if (!conf->recordingfilename) {
3090  snprintf(recordingtmp, recordingtmp_size, "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
3091  conf->recordingfilename = ast_strdup(recordingtmp);
3092  }
3093  if (!conf->recordingformat) {
3094  conf->recordingformat = ast_strdup("wav");
3095  }
3096  ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
3097  conf->confno, conf->recordingfilename, conf->recordingformat);
3098  }
3099 
3101  if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) {
3102  struct dahdi_confinfo dahdic;
3103 
3106  dahdic.chan = 0;
3107  dahdic.confno = conf->dahdiconf;
3108  dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
3109  if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, &dahdic)) {
3110  ast_log(LOG_WARNING, "Error starting listen channel\n");
3111  ast_hangup(conf->lchan);
3112  conf->lchan = NULL;
3113  } else {
3114  ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
3115  }
3116  }
3118  if (!ast_streamfile(chan, "conf-now-recording", ast_channel_language(chan))) {
3119  ast_waitstream(chan, "");
3120  }
3121  }
3122 
3123  ast_stopstream(chan);
3124  *menu_mode = MENU_DISABLED;
3125  break;
3126 
3127  case '8': /* *88 Exit the menu and return to the conference... without an error message */
3128  ast_stopstream(chan);
3129  *menu_mode = MENU_DISABLED;
3130  break;
3131 
3132  default:
3133  if (!ast_streamfile(chan, "conf-errormenu", ast_channel_language(chan))) {
3134  ast_waitstream(chan, "");
3135  }
3136  ast_stopstream(chan);
3137  *menu_mode = MENU_DISABLED;
3138  break;
3139  }
3140 }
3141 
3142 /*! \internal
3143  * \brief Processes menu options for the various menu types (accessible through the 's' option for app_meetme)
3144  *
3145  * \param menu_mode a pointer to the currently active menu_mode.
3146  * \param dtmf a pointer to the dtmf value currently being processed against the menu.
3147  * \param conf the active conference for which the user has called the menu from.
3148  * \param confflags flags used by conf for various options
3149  * \param chan ast_channel belonging to the user who called the menu
3150  * \param user which meetme conference user invoked the menu
3151  * \param recordingtmp character buffer which may hold the name of the conference recording file
3152  */
3153 static void meetme_menu(enum menu_modes *menu_mode, int *dtmf,
3154  struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan,
3155  struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size,
3156  struct ast_format_cap *cap_slin)
3157 {
3158  switch (*menu_mode) {
3159  case MENU_DISABLED:
3160  break;
3161  case MENU_NORMAL:
3162  meetme_menu_normal(menu_mode, dtmf, conf, confflags, chan, user);
3163  break;
3164  case MENU_ADMIN:
3165  meetme_menu_admin(menu_mode, dtmf, conf, confflags, chan, user);
3166  /* Admin Menu is capable of branching into another menu, in which case it will reset dtmf and change the menu mode. */
3167  if (*menu_mode != MENU_ADMIN_EXTENDED || (*dtmf <= 0)) {
3168  break;
3169  }
3170  case MENU_ADMIN_EXTENDED:
3171  meetme_menu_admin_extended(menu_mode, dtmf, conf, confflags, chan, user,
3172  recordingtmp, recordingtmp_size, cap_slin);
3173  break;
3174  }
3175 }
3176 
3177 static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struct ast_flags64 *confflags, char *optargs[])
3178 {
3179  struct ast_conf_user *user = NULL;
3180  int fd;
3181  struct dahdi_confinfo dahdic, dahdic_empty;
3182  struct ast_frame *f;
3183  struct ast_channel *c;
3184  struct ast_frame fr;
3185  int outfd;
3186  int ms;
3187  int nfds;
3188  int res;
3189  int retrydahdi;
3190  int origfd;
3191  int musiconhold = 0, mohtempstopped = 0;
3192  int firstpass = 0;
3193  int lastmarked = 0;
3194  int currentmarked = 0;
3195  int ret = -1;
3196  int x;
3197  enum menu_modes menu_mode = MENU_DISABLED;
3198  int talkreq_manager = 0;
3199  int using_pseudo = 0;
3200  int duration = 20;
3201  int sent_event = 0;
3202  int checked = 0;
3203  int announcement_played = 0;
3204  struct timeval now;
3205  struct ast_dsp *dsp = NULL;
3206  struct ast_app *agi_app;
3207  char *agifile;
3208  const char *agifiledefault = "conf-background.agi", *tmpvar;
3209  char meetmesecs[30] = "";
3210  char exitcontext[AST_MAX_CONTEXT] = "";
3211  char recordingtmp[AST_MAX_EXTENSION * 2] = "";
3212  char members[10] = "";
3213  int dtmf = 0, opt_waitmarked_timeout = 0;
3214  time_t timeout = 0;
3215  struct dahdi_bufferinfo bi;
3216  char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
3217  char *buf = __buf + AST_FRIENDLY_OFFSET;
3218  char *exitkeys = NULL;
3219  unsigned int calldurationlimit = 0;
3220  long timelimit = 0;
3221  long play_warning = 0;
3222  long warning_freq = 0;
3223  const char *warning_sound = NULL;
3224  const char *end_sound = NULL;
3225  char *parse;
3226  long time_left_ms = 0;
3227  struct timeval nexteventts = { 0, };
3228  int to;
3229  int setusercount = 0;
3230  int confsilence = 0, totalsilence = 0;
3231  char *mailbox, *context;
3233 
3234  if (!cap_slin) {
3235  goto conf_run_cleanup;
3236  }
3237  ast_format_cap_append(cap_slin, ast_format_slin, 0);
3238 
3239  if (!(user = ao2_alloc(sizeof(*user), NULL))) {
3240  goto conf_run_cleanup;
3241  }
3242 
3243  /* Possible timeout waiting for marked user */
3244  if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
3245  !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
3246  (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
3247  (opt_waitmarked_timeout > 0)) {
3248  timeout = time(NULL) + opt_waitmarked_timeout;
3249  }
3250 
3252  calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
3253  ast_verb(3, "Setting call duration limit to %u seconds.\n", calldurationlimit);
3254  }
3255 
3257  char *limit_str, *warning_str, *warnfreq_str;
3258  const char *var;
3259 
3260  parse = optargs[OPT_ARG_DURATION_LIMIT];
3261  limit_str = strsep(&parse, ":");
3262  warning_str = strsep(&parse, ":");
3263  warnfreq_str = parse;
3264 
3265  timelimit = atol(limit_str);
3266  if (warning_str)
3267  play_warning = atol(warning_str);
3268  if (warnfreq_str)
3269  warning_freq = atol(warnfreq_str);
3270 
3271  if (!timelimit) {
3272  timelimit = play_warning = warning_freq = 0;
3273  warning_sound = NULL;
3274  } else if (play_warning > timelimit) {
3275  if (!warning_freq) {
3276  play_warning = 0;
3277  } else {
3278  while (play_warning > timelimit)
3279  play_warning -= warning_freq;
3280  if (play_warning < 1)
3281  play_warning = warning_freq = 0;
3282  }
3283  }
3284 
3285  ast_verb(3, "Setting conference duration limit to: %ldms.\n", timelimit);
3286  if (play_warning) {
3287  ast_verb(3, "Setting warning time to %ldms from the conference duration limit.\n", play_warning);
3288  }
3289  if (warning_freq) {
3290  ast_verb(3, "Setting warning frequency to %ldms.\n", warning_freq);
3291  }
3292 
3293  ast_channel_lock(chan);
3294  if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
3295  var = ast_strdupa(var);
3296  }
3297  ast_channel_unlock(chan);
3298 
3299  warning_sound = var ? var : "timeleft";
3300 
3301  ast_channel_lock(chan);
3302  if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
3303  var = ast_strdupa(var);
3304  }
3305  ast_channel_unlock(chan);
3306 
3307  end_sound = var ? var : NULL;
3308 
3309  /* undo effect of S(x) in case they are both used */
3310  calldurationlimit = 0;
3311  /* more efficient do it like S(x) does since no advanced opts */
3312  if (!play_warning && !end_sound && timelimit) {
3313  calldurationlimit = timelimit / 1000;
3314  timelimit = play_warning = warning_freq = 0;
3315  } else {
3316  ast_debug(2, "Limit Data for this call:\n");
3317  ast_debug(2, "- timelimit = %ld\n", timelimit);
3318  ast_debug(2, "- play_warning = %ld\n", play_warning);
3319  ast_debug(2, "- warning_freq = %ld\n", warning_freq);
3320  ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
3321  ast_debug(2, "- end_sound = %s\n", end_sound ? end_sound : "UNDEF");
3322  }
3323  }
3324 
3325  /* Get exit keys */
3326  if (ast_test_flag64(confflags, CONFFLAG_KEYEXIT)) {
3327  if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
3328  exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
3329  else
3330  exitkeys = ast_strdupa("#"); /* Default */
3331  }
3332 
3333  if (ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
3334  if (!conf->recordingfilename) {
3335  const char *var;
3336  ast_channel_lock(chan);
3337  if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
3338  conf->recordingfilename = ast_strdup(var);
3339  }
3340  if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
3341  conf->recordingformat = ast_strdup(var);
3342  }
3343  ast_channel_unlock(chan);
3344  if (!conf->recordingfilename) {
3345  snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, ast_channel_uniqueid(chan));
3346  conf->recordingfilename = ast_strdup(recordingtmp);
3347  }
3348  if (!conf->recordingformat) {
3349  conf->recordingformat = ast_strdup("wav");
3350  }
3351  ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
3352  conf->confno, conf->recordingfilename, conf->recordingformat);
3353  }
3354  }
3355 
3357  if ((conf->recordthread == AST_PTHREADT_NULL) && ast_test_flag64(confflags, CONFFLAG_RECORDCONF) &&
3358  ((conf->lchan = ast_request("DAHDI", cap_slin, NULL, chan, "pseudo", NULL)))) {
3361  dahdic.chan = 0;
3362  dahdic.confno = conf->dahdiconf;
3363  dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
3364  if (ioctl(ast_channel_fd(conf->lchan, 0), DAHDI_SETCONF, &dahdic)) {
3365  ast_log(LOG_WARNING, "Error starting listen channel\n");
3366  ast_hangup(conf->lchan);
3367  conf->lchan = NULL;
3368  } else {
3369  ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
3370  }
3371  }
3373 
3375  if ((conf->announcethread == AST_PTHREADT_NULL) && !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
3380  }
3382 
3383  time(&user->jointime);
3384 
3385  user->timelimit = timelimit;
3386  user->play_warning = play_warning;
3387  user->warning_freq = warning_freq;
3388  user->warning_sound = warning_sound;
3389  user->end_sound = end_sound;
3390 
3391  if (calldurationlimit > 0) {
3392  time(&user->kicktime);
3393  user->kicktime = user->kicktime + calldurationlimit;
3394  }
3395 
3396  if (ast_tvzero(user->start_time))
3397  user->start_time = ast_tvnow();
3398  time_left_ms = user->timelimit;
3399 
3400  if (user->timelimit) {
3401  nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
3402  nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
3403  }
3404 
3405  if (conf->locked && (!ast_test_flag64(confflags, CONFFLAG_ADMIN))) {
3406  /* Sorry, but this conference is locked! */
3407  if (!ast_streamfile(chan, "conf-locked", ast_channel_language(chan)))
3408  ast_waitstream(chan, "");
3409  goto outrun;
3410  }
3411 
3412  ast_mutex_lock(&conf->playlock);
3413 
3414  if (rt_schedule && conf->maxusers) {
3415  if (conf->users >= conf->maxusers) {
3416  /* Sorry, but this confernce has reached the participant limit! */
3417  ast_mutex_unlock(&conf->playlock);
3418  if (!ast_streamfile(chan, "conf-full", ast_channel_language(chan)))
3419  ast_waitstream(chan, "");
3420  goto outrun;
3421  }
3422  }
3423 
3424  ao2_lock(conf->usercontainer);
3426  user->user_no++;
3427  ao2_link(conf->usercontainer, user);
3428  ao2_unlock(conf->usercontainer);
3429 
3430  user->chan = chan;
3431  user->userflags = *confflags;
3433  if (!ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
3434  user->adminflags |= (conf->gmuted) ? ADMINFLAG_MUTED : 0;
3435  }
3436  user->talking = -1;
3437 
3438  ast_mutex_unlock(&conf->playlock);
3439 
3441  char destdir[PATH_MAX];
3442 
3443  snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
3444 
3445  if (ast_mkdir(destdir, 0777) != 0) {
3446  ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
3447  goto outrun;
3448  }
3449 
3450  if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
3451  context = ast_strdupa(optargs[OPT_ARG_INTROUSER_VMREC]);
3452  mailbox = strsep(&context, "@");
3453 
3454  if (ast_strlen_zero(mailbox)) {
3455  /* invalid input, clear the v flag*/
3457  ast_log(LOG_WARNING,"You must specify a mailbox in the v() option\n");
3458  } else {
3459  if (ast_strlen_zero(context)) {
3460  context = "default";
3461  }
3462  /* if there is no mailbox we don't need to do this logic */
3463  snprintf(user->namerecloc, sizeof(user->namerecloc),
3464  "%s/voicemail/%s/%s/greet",ast_config_AST_SPOOL_DIR,context,mailbox);
3465 
3466  /* if the greeting doesn't exist then use the temp file method instead, clear flag v */
3467  if (!ast_fileexists(user->namerecloc, NULL, NULL)){
3468  snprintf(user->namerecloc, sizeof(user->namerecloc),
3469  "%s/meetme-username-%s-%d", destdir,
3470  conf->confno, user->user_no);
3472  }
3473  }
3474  } else {
3475  snprintf(user->namerecloc, sizeof(user->namerecloc),
3476  "%s/meetme-username-%s-%d", destdir,
3477  conf->confno, user->user_no);
3478  }
3479 
3480  res = 0;
3482  res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
3483  else if (ast_test_flag64(confflags, CONFFLAG_INTROUSER) && !ast_fileexists(user->namerecloc, NULL, NULL))
3484  res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
3485  if (res == -1)
3486  goto outrun;
3487 
3488  }
3489 
3490  ast_mutex_lock(&conf->playlock);
3491 
3492  if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER))
3493  conf->markedusers++;
3494  conf->users++;
3495  if (rt_log_members) {
3496  /* Update table */
3497  snprintf(members, sizeof(members), "%d", conf->users);
3498  ast_realtime_require_field("meetme",
3499  "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
3500  "members", RQ_UINTEGER1, strlen(members),
3501  NULL);
3502  ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
3503  }
3504  setusercount = 1;
3505 
3506  /* This device changed state now - if this is the first user */
3507  if (conf->users == 1)
3509 
3510  ast_mutex_unlock(&conf->playlock);
3511 
3512  /* return the unique ID of the conference */
3513  pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
3514 
3515  if (ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT)) {
3516  ast_channel_lock(chan);
3517  if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
3518  ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
3519  } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))) {
3520  ast_copy_string(exitcontext, ast_channel_macrocontext(chan), sizeof(exitcontext));
3521  } else {
3522  ast_copy_string(exitcontext, ast_channel_context(chan), sizeof(exitcontext));
3523  }
3524  ast_channel_unlock(chan);
3525  }
3526 
3527  /* Play an arbitrary intro message */
3528  if (ast_test_flag64(confflags, CONFFLAG_INTROMSG) &&
3529  !ast_strlen_zero(optargs[OPT_ARG_INTROMSG])) {
3530  if (!ast_streamfile(chan, optargs[OPT_ARG_INTROMSG], ast_channel_language(chan))) {
3531  ast_waitstream(chan, "");
3532  }
3533  }
3534 
3535  if (!ast_test_flag64(confflags, (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
3536  if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED))
3537  if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan)))
3538  ast_waitstream(chan, "");
3539  if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && conf->markedusers == 0)
3540  if (!ast_streamfile(chan, "conf-waitforleader", ast_channel_language(chan)))
3541  ast_waitstream(chan, "");
3542  }
3543 
3544  if (ast_test_flag64(confflags, CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
3545  int keepplaying = 1;
3546 
3547  if (conf->users == 2) {
3548  if (!ast_streamfile(chan, "conf-onlyone", ast_channel_language(chan))) {
3549  res = ast_waitstream(chan, AST_DIGIT_ANY);
3550  ast_stopstream(chan);
3551  if (res > 0)
3552  keepplaying = 0;
3553  else if (res == -1)
3554  goto outrun;
3555  }
3556  } else {
3557  if (!ast_streamfile(chan, "conf-thereare", ast_channel_language(chan))) {
3558  res = ast_waitstream(chan, AST_DIGIT_ANY);
3559  ast_stopstream(chan);
3560  if (res > 0)
3561  keepplaying = 0;
3562  else if (res == -1)
3563  goto outrun;
3564  }
3565  if (keepplaying) {
3566  res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3567  if (res > 0)
3568  keepplaying = 0;
3569  else if (res == -1)
3570  goto outrun;
3571  }
3572  if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", ast_channel_language(chan))) {
3573  res = ast_waitstream(chan, AST_DIGIT_ANY);
3574  ast_stopstream(chan);
3575  if (res > 0)
3576  keepplaying = 0;
3577  else if (res == -1)
3578  goto outrun;
3579  }
3580  }
3581  }
3582 
3583  if (!ast_test_flag64(confflags, CONFFLAG_NO_AUDIO_UNTIL_UP)) {
3584  /* We're leaving this alone until the state gets changed to up */
3585  ast_indicate(chan, -1);
3586  }
3587 
3588  if (ast_set_write_format(chan, ast_format_slin) < 0) {
3589  ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", ast_channel_name(chan));
3590  goto outrun;
3591  }
3592 
3593  if (ast_set_read_format(chan, ast_format_slin) < 0) {
3594  ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", ast_channel_name(chan));
3595  goto outrun;
3596  }
3597 
3598  /* Reduce background noise from each participant */
3599  if (!ast_test_flag64(confflags, CONFFLAG_DONT_DENOISE)) {
3600  ast_func_write(chan, "DENOISE(rx)", "on");
3601  }
3602 
3603  retrydahdi = (strcasecmp(ast_channel_tech(chan)->type, "DAHDI") || (ast_channel_audiohooks(chan) || ast_channel_monitor(chan)) ? 1 : 0);
3604  user->dahdichannel = !retrydahdi;
3605 
3606  dahdiretry:
3607  origfd = ast_channel_fd(chan, 0);
3608  if (retrydahdi) {
3609  /* open pseudo in non-blocking mode */
3610  fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
3611  if (fd < 0) {
3612  ast_log(LOG_WARNING, "Unable to open DAHDI pseudo channel: %s\n", strerror(errno));
3613  goto outrun;
3614  }
3615  using_pseudo = 1;
3616  /* Setup buffering information */
3617  memset(&bi, 0, sizeof(bi));
3618  bi.bufsize = CONF_SIZE / 2;
3619  bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
3620  bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
3621  bi.numbufs = audio_buffers;
3622  if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
3623  ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
3624  close(fd);
3625  goto outrun;
3626  }
3627  x = 1;
3628  if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
3629  ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
3630  close(fd);
3631  goto outrun;
3632  }
3633  nfds = 1;
3634  } else {
3635  /* XXX Make sure we're not running on a pseudo channel XXX */
3636  fd = ast_channel_fd(chan, 0);
3637  nfds = 0;
3638  }
3639  memset(&dahdic, 0, sizeof(dahdic));
3640  memset(&dahdic_empty, 0, sizeof(dahdic_empty));
3641  /* Check to see if we're in a conference... */
3642  dahdic.chan = 0;
3643  if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
3644  ast_log(LOG_WARNING, "Error getting conference\n");
3645  close(fd);
3646  goto outrun;
3647  }
3648  if (dahdic.confmode) {
3649  /* Whoa, already in a conference... Retry... */
3650  if (!retrydahdi) {
3651  ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
3652  retrydahdi = 1;
3653  goto dahdiretry;
3654  }
3655  }
3656  memset(&dahdic, 0, sizeof(dahdic));
3657  /* Add us to the conference */
3658  dahdic.chan = 0;
3659  dahdic.confno = conf->dahdiconf;
3660 
3661  if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && (ast_test_flag64(confflags, CONFFLAG_INTROUSER) ||
3663  struct announce_listitem *item;
3664  if (!(item = ao2_alloc(sizeof(*item), NULL)))
3665  goto outrun;
3666  ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
3667  ast_copy_string(item->language, ast_channel_language(chan), sizeof(item->language));
3668  item->confchan = conf->chan;
3669  item->confusers = conf->users;
3670  if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
3671  item->vmrec = 1;
3672  }
3673  item->announcetype = CONF_HASJOIN;
3675  ao2_ref(item, +1); /* add one more so we can determine when announce_thread is done playing it */
3676  AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
3679 
3680  while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
3681  ;
3682  }
3683  ao2_ref(item, -1);
3684  }
3685 
3686  if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && !conf->markedusers)
3687  dahdic.confmode = DAHDI_CONF_CONF;
3688  else if (ast_test_flag64(confflags, CONFFLAG_MONITOR))
3689  dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
3690  else if (ast_test_flag64(confflags, CONFFLAG_TALKER))
3691  dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
3692  else
3693  dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
3694 
3695  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3696  ast_log(LOG_WARNING, "Error setting conference\n");
3697  close(fd);
3698  goto outrun;
3699  }
3700  ast_debug(1, "Placed channel %s in DAHDI conf %d\n", ast_channel_name(chan), conf->dahdiconf);
3701 
3702  if (!sent_event) {
3703  meetme_stasis_generate_msg(conf, chan, user, meetme_join_type(), NULL);
3704  sent_event = 1;
3705  }
3706 
3707  if (!firstpass && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
3708  !ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
3709  firstpass = 1;
3710  if (!ast_test_flag64(confflags, CONFFLAG_QUIET))
3711  if (!ast_test_flag64(confflags, CONFFLAG_WAITMARKED) || (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER) &&
3712  (conf->markedusers >= 1))) {
3713  conf_play(chan, conf, ENTER);
3714  }
3715  }
3716 
3717  conf_flush(fd, chan);
3718 
3719  if (dsp)
3720  ast_dsp_free(dsp);
3721 
3722  if (!(dsp = ast_dsp_new())) {
3723  ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
3724  res = -1;
3725  }
3726 
3727  if (ast_test_flag64(confflags, CONFFLAG_AGI)) {
3728  /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
3729  or use default filename of conf-background.agi */
3730 
3731  ast_channel_lock(chan);
3732  if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
3733  agifile = ast_strdupa(tmpvar);
3734  } else {
3735  agifile = ast_strdupa(agifiledefault);
3736  }
3737  ast_channel_unlock(chan);
3738 
3739  if (user->dahdichannel) {
3740  /* Set CONFMUTE mode on DAHDI channel to mute DTMF tones */
3741  x = 1;
3742  ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
3743  }
3744  /* Find a pointer to the agi app and execute the script */
3745  agi_app = pbx_findapp("agi");
3746  if (agi_app) {
3747  ret = pbx_exec(chan, agi_app, agifile);
3748  } else {
3749  ast_log(LOG_WARNING, "Could not find application (agi)\n");
3750  ret = -2;
3751  }
3752  if (user->dahdichannel) {
3753  /* Remove CONFMUTE mode on DAHDI channel */
3754  x = 0;
3755  ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
3756  }
3757  } else {
3758  int lastusers = conf->users;
3759  if (user->dahdichannel && ast_test_flag64(confflags, CONFFLAG_STARMENU)) {
3760  /* Set CONFMUTE mode on DAHDI channel to mute DTMF tones when the menu is enabled */
3761  x = 1;
3762  ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
3763  }
3764 
3765  for (;;) {
3766  int menu_was_active = 0;
3767 
3768  outfd = -1;
3769  ms = -1;
3770  now = ast_tvnow();
3771 
3772  if (rt_schedule && conf->endtime) {
3773  char currenttime[32];
3774  long localendtime = 0;
3775  int extended = 0;
3776  struct ast_tm tm;
3777  struct ast_variable *var, *origvar;
3778  struct timeval tmp;
3779 
3780  if (now.tv_sec % 60 == 0) {
3781  if (!checked) {
3782  ast_localtime(&now, &tm, NULL);
3783  ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
3784  var = origvar = ast_load_realtime("meetme", "confno",
3785  conf->confno, "starttime <=", currenttime,
3786  "endtime >=", currenttime, NULL);
3787 
3788  for ( ; var; var = var->next) {
3789  if (!strcasecmp(var->name, "endtime")) {
3790  struct ast_tm endtime_tm;
3791  ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
3792  tmp = ast_mktime(&endtime_tm, NULL);
3793  localendtime = tmp.tv_sec;
3794  }
3795  }
3796  ast_variables_destroy(origvar);
3797 
3798  /* A conference can be extended from the
3799  Admin/User menu or by an external source */
3800  if (localendtime > conf->endtime){
3801  conf->endtime = localendtime;
3802  extended = 1;
3803  }
3804 
3805  if (conf->endtime && (now.tv_sec >= conf->endtime)) {
3806  ast_verbose("Quitting time...\n");
3807  goto outrun;
3808  }
3809 
3810  if (!announcement_played && conf->endalert) {
3811  if (now.tv_sec + conf->endalert >= conf->endtime) {
3812  if (!ast_streamfile(chan, "conf-will-end-in", ast_channel_language(chan)))
3813  ast_waitstream(chan, "");
3814  ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", ast_channel_language(chan));
3815  if (!ast_streamfile(chan, "minutes", ast_channel_language(chan)))
3816  ast_waitstream(chan, "");
3817  if (musiconhold) {
3818  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3819  }
3820  announcement_played = 1;
3821  }
3822  }
3823 
3824  if (extended) {
3825  announcement_played = 0;
3826  }
3827 
3828  checked = 1;
3829  }
3830  } else {
3831  checked = 0;
3832  }
3833  }
3834 
3835  if (user->kicktime && (user->kicktime <= now.tv_sec)) {
3836  if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3837  ret = 0;
3838  } else {
3839  ret = -1;
3840  }
3841  break;
3842  }
3843 
3844  to = -1;
3845  if (user->timelimit) {
3846  int minutes = 0, seconds = 0, remain = 0;
3847 
3848  to = ast_tvdiff_ms(nexteventts, now);
3849  if (to < 0) {
3850  to = 0;
3851  }
3852  time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
3853  if (time_left_ms < to) {
3854  to = time_left_ms;
3855  }
3856 
3857  if (time_left_ms <= 0) {
3858  if (user->end_sound) {
3859  res = ast_streamfile(chan, user->end_sound, ast_channel_language(chan));
3860  res = ast_waitstream(chan, "");
3861  }
3862  if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3863  ret = 0;
3864  } else {
3865  ret = -1;
3866  }
3867  break;
3868  }
3869 
3870  if (!to) {
3871  if (time_left_ms >= 5000) {
3872 
3873  remain = (time_left_ms + 500) / 1000;
3874  if (remain / 60 >= 1) {
3875  minutes = remain / 60;
3876  seconds = remain % 60;
3877  } else {
3878  seconds = remain;
3879  }
3880 
3881  /* force the time left to round up if appropriate */
3882  if (user->warning_sound && user->play_warning) {
3883  if (!strcmp(user->warning_sound, "timeleft")) {
3884 
3885  res = ast_streamfile(chan, "vm-youhave", ast_channel_language(chan));
3886  res = ast_waitstream(chan, "");
3887  if (minutes) {
3888  res = ast_say_number(chan, minutes, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3889  res = ast_streamfile(chan, "queue-minutes", ast_channel_language(chan));
3890  res = ast_waitstream(chan, "");
3891  }
3892  if (seconds) {
3893  res = ast_say_number(chan, seconds, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3894  res = ast_streamfile(chan, "queue-seconds", ast_channel_language(chan));
3895  res = ast_waitstream(chan, "");
3896  }
3897  } else {
3898  res = ast_streamfile(chan, user->warning_sound, ast_channel_language(chan));
3899  res = ast_waitstream(chan, "");
3900  }
3901  if (musiconhold) {
3902  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3903  }
3904  }
3905  }
3906  if (user->warning_freq) {
3907  nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
3908  } else {
3909  nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
3910  }
3911  }
3912  }
3913 
3914  now = ast_tvnow();
3915  if (timeout && now.tv_sec >= timeout) {
3916  if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3917  ret = 0;
3918  } else {
3919  ret = -1;
3920  }
3921  break;
3922  }
3923 
3924  /* if we have just exited from the menu, and the user had a channel-driver
3925  volume adjustment, restore it
3926  */
3927  if (!menu_mode && menu_was_active && user->listen.desired && !user->listen.actual) {
3928  set_talk_volume(user, user->listen.desired);
3929  }
3930 
3931  menu_was_active = menu_mode;
3932 
3933  currentmarked = conf->markedusers;
3934  if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
3935  ast_test_flag64(confflags, CONFFLAG_MARKEDUSER) &&
3936  ast_test_flag64(confflags, CONFFLAG_WAITMARKED) &&
3937  lastmarked == 0) {
3938  if (currentmarked == 1 && conf->users > 1) {
3939  ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, ast_channel_language(chan), (char *) NULL);
3940  if (conf->users - 1 == 1) {
3941  if (!ast_streamfile(chan, "conf-userwilljoin", ast_channel_language(chan))) {
3942  ast_waitstream(chan, "");
3943  }
3944  } else {
3945  if (!ast_streamfile(chan, "conf-userswilljoin", ast_channel_language(chan))) {
3946  ast_waitstream(chan, "");
3947  }
3948  }
3949  }
3950  if (conf->users == 1 && !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
3951  if (!ast_streamfile(chan, "conf-onlyperson", ast_channel_language(chan))) {
3952  ast_waitstream(chan, "");
3953  }
3954  }
3955  }
3956 
3957  /* Update the struct with the actual confflags */
3958  user->userflags = *confflags;
3959 
3960  if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
3961  if (currentmarked == 0) {
3962  if (lastmarked != 0) {
3963  if (!ast_test_flag64(confflags, CONFFLAG_QUIET)) {
3964  if (!ast_streamfile(chan, "conf-leaderhasleft", ast_channel_language(chan))) {
3965  ast_waitstream(chan, "");
3966  }
3967  }
3968  if (ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
3969  if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
3970  ret = 0;
3971  }
3972  break;
3973  } else {
3974  dahdic.confmode = DAHDI_CONF_CONF;
3975  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3976  ast_log(LOG_WARNING, "Error setting conference\n");
3977  close(fd);
3978  goto outrun;
3979  }
3980  }
3981  }
3982  if (!musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
3983  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
3984  musiconhold = 1;
3985  }
3986  } else if (currentmarked >= 1 && lastmarked == 0) {
3987  /* Marked user entered, so cancel timeout */
3988  timeout = 0;
3989  if (ast_test_flag64(confflags, CONFFLAG_MONITOR)) {
3990  dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
3991  } else if (ast_test_flag64(confflags, CONFFLAG_TALKER)) {
3992  dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
3993  } else {
3994  dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
3995  }
3996  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
3997  ast_log(LOG_WARNING, "Error setting conference\n");
3998  close(fd);
3999  goto outrun;
4000  }
4001  if (musiconhold && (ast_test_flag64(confflags, CONFFLAG_MOH))) {
4002  ast_moh_stop(chan);
4003  musiconhold = 0;
4004  }
4005  if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
4006  !ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
4007  if (!ast_streamfile(chan, "conf-placeintoconf", ast_channel_language(chan))) {
4008  ast_waitstream(chan, "");
4009  }
4010  conf_play(chan, conf, ENTER);
4011  }
4012  }
4013  }
4014 
4015  /* trying to add moh for single person conf */
4016  if (ast_test_flag64(confflags, CONFFLAG_MOH) && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)) {
4017  if (conf->users == 1) {
4018  if (!musiconhold) {
4019  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
4020  musiconhold = 1;
4021  }
4022  } else {
4023  if (musiconhold) {
4024  ast_moh_stop(chan);
4025  musiconhold = 0;
4026  }
4027  }
4028  }
4029 
4030  /* Leave if the last marked user left */
4031  if (currentmarked == 0 && lastmarked != 0 && ast_test_flag64(confflags, CONFFLAG_MARKEDEXIT)) {
4032  if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
4033  ret = 0;
4034  } else {
4035  ret = -1;
4036  }
4037  break;
4038  }
4039 
4040  /* Throw a TestEvent if a user exit did not cause this user to leave the conference */
4041  if (conf->users != lastusers) {
4042  if (conf->users < lastusers) {
4043  ast_test_suite_event_notify("NOEXIT", "Message: CONFFLAG_MARKEDEXIT\r\nLastUsers: %d\r\nUsers: %d", lastusers, conf->users);
4044  }
4045  lastusers = conf->users;
4046  }
4047 
4048  /* Check if my modes have changed */
4049 
4050  /* If I should be muted but am still talker, mute me */
4051  if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
4052  RAII_VAR(struct ast_json *, status_blob, status_to_json(1), ast_json_unref);
4053  dahdic.confmode ^= DAHDI_CONF_TALKER;
4054  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
4055  ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
4056  ret = -1;
4057  break;
4058  }
4059 
4060  /* Indicate user is not talking anymore - change him to unmonitored state */
4062  set_user_talking(chan, conf, user, -1, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
4063  }
4064  meetme_stasis_generate_msg(conf, chan, user, meetme_mute_type(), status_blob);
4065  }
4066 
4067  /* If I should be un-muted but am not talker, un-mute me */
4068  if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
4069  RAII_VAR(struct ast_json *, status_blob, status_to_json(0), ast_json_unref);
4070  dahdic.confmode |= DAHDI_CONF_TALKER;
4071  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
4072  ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
4073  ret = -1;
4074  break;
4075  }
4076  meetme_stasis_generate_msg(conf, chan, user, meetme_mute_type(), status_blob);
4077  }
4078 
4079  if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
4080  (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
4081 
4082  RAII_VAR(struct ast_json *, status_blob, status_to_json(1), ast_json_unref);
4083  talkreq_manager = 1;
4084  meetme_stasis_generate_msg(conf, chan, user, meetme_talk_request_type(), status_blob);
4085  }
4086 
4087  if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
4088  !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
4089  RAII_VAR(struct ast_json *, status_blob, status_to_json(0), ast_json_unref);
4090  talkreq_manager = 0;
4091  meetme_stasis_generate_msg(conf, chan, user, meetme_talk_request_type(), status_blob);
4092  }
4093 
4094  /* If user have been hung up, exit the conference */
4095  if (user->adminflags & ADMINFLAG_HANGUP) {
4096  ret = 0;
4097  break;
4098  }
4099 
4100  /* If I have been kicked, exit the conference */
4101  if (user->adminflags & ADMINFLAG_KICKME) {
4102  /* You have been kicked. */
4103  if (!ast_test_flag64(confflags, CONFFLAG_QUIET) &&
4104  !ast_streamfile(chan, "conf-kicked", ast_channel_language(chan))) {
4105  ast_waitstream(chan, "");
4106  }
4107  ret = 0;
4108  break;
4109  }
4110 
4111  /* Perform a hangup check here since ast_waitfor_nandfds will not always be able to get a channel after a hangup has occurred */
4112  if (ast_check_hangup(chan)) {
4113  break;
4114  }
4115 
4116  c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
4117 
4118  if (c) {
4119  char dtmfstr[2] = "";
4120 
4121  if (ast_channel_fd(c, 0) != origfd || (user->dahdichannel && (ast_channel_audiohooks(c) || ast_channel_monitor(c)))) {
4122  if (using_pseudo) {
4123  /* Kill old pseudo */
4124  close(fd);
4125  using_pseudo = 0;
4126  }
4127  ast_debug(1, "Ooh, something swapped out under us, starting over\n");
4128  retrydahdi = (strcasecmp(ast_channel_tech(c)->type, "DAHDI") || (ast_channel_audiohooks(c) || ast_channel_monitor(c)) ? 1 : 0);
4129  user->dahdichannel = !retrydahdi;
4130  goto dahdiretry;
4131  }
4133  f = ast_read_noaudio(c);
4134  } else {
4135  f = ast_read(c);
4136  }
4137  if (!f) {
4138  break;
4139  }
4140  if (f->frametype == AST_FRAME_DTMF) {
4141  dtmfstr[0] = f->subclass.integer;
4142  dtmfstr[1] = '\0';
4143  }
4144 
4146  if (user->talk.actual) {
4148  }
4149 
4151  if (user->talking == -1) {
4152  user->talking = 0;
4153  }
4154 
4155  res = ast_dsp_silence(dsp, f, &totalsilence);
4156  if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
4157  set_user_talking(chan, conf, user, 1, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
4158  }
4159 
4160  if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
4161  set_user_talking(chan, conf, user, 0, ast_test_flag64(confflags, CONFFLAG_MONITORTALKER));
4162  }
4163  }
4164  if (using_pseudo) {
4165  /* Absolutely do _not_ use careful_write here...
4166  it is important that we read data from the channel
4167  as fast as it arrives, and feed it into the conference.
4168  The buffering in the pseudo channel will take care of any
4169  timing differences, unless they are so drastic as to lose
4170  audio frames (in which case carefully writing would only
4171  have delayed the audio even further).
4172  */
4173  /* As it turns out, we do want to use careful write. We just
4174  don't want to block, but we do want to at least *try*
4175  to write out all the samples.
4176  */
4177  if (user->talking || !ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER)) {
4178  careful_write(fd, f->data.ptr, f->datalen, 0);
4179  }
4180  }
4181  } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '*') && ast_test_flag64(confflags, CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_mode)) {
4182  if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
4183  conf_queue_dtmf(conf, user, f);
4184  }
4185  /* Take out of conference */
4186  if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
4187  ast_log(LOG_WARNING, "Error setting conference\n");
4188  close(fd);
4189  ast_frfree(f);
4190  goto outrun;
4191  }
4192 
4193  /* if we are entering the menu, and the user has a channel-driver
4194  volume adjustment, clear it
4195  */
4196  if (!menu_mode && user->talk.desired && !user->talk.actual) {
4197  set_talk_volume(user, 0);
4198  }
4199 
4200  if (musiconhold) {
4201  ast_moh_stop(chan);
4202  } else if (!menu_mode) {
4203  char *menu_to_play;
4204  if (ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
4205  menu_mode = MENU_ADMIN;
4206  menu_to_play = "conf-adminmenu-18";
4207  } else {
4208  menu_mode = MENU_NORMAL;
4209  menu_to_play = "conf-usermenu-162";
4210  }
4211 
4212  if (!ast_streamfile(chan, menu_to_play, ast_channel_language(chan))) {
4213  dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
4214  ast_stopstream(chan);
4215  } else {
4216  dtmf = 0;
4217  }
4218  } else {
4219  dtmf = f->subclass.integer;
4220  }
4221 
4222  if (dtmf > 0) {
4223  meetme_menu(&menu_mode, &dtmf, conf, confflags,
4224  chan, user, recordingtmp, sizeof(recordingtmp), cap_slin);
4225  }
4226 
4227  if (musiconhold && !menu_mode) {
4228  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
4229  }
4230 
4231  /* Put back into conference */
4232  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
4233  ast_log(LOG_WARNING, "Error setting conference\n");
4234  close(fd);
4235  ast_frfree(f);
4236  goto outrun;
4237  }
4238 
4239  conf_flush(fd, chan);
4240  /*
4241  * Since options using DTMF could absorb DTMF meant for the
4242  * conference menu, we have to check them after the menu.
4243  */
4244  } else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
4245  if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
4246  conf_queue_dtmf(conf, user, f);
4247  }
4248 
4249  if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
4250  ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
4251  ret = 0;
4252  ast_frfree(f);
4253  break;
4254  } else {
4255  ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
4256  }
4257  } else if ((f->frametype == AST_FRAME_DTMF) && ast_test_flag64(confflags, CONFFLAG_KEYEXIT) &&
4258  (strchr(exitkeys, f->subclass.integer))) {
4259  pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
4260 
4261  if (ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
4262  conf_queue_dtmf(conf, user, f);
4263  }
4264  ret = 0;
4265  ast_frfree(f);
4266  break;
4267  } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
4268  && ast_test_flag64(confflags, CONFFLAG_PASS_DTMF)) {
4269  conf_queue_dtmf(conf, user, f);
4270  } else if (ast_test_flag64(confflags, CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
4271  switch (f->subclass.integer) {
4272  case AST_CONTROL_HOLD:
4273  sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
4274  break;
4275  default:
4276  break;
4277  }
4278  } else if (f->frametype == AST_FRAME_NULL) {
4279  /* Ignore NULL frames. It is perfectly normal to get these if the person is muted. */
4280  } else if (f->frametype == AST_FRAME_CONTROL) {
4281  switch (f->subclass.integer) {
4282  case AST_CONTROL_BUSY:
4284  ast_frfree(f);
4285  goto outrun;
4286  break;
4287  default:
4288  ast_debug(1,
4289  "Got ignored control frame on channel %s, f->frametype=%u,f->subclass=%d\n",
4290  ast_channel_name(chan), f->frametype, f->subclass.integer);
4291  }
4292  } else {
4293  ast_debug(1,
4294  "Got unrecognized frame on channel %s, f->frametype=%u,f->subclass=%d\n",
4295  ast_channel_name(chan), f->frametype, f->subclass.integer);
4296  }
4297  ast_frfree(f);
4298  } else if (outfd > -1) {
4299  res = read(outfd, buf, CONF_SIZE);
4300  if (res > 0) {
4301  memset(&fr, 0, sizeof(fr));
4304  fr.datalen = res;
4305  fr.samples = res / 2;
4306  fr.data.ptr = buf;
4308  if (!user->listen.actual &&
4309  (ast_test_flag64(confflags, CONFFLAG_MONITOR) ||
4311  (!user->talking && ast_test_flag64(confflags, CONFFLAG_OPTIMIZETALKER))
4312  )) {
4313  int idx;
4314  for (idx = 0; idx < AST_FRAME_BITS; idx++) {
4316  break;
4317  }
4318  }
4319  if (idx >= AST_FRAME_BITS) {
4320  goto bailoutandtrynormal;
4321  }
4322  ast_mutex_lock(&conf->listenlock);
4323  if (!conf->transframe[idx]) {
4324  if (conf->origframe) {
4325  if (musiconhold
4326  && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)
4327  && !ast_dsp_silence(dsp, conf->origframe, &confsilence)
4328  && confsilence < MEETME_DELAYDETECTTALK) {
4329  ast_moh_stop(chan);
4330  mohtempstopped = 1;
4331  }
4332  if (!conf->transpath[idx]) {
4334  }
4335  if (conf->transpath[idx]) {
4336  conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
4337  if (!conf->transframe[idx]) {
4338  conf->transframe[idx] = &ast_null_frame;
4339  }
4340  }
4341  }
4342  }
4343  if (conf->transframe[idx]) {
4344  if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
4345  can_write(chan, confflags)) {
4346  struct ast_frame *cur;
4347  /* the translator may have returned a list of frames, so
4348  write each one onto the channel
4349  */
4350  for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
4351  if (ast_write(chan, cur)) {
4352  ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", ast_channel_name(chan));
4353  break;
4354  }
4355  }
4356  if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
4357  mohtempstopped = 0;
4358  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
4359  }
4360  }
4361  } else {
4362  ast_mutex_unlock(&conf->listenlock);
4363  goto bailoutandtrynormal;
4364  }
4365  ast_mutex_unlock(&conf->listenlock);
4366  } else {
4367 bailoutandtrynormal:
4368  if (musiconhold
4369  && !ast_test_flag64(confflags, CONFFLAG_WAITMARKED)
4370  && !ast_dsp_silence(dsp, &fr, &confsilence)
4371  && confsilence < MEETME_DELAYDETECTTALK) {
4372  ast_moh_stop(chan);
4373  mohtempstopped = 1;
4374  }
4375  if (user->listen.actual) {
4377  }
4378  if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
4379  ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", ast_channel_name(chan));
4380  }
4381  if (musiconhold && mohtempstopped && confsilence > MEETME_DELAYDETECTENDTALK) {
4382  mohtempstopped = 0;
4383  conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
4384  }
4385  }
4386  } else {
4387  ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
4388  }
4389  }
4390  lastmarked = currentmarked;
4391  }
4392  }
4393 
4394  if (musiconhold) {
4395  ast_moh_stop(chan);
4396  }
4397 
4398  if (using_pseudo) {
4399  close(fd);
4400  } else {
4401  /* Take out of conference */
4402  dahdic.chan = 0;
4403  dahdic.confno = 0;
4404  dahdic.confmode = 0;
4405  if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
4406  ast_log(LOG_WARNING, "Error setting conference\n");
4407  }
4408  }
4409 
4410  reset_volumes(user);
4411 
4412  if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && !ast_test_flag64(confflags, CONFFLAG_MONITOR) &&
4413  !ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
4414  conf_play(chan, conf, LEAVE);
4415  }
4416 
4418  struct announce_listitem *item;
4419  if (!(item = ao2_alloc(sizeof(*item), NULL)))
4420  goto outrun;
4421  ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
4422  ast_copy_string(item->language, ast_channel_language(chan), sizeof(item->language));
4423  item->confchan = conf->chan;
4424  item->confusers = conf->users;
4425  item->announcetype = CONF_HASLEFT;
4426  if (ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC)){
4427  item->vmrec = 1;
4428  }
4430  AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
4433  } else if (!ast_test_flag64(confflags, CONFFLAG_QUIET) && ast_test_flag64(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW) && !ast_test_flag64(confflags, CONFFLAG_INTROUSER_VMREC) && conf->users == 1) {
4434  /* Last person is leaving, so no reason to try and announce, but should delete the name recording */
4435  ast_filedelete(user->namerecloc, NULL);
4436  }
4437 
4438  outrun:
4439  AST_LIST_LOCK(&confs);
4440 
4441  if (dsp) {
4442  ast_dsp_free(dsp);
4443  }
4444 
4445  if (user->user_no) {
4446  /* Only cleanup users who really joined! */
4447  now = ast_tvnow();
4448 
4449  if (sent_event) {
4450  meetme_stasis_generate_msg(conf, chan, user, meetme_leave_type(), NULL);
4451  }
4452 
4453  if (setusercount) {
4454  conf->users--;
4455  if (rt_log_members) {
4456  /* Update table */
4457  snprintf(members, sizeof(members), "%d", conf->users);
4458  ast_realtime_require_field("meetme",
4459  "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
4460  "members", RQ_UINTEGER1, strlen(members),
4461  NULL);
4462  ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
4463  }
4464  if (ast_test_flag64(confflags, CONFFLAG_MARKEDUSER)) {
4465  conf->markedusers--;
4466  }
4467  }
4468  /* Remove ourselves from the container */
4469  ao2_unlink(conf->usercontainer, user);
4470 
4471  /* Change any states */
4472  if (!conf->users) {
4473  ast_devstate_changed(AST_DEVICE_NOT_INUSE, (conf->isdynamic ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), "meetme:%s", conf->confno);
4474  }
4475 
4476  /* This flag is meant to kill a conference with only one participant remaining. */
4477  if (conf->users == 1 && ast_test_flag64(confflags, CONFFLAG_KILL_LAST_MAN_STANDING)) {
4479  }
4480 
4481  /* Return the number of seconds the user was in the conf */
4482  snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
4483  pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
4484 
4485  /* Return the RealTime bookid for CDR linking */
4486  if (rt_schedule) {
4487  pbx_builtin_setvar_helper(chan, "MEETMEBOOKID", conf->bookid);
4488  }
4489  }
4490  ao2_ref(user, -1);
4492 
4493 
4494 conf_run_cleanup:
4495  ao2_cleanup(cap_slin);
4496 
4497  return ret;
4498 }
4499 
4500 static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic,
4501  char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags, int *too_early, char **optargs)
4502 {
4503  struct ast_variable *var, *origvar;
4504  struct ast_conference *cnf;
4505 
4506  *too_early = 0;
4507 
4508  /* Check first in the conference list */
4509  AST_LIST_LOCK(&confs);
4510  AST_LIST_TRAVERSE(&confs, cnf, list) {
4511  if (!strcmp(confno, cnf->confno)) {
4512  break;
4513  }
4514  }
4515  if (cnf) {
4516  cnf->refcount += refcount;
4517  }
4519 
4520  if (!cnf) {
4521  char *pin = NULL, *pinadmin = NULL; /* For temp use */
4522  int maxusers = 0;
4523  struct timeval now;
4524  char recordingfilename[256] = "";
4525  char recordingformat[11] = "";
4526  char currenttime[32] = "";
4527  char eatime[32] = "";
4528  char bookid[51] = "";
4529  char recordingtmp[AST_MAX_EXTENSION * 2] = "";
4530  char useropts[OPTIONS_LEN + 1] = ""; /* Used for RealTime conferences */
4531  char adminopts[OPTIONS_LEN + 1] = "";
4532  struct ast_tm tm, etm;
4533  struct timeval endtime = { .tv_sec = 0 };
4534  const char *var2;
4535 
4536  if (rt_schedule) {
4537  now = ast_tvnow();
4538 
4539  ast_localtime(&now, &tm, NULL);
4540  ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
4541 
4542  ast_debug(1, "Looking for conference %s that starts after %s\n", confno, currenttime);
4543 
4544  var = ast_load_realtime("meetme", "confno",
4545  confno, "starttime <= ", currenttime, "endtime >= ",
4546  currenttime, NULL);
4547 
4548  if (!var && fuzzystart) {
4549  now = ast_tvnow();
4550  now.tv_sec += fuzzystart;
4551 
4552  ast_localtime(&now, &tm, NULL);
4553  ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
4554  var = ast_load_realtime("meetme", "confno",
4555  confno, "starttime <= ", currenttime, "endtime >= ",
4556  currenttime, NULL);
4557  }
4558 
4559  if (!var && earlyalert) {
4560  now = ast_tvnow();
4561  now.tv_sec += earlyalert;
4562  ast_localtime(&now, &etm, NULL);
4563  ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
4564  var = ast_load_realtime("meetme", "confno",
4565  confno, "starttime <= ", eatime, "endtime >= ",
4566  currenttime, NULL);
4567  if (var) {
4568  *too_early = 1;
4569  }
4570  }
4571 
4572  } else {
4573  var = ast_load_realtime("meetme", "confno", confno, NULL);
4574  }
4575 
4576  if (!var) {
4577  return NULL;
4578  }
4579 
4580  if (rt_schedule && *too_early) {
4581  /* Announce that the caller is early and exit */
4582  if (!ast_streamfile(chan, "conf-has-not-started", ast_channel_language(chan))) {
4583  ast_waitstream(chan, "");
4584  }
4585  ast_variables_destroy(var);
4586  return NULL;
4587  }
4588 
4589  for (origvar = var; var; var = var->next) {
4590  if (!strcasecmp(var->name, "pin")) {
4591  pin = ast_strdupa(var->value);
4592  } else if (!strcasecmp(var->name, "adminpin")) {
4593  pinadmin = ast_strdupa(var->value);
4594  } else if (!strcasecmp(var->name, "bookId")) {
4595  ast_copy_string(bookid, var->value, sizeof(bookid));
4596  } else if (!strcasecmp(var->name, "opts")) {
4597  ast_copy_string(useropts, var->value, sizeof(char[OPTIONS_LEN + 1]));
4598  } else if (!strcasecmp(var->name, "maxusers")) {
4599  maxusers = atoi(var->value);
4600  } else if (!strcasecmp(var->name, "adminopts")) {
4601  ast_copy_string(adminopts, var->value, sizeof(char[OPTIONS_LEN + 1]));
4602  } else if (!strcasecmp(var->name, "recordingfilename")) {
4603  ast_copy_string(recordingfilename, var->value, sizeof(recordingfilename));
4604  } else if (!strcasecmp(var->name, "recordingformat")) {
4605  ast_copy_string(recordingformat, var->value, sizeof(recordingformat));
4606  } else if (!strcasecmp(var->name, "endtime")) {
4607  struct ast_tm endtime_tm;
4608  ast_strptime(var->value, "%Y-%m-%d %H:%M:%S", &endtime_tm);
4609  endtime = ast_mktime(&endtime_tm, NULL);
4610  }
4611  }
4612 
4613  ast_variables_destroy(origvar);
4614 
4615  cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan, NULL);
4616 
4617  if (cnf) {
4618  struct ast_flags64 tmp_flags;
4619 
4620  cnf->maxusers = maxusers;
4621  cnf->endalert = endalert;
4622  cnf->endtime = endtime.tv_sec;
4623  cnf->useropts = ast_strdup(useropts);
4624  cnf->adminopts = ast_strdup(adminopts);
4625  cnf->bookid = ast_strdup(bookid);
4626  if (!ast_strlen_zero(recordingfilename)) {
4627  cnf->recordingfilename = ast_strdup(recordingfilename);
4628  }
4629  if (!ast_strlen_zero(recordingformat)) {
4630  cnf->recordingformat = ast_strdup(recordingformat);
4631  }
4632 
4633  /* Parse the other options into confflags -- need to do this in two
4634  * steps, because the parse_options routine zeroes the buffer. */
4635  ast_app_parse_options64(meetme_opts, &tmp_flags, optargs, useropts);
4636  ast_copy_flags64(confflags, &tmp_flags, tmp_flags.flags);
4637 
4638  if (strchr(cnf->useropts, 'r')) {
4639  if (ast_strlen_zero(recordingfilename)) { /* If the recordingfilename in the database is empty, use the channel definition or use the default. */
4640  ast_channel_lock(chan);
4641  if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
4643  cnf->recordingfilename = ast_strdup(var2);
4644  }
4645  ast_channel_unlock(chan);
4646  if (ast_strlen_zero(cnf->recordingfilename)) {
4647  snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", cnf->confno, ast_channel_uniqueid(chan));
4649  cnf->recordingfilename = ast_strdup(recordingtmp);
4650  }
4651  }
4652  if (ast_strlen_zero(cnf->recordingformat)) {/* If the recording format is empty, use the wav as default */
4653  ast_channel_lock(chan);
4654  if ((var2 = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
4655  ast_free(cnf->recordingformat);
4656  cnf->recordingformat = ast_strdup(var2);
4657  }
4658  ast_channel_unlock(chan);
4659  if (ast_strlen_zero(cnf->recordingformat)) {
4660  ast_free(cnf->recordingformat);
4661  cnf->recordingformat = ast_strdup("wav");
4662  }
4663  }
4664  ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
4665  }
4666  }
4667  }
4668 
4669  if (cnf) {
4670  if (confflags->flags && !cnf->chan &&
4671  !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
4673  ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
4675  }
4676 
4677  if (confflags && !cnf->chan &&
4678  ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
4679  ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
4681  }
4682  }
4683 
4684  return cnf;
4685 }
4686 
4687 
4688 static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic,
4689  char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags)
4690 {
4691  struct ast_config *cfg;
4692  struct ast_variable *var;
4693  struct ast_flags config_flags = { 0 };
4694  struct ast_conference *cnf;
4695 
4696  AST_DECLARE_APP_ARGS(args,
4697  AST_APP_ARG(confno);
4698  AST_APP_ARG(pin);
4700  );
4701 
4702  /* Check first in the conference list */
4703  ast_debug(1, "The requested confno is '%s'?\n", confno);
4704  AST_LIST_LOCK(&confs);
4705  AST_LIST_TRAVERSE(&confs, cnf, list) {
4706  ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
4707  if (!strcmp(confno, cnf->confno))
4708  break;
4709  }
4710  if (cnf) {
4711  cnf->refcount += refcount;
4712  }
4714 
4715  if (!cnf) {
4716  if (dynamic) {
4717  /* No need to parse meetme.conf */
4718  ast_debug(1, "Building dynamic conference '%s'\n", confno);
4719  if (dynamic_pin) {
4720  if (dynamic_pin[0] == 'q') {
4721  /* Query the user to enter a PIN */
4722  if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
4723  return NULL;
4724  }
4725  cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan, NULL);
4726  } else {
4727  cnf = build_conf(confno, "", "", make, dynamic, refcount, chan, NULL);
4728  }
4729  } else {
4730  /* Check the config */
4731  cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
4732  if (!cfg) {
4733  ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
4734  return NULL;
4735  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
4736  ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n");
4737  return NULL;
4738  }
4739 
4740  for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
4741  char parse[MAX_SETTINGS];
4742 
4743  if (strcasecmp(var->name, "conf"))
4744  continue;
4745 
4746  ast_copy_string(parse, var->value, sizeof(parse));
4747 
4748  AST_STANDARD_APP_ARGS(args, parse);
4749  ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
4750  if (!strcasecmp(args.confno, confno)) {
4751  /* Bingo it's a valid conference */
4752  cnf = build_conf(args.confno,
4753  S_OR(args.pin, ""),
4754  S_OR(args.pinadmin, ""),
4755  make, dynamic, refcount, chan, NULL);
4756  break;
4757  }
4758  }
4759  if (!var) {
4760  ast_debug(1, "%s isn't a valid conference\n", confno);
4761  }
4762  ast_config_destroy(cfg);
4763  }
4764  } else if (dynamic_pin) {
4765  /* Correct for the user selecting 'D' instead of 'd' to have
4766  someone join into a conference that has already been created
4767  with a pin. */
4768  if (dynamic_pin[0] == 'q') {
4769  dynamic_pin[0] = '\0';
4770  }
4771  }
4772 
4773  if (cnf) {
4774  if (confflags && !cnf->chan &&
4775  !ast_test_flag64(confflags, CONFFLAG_QUIET) &&
4777  ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
4779  }
4780 
4781  if (confflags && !cnf->chan &&
4782  ast_test_flag64(confflags, CONFFLAG_RECORDCONF)) {
4783  ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
4785  }
4786  }
4787 
4788  return cnf;
4789 }
4790 
4791 /*! \brief The MeetmeCount application */
4792 static int count_exec(struct ast_channel *chan, const char *data)
4793 {
4794  int res = 0;
4795  struct ast_conference *conf;
4796  int count;
4797  char *localdata;
4798  char val[80] = "0";
4799  AST_DECLARE_APP_ARGS(args,
4801  AST_APP_ARG(varname);
4802  );
4803 
4804  if (ast_strlen_zero(data)) {
4805  ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
4806  return -1;
4807  }
4808 
4809  localdata = ast_strdupa(data);
4810 
4811  AST_STANDARD_APP_ARGS(args, localdata);
4812 
4813  conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
4814 
4815  if (conf) {
4816  count = conf->users;
4817  dispose_conf(conf);
4818  conf = NULL;
4819  } else
4820  count = 0;
4821 
4822  if (!ast_strlen_zero(args.varname)) {
4823  /* have var so load it and exit */
4824  snprintf(val, sizeof(val), "%d", count);
4825  pbx_builtin_setvar_helper(chan, args.varname, val);
4826  } else {
4827  if (ast_channel_state(chan) != AST_STATE_UP) {
4828  ast_answer(chan);
4829  }
4830  res = ast_say_number(chan, count, "", ast_channel_language(chan), (char *) NULL); /* Needs gender */
4831  }
4832 
4833  return res;
4834 }
4835 
4836 /*! \brief The meetme() application */
4837 static int conf_exec(struct ast_channel *chan, const char *data)
4838 {
4839  int res = -1;
4840  char confno[MAX_CONFNUM] = "";
4841  int allowretry = 0;
4842  int retrycnt = 0;
4843  struct ast_conference *cnf = NULL;
4844  struct ast_flags64 confflags = {0};
4845  struct ast_flags config_flags = { 0 };
4846  int dynamic = 0;
4847  int empty = 0, empty_no_pin = 0;
4848  int always_prompt = 0;
4849  const char *notdata;
4850  char *info, the_pin[MAX_PIN] = "";
4851  AST_DECLARE_APP_ARGS(args,
4852  AST_APP_ARG(confno);
4854  AST_APP_ARG(pin);
4855  );
4856  char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
4857 
4858  if (ast_strlen_zero(data)) {
4859  allowretry = 1;
4860  notdata = "";
4861  } else {
4862  notdata = data;
4863  }
4864 
4865  if (ast_channel_state(chan) != AST_STATE_UP)
4866  ast_answer(chan);
4867 
4868  info = ast_strdupa(notdata);
4869 
4870  AST_STANDARD_APP_ARGS(args, info);
4871 
4872  if (args.confno) {
4873  ast_copy_string(confno, args.confno, sizeof(confno));
4874  if (ast_strlen_zero(confno)) {
4875  allowretry = 1;
4876  }
4877  }
4878 
4879  if (args.pin)
4880  ast_copy_string(the_pin, args.pin, sizeof(the_pin));
4881 
4882  if (args.options) {
4883  ast_app_parse_options64(meetme_opts, &confflags, optargs, args.options);
4884  dynamic = ast_test_flag64(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
4885  if (ast_test_flag64(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
4886  strcpy(the_pin, "q");
4887 
4888  empty = ast_test_flag64(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
4889  empty_no_pin = ast_test_flag64(&confflags, CONFFLAG_EMPTYNOPIN);
4890  always_prompt = ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
4891  }
4892 
4893  do {
4894  if (retrycnt > 3)
4895  allowretry = 0;
4896  if (empty) {
4897  int i;
4898  struct ast_config *cfg;
4899  struct ast_variable *var;
4900  int confno_int;
4901 
4902  /* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
4903  if ((empty_no_pin) || (!dynamic)) {
4904  cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
4905  if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
4906  var = ast_variable_browse(cfg, "rooms");
4907  while (var) {
4908  char parse[MAX_SETTINGS], *stringp = parse, *confno_tmp;
4909  if (!strcasecmp(var->name, "conf")) {
4910  int found = 0;
4911  ast_copy_string(parse, var->value, sizeof(parse));
4912  confno_tmp = strsep(&stringp, "|,");
4913  if (!dynamic) {
4914  /* For static: run through the list and see if this conference is empty */
4915  AST_LIST_LOCK(&confs);
4916  AST_LIST_TRAVERSE(&confs, cnf, list) {
4917  if (!strcmp(confno_tmp, cnf->confno)) {
4918  /* The conference exists, therefore it's not empty */
4919  found = 1;
4920  break;
4921  }
4922  }
4924  cnf = NULL;
4925  if (!found) {
4926  /* At this point, we have a confno_tmp (static conference) that is empty */
4927  if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
4928  /* Case 1: empty_no_pin and pin is nonexistent (NULL)
4929  * Case 2: empty_no_pin and pin is blank (but not NULL)
4930  * Case 3: not empty_no_pin
4931  */
4932  ast_copy_string(confno, confno_tmp, sizeof(confno));
4933  break;
4934  }
4935  }
4936  }
4937  }
4938  var = var->next;
4939  }
4940  ast_config_destroy(cfg);
4941  }
4942 
4943  if (ast_strlen_zero(confno) && (cfg = ast_load_realtime_multientry("meetme", "confno LIKE", "%", SENTINEL))) {
4944  const char *catg;
4945  for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
4946  const char *confno_tmp = ast_variable_retrieve(cfg, catg, "confno");
4947  const char *pin_tmp = ast_variable_retrieve(cfg, catg, "pin");
4948  if (ast_strlen_zero(confno_tmp)) {
4949  continue;
4950  }
4951  if (!dynamic) {
4952  int found = 0;
4953  /* For static: run through the list and see if this conference is empty */
4954  AST_LIST_LOCK(&confs);
4955  AST_LIST_TRAVERSE(&confs, cnf, list) {
4956  if (!strcmp(confno_tmp, cnf->confno)) {
4957  /* The conference exists, therefore it's not empty */
4958  found = 1;
4959  break;
4960  }
4961  }
4963  if (!found) {
4964  /* At this point, we have a confno_tmp (realtime conference) that is empty */
4965  if ((empty_no_pin && ast_strlen_zero(pin_tmp)) || (!empty_no_pin)) {
4966  /* Case 1: empty_no_pin and pin is nonexistent (NULL)
4967  * Case 2: empty_no_pin and pin is blank (but not NULL)
4968  * Case 3: not empty_no_pin
4969  */
4970  ast_copy_string(confno, confno_tmp, sizeof(confno));
4971  break;
4972  }
4973  }
4974  }
4975  }
4976  ast_config_destroy(cfg);
4977  }
4978  }
4979 
4980  /* Select first conference number not in use */
4981  if (ast_strlen_zero(confno) && dynamic) {
4982  AST_LIST_LOCK(&confs);
4983  for (i = 0; i < ARRAY_LEN(conf_map); i++) {
4984  if (!conf_map[i]) {
4985  snprintf(confno, sizeof(confno), "%d", i);
4986  conf_map[i] = 1;
4987  break;
4988  }
4989  }
4991  }
4992 
4993  /* Not found? */
4994  if (ast_strlen_zero(confno)) {
4995  res = ast_streamfile(chan, "conf-noempty", ast_channel_language(chan));
4996  ast_test_suite_event_notify("PLAYBACK", "Message: conf-noempty");
4997  if (!res)
4998  ast_waitstream(chan, "");
4999  } else {
5000  if (sscanf(confno, "%30d", &confno_int) == 1) {
5001  if (!ast_test_flag64(&confflags, CONFFLAG_QUIET)) {
5002  res = ast_streamfile(chan, "conf-enteringno", ast_channel_language(chan));
5003  if (!res) {
5004  ast_waitstream(chan, "");
5005  res = ast_say_digits(chan, confno_int, "", ast_channel_language(chan));
5006  }
5007  }
5008  } else {
5009  ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
5010  }
5011  }
5012  }
5013 
5014  while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
5015  /* Prompt user for conference number */
5016  res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
5017  if (res < 0) {
5018  /* Don't try to validate when we catch an error */
5019  confno[0] = '\0';
5020  allowretry = 0;
5021  break;
5022  }
5023  }
5024  if (!ast_strlen_zero(confno)) {
5025  /* Check the validity of the conference */
5026  cnf = find_conf(chan, confno, 1, dynamic, the_pin,
5027  sizeof(the_pin), 1, &confflags);
5028  if (!cnf) {
5029  int too_early = 0;
5030 
5031  cnf = find_conf_realtime(chan, confno, 1, dynamic,
5032  the_pin, sizeof(the_pin), 1, &confflags, &too_early, optargs);
5033  if (rt_schedule && too_early)
5034  allowretry = 0;
5035  }
5036 
5037  if (!cnf) {
5038  if (allowretry) {
5039  confno[0] = '\0';
5040  res = ast_streamfile(chan, "conf-invalid", ast_channel_language(chan));
5041  if (!res)
5042  ast_waitstream(chan, "");
5043  res = -1;
5044  }
5045  } else {
5046  /* Conference requires a pin for specified access level */
5047  int req_pin = !ast_strlen_zero(cnf->pin) ||
5048  (!ast_strlen_zero(cnf->pinadmin) &&
5049  ast_test_flag64(&confflags, CONFFLAG_ADMIN));
5050  /* The following logic was derived from a
5051  * 4 variable truth table and defines which
5052  * circumstances are not exempt from pin
5053  * checking.
5054  * If this needs to be modified, write the
5055  * truth table back out from the boolean
5056  * expression AB+A'D+C', change the erroneous
5057  * result, and rederive the expression.
5058  * Variables:
5059  * A: pin provided?
5060  * B: always prompt?
5061  * C: dynamic?
5062  * D: has users? */
5063  int not_exempt = !cnf->isdynamic;
5064  not_exempt = not_exempt || (!ast_strlen_zero(args.pin) && ast_test_flag64(&confflags, CONFFLAG_ALWAYSPROMPT));
5065  not_exempt = not_exempt || (ast_strlen_zero(args.pin) && cnf->users);
5066  if (req_pin && not_exempt) {
5067  char pin[MAX_PIN] = "";
5068  int j;
5069 
5070  /* Allow the pin to be retried up to 3 times */
5071  for (j = 0; j < 3; j++) {
5072  if (*the_pin && (always_prompt == 0)) {
5073  ast_copy_string(pin, the_pin, sizeof(pin));
5074  res = 0;
5075  } else {
5076  /* Prompt user for pin if pin is required */
5077  ast_test_suite_event_notify("PLAYBACK", "Message: conf-getpin\r\n"
5078  "Channel: %s",
5079  ast_channel_name(chan));
5080  res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
5081  }
5082  if (res >= 0) {
5083  if ((!strcasecmp(pin, cnf->pin) &&
5084  (ast_strlen_zero(cnf->pinadmin) ||
5085  !ast_test_flag64(&confflags, CONFFLAG_ADMIN))) ||
5086  (!ast_strlen_zero(cnf->pinadmin) &&
5087  !strcasecmp(pin, cnf->pinadmin))) {
5088  /* Pin correct */
5089  allowretry = 0;
5090  if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin)) {
5091  if (!ast_strlen_zero(cnf->adminopts)) {
5092  char *opts = ast_strdupa(cnf->adminopts);
5093  ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
5094  }
5095  } else {
5096  if (!ast_strlen_zero(cnf->useropts)) {
5097  char *opts = ast_strdupa(cnf->useropts);
5098  ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
5099  }
5100  }
5101  /* Run the conference */
5102  ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n", cnf->confno, cnf->recordingfilename, cnf->recordingformat);
5103  res = conf_run(chan, cnf, &confflags, optargs);
5104  break;
5105  } else {
5106  /* Pin invalid */
5107  if (!ast_streamfile(chan, "conf-invalidpin", ast_channel_language(chan))) {
5108  res = ast_waitstream(chan, AST_DIGIT_ANY);
5109  ast_stopstream(chan);
5110  } else {
5111  ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
5112  break;
5113  }
5114  if (res < 0)
5115  break;
5116  pin[0] = res;
5117  pin[1] = '\0';
5118  res = -1;
5119  if (allowretry)
5120  confno[0] = '\0';
5121  }
5122  } else {
5123  /* failed when getting the pin */
5124  res = -1;
5125  allowretry = 0;
5126  /* see if we need to get rid of the conference */
5127  break;
5128  }
5129 
5130  /* Don't retry pin with a static pin */
5131  if (*the_pin && (always_prompt == 0)) {
5132  break;
5133  }
5134  }
5135  } else {
5136  /* No pin required */
5137  allowretry = 0;
5138 
5139  /* For RealTime conferences without a pin
5140  * should still support loading options
5141  */
5142  if (!ast_strlen_zero(cnf->useropts)) {
5143  char *opts = ast_strdupa(cnf->useropts);
5144  ast_app_parse_options64(meetme_opts, &confflags, optargs, opts);
5145  }
5146 
5147  /* Run the conference */
5148  res = conf_run(chan, cnf, &confflags, optargs);
5149  }
5150  dispose_conf(cnf);
5151  cnf = NULL;
5152  }
5153  }
5154  } while (allowretry);
5155 
5156  if (cnf)
5157  dispose_conf(cnf);
5158 
5159  return res;
5160 }
5161 
5162 static struct ast_conf_user *find_user(struct ast_conference *conf, const char *callerident)
5163 {
5164  struct ast_conf_user *user = NULL;
5165  int cid;
5166 
5167  if (conf && callerident && sscanf(callerident, "%30d", &cid) == 1) {
5168  user = ao2_find(conf->usercontainer, &cid, 0);
5169  /* reference decremented later in admin_exec */
5170  return user;
5171  }
5172  return NULL;
5173 }
5174 
5175 static int user_listen_volup_cb(void *obj, void *unused, int flags)
5176 {
5177  struct ast_conf_user *user = obj;
5178  tweak_listen_volume(user, VOL_UP);
5179  return 0;
5180 }
5181 
5182 static int user_listen_voldown_cb(void *obj, void *unused, int flags)
5183 {
5184  struct ast_conf_user *user = obj;
5186  return 0;
5187 }
5188 
5189 static int user_talk_volup_cb(void *obj, void *unused, int flags)
5190 {
5191  struct ast_conf_user *user = obj;
5192  tweak_talk_volume(user, VOL_UP);
5193  return 0;
5194 }
5195 
5196 static int user_talk_voldown_cb(void *obj, void *unused, int flags)
5197 {
5198  struct ast_conf_user *user = obj;
5199  tweak_talk_volume(user, VOL_DOWN);
5200  return 0;
5201 }
5202 
5203 static int user_reset_vol_cb(void *obj, void *unused, int flags)
5204 {
5205  struct ast_conf_user *user = obj;
5206  reset_volumes(user);
5207  return 0;
5208 }
5209 
5210 static int user_chan_cb(void *obj, void *args, int flags)
5211 {
5212  struct ast_conf_user *user = obj;
5213  const char *channel = args;
5214 
5215  if (!strcmp(ast_channel_name(user->chan), channel)) {
5216  return (CMP_MATCH | CMP_STOP);
5217  }
5218 
5219  return 0;
5220 }
5221 
5222 /*! \brief The MeetMeadmin application
5223 
5224  MeetMeAdmin(confno, command, caller) */
5225 static int admin_exec(struct ast_channel *chan, const char *data) {
5226  char *params;
5227  struct ast_conference *cnf;
5228  struct ast_conf_user *user = NULL;
5229  AST_DECLARE_APP_ARGS(args,
5230  AST_APP_ARG(confno);
5231  AST_APP_ARG(command);
5232  AST_APP_ARG(user);
5233  );
5234  int res = 0;
5235 
5236  if (ast_strlen_zero(data)) {
5237  ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
5238  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
5239  return -1;
5240  }
5241 
5242  params = ast_strdupa(data);
5243  AST_STANDARD_APP_ARGS(args, params);
5244 
5245  if (!args.command) {
5246  ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
5247  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOPARSE");
5248  return -1;
5249  }
5250 
5251  AST_LIST_LOCK(&confs);
5252  AST_LIST_TRAVERSE(&confs, cnf, list) {
5253  if (!strcmp(cnf->confno, args.confno))
5254  break;
5255  }
5256 
5257  if (!cnf) {
5258  ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
5260  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", "NOTFOUND");
5261  return 0;
5262  }
5263 
5265 
5266  if (args.user) {
5267  user = find_user(cnf, args.user);
5268  if (!user) {
5269  ast_log(LOG_NOTICE, "Specified User not found!\n");
5270  res = -2;
5271  goto usernotfound;
5272  }
5273  } else {
5274  /* fail for commands that require a user */
5275  switch (*args.command) {
5276  case 'm': /* Unmute */
5277  case 'M': /* Mute */
5278  case 't': /* Lower user's talk volume */
5279  case 'T': /* Raise user's talk volume */
5280  case 'u': /* Lower user's listen volume */
5281  case 'U': /* Raise user's listen volume */
5282  case 'r': /* Reset user's volume level */
5283  case 'k': /* Kick user */
5284  res = -2;
5285  ast_log(LOG_NOTICE, "No user specified!\n");
5286  goto usernotfound;
5287  default:
5288  break;
5289  }
5290  }
5291 
5292  switch (*args.command) {
5293  case 76: /* L: Lock */
5294  cnf->locked = 1;
5295  break;
5296  case 108: /* l: Unlock */
5297  cnf->locked = 0;
5298  break;
5299  case 75: /* K: kick all users */
5301  break;
5302  case 101: /* e: Eject last user*/
5303  {
5304  int max_no = 0;
5305  RAII_VAR(struct ast_conf_user *, eject_user, NULL, ao2_cleanup);
5306 
5308  eject_user = ao2_find(cnf->usercontainer, &max_no, 0);
5309  if (!eject_user) {
5310  res = -1;
5311  ast_log(LOG_NOTICE, "No last user to kick!\n");
5312  break;
5313  }
5314 
5315  if (!ast_test_flag64(&eject_user->userflags, CONFFLAG_ADMIN)) {
5316  eject_user->adminflags |= ADMINFLAG_KICKME;
5317  } else {
5318  res = -1;
5319  ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
5320  }
5321  break;
5322  }
5323  case 77: /* M: Mute */
5324  user->adminflags |= ADMINFLAG_MUTED;
5325  break;
5326  case 78: /* N: Mute all (non-admin) users */
5328  break;
5329  case 109: /* m: Unmute */
5331  break;
5332  case 110: /* n: Unmute all users */
5334  break;
5335  case 107: /* k: Kick user */
5336  user->adminflags |= ADMINFLAG_KICKME;
5337  break;
5338  case 118: /* v: Lower all users listen volume */
5340  break;
5341  case 86: /* V: Raise all users listen volume */
5343  break;
5344  case 115: /* s: Lower all users speaking volume */
5346  break;
5347  case 83: /* S: Raise all users speaking volume */
5349  break;
5350  case 82: /* R: Reset all volume levels */
5352  break;
5353  case 114: /* r: Reset user's volume level */
5354  reset_volumes(user);
5355  break;
5356  case 85: /* U: Raise user's listen volume */
5357  tweak_listen_volume(user, VOL_UP);
5358  break;
5359  case 117: /* u: Lower user's listen volume */
5361  break;
5362  case 84: /* T: Raise user's talk volume */
5363  tweak_talk_volume(user, VOL_UP);
5364  break;
5365  case 116: /* t: Lower user's talk volume */
5366  tweak_talk_volume(user, VOL_DOWN);
5367  break;
5368  case 'E': /* E: Extend conference */
5369  if (rt_extend_conf(args.confno)) {
5370  res = -1;
5371  }
5372  break;
5373  }
5374 
5375  if (args.user) {
5376  /* decrement reference from find_user */
5377  ao2_ref(user, -1);
5378  }
5379 usernotfound:
5381 
5382  dispose_conf(cnf);
5383  pbx_builtin_setvar_helper(chan, "MEETMEADMINSTATUS", res == -2 ? "NOTFOUND" : res ? "FAILED" : "OK");
5384 
5385  return 0;
5386 }
5387 
5388 /*! \brief The MeetMeChannelAdmin application
5389  MeetMeChannelAdmin(channel, command) */
5390 static int channel_admin_exec(struct ast_channel *chan, const char *data) {
5391  char *params;
5392  struct ast_conference *conf = NULL;
5393  struct ast_conf_user *user = NULL;
5394  AST_DECLARE_APP_ARGS(args,
5396  AST_APP_ARG(command);
5397  );
5398 
5399  if (ast_strlen_zero(data)) {
5400  ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
5401  return -1;
5402  }
5403 
5404  params = ast_strdupa(data);
5405  AST_STANDARD_APP_ARGS(args, params);
5406 
5407  if (!args.channel) {
5408  ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
5409  return -1;
5410  }
5411 
5412  if (!args.command) {
5413  ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
5414  return -1;
5415  }
5416 
5417  AST_LIST_LOCK(&confs);
5418  AST_LIST_TRAVERSE(&confs, conf, list) {
5419  if ((user = ao2_callback(conf->usercontainer, 0, user_chan_cb, args.channel))) {
5420  break;
5421  }
5422  }
5423 
5424  if (!user) {
5425  ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
5427  return 0;
5428  }
5429 
5430  /* perform the specified action */
5431  switch (*args.command) {
5432  case 77: /* M: Mute */
5433  user->adminflags |= ADMINFLAG_MUTED;
5434  break;
5435  case 109: /* m: Unmute */
5436  user->adminflags &= ~ADMINFLAG_MUTED;
5437  break;
5438  case 107: /* k: Kick user */
5439  user->adminflags |= ADMINFLAG_KICKME;
5440  break;
5441  default: /* unknown command */
5442  ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
5443  break;
5444  }
5445  ao2_ref(user, -1);
5447 
5448  return 0;
5449 }
5450 
5451 static int meetmemute(struct mansession *s, const struct message *m, int mute)
5452 {
5453  struct ast_conference *conf;
5454  struct ast_conf_user *user;
5455  const char *confid = astman_get_header(m, "Meetme");
5456  char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
5457  int userno;
5458 
5459  if (ast_strlen_zero(confid)) {
5460  astman_send_error(s, m, "Meetme conference not specified");
5461  return 0;
5462  }
5463 
5464  if (ast_strlen_zero(userid)) {
5465  astman_send_error(s, m, "Meetme user number not specified");
5466  return 0;
5467  }
5468 
5469  userno = strtoul(userid, &userid, 10);
5470 
5471  if (*userid) {
5472  astman_send_error(s, m, "Invalid user number");
5473  return 0;
5474  }
5475 
5476  /* Look in the conference list */
5477  AST_LIST_LOCK(&confs);
5478  AST_LIST_TRAVERSE(&confs, conf, list) {
5479  if (!strcmp(confid, conf->confno))
5480  break;
5481  }
5482 
5483  if (!conf) {
5485  astman_send_error(s, m, "Meetme conference does not exist");
5486  return 0;
5487  }
5488 
5489  user = ao2_find(conf->usercontainer, &userno, 0);
5490 
5491  if (!user) {
5493  astman_send_error(s, m, "User number not found");
5494  return 0;
5495  }
5496 
5497  if (mute)
5498  user->adminflags |= ADMINFLAG_MUTED; /* request user muting */
5499  else
5500  user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST); /* request user unmuting */
5501 
5503 
5504  ast_log(LOG_NOTICE, "Requested to %smute conf %s user %d userchan %s uniqueid %s\n", mute ? "" : "un", conf->confno, user->user_no, ast_channel_name(user->chan), ast_channel_uniqueid(user->chan));
5505 
5506  ao2_ref(user, -1);
5507  astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
5508  return 0;
5509 }
5510 
5511 static int action_meetmemute(struct mansession *s, const struct message *m)
5512 {
5513  return meetmemute(s, m, 1);
5514 }
5515 
5516 static int action_meetmeunmute(struct mansession *s, const struct message *m)
5517 {
5518  return meetmemute(s, m, 0);
5519 }
5520 
5521 static int action_meetmelist(struct mansession *s, const struct message *m)
5522 {
5523  const char *actionid = astman_get_header(m, "ActionID");
5524  const char *conference = astman_get_header(m, "Conference");
5525  char idText[80] = "";
5526  struct ast_conference *cnf;
5527  struct ast_conf_user *user;
5528  struct ao2_iterator user_iter;
5529  int total = 0;
5530 
5531  if (!ast_strlen_zero(actionid))
5532  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
5533 
5534  if (AST_LIST_EMPTY(&confs)) {
5535  astman_send_error(s, m, "No active conferences.");
5536  return 0;
5537  }
5538 
5539  astman_send_listack(s, m, "Meetme user list will follow", "start");
5540 
5541  /* Find the right conference */
5542  AST_LIST_LOCK(&confs);
5543  AST_LIST_TRAVERSE(&confs, cnf, list) {
5544  /* If we ask for one particular, and this isn't it, skip it */
5545  if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
5546  continue;
5547 
5548  /* Show all the users */
5549  user_iter = ao2_iterator_init(cnf->usercontainer, 0);
5550  while ((user = ao2_iterator_next(&user_iter))) {
5551  total++;
5552  astman_append(s,
5553  "Event: MeetmeList\r\n"
5554  "%s"
5555  "Conference: %s\r\n"
5556  "UserNumber: %d\r\n"
5557  "CallerIDNum: %s\r\n"
5558  "CallerIDName: %s\r\n"
5559  "ConnectedLineNum: %s\r\n"
5560  "ConnectedLineName: %s\r\n"
5561  "Channel: %s\r\n"
5562  "Admin: %s\r\n"
5563  "Role: %s\r\n"
5564  "MarkedUser: %s\r\n"
5565  "Muted: %s\r\n"
5566  "Talking: %s\r\n"
5567  "\r\n",
5568  idText,
5569  cnf->confno,
5570  user->user_no,
5571  S_COR(ast_channel_caller(user->chan)->id.number.valid, ast_channel_caller(user->chan)->id.number.str, "<unknown>"),
5572  S_COR(ast_channel_caller(user->chan)->id.name.valid, ast_channel_caller(user->chan)->id.name.str, "<no name>"),
5574  S_COR(ast_channel_connected(user->chan)->id.name.valid, ast_channel_connected(user->chan)->id.name.str, "<no name>"),
5575  ast_channel_name(user->chan),
5576  ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "Yes" : "No",
5577  ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "Listen only" : ast_test_flag64(&user->userflags, CONFFLAG_TALKER) ? "Talk only" : "Talk and listen",
5578  ast_test_flag64(&user->userflags, CONFFLAG_MARKEDUSER) ? "Yes" : "No",
5579  user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
5580  user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
5581  ao2_ref(user, -1);
5582  }
5583  ao2_iterator_destroy(&user_iter);
5584  }
5586 
5587  /* Send final confirmation */
5588  astman_send_list_complete_start(s, m, "MeetmeListComplete", total);
5590  return 0;
5591 }
5592 
5593 static int action_meetmelistrooms(struct mansession *s, const struct message *m)
5594 {
5595  const char *actionid = astman_get_header(m, "ActionID");
5596  char idText[80] = "";
5597  struct ast_conference *cnf;
5598  int totalitems = 0;
5599  int hr, min, sec;
5600  time_t now;
5601  char markedusers[5];
5602 
5603  if (!ast_strlen_zero(actionid)) {
5604  snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
5605  }
5606 
5607  if (AST_LIST_EMPTY(&confs)) {
5608  astman_send_error(s, m, "No active conferences.");
5609  return 0;
5610  }
5611 
5612  astman_send_listack(s, m, "Meetme conferences will follow", "start");
5613 
5614  now = time(NULL);
5615 
5616  /* Traverse the conference list */
5617  AST_LIST_LOCK(&confs);
5618  AST_LIST_TRAVERSE(&confs, cnf, list) {
5619  totalitems++;
5620 
5621  if (cnf->markedusers == 0) {
5622  strcpy(markedusers, "N/A");
5623  } else {
5624  sprintf(markedusers, "%.4d", cnf->markedusers);
5625  }
5626  hr = (now - cnf->start) / 3600;
5627  min = ((now - cnf->start) % 3600) / 60;
5628  sec = (now - cnf->start) % 60;
5629 
5630  astman_append(s,
5631  "Event: MeetmeListRooms\r\n"
5632  "%s"
5633  "Conference: %s\r\n"
5634  "Parties: %d\r\n"
5635  "Marked: %s\r\n"
5636  "Activity: %2.2d:%2.2d:%2.2d\r\n"
5637  "Creation: %s\r\n"
5638  "Locked: %s\r\n"
5639  "\r\n",
5640  idText,
5641  cnf->confno,
5642  cnf->users,
5643  markedusers,
5644  hr, min, sec,
5645  cnf->isdynamic ? "Dynamic" : "Static",
5646  cnf->locked ? "Yes" : "No");
5647  }
5649 
5650  /* Send final confirmation */
5651  astman_send_list_complete_start(s, m, "MeetmeListRoomsComplete", totalitems);
5653  return 0;
5654 }
5655 
5656 /*! \internal
5657  * \brief creates directory structure and assigns absolute path from relative paths for filenames
5658  *
5659  * \param filename contains the absolute or relative path to the desired file
5660  * \param buffer stores completed filename, absolutely must be a buffer of PATH_MAX length
5661  */
5662 static void filename_parse(char *filename, char *buffer)
5663 {
5664  char *slash;
5665  if (ast_strlen_zero(filename)) {
5666  ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
5667  } else if (filename[0] != '/') {
5668  snprintf(buffer, PATH_MAX, "%s/meetme/%s", ast_config_AST_SPOOL_DIR, filename);
5669  } else {
5670  ast_copy_string(buffer, filename, PATH_MAX);
5671  }
5672 
5673  slash = buffer;
5674  if ((slash = strrchr(slash, '/'))) {
5675  *slash = '\0';
5676  ast_mkdir(buffer, 0777);
5677  *slash = '/';
5678  }
5679 }
5680 
5681 static void *recordthread(void *args)
5682 {
5683  struct ast_conference *cnf = args;
5684  struct ast_frame *f = NULL;
5685  int flags;
5686  struct ast_filestream *s = NULL;
5687  int res = 0;
5688  int x;
5689  const char *oldrecordingfilename = NULL;
5690  char filename_buffer[PATH_MAX];
5691 
5692  if (!cnf || !cnf->lchan) {
5693  pthread_exit(0);
5694  }
5695 
5696  filename_buffer[0] = '\0';
5697  filename_parse(cnf->recordingfilename, filename_buffer);
5698 
5699  ast_stopstream(cnf->lchan);
5700  flags = O_CREAT | O_TRUNC | O_WRONLY;
5701 
5702 
5704  while (ast_waitfor(cnf->lchan, -1) > -1) {
5705  if (cnf->recording == MEETME_RECORD_TERMINATE) {
5706  AST_LIST_LOCK(&confs);
5708  break;
5709  }
5710  if (!s && !(ast_strlen_zero(filename_buffer)) && (filename_buffer != oldrecordingfilename)) {
5711  s = ast_writefile(filename_buffer, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
5712  oldrecordingfilename = filename_buffer;
5713  }
5714 
5715  f = ast_read(cnf->lchan);
5716  if (!f) {
5717  res = -1;
5718  break;
5719  }
5720  if (f->frametype == AST_FRAME_VOICE) {
5721  ast_mutex_lock(&cnf->listenlock);
5722  for (x = 0; x < AST_FRAME_BITS; x++) {
5723  /* Free any translations that have occured */
5724  if (cnf->transframe[x]) {
5725  ast_frfree(cnf->transframe[x]);
5726  cnf->transframe[x] = NULL;
5727  }
5728  }
5729  if (cnf->origframe)
5730  ast_frfree(cnf->origframe);
5731  cnf->origframe = ast_frdup(f);
5733  if (s)
5734  res = ast_writestream(s, f);
5735  if (res) {
5736  ast_frfree(f);
5737  break;
5738  }
5739  }
5740  ast_frfree(f);
5741  }
5743  if (s)
5744  ast_closestream(s);
5745 
5746  pthread_exit(0);
5747 }
5748 
5749 /*! \brief Callback for devicestate providers */
5750 static enum ast_device_state meetmestate(const char *data)
5751 {
5752  struct ast_conference *conf;
5753 
5754  /* Find conference */
5755  AST_LIST_LOCK(&confs);
5756  AST_LIST_TRAVERSE(&confs, conf, list) {
5757  if (!strcmp(data, conf->confno))
5758  break;
5759  }
5761  if (!conf)
5762  return AST_DEVICE_INVALID;
5763 
5764 
5765  /* SKREP to fill */
5766  if (!conf->users)
5767  return AST_DEVICE_NOT_INUSE;
5768 
5769  return AST_DEVICE_INUSE;
5770 }
5771 
5772 static void meetme_set_defaults(void)
5773 {
5774  /* Scheduling support is off by default */
5775  rt_schedule = 0;
5776  fuzzystart = 0;
5777  earlyalert = 0;
5778  endalert = 0;
5779  extendby = 0;
5780 
5781  /* Logging of participants defaults to ON for compatibility reasons */
5782  rt_log_members = 1;
5783 
5784  /* Set default number of buffers to be allocated. */
5785  audio_buffers = DEFAULT_AUDIO_BUFFERS;
5786 }
5787 
5788 static void load_config_meetme(int reload)
5789 {
5790  struct ast_config *cfg;
5791  struct ast_flags config_flags = { 0 };
5792  const char *val;
5793 
5794  if (!reload) {
5796  }
5797 
5798  if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags))) {
5799  return;
5800  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
5801  ast_log(LOG_ERROR, "Config file " CONFIG_FILE_NAME " is in an invalid format. Aborting.\n");
5802  return;
5803  }
5804 
5805  if (reload) {
5807  }
5808 
5809  if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
5810  if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
5811  ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
5812  audio_buffers = DEFAULT_AUDIO_BUFFERS;
5813  } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
5814  ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
5815  DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
5816  audio_buffers = DEFAULT_AUDIO_BUFFERS;
5817  }
5818  if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
5819  ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
5820  }
5821 
5822  if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
5823  rt_schedule = ast_true(val);
5824  if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
5825  rt_log_members = ast_true(val);
5826  if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
5827  if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
5828  ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
5829  fuzzystart = 0;
5830  }
5831  }
5832  if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
5833  if ((sscanf(val, "%30d", &earlyalert) != 1)) {
5834  ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
5835  earlyalert = 0;
5836  }
5837  }
5838  if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
5839  if ((sscanf(val, "%30d", &endalert) != 1)) {
5840  ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
5841  endalert = 0;
5842  }
5843  }
5844  if ((val = ast_variable_retrieve(cfg, "general", "extendby"))) {
5845  if ((sscanf(val, "%30d", &extendby) != 1)) {
5846  ast_log(LOG_WARNING, "extendby must be a number, not '%s'\n", val);
5847  extendby = 0;
5848  }
5849  }
5850 
5851  ast_config_destroy(cfg);
5852 }
5853 
5854 /*!
5855  * \internal
5856  * \brief Find an SLA trunk by name
5857  */
5858 static struct sla_trunk *sla_find_trunk(const char *name)
5859 {
5860  struct sla_trunk tmp_trunk = {
5861  .name = name,
5862  };
5863 
5864  return ao2_find(sla_trunks, &tmp_trunk, OBJ_POINTER);
5865 }
5866 
5867 /*!
5868  * \internal
5869  * \brief Find an SLA station by name
5870  */
5871 static struct sla_station *sla_find_station(const char *name)
5872 {
5873  struct sla_station tmp_station = {
5874  .name = name,
5875  };
5876 
5877  return ao2_find(sla_stations, &tmp_station, OBJ_POINTER);
5878 }
5879 
5880 static int sla_check_station_hold_access(const struct sla_trunk *trunk,
5881  const struct sla_station *station)
5882 {
5883  struct sla_station_ref *station_ref;
5884  struct sla_trunk_ref *trunk_ref;
5885 
5886  /* For each station that has this call on hold, check for private hold. */
5887  AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
5888  AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
5889  if (trunk_ref->trunk != trunk || station_ref->station == station)
5890  continue;
5891  if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
5892  station_ref->station->hold_access == SLA_HOLD_PRIVATE)
5893  return 1;
5894  return 0;
5895  }
5896  }
5897 
5898  return 0;
5899 }
5900 
5901 /*!
5902  * \brief Find a trunk reference on a station by name
5903  * \param station the station
5904  * \param name the trunk's name
5905  * \pre sla_station is locked
5906  * \return a pointer to the station's trunk reference. If the trunk
5907  * is not found, it is not idle and barge is disabled, or if
5908  * it is on hold and private hold is set, then NULL will be returned.
5909  */
5910 static struct sla_trunk_ref *sla_find_trunk_ref_byname(const struct sla_station *station,
5911  const char *name)
5912 {
5913  struct sla_trunk_ref *trunk_ref = NULL;
5914 
5915  AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
5916  if (strcasecmp(trunk_ref->trunk->name, name))
5917  continue;
5918 
5919  if ( (trunk_ref->trunk->barge_disabled
5920  && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
5921  (trunk_ref->trunk->hold_stations
5922  && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
5923  && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
5924  sla_check_station_hold_access(trunk_ref->trunk, station) )
5925  {
5926  trunk_ref = NULL;
5927  }
5928 
5929  break;
5930  }
5931 
5932  if (trunk_ref) {
5933  ao2_ref(trunk_ref, 1);
5934  }
5935 
5936  return trunk_ref;
5937 }
5938 
5939 static void sla_station_ref_destructor(void *obj)
5940 {
5941  struct sla_station_ref *station_ref = obj;
5942 
5943  if (station_ref->station) {
5944  ao2_ref(station_ref->station, -1);
5945  station_ref->station = NULL;
5946  }
5947 }
5948 
5950 {
5951  struct sla_station_ref *station_ref;
5952 
5953  if (!(station_ref = ao2_alloc(sizeof(*station_ref), sla_station_ref_destructor))) {
5954  return NULL;
5955  }
5956 
5957  ao2_ref(station, 1);
5958  station_ref->station = station;
5959 
5960  return station_ref;
5961 }
5962 
5964 {
5965  struct sla_ringing_station *ringing_station;
5966 
5967  if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
5968  return NULL;
5969 
5970  ao2_ref(station, 1);
5971  ringing_station->station = station;
5972  ringing_station->ring_begin = ast_tvnow();
5973 
5974  return ringing_station;
5975 }
5976 
5977 static void sla_ringing_station_destroy(struct sla_ringing_station *ringing_station)
5978 {
5979  if (ringing_station->station) {
5980  ao2_ref(ringing_station->station, -1);
5981  ringing_station->station = NULL;
5982  }
5983 
5984  ast_free(ringing_station);
5985 }
5986 
5988 {
5989  struct sla_failed_station *failed_station;
5990 
5991  if (!(failed_station = ast_calloc(1, sizeof(*failed_station)))) {
5992  return NULL;
5993  }
5994 
5995  ao2_ref(station, 1);
5996  failed_station->station = station;
5997  failed_station->last_try = ast_tvnow();
5998 
5999  return failed_station;
6000 }
6001 
6002 static void sla_failed_station_destroy(struct sla_failed_station *failed_station)
6003 {
6004  if (failed_station->station) {
6005  ao2_ref(failed_station->station, -1);
6006  failed_station->station = NULL;
6007  }
6008 
6009  ast_free(failed_station);
6010 }
6011 
6013 {
6014  switch (state) {
6015  case SLA_TRUNK_STATE_IDLE:
6016  return AST_DEVICE_NOT_INUSE;
6018  return AST_DEVICE_RINGING;
6019  case SLA_TRUNK_STATE_UP:
6020  return AST_DEVICE_INUSE;
6023  return AST_DEVICE_ONHOLD;
6024  }
6025 
6026  return AST_DEVICE_UNKNOWN;
6027 }
6028 
6029 static void sla_change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk_state state,
6030  enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
6031 {
6032  struct sla_station *station;
6033  struct sla_trunk_ref *trunk_ref;
6034  struct ao2_iterator i;
6035 
6036  i = ao2_iterator_init(sla_stations, 0);
6037  while ((station = ao2_iterator_next(&i))) {
6038  ao2_lock(station);
6039  AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
6040  if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
6041  || trunk_ref == exclude) {
6042  continue;
6043  }
6044  trunk_ref->state = state;
6046  "SLA:%s_%s", station->name, trunk->name);
6047  break;
6048  }
6049  ao2_unlock(station);
6050  ao2_ref(station, -1);
6051  }
6053 }
6054 
6060 };
6061 
6062 static void answer_trunk_chan(struct ast_channel *chan)
6063 {
6064  ast_answer(chan);
6065  ast_indicate(chan, -1);
6066 }
6067 
6068 static void *run_station(void *data)
6069 {
6070  RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
6071  RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
6072  struct ast_str *conf_name = ast_str_create(16);
6073  struct ast_flags64 conf_flags = { 0 };
6074  struct ast_conference *conf;
6075 
6076  {
6077  struct run_station_args *args = data;
6078  station = args->station;
6079  trunk_ref = args->trunk_ref;
6080  ast_mutex_lock(args->cond_lock);
6081  ast_cond_signal(args->cond);
6082  ast_mutex_unlock(args->cond_lock);
6083  /* args is no longer valid here. */
6084  }
6085 
6087  ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
6088  ast_set_flag64(&conf_flags,
6091  conf = build_conf(ast_str_buffer(conf_name), "", "", 0, 0, 1, trunk_ref->chan, NULL);
6092  if (conf) {
6093  conf_run(trunk_ref->chan, conf, &conf_flags, NULL);
6094  dispose_conf(conf);
6095  conf = NULL;
6096  }
6097  trunk_ref->chan = NULL;
6100  ast_str_append(&conf_name, 0, ",K");
6101  admin_exec(NULL, ast_str_buffer(conf_name));
6104  }
6105 
6108  station->dial = NULL;
6109  ast_free(conf_name);
6110 
6111  return NULL;
6112 }
6113 
6114 static void sla_ringing_trunk_destroy(struct sla_ringing_trunk *ringing_trunk);
6115 
6116 static void sla_stop_ringing_trunk(struct sla_ringing_trunk *ringing_trunk)
6117 {
6118  char buf[80];
6119  struct sla_station_ref *station_ref;
6120 
6121  snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
6122  admin_exec(NULL, buf);
6124 
6125  while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry))) {
6126  ao2_ref(station_ref, -1);
6127  }
6128 
6129  sla_ringing_trunk_destroy(ringing_trunk);
6130 }
6131 
6132 static void sla_stop_ringing_station(struct sla_ringing_station *ringing_station,
6134 {
6135  struct sla_ringing_trunk *ringing_trunk;
6136  struct sla_trunk_ref *trunk_ref;
6137  struct sla_station_ref *station_ref;
6138 
6139  ast_dial_join(ringing_station->station->dial);
6140  ast_dial_destroy(ringing_station->station->dial);
6141  ringing_station->station->dial = NULL;
6142 
6143  if (hangup == SLA_STATION_HANGUP_NORMAL)
6144  goto done;
6145 
6146  /* If the station is being hung up because of a timeout, then add it to the
6147  * list of timed out stations on each of the ringing trunks. This is so
6148  * that when doing further processing to figure out which stations should be
6149  * ringing, which trunk to answer, determining timeouts, etc., we know which
6150  * ringing trunks we should ignore. */
6151  AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
6152  AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
6153  if (ringing_trunk->trunk == trunk_ref->trunk)
6154  break;
6155  }
6156  if (!trunk_ref)
6157  continue;
6158  if (!(station_ref = sla_create_station_ref(ringing_station->station)))
6159  continue;
6160  AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
6161  }
6162 
6163 done:
6164  sla_ringing_station_destroy(ringing_station);
6165 }
6166 
6167 static void sla_dial_state_callback(struct ast_dial *dial)
6168 {
6170 }
6171 
6172 /*! \brief Check to see if dialing this station already timed out for this ringing trunk
6173  * \note Assumes sla.lock is locked
6174  */
6175 static int sla_check_timed_out_station(const struct sla_ringing_trunk *ringing_trunk,
6176  const struct sla_station *station)
6177 {
6178  struct sla_station_ref *timed_out_station;
6179 
6180  AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
6181  if (station == timed_out_station->station)
6182  return 1;
6183  }
6184 
6185  return 0;
6186 }
6187 
6188 /*! \brief Choose the highest priority ringing trunk for a station
6189  * \param station the station
6190  * \param rm remove the ringing trunk once selected
6191  * \param trunk_ref a place to store the pointer to this stations reference to
6192  * the selected trunk
6193  * \return a pointer to the selected ringing trunk, or NULL if none found
6194  * \note Assumes that sla.lock is locked
6195  */
6197  struct sla_trunk_ref **trunk_ref, int rm)
6198 {
6199  struct sla_trunk_ref *s_trunk_ref;
6200  struct sla_ringing_trunk *ringing_trunk = NULL;
6201 
6202  AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
6203  AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
6204  /* Make sure this is the trunk we're looking for */
6205  if (s_trunk_ref->trunk != ringing_trunk->trunk)
6206  continue;
6207 
6208  /* This trunk on the station is ringing. But, make sure this station
6209  * didn't already time out while this trunk was ringing. */
6210  if (sla_check_timed_out_station(ringing_trunk, station))
6211  continue;
6212 
6213  if (rm)
6215 
6216  if (trunk_ref) {
6217  ao2_ref(s_trunk_ref, 1);
6218  *trunk_ref = s_trunk_ref;
6219  }
6220 
6221  break;
6222  }
6224 
6225  if (ringing_trunk)
6226  break;
6227  }
6228 
6229  return ringing_trunk;
6230 }
6231 
6233 {
6234  struct sla_ringing_station *ringing_station;
6235 
6236  AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
6237  RAII_VAR(struct sla_trunk_ref *, s_trunk_ref, NULL, ao2_cleanup);
6238  struct sla_ringing_trunk *ringing_trunk = NULL;
6239  struct run_station_args args;
6240  enum ast_dial_result dial_res;
6241  pthread_t dont_care;
6243  ast_cond_t cond;
6244 
6245  switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
6253  break;
6256  /* Find the appropriate trunk to answer. */
6257  ast_mutex_lock(&sla.lock);
6258  ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
6259  ast_mutex_unlock(&sla.lock);
6260  if (!ringing_trunk) {
6261  /* This case happens in a bit of a race condition. If two stations answer
6262  * the outbound call at the same time, the first one will get connected to
6263  * the trunk. When the second one gets here, it will not see any trunks
6264  * ringing so we have no idea what to conect it to. So, we just hang up
6265  * on it. */
6266  ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
6267  ast_dial_join(ringing_station->station->dial);
6268  ast_dial_destroy(ringing_station->station->dial);
6269  ringing_station->station->dial = NULL;
6270  sla_ringing_station_destroy(ringing_station);
6271  break;
6272  }
6273  /* Track the channel that answered this trunk */
6274  s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
6275  /* Actually answer the trunk */
6276  answer_trunk_chan(ringing_trunk->trunk->chan);
6278  /* Now, start a thread that will connect this station to the trunk. The rest of
6279  * the code here sets up the thread and ensures that it is able to save the arguments
6280  * before they are no longer valid since they are allocated on the stack. */
6281  ao2_ref(s_trunk_ref, 1);
6282  args.trunk_ref = s_trunk_ref;
6283  ao2_ref(ringing_station->station, 1);
6284  args.station = ringing_station->station;
6285  args.cond = &cond;
6286  args.cond_lock = &cond_lock;
6287  sla_ringing_trunk_destroy(ringing_trunk);
6288  sla_ringing_station_destroy(ringing_station);
6289  ast_mutex_init(&cond_lock);
6290  ast_cond_init(&cond, NULL);
6291  ast_mutex_lock(&cond_lock);
6293  ast_cond_wait(&cond, &cond_lock);
6294  ast_mutex_unlock(&cond_lock);
6295  ast_mutex_destroy(&cond_lock);
6296  ast_cond_destroy(&cond);
6297  break;
6302  break;
6303  }
6304  if (dial_res == AST_DIAL_RESULT_ANSWERED) {
6305  /* Queue up reprocessing ringing trunks, and then ringing stations again */
6308  break;
6309  }
6310  }
6312 }
6313 
6314 /*! \brief Check to see if this station is already ringing
6315  * \note Assumes sla.lock is locked
6316  */
6318 {
6319  struct sla_ringing_station *ringing_station;
6320 
6321  AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
6322  if (station == ringing_station->station)
6323  return 1;
6324  }
6325 
6326  return 0;
6327 }
6328 
6329 /*! \brief Check to see if this station has failed to be dialed in the past minute
6330  * \note assumes sla.lock is locked
6331  */
6333 {
6334  struct sla_failed_station *failed_station;
6335  int res = 0;
6336 
6337  AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
6338  if (station != failed_station->station)
6339  continue;
6340  if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
6342  sla_failed_station_destroy(failed_station);
6343  break;
6344  }
6345  res = 1;
6346  }
6348 
6349  return res;
6350 }
6351 
6352 /*! \brief Ring a station
6353  * \note Assumes sla.lock is locked
6354  */
6355 static int sla_ring_station(struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
6356 {
6357  char *tech, *tech_data;
6358  struct ast_dial *dial;
6359  struct sla_ringing_station *ringing_station;
6360  enum ast_dial_result res;
6361  int caller_is_saved;
6362  struct ast_party_caller caller;
6363 
6364  if (!(dial = ast_dial_create()))
6365  return -1;
6366 
6368  tech_data = ast_strdupa(station->device);
6369  tech = strsep(&tech_data, "/");
6370 
6371  if (ast_dial_append(dial, tech, tech_data, NULL) == -1) {
6372  ast_dial_destroy(dial);
6373  return -1;
6374  }
6375 
6376  /* Do we need to save off the caller ID data? */
6377  caller_is_saved = 0;
6378  if (!sla.attempt_callerid) {
6379  caller_is_saved = 1;
6380  caller = *ast_channel_caller(ringing_trunk->trunk->chan);
6382  }
6383 
6384  res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
6385 
6386  /* Restore saved caller ID */
6387  if (caller_is_saved) {
6389  ast_channel_caller_set(ringing_trunk->trunk->chan, &caller);
6390  }
6391 
6392  if (res != AST_DIAL_RESULT_TRYING) {
6393  struct sla_failed_station *failed_station;
6394  ast_dial_destroy(dial);
6395  if ((failed_station = sla_create_failed_station(station))) {
6396  AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
6397  }
6398  return -1;
6399  }
6400  if (!(ringing_station = sla_create_ringing_station(station))) {
6401  ast_dial_join(dial);
6402  ast_dial_destroy(dial);
6403  return -1;
6404  }
6405 
6406  station->dial = dial;
6407 
6408  AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
6409 
6410  return 0;
6411 }
6412 
6413 /*! \brief Check to see if a station is in use
6414  */
6416 {
6417  struct sla_trunk_ref *trunk_ref;
6418 
6419  AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
6420  if (trunk_ref->chan)
6421  return 1;
6422  }
6423 
6424  return 0;
6425 }
6426 
6427 static struct sla_trunk_ref *sla_find_trunk_ref(const struct sla_station *station,
6428  const struct sla_trunk *trunk)
6429 {
6430  struct sla_trunk_ref *trunk_ref = NULL;
6431 
6432  AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
6433  if (trunk_ref->trunk == trunk)
6434  break;
6435  }
6436 
6437  ao2_ref(trunk_ref, 1);
6438 
6439  return trunk_ref;
6440 }
6441 
6442 /*! \brief Calculate the ring delay for a given ringing trunk on a station
6443  * \param station the station
6444  * \param ringing_trunk the trunk. If NULL, the highest priority ringing trunk will be used
6445  * \return the number of ms left before the delay is complete, or INT_MAX if there is no delay
6446  */
6447 static int sla_check_station_delay(struct sla_station *station,
6448  struct sla_ringing_trunk *ringing_trunk)
6449 {
6450  RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
6451  unsigned int delay = UINT_MAX;
6452  int time_left, time_elapsed;
6453 
6454  if (!ringing_trunk)
6455  ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
6456  else
6457  trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
6458 
6459  if (!ringing_trunk || !trunk_ref)
6460  return delay;
6461 
6462  /* If this station has a ring delay specific to the highest priority
6463  * ringing trunk, use that. Otherwise, use the ring delay specified
6464  * globally for the station. */
6465  delay = trunk_ref->ring_delay;
6466  if (!delay)
6467  delay = station->ring_delay;
6468  if (!delay)
6469  return INT_MAX;
6470 
6471  time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
6472  time_left = (delay * 1000) - time_elapsed;
6473 
6474  return time_left;
6475 }
6476 
6477 /*! \brief Ring stations based on current set of ringing trunks
6478  * \note Assumes that sla.lock is locked
6479  */
6480 static void sla_ring_stations(void)
6481 {
6482  struct sla_station_ref *station_ref;
6483  struct sla_ringing_trunk *ringing_trunk;
6484 
6485  /* Make sure that every station that uses at least one of the ringing
6486  * trunks, is ringing. */
6487  AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
6488  AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
6489  int time_left;
6490 
6491  /* Is this station already ringing? */
6492  if (sla_check_ringing_station(station_ref->station))
6493  continue;
6494 
6495  /* Is this station already in a call? */
6496  if (sla_check_inuse_station(station_ref->station))
6497  continue;
6498 
6499  /* Did we fail to dial this station earlier? If so, has it been
6500  * a minute since we tried? */
6501  if (sla_check_failed_station(station_ref->station))
6502  continue;
6503 
6504  /* If this station already timed out while this trunk was ringing,
6505  * do not dial it again for this ringing trunk. */
6506  if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
6507  continue;
6508 
6509  /* Check for a ring delay in progress */
6510  time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
6511  if (time_left != INT_MAX && time_left > 0)
6512  continue;
6513 
6514  /* It is time to make this station begin to ring. Do it! */
6515  sla_ring_station(ringing_trunk, station_ref->station);
6516  }
6517  }
6518  /* Now, all of the stations that should be ringing, are ringing. */
6519 }
6520 
6521 static void sla_hangup_stations(void)
6522 {
6523  struct sla_trunk_ref *trunk_ref;
6524  struct sla_ringing_station *ringing_station;
6525 
6526  AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
6527  AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
6528  struct sla_ringing_trunk *ringing_trunk;
6529  ast_mutex_lock(&sla.lock);
6530  AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
6531  if (trunk_ref->trunk == ringing_trunk->trunk)
6532  break;
6533  }
6534  ast_mutex_unlock(&sla.lock);
6535  if (ringing_trunk)
6536  break;
6537  }
6538  if (!trunk_ref) {
6540  ast_dial_join(ringing_station->station->dial);
6541  ast_dial_destroy(ringing_station->station->dial);
6542  ringing_station->station->dial = NULL;
6543  sla_ringing_station_destroy(ringing_station);
6544  }
6545  }
6547 }
6548 
6550 {
6551  ast_mutex_lock(&sla.lock);
6553  ast_mutex_unlock(&sla.lock);
6554 
6555  /* Find stations that shouldn't be ringing anymore. */
6557 }
6558 
6560 {
6561  ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
6562  event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
6564  event->station->name, event->trunk_ref->trunk->name);
6566  INACTIVE_TRUNK_REFS, event->trunk_ref);
6567 
6568  if (event->trunk_ref->trunk->active_stations == 1) {
6569  /* The station putting it on hold is the only one on the call, so start
6570  * Music on hold to the trunk. */
6571  event->trunk_ref->trunk->on_hold = 1;
6573  }
6574 
6576  event->trunk_ref->chan = NULL;
6577 }
6578 
6579 /*! \brief Process trunk ring timeouts
6580  * \note Called with sla.lock locked
6581  * \return non-zero if a change to the ringing trunks was made
6582  */
6583 static int sla_calc_trunk_timeouts(unsigned int *timeout)
6584 {
6585  struct sla_ringing_trunk *ringing_trunk;
6586  int res = 0;
6587 
6588  AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
6589  int time_left, time_elapsed;
6590  if (!ringing_trunk->trunk->ring_timeout)
6591  continue;
6592  time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
6593  time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
6594  if (time_left <= 0) {
6595  pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
6597  sla_stop_ringing_trunk(ringing_trunk);
6598  res = 1;
6599  continue;
6600  }
6601  if (time_left < *timeout)
6602  *timeout = time_left;
6603  }
6605 
6606  return res;
6607 }
6608 
6609 /*! \brief Process station ring timeouts
6610  * \note Called with sla.lock locked
6611  * \return non-zero if a change to the ringing stations was made
6612  */
6613 static int sla_calc_station_timeouts(unsigned int *timeout)
6614 {
6615  struct sla_ringing_trunk *ringing_trunk;
6616  struct sla_ringing_station *ringing_station;
6617  int res = 0;
6618 
6619  AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
6620  unsigned int ring_timeout = 0;
6621  int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
6622  struct sla_trunk_ref *trunk_ref;
6623 
6624  /* If there are any ring timeouts specified for a specific trunk
6625  * on the station, then use the highest per-trunk ring timeout.
6626  * Otherwise, use the ring timeout set for the entire station. */
6627  AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
6628  struct sla_station_ref *station_ref;
6629  int trunk_time_elapsed, trunk_time_left;
6630 
6631  AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
6632  if (ringing_trunk->trunk == trunk_ref->trunk)
6633  break;
6634  }
6635  if (!ringing_trunk)
6636  continue;
6637 
6638  /* If there is a trunk that is ringing without a timeout, then the
6639  * only timeout that could matter is a global station ring timeout. */
6640  if (!trunk_ref->ring_timeout)
6641  break;
6642 
6643  /* This trunk on this station is ringing and has a timeout.
6644  * However, make sure this trunk isn't still ringing from a
6645  * previous timeout. If so, don't consider it. */
6646  AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
6647  if (station_ref->station == ringing_station->station)
6648  break;
6649  }
6650  if (station_ref)
6651  continue;
6652 
6653  trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
6654  trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
6655  if (trunk_time_left > final_trunk_time_left)
6656  final_trunk_time_left = trunk_time_left;
6657  }
6658 
6659  /* No timeout was found for ringing trunks, and no timeout for the entire station */
6660  if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
6661  continue;
6662 
6663  /* Compute how much time is left for a global station timeout */
6664  if (ringing_station->station->ring_timeout) {
6665  ring_timeout = ringing_station->station->ring_timeout;
6666  time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
6667  time_left = (ring_timeout * 1000) - time_elapsed;
6668  }
6669 
6670  /* If the time left based on the per-trunk timeouts is smaller than the
6671  * global station ring timeout, use that. */
6672  if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
6673  time_left = final_trunk_time_left;
6674 
6675  /* If there is no time left, the station needs to stop ringing */
6676  if (time_left <= 0) {
6679  res = 1;
6680  continue;
6681  }
6682 
6683  /* There is still some time left for this station to ring, so save that
6684  * timeout if it is the first event scheduled to occur */
6685  if (time_left < *timeout)
6686  *timeout = time_left;
6687  }
6689 
6690  return res;
6691 }
6692 
6693 /*! \brief Calculate the ring delay for a station
6694  * \note Assumes sla.lock is locked
6695  */
6696 static int sla_calc_station_delays(unsigned int *timeout)
6697 {
6698  struct sla_station *station;
6699  int res = 0;
6700  struct ao2_iterator i;
6701 
6702  i = ao2_iterator_init(sla_stations, 0);
6703  for (; (station = ao2_iterator_next(&i)); ao2_ref(station, -1)) {
6704  struct sla_ringing_trunk *ringing_trunk;
6705  int time_left;
6706 
6707  /* Ignore stations already ringing */
6708  if (sla_check_ringing_station(station))
6709  continue;
6710 
6711  /* Ignore stations already on a call */
6712  if (sla_check_inuse_station(station))
6713  continue;
6714 
6715  /* Ignore stations that don't have one of their trunks ringing */
6716  if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
6717  continue;
6718 
6719  if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
6720  continue;
6721 
6722  /* If there is no time left, then the station needs to start ringing.
6723  * Return non-zero so that an event will be queued up an event to
6724  * make that happen. */
6725  if (time_left <= 0) {
6726  res = 1;
6727  continue;
6728  }
6729 
6730  if (time_left < *timeout)
6731  *timeout = time_left;
6732  }
6734 
6735  return res;
6736 }
6737 
6738 /*! \brief Calculate the time until the next known event
6739  * \note Called with sla.lock locked */
6740 static int sla_process_timers(struct timespec *ts)
6741 {
6742  unsigned int timeout = UINT_MAX;
6743  struct timeval wait;
6744  unsigned int change_made = 0;
6745 
6746  /* Check for ring timeouts on ringing trunks */
6747  if (sla_calc_trunk_timeouts(&timeout))
6748  change_made = 1;
6749 
6750  /* Check for ring timeouts on ringing stations */
6751  if (sla_calc_station_timeouts(&timeout))
6752  change_made = 1;
6753 
6754  /* Check for station ring delays */
6755  if (sla_calc_station_delays(&timeout))
6756  change_made = 1;
6757 
6758  /* queue reprocessing of ringing trunks */
6759  if (change_made)
6761 
6762  /* No timeout */
6763  if (timeout == UINT_MAX)
6764  return 0;
6765 
6766  if (ts) {
6767  wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
6768  ts->tv_sec = wait.tv_sec;
6769  ts->tv_nsec = wait.tv_usec * 1000;
6770  }
6771 
6772  return 1;
6773 }
6774 
6775 static void sla_event_destroy(struct sla_event *event)
6776 {
6777  if (event->trunk_ref) {
6778  ao2_ref(event->trunk_ref, -1);
6779  event->trunk_ref = NULL;
6780  }
6781 
6782  if (event->station) {
6783  ao2_ref(event->station, -1);
6784  event->station = NULL;
6785  }
6786 
6787  ast_free(event);
6788 }
6789 
6790 static void *sla_thread(void *data)
6791 {
6792  struct sla_failed_station *failed_station;
6793  struct sla_ringing_station *ringing_station;
6794 
6795  ast_mutex_lock(&sla.lock);
6796 
6797  while (!sla.stop) {
6798  struct sla_event *event;
6799  struct timespec ts = { 0, };
6800  unsigned int have_timeout = 0;
6801 
6802  if (AST_LIST_EMPTY(&sla.event_q)) {
6803  if ((have_timeout = sla_process_timers(&ts)))
6804  ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
6805  else
6806  ast_cond_wait(&sla.cond, &sla.lock);
6807  if (sla.stop)
6808  break;
6809  }
6810 
6811  if (have_timeout)
6813 
6814  while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
6815  ast_mutex_unlock(&sla.lock);
6816  switch (event->type) {
6817  case SLA_EVENT_HOLD:
6818  sla_handle_hold_event(event);
6819  break;
6820  case SLA_EVENT_DIAL_STATE:
6822  break;
6825  break;
6826  }
6827  sla_event_destroy(event);
6828  ast_mutex_lock(&sla.lock);
6829  }
6830  }
6831 
6832  ast_mutex_unlock(&sla.lock);
6833 
6834  while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry))) {
6835  sla_ringing_station_destroy(ringing_station);
6836  }
6837 
6838  while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry))) {
6839  sla_failed_station_destroy(failed_station);
6840  }
6841 
6842  return NULL;
6843 }
6844 
6850 };
6851 
6852 static void *dial_trunk(void *data)
6853 {
6854  struct dial_trunk_args *args = data;
6855  struct ast_dial *dial;
6856  char *tech, *tech_data;
6857  enum ast_dial_result dial_res;
6858  char conf_name[MAX_CONFNUM];
6859  struct ast_conference *conf;
6860  struct ast_flags64 conf_flags = { 0 };
6861  RAII_VAR(struct sla_trunk_ref *, trunk_ref, args->trunk_ref, ao2_cleanup);
6862  RAII_VAR(struct sla_station *, station, args->station, ao2_cleanup);
6863  int caller_is_saved;
6864  struct ast_party_caller caller;
6865  int last_state = 0;
6866  int current_state = 0;
6867 
6868  if (!(dial = ast_dial_create())) {
6869  ast_mutex_lock(args->cond_lock);
6870  ast_cond_signal(args->cond);
6871  ast_mutex_unlock(args->cond_lock);
6872  return NULL;
6873  }
6874 
6875  tech_data = ast_strdupa(trunk_ref->trunk->device);
6876  tech = strsep(&tech_data, "/");
6877  if (ast_dial_append(dial, tech, tech_data, NULL) == -1) {
6878  ast_mutex_lock(args->cond_lock);
6879  ast_cond_signal(args->cond);
6880  ast_mutex_unlock(args->cond_lock);
6881  ast_dial_destroy(dial);
6882  return NULL;
6883  }
6884 
6885  /* Do we need to save of the caller ID data? */
6886  caller_is_saved = 0;
6887  if (!sla.attempt_callerid) {
6888  caller_is_saved = 1;
6889  caller = *ast_channel_caller(trunk_ref->chan);
6890  ast_party_caller_init(ast_channel_caller(trunk_ref->chan));
6891  }
6892 
6893  dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
6894 
6895  /* Restore saved caller ID */
6896  if (caller_is_saved) {
6897  ast_party_caller_free(ast_channel_caller(trunk_ref->chan));
6898  ast_channel_caller_set(trunk_ref->chan, &caller);
6899  }
6900 
6901  if (dial_res != AST_DIAL_RESULT_TRYING) {
6902  ast_mutex_lock(args->cond_lock);
6903  ast_cond_signal(args->cond);
6904  ast_mutex_unlock(args->cond_lock);
6905  ast_dial_destroy(dial);
6906  return NULL;
6907  }
6908 
6909  for (;;) {
6910  unsigned int done = 0;
6911  switch ((dial_res = ast_dial_state(dial))) {
6913  trunk_ref->trunk->chan = ast_dial_answered(dial);
6919  done = 1;
6920  break;
6922  current_state = AST_CONTROL_PROGRESS;
6923  break;
6927  current_state = AST_CONTROL_RINGING;
6928  break;
6929  }
6930  if (done)
6931  break;
6932 
6933  /* check that SLA station that originated trunk call is still alive */
6934  if (station && ast_device_state(station->device) == AST_DEVICE_NOT_INUSE) {
6935  ast_debug(3, "Originating station device %s no longer active\n", station->device);
6936  trunk_ref->trunk->chan = NULL;
6937  break;
6938  }
6939 
6940  /* If trunk line state changed, send indication back to originating SLA Station channel */
6941  if (current_state != last_state) {
6942  ast_debug(3, "Indicating State Change %d to channel %s\n", current_state, ast_channel_name(trunk_ref->chan));
6943  ast_indicate(trunk_ref->chan, current_state);
6944  last_state = current_state;
6945  }
6946 
6947  /* avoid tight loop... sleep for 1/10th second */
6948  ast_safe_sleep(trunk_ref->chan, 100);
6949  }
6950 
6951  if (!trunk_ref->trunk->chan) {
6952  ast_mutex_lock(args->cond_lock);
6953  ast_cond_signal(args->cond);
6954  ast_mutex_unlock(args->cond_lock);
6955  ast_dial_join(dial);
6956  ast_dial_destroy(dial);
6957  return NULL;
6958  }
6959 
6960  snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
6961  ast_set_flag64(&conf_flags,
6964  conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan, NULL);
6965 
6966  ast_mutex_lock(args->cond_lock);
6967  ast_cond_signal(args->cond);
6968  ast_mutex_unlock(args->cond_lock);
6969 
6970  if (conf) {
6971  conf_run(trunk_ref->trunk->chan, conf, &conf_flags, NULL);
6972  dispose_conf(conf);
6973  conf = NULL;
6974  }
6975 
6976  /* If the trunk is going away, it is definitely now IDLE. */
6978 
6979  trunk_ref->trunk->chan = NULL;
6980  trunk_ref->trunk->on_hold = 0;
6981 
6982  ast_dial_join(dial);
6983  ast_dial_destroy(dial);
6984 
6985  return NULL;
6986 }
6987 
6988 /*!
6989  * \brief For a given station, choose the highest priority idle trunk
6990  * \pre sla_station is locked
6991  */
6992 static struct sla_trunk_ref *sla_choose_idle_trunk(const struct sla_station *station)
6993 {
6994  struct sla_trunk_ref *trunk_ref = NULL;
6995 
6996  AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
6997  if (trunk_ref->state == SLA_TRUNK_STATE_IDLE) {
6998  ao2_ref(trunk_ref, 1);
6999  break;
7000  }
7001  }
7002 
7003  return trunk_ref;
7004 }
7005 
7006 static int sla_station_exec(struct ast_channel *chan, const char *data)
7007 {
7008  char *station_name, *trunk_name;
7009  RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
7010  RAII_VAR(struct sla_trunk_ref *, trunk_ref, NULL, ao2_cleanup);
7011  char conf_name[MAX_CONFNUM];
7012  struct ast_flags64 conf_flags = { 0 };
7013  struct ast_conference *conf;
7014 
7015  if (ast_strlen_zero(data)) {
7016  ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
7017  pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
7018  return 0;
7019  }
7020 
7021  trunk_name = ast_strdupa(data);
7022  station_name = strsep(&trunk_name, "_");
7023 
7024  if (ast_strlen_zero(station_name)) {
7025  ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
7026  pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
7027  return 0;
7028  }
7029 
7030  station = sla_find_station(station_name);
7031 
7032  if (!station) {
7033  ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
7034  pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
7035  return 0;
7036  }
7037 
7038  ao2_lock(station);
7039  if (!ast_strlen_zero(trunk_name)) {
7040  trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
7041  } else {
7042  trunk_ref = sla_choose_idle_trunk(station);
7043  }
7044  ao2_unlock(station);
7045 
7046  if (!trunk_ref) {
7047  if (ast_strlen_zero(trunk_name))
7048  ast_log(LOG_NOTICE, "No trunks available for call.\n");
7049  else {
7050  ast_log(LOG_NOTICE, "Can't join existing call on trunk "
7051  "'%s' due to access controls.\n", trunk_name);
7052  }
7053  pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
7054  return 0;
7055  }
7056 
7057  if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
7058  if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
7060  else {
7061  trunk_ref->state = SLA_TRUNK_STATE_UP;
7063  "SLA:%s_%s", station->name, trunk_ref->trunk->name);
7064  }
7065  } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
7066  struct sla_ringing_trunk *ringing_trunk;
7067 
7068  ast_mutex_lock(&sla.lock);
7069  AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
7070  if (ringing_trunk->trunk == trunk_ref->trunk) {
7072  break;
7073  }
7074  }
7076  ast_mutex_unlock(&sla.lock);
7077 
7078  if (ringing_trunk) {
7079  answer_trunk_chan(ringing_trunk->trunk->chan);
7081 
7082  sla_ringing_trunk_destroy(ringing_trunk);
7083 
7084  /* Queue up reprocessing ringing trunks, and then ringing stations again */
7087  }
7088  }
7089 
7090  trunk_ref->chan = chan;
7091 
7092  if (!trunk_ref->trunk->chan) {
7093  ast_mutex_t cond_lock;
7094  ast_cond_t cond;
7095  pthread_t dont_care;
7096  struct dial_trunk_args args = {
7097  .trunk_ref = trunk_ref,
7098  .station = station,
7099  .cond_lock = &cond_lock,
7100  .cond = &cond,
7101  };
7102  ao2_ref(trunk_ref, 1);
7103  ao2_ref(station, 1);
7105  /* Create a thread to dial the trunk and dump it into the conference.
7106  * However, we want to wait until the trunk has been dialed and the
7107  * conference is created before continuing on here. */
7108  ast_autoservice_start(chan);
7109  ast_mutex_init(&cond_lock);
7110  ast_cond_init(&cond, NULL);
7111  ast_mutex_lock(&cond_lock);
7113  ast_cond_wait(&cond, &cond_lock);
7114  ast_mutex_unlock(&cond_lock);
7115  ast_mutex_destroy(&cond_lock);
7116  ast_cond_destroy(&cond);
7117  ast_autoservice_stop(chan);
7118  if (!trunk_ref->trunk->chan) {
7119  ast_debug(1, "Trunk didn't get created. chan: %lx\n", (unsigned long) trunk_ref->trunk->chan);
7120  pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
7122  trunk_ref->chan = NULL;
7123  return 0;
7124  }
7125  }
7126 
7127  if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
7128  trunk_ref->trunk->on_hold) {
7129  trunk_ref->trunk->on_hold = 0;
7132  }
7133 
7134  snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
7135  ast_set_flag64(&conf_flags,
7137  ast_answer(chan);
7138  conf = build_conf(conf_name, "", "", 0, 0, 1, chan, NULL);
7139  if (conf) {
7140  conf_run(chan, conf, &conf_flags, NULL);
7141  dispose_conf(conf);
7142  conf = NULL;
7143  }
7144  trunk_ref->chan = NULL;
7147  strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
7148  admin_exec(NULL, conf_name);
7151  }
7152 
7153  pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
7154 
7155  return 0;
7156 }
7157 
7158 static void sla_trunk_ref_destructor(void *obj)
7159 {
7160  struct sla_trunk_ref *trunk_ref = obj;
7161 
7162  if (trunk_ref->trunk) {
7163  ao2_ref(trunk_ref->trunk, -1);
7164  trunk_ref->trunk = NULL;
7165  }
7166 }
7167 
7169 {
7170  struct sla_trunk_ref *trunk_ref;
7171 
7172  if (!(trunk_ref = ao2_alloc(sizeof(*trunk_ref), sla_trunk_ref_destructor))) {
7173  return NULL;
7174  }
7175 
7176  ao2_ref(trunk, 1);
7177  trunk_ref->trunk = trunk;
7178 
7179  return trunk_ref;
7180 }
7181 
7183 {
7184  struct sla_ringing_trunk *ringing_trunk;
7185 
7186  if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk)))) {
7187  return NULL;
7188  }
7189 
7190  ao2_ref(trunk, 1);
7191  ringing_trunk->trunk = trunk;
7192  ringing_trunk->ring_begin = ast_tvnow();
7193 
7195 
7196  ast_mutex_lock(&sla.lock);
7197  AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
7198  ast_mutex_unlock(&sla.lock);
7199 
7201 
7202  return ringing_trunk;
7203 }
7204 
7205 static void sla_ringing_trunk_destroy(struct sla_ringing_trunk *ringing_trunk)
7206 {
7207  if (ringing_trunk->trunk) {
7208  ao2_ref(ringing_trunk->trunk, -1);
7209  ringing_trunk->trunk = NULL;
7210  }
7211 
7212  ast_free(ringing_trunk);
7213 }
7214 
7215 enum {
7216  SLA_TRUNK_OPT_MOH = (1 << 0),
7217 };
7218 
7219 enum {
7222 };
7223 
7227 
7228 static int sla_trunk_exec(struct ast_channel *chan, const char *data)
7229 {
7230  char conf_name[MAX_CONFNUM];
7231  struct ast_conference *conf;
7232  struct ast_flags64 conf_flags = { 0 };
7233  RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
7234  struct sla_ringing_trunk *ringing_trunk;
7235  AST_DECLARE_APP_ARGS(args,
7236  AST_APP_ARG(trunk_name);
7238  );
7239  char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
7240  struct ast_flags opt_flags = { 0 };
7241  char *parse;
7242 
7243  if (ast_strlen_zero(data)) {
7244  ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
7245  return -1;
7246  }
7247 
7248  parse = ast_strdupa(data);
7249  AST_STANDARD_APP_ARGS(args, parse);
7250  if (args.argc == 2) {
7251  if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
7252  ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
7253  return -1;
7254  }
7255  }
7256 
7257  trunk = sla_find_trunk(args.trunk_name);
7258 
7259  if (!trunk) {
7260  ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
7261  pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
7262  return 0;
7263  }
7264 
7265  if (trunk->chan) {
7266  ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
7267  args.trunk_name);
7268  pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
7269  return 0;
7270  }
7271 
7272  trunk->chan = chan;
7273 
7274  if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
7275  pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
7276  return 0;
7277  }
7278 
7279  snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
7280  conf = build_conf(conf_name, "", "", 1, 1, 1, chan, NULL);
7281  if (!conf) {
7282  pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
7283  return 0;
7284  }
7285  ast_set_flag64(&conf_flags,
7287 
7288  if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
7289  ast_indicate(chan, -1);
7290  ast_set_flag64(&conf_flags, CONFFLAG_MOH);
7291  } else
7293 
7294  conf_run(chan, conf, &conf_flags, opts);
7295  dispose_conf(conf);
7296  conf = NULL;
7297  trunk->chan = NULL;
7298  trunk->on_hold = 0;
7299 
7301 
7302  if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
7303  pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
7304 
7305  /* Remove the entry from the list of ringing trunks if it is still there. */
7306  ast_mutex_lock(&sla.lock);
7307  AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
7308  if (ringing_trunk->trunk == trunk) {
7310  break;
7311  }
7312  }
7314  ast_mutex_unlock(&sla.lock);
7315  if (ringing_trunk) {
7316  sla_ringing_trunk_destroy(ringing_trunk);
7317  pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
7318  /* Queue reprocessing of ringing trunks to make stations stop ringing
7319  * that shouldn't be ringing after this trunk stopped. */
7321  }
7322 
7323  return 0;
7324 }
7325 
7326 static enum ast_device_state sla_state(const char *data)
7327 {
7328  char *buf, *station_name, *trunk_name;
7329  RAII_VAR(struct sla_station *, station, NULL, ao2_cleanup);
7330  struct sla_trunk_ref *trunk_ref;
7332 
7333  trunk_name = buf = ast_strdupa(data);
7334  station_name = strsep(&trunk_name, "_");
7335 
7336  station = sla_find_station(station_name);
7337  if (station) {
7338  ao2_lock(station);
7339  AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
7340  if (!strcasecmp(trunk_name, trunk_ref->trunk->name)) {
7341  res = sla_state_to_devstate(trunk_ref->state);
7342  break;
7343  }
7344  }
7345  ao2_unlock(station);
7346  }
7347 
7348  if (res == AST_DEVICE_INVALID) {
7349  ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
7350  trunk_name, station_name);
7351  }
7352 
7353  return res;
7354 }
7355 
7356 static int sla_trunk_release_refs(void *obj, void *arg, int flags)
7357 {
7358  struct sla_trunk *trunk = obj;
7359  struct sla_station_ref *station_ref;
7360 
7361  while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry))) {
7362  ao2_ref(station_ref, -1);
7363  }
7364 
7365  return 0;
7366 }
7367 
7368 static int sla_station_release_refs(void *obj, void *arg, int flags)
7369 {
7370  struct sla_station *station = obj;
7371  struct sla_trunk_ref *trunk_ref;
7372 
7373  while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry))) {
7374  ao2_ref(trunk_ref, -1);
7375  }
7376 
7377  return 0;
7378 }
7379 
7380 static void sla_station_destructor(void *obj)
7381 {
7382  struct sla_station *station = obj;
7383 
7384  ast_debug(1, "sla_station destructor for '%s'\n", station->name);
7385 
7386  if (!ast_strlen_zero(station->autocontext)) {
7387  struct sla_trunk_ref *trunk_ref;
7388 
7389  AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
7390  char exten[AST_MAX_EXTENSION];
7391  char hint[AST_MAX_APP];
7392  snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
7393  snprintf(hint, sizeof(hint), "SLA:%s", exten);
7394  ast_context_remove_extension(station->autocontext, exten,
7395  1, sla_registrar);
7396  ast_context_remove_extension(station->autocontext, hint,
7397  PRIORITY_HINT, sla_registrar);
7398  }
7399  }
7400 
7401  sla_station_release_refs(station, NULL, 0);
7402 
7404 }
7405 
7406 static int sla_trunk_cmp(void *obj, void *arg, int flags)
7407 {
7408  struct sla_trunk *trunk = obj, *trunk2 = arg;
7409 
7410  return !strcasecmp(trunk->name, trunk2->name) ? CMP_MATCH | CMP_STOP : 0;
7411 }
7412 
7413 static int sla_station_cmp(void *obj, void *arg, int flags)
7414 {
7415  struct sla_station *station = obj, *station2 = arg;
7416 
7417  return !strcasecmp(station->name, station2->name) ? CMP_MATCH | CMP_STOP : 0;
7418 }
7419 
7420 static void sla_destroy(void)
7421 {
7422  if (sla.thread != AST_PTHREADT_NULL) {
7423  ast_mutex_lock(&sla.lock);
7424  sla.stop = 1;
7425  ast_cond_signal(&sla.cond);
7426  ast_mutex_unlock(&sla.lock);
7427  pthread_join(sla.thread, NULL);
7428  }
7429 
7430  /* Drop any created contexts from the dialplan */
7431  ast_context_destroy(NULL, sla_registrar);
7432 
7433  ast_mutex_destroy(&sla.lock);
7434  ast_cond_destroy(&sla.cond);
7435 
7436  ao2_callback(sla_trunks, 0, sla_trunk_release_refs, NULL);
7437  ao2_callback(sla_stations, 0, sla_station_release_refs, NULL);
7438 
7439  ao2_ref(sla_trunks, -1);
7440  sla_trunks = NULL;
7441 
7442  ao2_ref(sla_stations, -1);
7443  sla_stations = NULL;
7444 }
7445 
7446 static int sla_check_device(const char *device)
7447 {
7448  char *tech, *tech_data;
7449 
7450  tech_data = ast_strdupa(device);
7451  tech = strsep(&tech_data, "/");
7452 
7453  if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
7454  return -1;
7455 
7456  return 0;
7457 }
7458 
7459 static void sla_trunk_destructor(void *obj)
7460 {
7461  struct sla_trunk *trunk = obj;
7462 
7463  ast_debug(1, "sla_trunk destructor for '%s'\n", trunk->name);
7464 
7465  if (!ast_strlen_zero(trunk->autocontext)) {
7466  ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
7467  }
7468 
7469  sla_trunk_release_refs(trunk, NULL, 0);
7470 
7472 }
7473 
7474 static int sla_build_trunk(struct ast_config *cfg, const char *cat)
7475 {
7476  RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
7477  struct ast_variable *var;
7478  const char *dev;
7479  int existing_trunk = 0;
7480 
7481  if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
7482  ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
7483  return -1;
7484  }
7485 
7486  if (sla_check_device(dev)) {
7487  ast_log(LOG_ERROR, "SLA Trunk '%s' defined with invalid device '%s'!\n",
7488  cat, dev);
7489  return -1;
7490  }
7491 
7492  if ((trunk = sla_find_trunk(cat))) {
7493  trunk->mark = 0;
7494  existing_trunk = 1;
7495  } else if ((trunk = ao2_alloc(sizeof(*trunk), sla_trunk_destructor))) {
7496  if (ast_string_field_init(trunk, 32)) {
7497  return -1;
7498  }
7499  ast_string_field_set(trunk, name, cat);
7500  } else {
7501  return -1;
7502  }
7503 
7504  ao2_lock(trunk);
7505 
7506  ast_string_field_set(trunk, device, dev);
7507 
7508  for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
7509  if (!strcasecmp(var->name, "autocontext"))
7510  ast_string_field_set(trunk, autocontext, var->value);
7511  else if (!strcasecmp(var->name, "ringtimeout")) {
7512  if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
7513  ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
7514  var->value, trunk->name);
7515  trunk->ring_timeout = 0;
7516  }
7517  } else if (!strcasecmp(var->name, "barge"))
7518  trunk->barge_disabled = ast_false(var->value);
7519  else if (!strcasecmp(var->name, "hold")) {
7520  if (!strcasecmp(var->value, "private"))
7521  trunk->hold_access = SLA_HOLD_PRIVATE;
7522  else if (!strcasecmp(var->value, "open"))
7523  trunk->hold_access = SLA_HOLD_OPEN;
7524  else {
7525  ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
7526  var->value, trunk->name);
7527  }
7528  } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
7529  ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
7530  var->name, var->lineno, SLA_CONFIG_FILE);
7531  }
7532  }
7533 
7534  ao2_unlock(trunk);
7535 
7536  if (!ast_strlen_zero(trunk->autocontext)) {
7537  if (!ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar)) {
7538  ast_log(LOG_ERROR, "Failed to automatically find or create "
7539  "context '%s' for SLA!\n", trunk->autocontext);
7540  return -1;
7541  }
7542 
7543  if (ast_add_extension(trunk->autocontext, 0 /* don't replace */, "s", 1,
7544  NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
7545  ast_log(LOG_ERROR, "Failed to automatically create extension "
7546  "for trunk '%s'!\n", trunk->name);
7547  return -1;
7548  }
7549  }
7550 
7551  if (!existing_trunk) {
7552  ao2_link(sla_trunks, trunk);
7553  }
7554 
7555  return 0;
7556 }
7557 
7558 /*!
7559  * \internal
7560  * \pre station is not locked
7561  */
7562 static void sla_add_trunk_to_station(struct sla_station *station, struct ast_variable *var)
7563 {
7564  RAII_VAR(struct sla_trunk *, trunk, NULL, ao2_cleanup);
7565  struct sla_trunk_ref *trunk_ref = NULL;
7566  struct sla_station_ref *station_ref;
7567  char *trunk_name, *options, *cur;
7568  int existing_trunk_ref = 0;
7569  int existing_station_ref = 0;
7570 
7571  options = ast_strdupa(var->value);
7572  trunk_name = strsep(&options, ",");
7573 
7574  trunk = sla_find_trunk(trunk_name);
7575  if (!trunk) {
7576  ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
7577  return;
7578  }
7579 
7580  AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
7581  if (trunk_ref->trunk == trunk) {
7582  trunk_ref->mark = 0;
7583  existing_trunk_ref = 1;
7584  break;
7585  }
7586  }
7587 
7588  if (!trunk_ref && !(trunk_ref = create_trunk_ref(trunk))) {
7589  return;
7590  }
7591 
7592  trunk_ref->state = SLA_TRUNK_STATE_IDLE;
7593 
7594  while ((cur = strsep(&options, ","))) {
7595  char *name, *value = cur;
7596  name = strsep(&value, "=");
7597  if (!strcasecmp(name, "ringtimeout")) {
7598  if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
7599  ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
7600  "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
7601  trunk_ref->ring_timeout = 0;
7602  }
7603  } else if (!strcasecmp(name, "ringdelay")) {
7604  if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
7605  ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
7606  "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
7607  trunk_ref->ring_delay = 0;
7608  }
7609  } else {
7610  ast_log(LOG_WARNING, "Invalid option '%s' for "
7611  "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
7612  }
7613  }
7614 
7615  AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
7616  if (station_ref->station == station) {
7617  station_ref->mark = 0;
7618  existing_station_ref = 1;
7619  break;
7620  }
7621  }
7622 
7623  if (!station_ref && !(station_ref = sla_create_station_ref(station))) {
7624  if (!existing_trunk_ref) {
7625  ao2_ref(trunk_ref, -1);
7626  } else {
7627  trunk_ref->mark = 1;
7628  }
7629  return;
7630  }
7631 
7632  if (!existing_station_ref) {
7633  ao2_lock(trunk);
7634  AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
7635  ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
7636  ao2_unlock(trunk);
7637  }
7638 
7639  if (!existing_trunk_ref) {
7640  ao2_lock(station);
7641  AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
7642  ao2_unlock(station);
7643  }
7644 }
7645 
7646 static int sla_build_station(struct ast_config *cfg, const char *cat)
7647 {
7649  struct ast_variable *var;
7650  const char *dev;
7651  int existing_station = 0;
7652 
7653  if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
7654  ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
7655  return -1;
7656  }
7657 
7658  if ((station = sla_find_station(cat))) {
7659  station->mark = 0;
7660  existing_station = 1;
7661  } else if ((station = ao2_alloc(sizeof(*station), sla_station_destructor))) {
7662  if (ast_string_field_init(station, 32)) {
7663  return -1;
7664  }
7665  ast_string_field_set(station, name, cat);
7666  } else {
7667  return -1;
7668  }
7669 
7670  ao2_lock(station);
7671 
7672  ast_string_field_set(station, device, dev);
7673 
7674  for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
7675  if (!strcasecmp(var->name, "trunk")) {
7676  ao2_unlock(station);
7677  sla_add_trunk_to_station(station, var);
7678  ao2_lock(station);
7679  } else if (!strcasecmp(var->name, "autocontext")) {
7680  ast_string_field_set(station, autocontext, var->value);
7681  } else if (!strcasecmp(var->name, "ringtimeout")) {
7682  if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
7683  ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
7684  var->value, station->name);
7685  station->ring_timeout = 0;
7686  }
7687  } else if (!strcasecmp(var->name, "ringdelay")) {
7688  if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
7689  ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
7690  var->value, station->name);
7691  station->ring_delay = 0;
7692  }
7693  } else if (!strcasecmp(var->name, "hold")) {
7694  if (!strcasecmp(var->value, "private"))
7695  station->hold_access = SLA_HOLD_PRIVATE;
7696  else if (!strcasecmp(var->value, "open"))
7697  station->hold_access = SLA_HOLD_OPEN;
7698  else {
7699  ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
7700  var->value, station->name);
7701  }
7702 
7703  } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
7704  ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
7705  var->name, var->lineno, SLA_CONFIG_FILE);
7706  }
7707  }
7708 
7709  ao2_unlock(station);
7710 
7711  if (!ast_strlen_zero(station->autocontext)) {
7712  struct sla_trunk_ref *trunk_ref;
7713 
7714  if (!ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar)) {
7715  ast_log(LOG_ERROR, "Failed to automatically find or create "
7716  "context '%s' for SLA!\n", station->autocontext);
7717  return -1;
7718  }
7719  /* The extension for when the handset goes off-hook.
7720  * exten => station1,1,SLAStation(station1) */
7721  if (ast_add_extension(station->autocontext, 0 /* don't replace */, station->name, 1,
7722  NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
7723  ast_log(LOG_ERROR, "Failed to automatically create extension "
7724  "for trunk '%s'!\n", station->name);
7725  return -1;
7726  }
7727  AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
7728  char exten[AST_MAX_EXTENSION];
7729  char hint[AST_MAX_APP];
7730  snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
7731  snprintf(hint, sizeof(hint), "SLA:%s", exten);
7732  /* Extension for this line button
7733  * exten => station1_line1,1,SLAStation(station1_line1) */
7734  if (ast_add_extension(station->autocontext, 0 /* don't replace */, exten, 1,
7735  NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
7736  ast_log(LOG_ERROR, "Failed to automatically create extension "
7737  "for trunk '%s'!\n", station->name);
7738  return -1;
7739  }
7740  /* Hint for this line button
7741  * exten => station1_line1,hint,SLA:station1_line1 */
7742  if (ast_add_extension(station->autocontext, 0 /* don't replace */, exten, PRIORITY_HINT,
7743  NULL, NULL, hint, NULL, NULL, sla_registrar)) {
7744  ast_log(LOG_ERROR, "Failed to automatically create hint "
7745  "for trunk '%s'!\n", station->name);
7746  return -1;
7747  }
7748  }
7749  }
7750 
7751  if (!existing_station) {
7752  ao2_link(sla_stations, station);
7753  }
7754 
7755  return 0;
7756 }
7757 
7758 static int sla_trunk_mark(void *obj, void *arg, int flags)
7759 {
7760  struct sla_trunk *trunk = obj;
7761  struct sla_station_ref *station_ref;
7762 
7763  ao2_lock(trunk);
7764 
7765  trunk->mark = 1;
7766 
7767  AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
7768  station_ref->mark = 1;
7769  }
7770 
7771  ao2_unlock(trunk);
7772 
7773  return 0;
7774 }
7775 
7776 static int sla_station_mark(void *obj, void *arg, int flags)
7777 {
7778  struct sla_station *station = obj;
7779  struct sla_trunk_ref *trunk_ref;
7780 
7781  ao2_lock(station);
7782 
7783  station->mark = 1;
7784 
7785  AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
7786  trunk_ref->mark = 1;
7787  }
7788 
7789  ao2_unlock(station);
7790 
7791  return 0;
7792 }
7793 
7794 static int sla_trunk_is_marked(void *obj, void *arg, int flags)
7795 {
7796  struct sla_trunk *trunk = obj;
7797 
7798  ao2_lock(trunk);
7799 
7800  if (trunk->mark) {
7801  /* Only remove all of the station references if the trunk itself is going away */
7802  sla_trunk_release_refs(trunk, NULL, 0);
7803  } else {
7804  struct sla_station_ref *station_ref;
7805 
7806  /* Otherwise only remove references to stations no longer in the config */
7807  AST_LIST_TRAVERSE_SAFE_BEGIN(&trunk->stations, station_ref, entry) {
7808  if (!station_ref->mark) {
7809  continue;
7810  }
7812  ao2_ref(station_ref, -1);
7813  }
7815  }
7816 
7817  ao2_unlock(trunk);
7818 
7819  return trunk->mark ? CMP_MATCH : 0;
7820 }
7821 
7822 static int sla_station_is_marked(void *obj, void *arg, int flags)
7823 {
7824  struct sla_station *station = obj;
7825 
7826  ao2_lock(station);
7827 
7828  if (station->mark) {
7829  /* Only remove all of the trunk references if the station itself is going away */
7830  sla_station_release_refs(station, NULL, 0);
7831  } else {
7832  struct sla_trunk_ref *trunk_ref;
7833 
7834  /* Otherwise only remove references to trunks no longer in the config */
7835  AST_LIST_TRAVERSE_SAFE_BEGIN(&station->trunks, trunk_ref, entry) {
7836  if (!trunk_ref->mark) {
7837  continue;
7838  }
7840  ao2_ref(trunk_ref, -1);
7841  }
7843  }
7844 
7845  ao2_unlock(station);
7846 
7847  return station->mark ? CMP_MATCH : 0;
7848 }
7849 
7850 static int sla_in_use(void)
7851 {
7852  return ao2_container_count(sla_trunks) || ao2_container_count(sla_stations);
7853 }
7854 
7855 static int sla_load_config(int reload)
7856 {
7857  struct ast_config *cfg;
7858  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
7859  const char *cat = NULL;
7860  int res = 0;
7861  const char *val;
7862 
7863  if (!reload) {
7864  ast_mutex_init(&sla.lock);
7865  ast_cond_init(&sla.cond, NULL);
7867  NULL, sla_trunk_cmp);
7870  }
7871 
7872  if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) {
7873  return 0; /* Treat no config as normal */
7874  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
7875  return 0;
7876  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
7877  ast_log(LOG_ERROR, "Config file " SLA_CONFIG_FILE " is in an invalid format. Aborting.\n");
7878  return 0;
7879  }
7880 
7881  if (reload) {
7882  ao2_callback(sla_trunks, 0, sla_trunk_mark, NULL);
7883  ao2_callback(sla_stations, 0, sla_station_mark, NULL);
7884  }
7885 
7886  if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
7887  sla.attempt_callerid = ast_true(val);
7888 
7889  while ((cat = ast_category_browse(cfg, cat)) && !res) {
7890  const char *type;
7891  if (!strcasecmp(cat, "general"))
7892  continue;
7893  if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
7894  ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
7895  SLA_CONFIG_FILE);
7896  continue;
7897  }
7898  if (!strcasecmp(type, "trunk"))
7899  res = sla_build_trunk(cfg, cat);
7900  else if (!strcasecmp(type, "station"))
7901  res = sla_build_station(cfg, cat);
7902  else {
7903  ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
7904  SLA_CONFIG_FILE, type);
7905  }
7906  }
7907 
7908  ast_config_destroy(cfg);
7909 
7910  if (reload) {
7913  }
7914 
7915  /* Start SLA event processing thread once SLA has been configured. */
7916  if (sla.thread == AST_PTHREADT_NULL && sla_in_use()) {
7918  }
7919 
7920  return res;
7921 }
7922 
7923 static int acf_meetme_info_eval(const char *keyword, const struct ast_conference *conf)
7924 {
7925  if (!strcasecmp("lock", keyword)) {
7926  return conf->locked;
7927  } else if (!strcasecmp("parties", keyword)) {
7928  return conf->users;
7929  } else if (!strcasecmp("activity", keyword)) {
7930  time_t now;
7931  now = time(NULL);
7932  return (now - conf->start);
7933  } else if (!strcasecmp("dynamic", keyword)) {
7934  return conf->isdynamic;
7935  } else {
7936  return -1;
7937  }
7938 
7939 }
7940 
7941 static int acf_meetme_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
7942 {
7943  struct ast_conference *conf;
7944  char *parse;
7945  int result = -2; /* only non-negative numbers valid, -1 is used elsewhere */
7946  AST_DECLARE_APP_ARGS(args,
7947  AST_APP_ARG(keyword);
7949  );
7950 
7951  if (ast_strlen_zero(data)) {
7952  ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
7953  return -1;
7954  }
7955 
7956  parse = ast_strdupa(data);
7957  AST_STANDARD_APP_ARGS(args, parse);
7958 
7959  if (ast_strlen_zero(args.keyword)) {
7960  ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
7961  return -1;
7962  }
7963 
7964  if (ast_strlen_zero(args.confno)) {
7965  ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
7966  return -1;
7967  }
7968 
7969  AST_LIST_LOCK(&confs);
7970  AST_LIST_TRAVERSE(&confs, conf, list) {
7971  if (!strcmp(args.confno, conf->confno)) {
7972  result = acf_meetme_info_eval(args.keyword, conf);
7973  break;
7974  }
7975  }
7977 
7978  if (result > -1) {
7979  snprintf(buf, len, "%d", result);
7980  } else if (result == -1) {
7981  ast_log(LOG_NOTICE, "Error: invalid keyword: '%s'\n", args.keyword);
7982  snprintf(buf, len, "0");
7983  } else if (result == -2) {
7984  ast_log(LOG_NOTICE, "Error: conference (%s) not found\n", args.confno);
7985  snprintf(buf, len, "0");
7986  }
7987 
7988  return 0;
7989 }
7990 
7991 
7993  .name = "MEETME_INFO",
7994  .read = acf_meetme_info,
7995 };
7996 
7997 
7998 static int load_config(int reload)
7999 {
8000  load_config_meetme(reload);
8001  return sla_load_config(reload);
8002 }
8003 
8004 static int unload_module(void)
8005 {
8006  int res = 0;
8007 
8008  ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
8009  res = ast_manager_unregister("MeetmeMute");
8010  res |= ast_manager_unregister("MeetmeUnmute");
8011  res |= ast_manager_unregister("MeetmeList");
8012  res |= ast_manager_unregister("MeetmeListRooms");
8013  res |= ast_unregister_application(app4);
8014  res |= ast_unregister_application(app3);
8015  res |= ast_unregister_application(app2);
8016  res |= ast_unregister_application(app);
8017  res |= ast_unregister_application(slastation_app);
8018  res |= ast_unregister_application(slatrunk_app);
8019 
8020  ast_devstate_prov_del("Meetme");
8021  ast_devstate_prov_del("SLA");
8022 
8023  sla_destroy();
8024 
8025  res |= ast_custom_function_unregister(&meetme_info_acf);
8026  ast_unload_realtime("meetme");
8027 
8029 
8030  return res;
8031 }
8032 
8033 /*!
8034  * \brief Load the module
8035  *
8036  * Module loading including tests for configuration or dependencies.
8037  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
8038  * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
8039  * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
8040  * configuration file or other non-critical problem return
8041  * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
8042  */
8043 static int load_module(void)
8044 {
8045  int res = 0;
8046 
8047  res |= load_config(0);
8048 
8049  res |= meetme_stasis_init();
8050 
8051  ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
8057  res |= ast_register_application_xml(app3, admin_exec);
8060  res |= ast_register_application_xml(slastation_app, sla_station_exec);
8061  res |= ast_register_application_xml(slatrunk_app, sla_trunk_exec);
8062 
8063  res |= ast_devstate_prov_add("Meetme", meetmestate);
8064  res |= ast_devstate_prov_add("SLA", sla_state);
8065 
8066  res |= ast_custom_function_register(&meetme_info_acf);
8067  ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
8068 
8069  return res;
8070 }
8071 
8072 static int reload(void)
8073 {
8074  ast_unload_realtime("meetme");
8075  return load_config(1);
8076 }
8077 
8078 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "MeetMe conference bridge",
8079  .support_level = AST_MODULE_SUPPORT_EXTENDED,
8080  .load = load_module,
8081  .unload = unload_module,
8082  .reload = reload,
8083  .load_pri = AST_MODPRI_DEVSTATE_PROVIDER,
8084  .optional_modules = "func_speex",
8085 );
static char user[512]
const char * name
Definition: pbx.h:119
const ast_string_field name
Definition: app_meetme.c:986
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
unsigned int active_stations
Definition: app_meetme.c:991
static void meetme_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition: app_meetme.c:1226
static int fuzzystart
Definition: app_meetme.c:811
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3339
static char musicclass[MAX_MUSICCLASS]
Definition: chan_mgcp.c:162
struct ast_variable * next
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1574
static const char type[]
Definition: chan_ooh323.c:109
static int conf_free(struct ast_conference *conf)
Remove the conference from the list and free it.
Definition: app_meetme.c:2331
static void set_user_talking(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking, int monitor)
Definition: app_meetme.c:2687
enum sip_cc_notify_state state
Definition: chan_sip.c:959
static struct sla_trunk_ref * sla_choose_idle_trunk(const struct sla_station *station)
For a given station, choose the highest priority idle trunk.
Definition: app_meetme.c:6992
const char * warning_sound
Definition: app_meetme.c:911
pthread_t thread
Definition: app_meetme.c:1089
#define ast_channel_lock(chan)
Definition: channel.h:2945
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
static char * complete_meetmecmd_list(const char *line, const char *word, int pos, int state)
Definition: app_meetme.c:1814
Main Channel structure associated with a channel.
Music on hold handling.
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
ast_device_state
Device States.
Definition: devicestate.h:52
#define ast_frdup(fr)
Copies a frame.
char * str
Subscriber phone number (Malloced)
Definition: channel.h:292
int ast_dial_destroy(struct ast_dial *dial)
Destroys a dialing structure.
Definition: dial.c:1091
static void sla_add_trunk_to_station(struct sla_station *station, struct ast_variable *var)
Definition: app_meetme.c:7562
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1250
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
struct sla_trunk_ref * trunk_ref
Definition: app_meetme.c:6057
static int user_chan_cb(void *obj, void *args, int flags)
Definition: app_meetme.c:5210
static int action_meetmelistrooms(struct mansession *s, const struct message *m)
Definition: app_meetme.c:5593
static struct ast_conf_user * find_user(struct ast_conference *conf, const char *callerident)
Definition: app_meetme.c:5162
Asterisk locking-related definitions:
static const char * get_announce_filename(enum announcetypes type)
Definition: app_meetme.c:2601
static struct @35 sla
A structure for data used by the sla thread.
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
sla_trunk_state
Definition: app_meetme.c:923
static int endalert
Definition: app_meetme.c:813
Asterisk main include file. File version handling, generic pbx functions.
static void sla_handle_ringing_trunk_event(void)
Definition: app_meetme.c:6549
static int dispose_conf(struct ast_conference *conf)
Decrement reference counts, as incremented by find_conf()
Definition: app_meetme.c:2504
struct timeval start_time
Definition: app_meetme.c:907
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
Definition: app_meetme.c:1494
struct ast_channel * chan
Definition: app_meetme.c:846
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define ast_copy_flags64(dest, src, flagz)
Definition: utils.h:141
static void meetme_menu_normal(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
Definition: app_meetme.c:2766
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
volume_action
Definition: app_meetme.c:666
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
uint64_t ast_format_compatibility_format2bitfield(const struct ast_format *format)
Convert a format structure to its respective bitfield.
unsigned int ring_timeout
Definition: app_meetme.c:1023
#define AST_OPTION_TXGAIN
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
static int careful_write(int fd, unsigned char *data, int len, int block)
Definition: app_meetme.c:1408
static void sla_ring_stations(void)
Ring stations based on current set of ringing trunks.
Definition: app_meetme.c:6480
static int sla_build_station(struct ast_config *cfg, const char *cat)
Definition: app_meetme.c:7646
#define STR_CONCISE
Definition: app_meetme.c:644
Main dialing structure. Contains global options, channels being dialed, and more! ...
Definition: dial.c:48
static struct ast_conference * find_conf(struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags)
Definition: app_meetme.c:4688
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
Definition: ast_expr2.c:325
static int rt_extend_conf(const char *confno)
Definition: app_meetme.c:2523
static int user_set_unmuted_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2727
static void sla_queue_event_nolock(enum sla_event_type type)
Definition: app_meetme.c:2451
static void send_talking_event(struct ast_channel *chan, struct ast_conference *conf, struct ast_conf_user *user, int talking)
Definition: app_meetme.c:2681
static unsigned char leave[]
Definition: leave.h:12
static char * meetme_kick_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_meetme.c:2076
ast_mutex_t playlock
Definition: app_meetme.c:843
#define AST_FRAME_BITS
Definition: app_meetme.c:664
static char * meetme_mute_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_meetme.c:2096
struct ast_party_id id
Connected party ID.
Definition: channel.h:459
#define AST_DIGIT_ANY
Definition: file.h:48
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
static unsigned char enter[]
Definition: enter.h:12
unsigned int mark
Definition: app_meetme.c:1029
unsigned int mark
Definition: app_meetme.c:963
#define ast_test_flag(p, flag)
Definition: utils.h:63
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
static void sla_ringing_station_destroy(struct sla_ringing_station *ringing_station)
Definition: app_meetme.c:5977
struct sla_station * station
Definition: app_meetme.c:1049
Device state management.
Support for translation of data formats. translate.c.
#define BEGIN_OPTIONS
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4322
static void meetme_set_defaults(void)
Definition: app_meetme.c:5772
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_party_name name
Subscriber name.
Definition: channel.h:341
struct ast_frame * origframe
Definition: app_meetme.c:873
pthread_t recordthread
Definition: app_meetme.c:860
void ast_dsp_free(struct ast_dsp *dsp)
Definition: dsp.c:1770
static void * recordthread(void *args)
Definition: app_meetme.c:5681
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
struct ast_json * blob
static int action_meetmeunmute(struct mansession *s, const struct message *m)
Definition: app_meetme.c:5516
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.
static const char *const app4
Definition: app_meetme.c:805
static int sla_check_station_hold_access(const struct sla_trunk *trunk, const struct sla_station *station)
Definition: app_meetme.c:5880
const ast_string_field autocontext
Definition: app_meetme.c:986
struct ast_channel * confchan
Definition: app_meetme.c:835
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1501
static const char * istalking(int x)
Definition: app_meetme.c:1398
struct ast_channel_snapshot * snapshot
Convenient Signal Processing routines.
struct sla_trunk * trunk
Definition: app_meetme.c:1017
static void hold(struct ast_channel *chan)
Helper method to place a channel in a bridge on hold.
#define CONFFLAG_INTROUSER_VMREC
Definition: app_meetme.c:749
#define OBJ_POINTER
Definition: astobj2.h:1154
#define MEETME_DELAYDETECTENDTALK
Definition: app_meetme.c:662
static int meetme_stasis_init(void)
Definition: app_meetme.c:1157
sla_event_type
Event types that can be queued up for the SLA thread.
Definition: app_meetme.c:1038
static int conf_exec(struct ast_channel *chan, const char *data)
The meetme() application.
Definition: app_meetme.c:4837
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
int ast_json_object_update(struct ast_json *object, struct ast_json *other)
Update object with all of the fields of other.
Definition: json.c:416
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3237
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
#define LOG_WARNING
Definition: logger.h:274
struct ast_channel * chan
Definition: app_meetme.c:994
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
unsigned int isdynamic
Definition: app_meetme.c:857
static int sla_station_mark(void *obj, void *arg, int flags)
Definition: app_meetme.c:7776
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static int user_listen_volup_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5175
#define CONF_SIZE
Definition: app_meetme.c:683
static void sla_dial_state_callback(struct ast_dial *dial)
Definition: app_meetme.c:6167
static int user_reset_vol_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5203
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
char * recordingformat
Definition: app_meetme.c:864
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3406
#define CONFIG_STATUS_FILEINVALID
struct ast_dsp * ast_dsp_new(void)
Allocates a new dsp, assumes 8khz for internal sample rate.
Definition: dsp.c:1745
struct announce_listitem::@38 entry
recording_state
Definition: app_meetme.c:676
static int timeout
Definition: cdr_mysql.c:86
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
struct ast_conference::@40 announcelist
Structure for variables, used for configurations and for channel variables.
#define CONFFLAG_DONT_DENOISE
Definition: app_meetme.c:753
struct ast_frame * transframe[32]
Definition: app_meetme.c:872
static int sla_check_ringing_station(const struct sla_station *station)
Check to see if this station is already ringing.
Definition: app_meetme.c:6317
#define var
Definition: ast_expr2f.c:614
static const char *const app2
Definition: app_meetme.c:803
static int count_exec(struct ast_channel *chan, const char *data)
The MeetmeCount application.
Definition: app_meetme.c:4792
static int load_module(void)
Load the module.
Definition: app_meetme.c:8043
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:108
ast_mutex_t * cond_lock
Definition: app_meetme.c:6058
static void sla_change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk_state state, enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
Definition: app_meetme.c:6029
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
Test Framework API.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4302
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1523
struct ast_dial * dial
Definition: app_meetme.c:950
static const struct ast_app_option meetme_opts[128]
Definition: app_meetme.c:800
#define EVENT_FLAG_CALL
Definition: manager.h:72
Definition: cli.h:152
int ast_devstate_prov_del(const char *label)
Remove device state provider.
Definition: devicestate.c:418
A station that is ringing.
Definition: app_meetme.c:1077
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
static int sla_calc_station_delays(unsigned int *timeout)
Calculate the ring delay for a station.
Definition: app_meetme.c:6696
ast_mutex_t listenlock
Definition: app_meetme.c:844
ast_channel_state
ast_channel states
Definition: channelstate.h:35
static void sla_event_destroy(struct sla_event *event)
Definition: app_meetme.c:6775
char * str
Subscriber name (Malloced)
Definition: channel.h:265
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition: channel.c:8349
unsigned int stop
Definition: app_meetme.c:1096
Definition: astman.c:222
Dialing API.
static const char *const slastation_app
Definition: app_meetme.c:806
#define ast_cond_wait(cond, mutex)
Definition: lock.h:203
void ast_party_caller_free(struct ast_party_caller *doomed)
Destroy the caller party contents.
Definition: channel.c:2015
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
#define ast_cond_init(cond, attr)
Definition: lock.h:199
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
static struct aco_type item
Definition: test_config.c:1463
static struct ast_conference * build_conf(const char *confno, const char *pin, const char *pinadmin, int make, int dynamic, int refcount, const struct ast_channel *chan, struct ast_test *test)
Find or create a conference.
Definition: app_meetme.c:1606
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int ast_devstate_prov_add(const char *label, ast_devstate_prov_cb_type callback)
Add device state provider.
Definition: devicestate.c:391
static int earlyalert
Definition: app_meetme.c:812
enum sla_event_type type
Definition: app_meetme.c:1048
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:337
#define ast_set_flag64(p, flag)
Definition: utils.h:127
long warning_freq
Definition: app_meetme.c:910
static void sla_stop_ringing_trunk(struct sla_ringing_trunk *ringing_trunk)
Definition: app_meetme.c:6116
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
static char * sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_meetme.c:2207
#define ast_assert(a)
Definition: utils.h:695
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3191
#define ast_mutex_lock(a)
Definition: lock.h:187
struct ast_frame * ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f, int consume)
translates one or more frames Apply an input frame into the translator and receive zero or one output...
Definition: translate.c:565
A reference to a station.
Definition: app_meetme.c:974
#define ao2_unlock(a)
Definition: astobj2.h:730
static struct test_val c
Definition: muted.c:95
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2207
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
const char * useropts
Definition: app_meetme.c:869
static void answer_trunk_chan(struct ast_channel *chan)
Definition: app_meetme.c:6062
static int hangup(void *data)
Definition: chan_pjsip.c:2483
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
static int action_meetmelist(struct mansession *s, const struct message *m)
Definition: app_meetme.c:5521
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
const char * args
const ast_string_field device
Definition: app_meetme.c:986
static struct stasis_message_router * meetme_event_message_router
Definition: app_meetme.c:1130
ast_cond_t * cond
Definition: app_meetme.c:6849
#define S(e)
#define NULL
Definition: resample.c:96
unsigned int ring_delay
Definition: app_meetme.c:958
static void * sla_thread(void *data)
Definition: app_meetme.c:6790
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition: file.c:1098
int value
Definition: syslog.c:37
struct sla_trunk_ref * trunk_ref
Definition: app_meetme.c:1050
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:855
#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
static void sla_queue_event(enum sla_event_type type)
Definition: app_meetme.c:2456
ast_mutex_t * cond_lock
Definition: app_meetme.c:6848
Structure used to handle a large number of boolean flags == used only in app_dial?
Definition: utils.h:204
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
struct ast_conf_user::@41 list
#define AST_FILE_MODE
Definition: asterisk.h:32
static void meetme_menu(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size, struct ast_format_cap *cap_slin)
Definition: app_meetme.c:3153
static char * complete_meetmecmd_mute_kick(const char *line, const char *word, int pos, int state)
Definition: app_meetme.c:1766
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7876
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1771
#define ast_cond_signal(cond)
Definition: lock.h:201
struct ast_channel * ast_waitfor_nandfds(struct ast_channel **chan, int n, int *fds, int nfds, int *exception, int *outfd, int *ms)
Waits for activity on a group of channels.
Definition: channel.c:2997
static int sla_ring_station(struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
Ring a station.
Definition: app_meetme.c:6355
static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
Definition: app_meetme.c:1526
#define ast_pthread_create_detached_background(a, b, c, d)
Definition: utils.h:572
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3489
#define ast_verb(level,...)
Definition: logger.h:463
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
unsigned int locked
Definition: app_meetme.c:858
const char * line
Definition: cli.h:162
unsigned int hold_access
Definition: app_meetme.c:961
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
static int sla_check_station_delay(struct sla_station *station, struct sla_ringing_trunk *ringing_trunk)
Calculate the ring delay for a given ringing trunk on a station.
Definition: app_meetme.c:6447
static struct sla_failed_station * sla_create_failed_station(struct sla_station *station)
Definition: app_meetme.c:5987
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
static int user_max_cmp(void *obj, void *arg, int flags)
Definition: app_meetme.c:1579
struct ast_frame_subclass subclass
static enum ast_device_state sla_state_to_devstate(enum sla_trunk_state state)
Definition: app_meetme.c:6012
#define MAX_LANGUAGE
Definition: channel.h:173
static int mute
Definition: chan_alsa.c:144
int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
Simply remove extension from context.
Definition: pbx.c:4952
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition: json.c:404
Utility functions.
Blob of data associated with a channel.
unsigned int gmuted
Definition: app_meetme.c:859
static struct ast_json * status_to_json(int on)
Definition: app_meetme.c:1324
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
static const struct ast_app_option sla_trunk_opts[128]
Definition: app_meetme.c:7226
#define CONFFLAG_INTROMSG
Definition: app_meetme.c:748
pthread_cond_t ast_cond_t
Definition: lock.h:176
#define ast_strlen_zero(foo)
Definition: strings.h:52
enum sla_trunk_state state
Definition: app_meetme.c:1018
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition: channel.c:6444
All configuration options for statsd client.
Definition: res_statsd.c:95
static int rt_schedule
Definition: app_meetme.c:810
static int user_listen_voldown_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5182
int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path)
Allow to record message and have a review option.
Definition: main/app.c:2489
static void meetme_stasis_generate_msg(struct ast_conference *meetme_conference, struct ast_channel *chan, struct ast_conf_user *user, struct stasis_message_type *message_type, struct ast_json *extras)
Definition: app_meetme.c:1343
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:567
int done
Definition: test_amihooks.c:48
static int sla_load_config(int reload)
Definition: app_meetme.c:7855
static int user_set_kickme_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2716
static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struct ast_flags64 *confflags, char *optargs[])
Definition: app_meetme.c:3177
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
struct ast_party_id id
Caller party ID.
Definition: channel.h:421
void ast_dial_set_state_callback(struct ast_dial *dial, ast_dial_state_callback callback)
Set a callback for state changes.
Definition: dial.c:1293
announcetypes
Definition: app_meetme.c:826
Configuration File Parser.
#define CONFFLAG_KILL_LAST_MAN_STANDING
Definition: app_meetme.c:751
static char mailbox[AST_MAX_MAILBOX_UNIQUEID]
Definition: chan_mgcp.c:204
static int user_no_cmp(void *obj, void *arg, int flags)
Definition: app_meetme.c:1567
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
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 SENTINEL
Definition: compiler.h:87
u-Law to Signed linear conversion
static void sla_station_destructor(void *obj)
Definition: app_meetme.c:7380
#define ast_config_load(filename, flags)
Load a config file.
unsigned int mark
Definition: app_meetme.c:1006
struct sla_station * station
Definition: app_meetme.c:6847
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
ast_dial_result
List of return codes for dial run API calls.
Definition: dial.h:54
struct ast_trans_pvt * ast_translator_build_path(struct ast_format *dest, struct ast_format *source)
Builds a translator path Build a path (possibly NULL) from source to dest.
Definition: translate.c:485
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:510
int actual
Definition: app_meetme.c:892
const char * end_sound
Definition: app_meetme.c:912
static int can_write(struct ast_channel *chan, struct ast_flags64 *confflags)
Definition: app_meetme.c:2672
General Asterisk PBX channel definitions.
Asterisk JSON abstraction layer.
static void * run_station(void *data)
Definition: app_meetme.c:6068
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: main/config.c:3382
const char * bookid
Definition: app_meetme.c:871
static int unload_module(void)
Definition: app_meetme.c:8004
Asterisk file paths, configured in asterisk.conf.
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
struct timeval ring_begin
Definition: app_meetme.c:1066
enum ast_dial_result ast_dial_join(struct ast_dial *dial)
Cancel async thread.
Definition: dial.c:1021
int ast_set_read_format(struct ast_channel *chan, struct ast_format *format)
Sets read format on channel chan.
Definition: channel.c:5849
#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
unsigned int on_hold
Definition: app_meetme.c:1004
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
const int fd
Definition: cli.h:159
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
A trunk that is ringing.
Definition: app_meetme.c:1063
Definition: dsp.c:405
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
static const struct _map_x_s dtmfstr[]
mapping between dtmf flags and strings
Definition: chan_sip.c:20588
#define AST_PTHREADT_NULL
Definition: lock.h:66
static int sla_calc_station_timeouts(unsigned int *timeout)
Process station ring timeouts.
Definition: app_meetme.c:6613
const int n
Definition: cli.h:165
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
ast_mutex_t lock
Definition: app_meetme.c:1091
ast_cond_t cond
Definition: app_meetme.c:1090
#define AST_MAX_EXTENSION
Definition: channel.h:135
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:299
Caller Party information.
Definition: channel.h:419
The MeetMe User object.
Definition: app_meetme.c:896
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
int ast_softhangup(struct ast_channel *chan, int reason)
Softly hangup up a channel.
Definition: channel.c:2476
static void sla_queue_event_full(enum sla_event_type type, struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
Definition: app_meetme.c:2419
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
In case you didn&#39;t read that giant block of text above the mansession_session struct, the struct mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
Definition: manager.c:1625
static struct sla_station_ref * sla_create_station_ref(struct sla_station *station)
Definition: app_meetme.c:5949
#define ao2_lock(a)
Definition: astobj2.h:718
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Definition: time.h:238
static enum ast_device_state sla_state(const char *data)
Definition: app_meetme.c:7326
static struct ast_custom_function meetme_info_acf
Definition: app_meetme.c:7992
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int sla_process_timers(struct timespec *ts)
Calculate the time until the next known event.
Definition: app_meetme.c:6740
static int meetmemute(struct mansession *s, const struct message *m, int mute)
Definition: app_meetme.c:5451
static void conf_start_moh(struct ast_channel *chan, const char *musicclass)
Definition: app_meetme.c:2585
int ast_atomic_dec_and_test(volatile int *p)
decrement *p by 1 and return true if the variable has reached 0.
Definition: lock.h:765
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
static enum ast_device_state meetmestate(const char *data)
Callback for devicestate providers.
Definition: app_meetme.c:5750
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:273
static struct sla_ringing_station * sla_create_ringing_station(struct sla_station *station)
Definition: app_meetme.c:5963
static int sla_trunk_cmp(void *obj, void *arg, int flags)
Definition: app_meetme.c:7406
unsigned int barge_disabled
Definition: app_meetme.c:998
static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
Definition: app_meetme.c:1506
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5890
static int sla_station_exec(struct ast_channel *chan, const char *data)
Definition: app_meetme.c:7006
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
static void sla_trunk_destructor(void *obj)
Definition: app_meetme.c:7459
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
struct @35::@53 event_q
#define PRIORITY_HINT
Definition: pbx.h:54
struct sla_station * station
Definition: app_meetme.c:1057
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4179
static struct sla_trunk_ref * create_trunk_ref(struct sla_trunk *trunk)
Definition: app_meetme.c:7168
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
struct timeval ring_begin
Definition: app_meetme.c:1080
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
static void tweak_volume(struct volume *vol, enum volume_action action)
Definition: app_meetme.c:1459
ast_mutex_t announcelistlock
Definition: app_meetme.c:883
void ast_channel_caller_set(struct ast_channel *chan, struct ast_party_caller *value)
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
static int action_meetmemute(struct mansession *s, const struct message *m)
Definition: app_meetme.c:5511
static void reset_volumes(struct ast_conf_user *user)
Definition: app_meetme.c:1518
static void meetme_menu_admin(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user)
Definition: app_meetme.c:2846
enum ast_dial_result ast_dial_state(struct ast_dial *dial)
Return state of dial.
Definition: dial.c:1012
Core PBX routines and definitions.
char * ast_strptime(const char *s, const char *format, struct ast_tm *tm)
Special version of strptime(3) which places the answer in the common structure ast_tm. Also, unlike strptime(3), ast_strptime() initializes its memory prior to use.
Definition: localtime.c:2550
int ast_app_parse_options64(const struct ast_app_option *options, struct ast_flags64 *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:2911
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
enum ast_dial_result ast_dial_run(struct ast_dial *dial, struct ast_channel *chan, int async)
Execute dialing synchronously or asynchronously.
Definition: dial.c:939
#define stasis_message_router_create(topic)
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
static void conf_flush(int fd, struct ast_channel *chan)
Definition: app_meetme.c:2299
static void * announce_thread(void *data)
Definition: app_meetme.c:2615
#define CONFIG_STATUS_FILEUNCHANGED
static int set_talk_volume(struct ast_conf_user *user, int volume)
Definition: app_meetme.c:1435
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: linkedlists.h:290
static void sla_destroy(void)
Definition: app_meetme.c:7420
uint64_t flags
Definition: utils.h:205
struct volume listen
Definition: app_meetme.c:914
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char *const * argv
Definition: cli.h:161
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
char uniqueid[32]
Definition: app_meetme.c:867
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7258
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
static char * meetme_cmd_helper(struct ast_cli_args *a)
Definition: app_meetme.c:1996
char pin[MAX_PIN]
Definition: app_meetme.c:865
static int sla_in_use(void)
Definition: app_meetme.c:7850
struct sla_trunk_ref * trunk_ref
Definition: app_meetme.c:6846
struct sla_trunk * trunk
Definition: app_meetme.c:1064
static int acf_meetme_info_eval(const char *keyword, const struct ast_conference *conf)
Definition: app_meetme.c:7923
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3452
unsigned int num_stations
Definition: app_meetme.c:989
static struct sla_trunk_ref * sla_find_trunk_ref(const struct sla_station *station, const struct sla_trunk *trunk)
Definition: app_meetme.c:6427
static struct sla_ringing_trunk * sla_choose_ringing_trunk(struct sla_station *station, struct sla_trunk_ref **trunk_ref, int rm)
Choose the highest priority ringing trunk for a station.
Definition: app_meetme.c:6196
static char * sla_show_trunks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_meetme.c:2133
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
struct sla_trunk::@43 stations
struct ast_flags64 userflags
Definition: app_meetme.c:898
static void sla_ringing_trunk_destroy(struct sla_ringing_trunk *ringing_trunk)
Definition: app_meetme.c:7205
#define DEFAULT_AUDIO_BUFFERS
Definition: app_meetme.c:647
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
static int sla_trunk_exec(struct ast_channel *chan, const char *data)
Definition: app_meetme.c:7228
#define AST_MAX_APP
Definition: pbx.h:40
Default structure for translators, with the basic fields and buffers, all allocated as part of the sa...
Definition: translate.h:213
#define AST_OPTION_RXGAIN
struct ast_channel * chan
Definition: app_meetme.c:1019
static void meetme_menu_admin_extended(enum menu_modes *menu_mode, int *dtmf, struct ast_conference *conf, struct ast_flags64 *confflags, struct ast_channel *chan, struct ast_conf_user *user, char *recordingtmp, int recordingtmp_size, struct ast_format_cap *cap_slin)
Definition: app_meetme.c:2966
Media Format Bitfield Compatibility API.
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
unsigned int hold_access
Definition: app_meetme.c:1001
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
#define CLI_SHOWUSAGE
Definition: cli.h:45
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
#define DATE_FORMAT
Definition: app_meetme.c:650
STASIS_MESSAGE_TYPE_DEFN_LOCAL(meetme_join_type)
static unsigned int monitor
Definition: chan_phone.c:116
static int reload(void)
Definition: app_meetme.c:8072
sla_station_hangup
Definition: app_meetme.c:1071
enum recording_state recording
Definition: app_meetme.c:856
static int user_talk_volup_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5189
def info(msg)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int errno
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2283
int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence_ms, const char *path)
Record a file based on input from a channel. Use default accept and cancel DTMF. This function will p...
Definition: main/app.c:1997
int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device, const struct ast_assigned_ids *assignedids)
Append a channel.
Definition: dial.c:282
struct ast_filestream * ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
Starts writing a file.
Definition: file.c:1361
time_t kicktime
Definition: app_meetme.c:906
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7866
static struct ast_cli_entry cli_meetme[]
Definition: app_meetme.c:2290
char namerecloc[PATH_MAX]
Definition: app_meetme.c:833
static int set_listen_volume(struct ast_conf_user *user, int volume)
Definition: app_meetme.c:1447
static void load_config_meetme(int reload)
Definition: app_meetme.c:5788
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
#define ast_cond_destroy(cond)
Definition: lock.h:200
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
pthread_t announcethread
Definition: app_meetme.c:878
#define LOG_NOTICE
Definition: logger.h:263
int desired
Definition: app_meetme.c:891
static int rt_log_members
Definition: app_meetme.c:817
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8793
struct stasis_message * ast_channel_blob_create(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Creates a ast_channel_blob message.
struct ast_channel * ast_dial_answered(struct ast_dial *dial)
Return channel that answered.
Definition: dial.c:981
char * strcasestr(const char *, const char *)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
static void sla_queue_event_conf(enum sla_event_type type, struct ast_channel *chan, struct ast_conference *conf)
Queue a SLA event from the conference.
Definition: app_meetme.c:2462
static int sla_station_is_marked(void *obj, void *arg, int flags)
Definition: app_meetme.c:7822
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
#define OPTIONS_LEN
Definition: app_meetme.c:821
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define CLI_FAILURE
Definition: cli.h:46
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
static const char * trunkstate2str(enum sla_trunk_state state)
Definition: app_meetme.c:2193
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1511
static int sla_check_device(const char *device)
Definition: app_meetme.c:7446
#define AST_MAX_CONTEXT
Definition: channel.h:136
unsigned int ring_timeout
Definition: app_meetme.c:995
char namerecloc[PATH_MAX]
Definition: app_meetme.c:904
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
#define ast_pthread_create(a, b, c, d)
Definition: utils.h:559
struct ast_dial * ast_dial_create(void)
New dialing structure.
Definition: dial.c:225
static const char *const app3
Definition: app_meetme.c:804
char language[MAX_LANGUAGE]
Definition: app_meetme.c:834
struct volume talk
Definition: app_meetme.c:913
#define MC_HEADER_FORMAT
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:1068
static int sla_station_cmp(void *obj, void *arg, int flags)
Definition: app_meetme.c:7413
static void conf_queue_dtmf(const struct ast_conference *conf, const struct ast_conf_user *sender, struct ast_frame *f)
Definition: app_meetme.c:2400
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
#define CONFFLAG_NO_AUDIO_UNTIL_UP
Definition: app_meetme.c:747
static const char *const slatrunk_app
Definition: app_meetme.c:807
unsigned int flags
static char * meetme_show_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_meetme.c:1853
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
ast_cond_t * cond
Definition: app_meetme.c:6059
const char * word
Definition: cli.h:163
static int extendby
Definition: app_meetme.c:814
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:154
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
unsigned int hold_stations
Definition: app_meetme.c:993
struct ao2_container * usercontainer
Definition: app_meetme.c:875
const char * adminopts
Definition: app_meetme.c:870
int ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)
Plays a stream and gets DTMF data from a channel.
Definition: main/app.c:197
static int sla_trunk_is_marked(void *obj, void *arg, int flags)
Definition: app_meetme.c:7794
time_t jointime
Definition: app_meetme.c:905
structure to hold users read from users.conf
Structure used to handle boolean flags.
Definition: utils.h:199
static int sla_station_release_refs(void *obj, void *arg, int flags)
Definition: app_meetme.c:7368
#define ast_clear_flag64(p, flag)
Definition: utils.h:134
static void sla_hangup_stations(void)
Definition: app_meetme.c:6521
static int sla_trunk_mark(void *obj, void *arg, int flags)
Definition: app_meetme.c:7758
struct sla_station * station
Definition: app_meetme.c:1078
static const char *const app
Definition: app_meetme.c:802
#define MEETME_DELAYDETECTTALK
Definition: app_meetme.c:661
#define AST_RWLIST_ENTRY
Definition: linkedlists.h:414
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
pthread_attr_t attr
Definition: app_meetme.c:862
const char * usage
Definition: cli.h:177
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...
#define SLA_CONFIG_FILE
Definition: app_meetme.c:643
struct ast_frame ast_null_frame
Definition: main/frame.c:79
struct @35::@52 failed_stations
static void * dial_trunk(void *data)
Definition: app_meetme.c:6852
menu_modes
Definition: app_meetme.c:2749
sla_which_trunk_refs
Definition: app_meetme.c:918
#define EVENT_FLAG_REPORTING
Definition: manager.h:80
#define CLI_SUCCESS
Definition: cli.h:44
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
static char * complete_userno(struct ast_conference *cnf, const char *word, int state)
Definition: app_meetme.c:1744
static int sla_build_trunk(struct ast_config *cfg, const char *cat)
Definition: app_meetme.c:7474
int ast_channel_fd(const struct ast_channel *chan, int which)
int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence)
Process the audio frame for silence.
Definition: dsp.c:1483
static const char gain_map[]
Map &#39;volume&#39; levels from -5 through +5 into decibel (dB) settings for channel drivers.
Definition: app_meetme.c:1115
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:680
char * strsep(char **str, const char *delims)
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition: mod_format.h:101
struct sla_station * station
Definition: app_meetme.c:6056
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3171
#define MAX_CONFNUM
Definition: app_meetme.c:819
int ast_add_extension(const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
Add and extension to an extension context.
Definition: pbx.c:6970
Definition: test.c:65
#define MAX_SETTINGS
Definition: app_meetme.c:824
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
struct timeval ast_mktime(struct ast_tm *const tmp, const char *zone)
Timezone-independent version of mktime(3).
Definition: localtime.c:2357
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Definition: channel.c:8337
Standard Command Line Interface.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:397
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
ast_app: A registered application
Definition: pbx_app.c:45
const char * ast_channel_name(const struct ast_channel *chan)
static int audio_buffers
The number of audio buffers to be allocated on pseudo channels when in a conference.
Definition: app_meetme.c:1106
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition: file.c:209
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1968
const int pos
Definition: cli.h:164
A station that failed to be dialed.
Definition: app_meetme.c:1056
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
static int acf_meetme_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: app_meetme.c:7941
struct sla_ringing_trunk::@47 timed_out_stations
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1086
char pinadmin[MAX_PIN]
Definition: app_meetme.c:866
static const char * sla_hold_str(unsigned int hold_access)
Definition: app_meetme.c:2116
static int load_config(int reload)
Definition: app_meetme.c:7998
#define END_OPTIONS
struct ast_trans_pvt * transpath[32]
Definition: app_meetme.c:874
void stasis_message_router_unsubscribe(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic.
#define ast_frfree(fr)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2814
ast_cond_t announcelist_addition
Definition: app_meetme.c:881
static PGresult * result
Definition: cel_pgsql.c:88
long play_warning
Definition: app_meetme.c:909
static struct ast_conference * find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags64 *confflags, int *too_early, char **optargs)
Definition: app_meetme.c:4500
static int sla_check_failed_station(const struct sla_station *station)
Check to see if this station has failed to be dialed in the past minute.
Definition: app_meetme.c:6332
struct stasis_forward * sub
Definition: res_corosync.c:240
Data structure associated with a single frame of data.
unsigned int announcethread_stop
Definition: app_meetme.c:880
Internal Asterisk hangup causes.
static int total
Definition: res_adsi.c:968
#define MC_DATA_FORMAT
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context or ANY context if NULL)
Definition: conf2ael.c:625
const char * ast_channel_language(const struct ast_channel *chan)
static int sla_calc_trunk_timeouts(unsigned int *timeout)
Process trunk ring timeouts.
Definition: app_meetme.c:6583
static char * complete_meetmecmd_lock(const char *word, int pos, int state)
Definition: app_meetme.c:1806
Abstract JSON element (object, array, string, int, ...).
entrance_sound
Definition: app_meetme.c:671
static void sla_failed_station_destroy(struct sla_failed_station *failed_station)
Definition: app_meetme.c:6002
static const char sla_registrar[]
Definition: app_meetme.c:1035
static int admin_exec(struct ast_channel *chan, const char *data)
The MeetMeadmin application.
Definition: app_meetme.c:5225
#define AST_OPTION_TONE_VERIFY
static unsigned int conf_map[1024]
Definition: app_meetme.c:888
struct ast_channel_id uniqueid
Definition: search.h:40
const char * ast_channel_context(const struct ast_channel *chan)
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition: extconf.c:2298
static struct sla_station * sla_find_station(const char *name)
Definition: app_meetme.c:5871
char * recordingfilename
Definition: app_meetme.c:863
struct ast_channel * lchan
Definition: app_meetme.c:847
union ast_frame::@263 data
static struct sla_trunk_ref * sla_find_trunk_ref_byname(const struct sla_station *station, const char *name)
Find a trunk reference on a station by name.
Definition: app_meetme.c:5910
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
enum ast_frame_type frametype
enum announcetypes announcetype
Definition: app_meetme.c:838
#define PATH_MAX
Definition: asterisk.h:40
int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
Adjusts the volume of the audio samples contained in a frame.
Definition: main/frame.c:787
static int user_set_hangup_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2705
#define MAX_PIN
Definition: app_meetme.c:820
#define ast_mutex_init(pmutex)
Definition: lock.h:184
Generic container type.
A station&#39;s reference to a trunk.
Definition: app_meetme.c:1015
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:280
static struct test_options options
static struct ao2_container * sla_trunks
Definition: app_meetme.c:1033
unsigned int ring_timeout
Definition: app_meetme.c:954
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
#define ast_mutex_destroy(a)
Definition: lock.h:186
static int sla_check_inuse_station(const struct sla_station *station)
Check to see if a station is in use.
Definition: app_meetme.c:6415
static int sla_trunk_release_refs(void *obj, void *arg, int flags)
Definition: app_meetme.c:7356
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
Definition: pbx.c:6198
The MeetMe Conference object.
Definition: app_meetme.c:842
struct ast_format * format
static void sla_handle_dial_state_event(void)
Definition: app_meetme.c:6232
struct ast_audiohook_list * ast_channel_audiohooks(const struct ast_channel *chan)
const char * ast_channel_macrocontext(const struct ast_channel *chan)
static void sla_station_ref_destructor(void *obj)
Definition: app_meetme.c:5939
struct ast_conference::@39 list
struct timeval last_try
Definition: app_meetme.c:1058
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
void ast_party_caller_init(struct ast_party_caller *init)
Initialize the given caller structure.
Definition: channel.c:1978
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:186
unsigned int mark
Definition: app_meetme.c:978
Say numbers and dates (maybe words one day too)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
static void sla_trunk_ref_destructor(void *obj)
Definition: app_meetme.c:7158
static struct sla_ringing_trunk * queue_ringing_trunk(struct sla_trunk *trunk)
Definition: app_meetme.c:7182
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:248
static void sla_stop_ringing_station(struct sla_ringing_station *ringing_station, enum sla_station_hangup hangup)
Definition: app_meetme.c:6132
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Definition: dsp.c:1996
static void filename_parse(char *filename, char *buffer)
Definition: app_meetme.c:5662
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3159
Asterisk module definitions.
struct @35::@50 ringing_trunks
static struct ao2_container * sla_stations
Definition: app_meetme.c:1032
struct ast_channel_monitor * ast_channel_monitor(const struct ast_channel *chan)
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:322
int ast_str_append_event_header(struct ast_str **fields_string, const char *header, const char *value)
append an event header to an ast string
Definition: manager.c:9705
unsigned int attempt_callerid
Definition: app_meetme.c:1099
unsigned int ring_delay
Definition: app_meetme.c:1027
sla_hold_access
Definition: app_meetme.c:931
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
executes a write operation on a function
struct sla_station * station
Definition: app_meetme.c:976
#define min(a, b)
Definition: f2c.h:197
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
struct ast_frame * ast_read_noaudio(struct ast_channel *chan)
Reads a frame, returning AST_FRAME_NULL frame if audio.
Definition: channel.c:4312
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define CONFIG_FILE_NAME
Definition: app_meetme.c:642
struct ast_format * ast_channel_rawwriteformat(struct ast_channel *chan)
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:298
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
struct ast_channel * chan
Definition: app_meetme.c:900
#define ast_cond_timedwait(cond, mutex, time)
Definition: lock.h:204
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
static void sla_handle_hold_event(struct sla_event *event)
Definition: app_meetme.c:6559
static struct sla_trunk * sla_find_trunk(const char *name)
Definition: app_meetme.c:5858
static int channel_admin_exec(struct ast_channel *chan, const char *data)
The MeetMeChannelAdmin application MeetMeChannelAdmin(channel, command)
Definition: app_meetme.c:5390
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:187
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
static int user_talk_voldown_cb(void *obj, void *unused, int flags)
Definition: app_meetme.c:5196
Structure for mutex and tracking information.
Definition: lock.h:135
static int user_set_muted_cb(void *obj, void *check_admin_arg, int flags)
Definition: app_meetme.c:2738
struct @35::@51 ringing_stations
void ast_translator_free_path(struct ast_trans_pvt *tr)
Frees a translator path Frees the given translator path structure.
Definition: translate.c:475
const char * ast_channel_musicclass(const struct ast_channel *chan)
jack_status_t status
Definition: app_jack.c:146
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
short word
#define ast_mutex_unlock(a)
Definition: lock.h:188
ast_mutex_t recordthreadlock
Definition: app_meetme.c:861
static void meetme_stasis_cleanup(void)
Definition: app_meetme.c:1142
static char * complete_confno(const char *word, int state)
Definition: app_meetme.c:1725
#define AST_APP_ARG(name)
Define an application argument.
#define AST_LIST_APPEND_LIST(head, list, field)
Appends a whole list to the tail of a list.
Definition: linkedlists.h:782
static int sla_check_timed_out_station(const struct sla_ringing_trunk *ringing_trunk, const struct sla_station *station)
Check to see if dialing this station already timed out for this ringing trunk.
Definition: app_meetme.c:6175
static char * meetme_lock_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_meetme.c:2056
char confno[MAX_CONFNUM]
Definition: app_meetme.c:845
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition: main/utils.c:2231
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3201
ast_mutex_t announcethreadlock
Definition: app_meetme.c:879
struct ast_json * ast_json_integer_create(intmax_t value)
Create a JSON integer.
Definition: json.c:317
static struct test_val a
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:343
#define ast_test_flag64(p, flag)
Definition: utils.h:120
#define ao2_link(container, obj)
Definition: astobj2.h:1549