Wed Jan 8 2020 09:49:39

Asterisk developer's documentation


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