00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "asterisk.h"
00037
00038 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211569 $")
00039
00040 #include <dahdi/user.h>
00041
00042 #include "asterisk/lock.h"
00043 #include "asterisk/file.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/pbx.h"
00046 #include "asterisk/module.h"
00047 #include "asterisk/config.h"
00048 #include "asterisk/app.h"
00049 #include "asterisk/dsp.h"
00050 #include "asterisk/musiconhold.h"
00051 #include "asterisk/manager.h"
00052 #include "asterisk/cli.h"
00053 #include "asterisk/say.h"
00054 #include "asterisk/utils.h"
00055 #include "asterisk/translate.h"
00056 #include "asterisk/ulaw.h"
00057 #include "asterisk/astobj2.h"
00058 #include "asterisk/devicestate.h"
00059 #include "asterisk/dial.h"
00060 #include "asterisk/causes.h"
00061 #include "asterisk/paths.h"
00062
00063 #include "enter.h"
00064 #include "leave.h"
00065
00066 #define CONFIG_FILE_NAME "meetme.conf"
00067 #define SLA_CONFIG_FILE "sla.conf"
00068
00069
00070 #define DEFAULT_AUDIO_BUFFERS 32
00071
00072
00073 #define DATE_FORMAT "%Y-%m-%d %H:%M:%S"
00074
00075 enum {
00076 ADMINFLAG_MUTED = (1 << 1),
00077 ADMINFLAG_SELFMUTED = (1 << 2),
00078 ADMINFLAG_KICKME = (1 << 3),
00079
00080 ADMINFLAG_T_REQUEST = (1 << 4),
00081 };
00082
00083 #define MEETME_DELAYDETECTTALK 300
00084 #define MEETME_DELAYDETECTENDTALK 1000
00085
00086 #define AST_FRAME_BITS 32
00087
00088 enum volume_action {
00089 VOL_UP,
00090 VOL_DOWN
00091 };
00092
00093 enum entrance_sound {
00094 ENTER,
00095 LEAVE
00096 };
00097
00098 enum recording_state {
00099 MEETME_RECORD_OFF,
00100 MEETME_RECORD_STARTED,
00101 MEETME_RECORD_ACTIVE,
00102 MEETME_RECORD_TERMINATE
00103 };
00104
00105 #define CONF_SIZE 320
00106
00107 enum {
00108
00109 CONFFLAG_ADMIN = (1 << 0),
00110
00111 CONFFLAG_MONITOR = (1 << 1),
00112
00113 CONFFLAG_KEYEXIT = (1 << 2),
00114
00115 CONFFLAG_STARMENU = (1 << 3),
00116
00117 CONFFLAG_TALKER = (1 << 4),
00118
00119 CONFFLAG_QUIET = (1 << 5),
00120
00121
00122 CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
00123
00124 CONFFLAG_AGI = (1 << 7),
00125
00126 CONFFLAG_MOH = (1 << 8),
00127
00128 CONFFLAG_MARKEDEXIT = (1 << 9),
00129
00130 CONFFLAG_WAITMARKED = (1 << 10),
00131
00132 CONFFLAG_EXIT_CONTEXT = (1 << 11),
00133
00134 CONFFLAG_MARKEDUSER = (1 << 12),
00135
00136 CONFFLAG_INTROUSER = (1 << 13),
00137
00138 CONFFLAG_RECORDCONF = (1<< 14),
00139
00140 CONFFLAG_MONITORTALKER = (1 << 15),
00141 CONFFLAG_DYNAMIC = (1 << 16),
00142 CONFFLAG_DYNAMICPIN = (1 << 17),
00143 CONFFLAG_EMPTY = (1 << 18),
00144 CONFFLAG_EMPTYNOPIN = (1 << 19),
00145 CONFFLAG_ALWAYSPROMPT = (1 << 20),
00146
00147 CONFFLAG_OPTIMIZETALKER = (1 << 21),
00148
00149
00150 CONFFLAG_NOONLYPERSON = (1 << 22),
00151
00152
00153 CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
00154
00155 CONFFLAG_STARTMUTED = (1 << 24),
00156
00157 CONFFLAG_PASS_DTMF = (1 << 25),
00158 CONFFLAG_SLA_STATION = (1 << 26),
00159 CONFFLAG_SLA_TRUNK = (1 << 27),
00160
00161 CONFFLAG_KICK_CONTINUE = (1 << 28),
00162 CONFFLAG_DURATION_STOP = (1 << 29),
00163 CONFFLAG_DURATION_LIMIT = (1 << 30),
00164
00165 CONFFLAG_NO_AUDIO_UNTIL_UP = (1 << 31),
00166 };
00167
00168 enum {
00169 OPT_ARG_WAITMARKED = 0,
00170 OPT_ARG_EXITKEYS = 1,
00171 OPT_ARG_DURATION_STOP = 2,
00172 OPT_ARG_DURATION_LIMIT = 3,
00173 OPT_ARG_MOH_CLASS = 4,
00174 OPT_ARG_ARRAY_SIZE = 5,
00175 };
00176
00177 AST_APP_OPTIONS(meetme_opts, BEGIN_OPTIONS
00178 AST_APP_OPTION('A', CONFFLAG_MARKEDUSER ),
00179 AST_APP_OPTION('a', CONFFLAG_ADMIN ),
00180 AST_APP_OPTION('b', CONFFLAG_AGI ),
00181 AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT ),
00182 AST_APP_OPTION('C', CONFFLAG_KICK_CONTINUE),
00183 AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN ),
00184 AST_APP_OPTION('d', CONFFLAG_DYNAMIC ),
00185 AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN ),
00186 AST_APP_OPTION('e', CONFFLAG_EMPTY ),
00187 AST_APP_OPTION('F', CONFFLAG_PASS_DTMF ),
00188 AST_APP_OPTION('i', CONFFLAG_INTROUSER ),
00189 AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW ),
00190 AST_APP_OPTION_ARG('M', CONFFLAG_MOH, OPT_ARG_MOH_CLASS ),
00191 AST_APP_OPTION('m', CONFFLAG_STARTMUTED ),
00192 AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER ),
00193 AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ),
00194 AST_APP_OPTION_ARG('p', CONFFLAG_KEYEXIT, OPT_ARG_EXITKEYS ),
00195 AST_APP_OPTION('q', CONFFLAG_QUIET ),
00196 AST_APP_OPTION('r', CONFFLAG_RECORDCONF ),
00197 AST_APP_OPTION('s', CONFFLAG_STARMENU ),
00198 AST_APP_OPTION('T', CONFFLAG_MONITORTALKER ),
00199 AST_APP_OPTION('l', CONFFLAG_MONITOR ),
00200 AST_APP_OPTION('t', CONFFLAG_TALKER ),
00201 AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED ),
00202 AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT ),
00203 AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT ),
00204 AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON ),
00205 AST_APP_OPTION_ARG('S', CONFFLAG_DURATION_STOP, OPT_ARG_DURATION_STOP),
00206 AST_APP_OPTION_ARG('L', CONFFLAG_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
00207 END_OPTIONS );
00208
00209 static const char *app = "MeetMe";
00210 static const char *app2 = "MeetMeCount";
00211 static const char *app3 = "MeetMeAdmin";
00212 static const char *app4 = "MeetMeChannelAdmin";
00213 static const char *slastation_app = "SLAStation";
00214 static const char *slatrunk_app = "SLATrunk";
00215
00216 static const char *synopsis = "MeetMe conference bridge";
00217 static const char *synopsis2 = "MeetMe participant count";
00218 static const char *synopsis3 = "MeetMe conference Administration";
00219 static const char *synopsis4 = "MeetMe conference Administration (channel specific)";
00220 static const char *slastation_synopsis = "Shared Line Appearance Station";
00221 static const char *slatrunk_synopsis = "Shared Line Appearance Trunk";
00222
00223
00224 static int rt_schedule;
00225 static int fuzzystart;
00226 static int earlyalert;
00227 static int endalert;
00228
00229
00230 static int rt_log_members;
00231
00232 static const char *descrip =
00233 " MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe\n"
00234 "conference. If the conference number is omitted, the user will be prompted\n"
00235 "to enter one. User can exit the conference by hangup, or if the 'p' option\n"
00236 "is specified, by pressing '#'.\n"
00237 "Please note: The DAHDI kernel modules and at least one hardware driver (or dahdi_dummy)\n"
00238 " must be present for conferencing to operate properly. In addition, the chan_dahdi\n"
00239 " channel driver must be loaded for the 'i' and 'r' options to operate at all.\n\n"
00240 "The option string may contain zero or more of the following characters:\n"
00241 " 'a' -- set admin mode\n"
00242 " 'A' -- set marked mode\n"
00243 " 'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND}\n"
00244 " Default: conf-background.agi (Note: This does not work with\n"
00245 " non-DAHDI channels in the same conference)\n"
00246 " 'c' -- announce user(s) count on joining a conference\n"
00247 " 'C' -- continue in dialplan when kicked out of conference\n"
00248 " 'd' -- dynamically add conference\n"
00249 " 'D' -- dynamically add conference, prompting for a PIN\n"
00250 " 'e' -- select an empty conference\n"
00251 " 'E' -- select an empty pinless conference\n"
00252 " 'F' -- Pass DTMF through the conference.\n"
00253 " 'i' -- announce user join/leave with review\n"
00254 " 'I' -- announce user join/leave without review\n"
00255 " 'l' -- set listen only mode (Listen only, no talking)\n"
00256 " 'm' -- set initially muted\n"
00257 " 'M[(<class>)]'\n"
00258 " -- enable music on hold when the conference has a single caller.\n"
00259 " Optionally, specify a musiconhold class to use. If one is not\n"
00260 " provided, it will use the channel's currently set music class,\n"
00261 " or \"default\".\n"
00262 " 'o' -- set talker optimization - treats talkers who aren't speaking as\n"
00263 " being muted, meaning (a) No encode is done on transmission and\n"
00264 " (b) Received audio that is not registered as talking is omitted\n"
00265 " causing no buildup in background noise\n"
00266 " 'p[(<keys>)]'\n"
00267 " -- allow user to exit the conference by pressing '#' (default)\n"
00268 " or any of the defined keys. If keys contain '*' this will override\n"
00269 " option 's'. The key used is set to channel variable MEETME_EXIT_KEY.\n"
00270 " 'P' -- always prompt for the pin even if it is specified\n"
00271 " 'q' -- quiet mode (don't play enter/leave sounds)\n"
00272 " 'r' -- Record conference (records as ${MEETME_RECORDINGFILE}\n"
00273 " using format ${MEETME_RECORDINGFORMAT}). Default filename is\n"
00274 " meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is\n"
00275 " wav.\n"
00276 " 's' -- Present menu (user or admin) when '*' is received ('send' to menu)\n"
00277 " 't' -- set talk only mode. (Talk only, no listening)\n"
00278 " 'T' -- set talker detection (sent to manager interface and meetme list)\n"
00279 " 'w[(<secs>)]'\n"
00280 " -- wait until the marked user enters the conference\n"
00281 " 'x' -- close the conference when last marked user exits\n"
00282 " 'X' -- allow user to exit the conference by entering a valid single\n"
00283 " digit extension ${MEETME_EXIT_CONTEXT} or the current context\n"
00284 " if that variable is not defined.\n"
00285 " '1' -- do not play message when first person enters\n"
00286 " 'S(x)' -- Kick the user 'x' seconds *after* he entered into the conference.\n"
00287 " 'L(x[:y][:z])' - Limit the conference to 'x' ms. Play a warning when 'y' ms are\n"
00288 " left. Repeat the warning every 'z' ms. The following special\n"
00289 " variables can be used with this option:\n"
00290 " * CONF_LIMIT_TIMEOUT_FILE File to play when time is up.\n"
00291 " * CONF_LIMIT_WARNING_FILE File to play as warning if 'y' is defined.\n"
00292 " The default is to say the time remaining.\n"
00293 "";
00294
00295 static const char *descrip2 =
00296 " MeetMeCount(confno[,var]): Plays back the number of users in the specified\n"
00297 "MeetMe conference. If var is specified, playback will be skipped and the value\n"
00298 "will be returned in the variable. Upon app completion, MeetMeCount will hangup\n"
00299 "the channel, unless priority n+1 exists, in which case priority progress will\n"
00300 "continue.\n"
00301 "";
00302
00303 static const char *descrip3 =
00304 " MeetMeAdmin(confno,command[,user]): Run admin command for conference\n"
00305 " 'e' -- Eject last user that joined\n"
00306 " 'k' -- Kick one user out of conference\n"
00307 " 'K' -- Kick all users out of conference\n"
00308 " 'l' -- Unlock conference\n"
00309 " 'L' -- Lock conference\n"
00310 " 'm' -- Unmute one user\n"
00311 " 'M' -- Mute one user\n"
00312 " 'n' -- Unmute all users in the conference\n"
00313 " 'N' -- Mute all non-admin users in the conference\n"
00314 " 'r' -- Reset one user's volume settings\n"
00315 " 'R' -- Reset all users volume settings\n"
00316 " 's' -- Lower entire conference speaking volume\n"
00317 " 'S' -- Raise entire conference speaking volume\n"
00318 " 't' -- Lower one user's talk volume\n"
00319 " 'T' -- Raise one user's talk volume\n"
00320 " 'u' -- Lower one user's listen volume\n"
00321 " 'U' -- Raise one user's listen volume\n"
00322 " 'v' -- Lower entire conference listening volume\n"
00323 " 'V' -- Raise entire conference listening volume\n"
00324 "";
00325
00326 static const char *descrip4 =
00327 " MeetMeChannelAdmin(channel,command): Run admin command for a specific\n"
00328 "channel in any coference.\n"
00329 " 'k' -- Kick the specified user out of the conference he is in\n"
00330 " 'm' -- Unmute the specified user\n"
00331 " 'M' -- Mute the specified user\n"
00332 "";
00333
00334 static const char *slastation_desc =
00335 " SLAStation(<station name>):\n"
00336 "This application should be executed by an SLA station. The argument depends\n"
00337 "on how the call was initiated. If the phone was just taken off hook, then\n"
00338 "the argument \"station\" should be just the station name. If the call was\n"
00339 "initiated by pressing a line key, then the station name should be preceded\n"
00340 "by an underscore and the trunk name associated with that line button.\n"
00341 "For example: \"station1_line1\"."
00342 " On exit, this application will set the variable SLASTATION_STATUS to\n"
00343 "one of the following values:\n"
00344 " FAILURE | CONGESTION | SUCCESS\n"
00345 "";
00346
00347 static const char *slatrunk_desc =
00348 " SLATrunk(<trunk name>[,options]):\n"
00349 "This application should be executed by an SLA trunk on an inbound call.\n"
00350 "The channel calling this application should correspond to the SLA trunk\n"
00351 "with the name \"trunk\" that is being passed as an argument.\n"
00352 " On exit, this application will set the variable SLATRUNK_STATUS to\n"
00353 "one of the following values:\n"
00354 " FAILURE | SUCCESS | UNANSWERED | RINGTIMEOUT\n"
00355 " The available options are:\n"
00356 " M[(<class>)] - Play back the specified MOH class instead of ringing\n"
00357 "";
00358
00359 #define MAX_CONFNUM 80
00360 #define MAX_PIN 80
00361
00362 enum announcetypes {
00363 CONF_HASJOIN,
00364 CONF_HASLEFT
00365 };
00366
00367 struct announce_listitem {
00368 AST_LIST_ENTRY(announce_listitem) entry;
00369 char namerecloc[PATH_MAX];
00370 char language[MAX_LANGUAGE];
00371 struct ast_channel *confchan;
00372 int confusers;
00373 enum announcetypes announcetype;
00374 };
00375
00376
00377 struct ast_conference {
00378 ast_mutex_t playlock;
00379 ast_mutex_t listenlock;
00380 char confno[MAX_CONFNUM];
00381 struct ast_channel *chan;
00382 struct ast_channel *lchan;
00383 int fd;
00384 int dahdiconf;
00385 int users;
00386 int markedusers;
00387 int maxusers;
00388 int endalert;
00389 time_t start;
00390 int refcount;
00391 enum recording_state recording:2;
00392 unsigned int isdynamic:1;
00393 unsigned int locked:1;
00394 pthread_t recordthread;
00395 ast_mutex_t recordthreadlock;
00396 pthread_attr_t attr;
00397 char *recordingfilename;
00398 char *recordingformat;
00399 char pin[MAX_PIN];
00400 char pinadmin[MAX_PIN];
00401 char uniqueid[32];
00402 long endtime;
00403 struct ast_frame *transframe[32];
00404 struct ast_frame *origframe;
00405 struct ast_trans_pvt *transpath[32];
00406 AST_LIST_HEAD_NOLOCK(, ast_conf_user) userlist;
00407 AST_LIST_ENTRY(ast_conference) list;
00408
00409 pthread_t announcethread;
00410 ast_mutex_t announcethreadlock;
00411 unsigned int announcethread_stop:1;
00412 ast_cond_t announcelist_addition;
00413 AST_LIST_HEAD_NOLOCK(, announce_listitem) announcelist;
00414 ast_mutex_t announcelistlock;
00415 };
00416
00417 static AST_LIST_HEAD_STATIC(confs, ast_conference);
00418
00419 static unsigned int conf_map[1024] = {0, };
00420
00421 struct volume {
00422 int desired;
00423 int actual;
00424 };
00425
00426
00427 struct ast_conf_user {
00428 int user_no;
00429 int userflags;
00430 int adminflags;
00431 struct ast_channel *chan;
00432 int talking;
00433 int dahdichannel;
00434 char usrvalue[50];
00435 char namerecloc[PATH_MAX];
00436 time_t jointime;
00437 time_t kicktime;
00438 struct timeval start_time;
00439 long timelimit;
00440 long play_warning;
00441 long warning_freq;
00442 const char *warning_sound;
00443 const char *end_sound;
00444 struct volume talk;
00445 struct volume listen;
00446 AST_LIST_ENTRY(ast_conf_user) list;
00447 };
00448
00449 enum sla_which_trunk_refs {
00450 ALL_TRUNK_REFS,
00451 INACTIVE_TRUNK_REFS,
00452 };
00453
00454 enum sla_trunk_state {
00455 SLA_TRUNK_STATE_IDLE,
00456 SLA_TRUNK_STATE_RINGING,
00457 SLA_TRUNK_STATE_UP,
00458 SLA_TRUNK_STATE_ONHOLD,
00459 SLA_TRUNK_STATE_ONHOLD_BYME,
00460 };
00461
00462 enum sla_hold_access {
00463
00464
00465 SLA_HOLD_OPEN,
00466
00467
00468 SLA_HOLD_PRIVATE,
00469 };
00470
00471 struct sla_trunk_ref;
00472
00473 struct sla_station {
00474 AST_RWLIST_ENTRY(sla_station) entry;
00475 AST_DECLARE_STRING_FIELDS(
00476 AST_STRING_FIELD(name);
00477 AST_STRING_FIELD(device);
00478 AST_STRING_FIELD(autocontext);
00479 );
00480 AST_LIST_HEAD_NOLOCK(, sla_trunk_ref) trunks;
00481 struct ast_dial *dial;
00482
00483
00484
00485 unsigned int ring_timeout;
00486
00487
00488
00489 unsigned int ring_delay;
00490
00491
00492 unsigned int hold_access:1;
00493
00494 unsigned int ref_count;
00495 };
00496
00497 struct sla_station_ref {
00498 AST_LIST_ENTRY(sla_station_ref) entry;
00499 struct sla_station *station;
00500 };
00501
00502 struct sla_trunk {
00503 AST_RWLIST_ENTRY(sla_trunk) entry;
00504 AST_DECLARE_STRING_FIELDS(
00505 AST_STRING_FIELD(name);
00506 AST_STRING_FIELD(device);
00507 AST_STRING_FIELD(autocontext);
00508 );
00509 AST_LIST_HEAD_NOLOCK(, sla_station_ref) stations;
00510
00511 unsigned int num_stations;
00512
00513 unsigned int active_stations;
00514
00515 unsigned int hold_stations;
00516 struct ast_channel *chan;
00517 unsigned int ring_timeout;
00518
00519
00520 unsigned int barge_disabled:1;
00521
00522
00523 unsigned int hold_access:1;
00524
00525
00526 unsigned int on_hold:1;
00527
00528 unsigned int ref_count;
00529 };
00530
00531 struct sla_trunk_ref {
00532 AST_LIST_ENTRY(sla_trunk_ref) entry;
00533 struct sla_trunk *trunk;
00534 enum sla_trunk_state state;
00535 struct ast_channel *chan;
00536
00537
00538
00539 unsigned int ring_timeout;
00540
00541
00542
00543 unsigned int ring_delay;
00544 };
00545
00546 static AST_RWLIST_HEAD_STATIC(sla_stations, sla_station);
00547 static AST_RWLIST_HEAD_STATIC(sla_trunks, sla_trunk);
00548
00549 static const char sla_registrar[] = "SLA";
00550
00551
00552 enum sla_event_type {
00553
00554 SLA_EVENT_HOLD,
00555
00556 SLA_EVENT_DIAL_STATE,
00557
00558 SLA_EVENT_RINGING_TRUNK,
00559
00560 SLA_EVENT_RELOAD,
00561
00562 SLA_EVENT_CHECK_RELOAD,
00563 };
00564
00565 struct sla_event {
00566 enum sla_event_type type;
00567 struct sla_station *station;
00568 struct sla_trunk_ref *trunk_ref;
00569 AST_LIST_ENTRY(sla_event) entry;
00570 };
00571
00572
00573
00574 struct sla_failed_station {
00575 struct sla_station *station;
00576 struct timeval last_try;
00577 AST_LIST_ENTRY(sla_failed_station) entry;
00578 };
00579
00580
00581 struct sla_ringing_trunk {
00582 struct sla_trunk *trunk;
00583
00584 struct timeval ring_begin;
00585 AST_LIST_HEAD_NOLOCK(, sla_station_ref) timed_out_stations;
00586 AST_LIST_ENTRY(sla_ringing_trunk) entry;
00587 };
00588
00589 enum sla_station_hangup {
00590 SLA_STATION_HANGUP_NORMAL,
00591 SLA_STATION_HANGUP_TIMEOUT,
00592 };
00593
00594
00595 struct sla_ringing_station {
00596 struct sla_station *station;
00597
00598 struct timeval ring_begin;
00599 AST_LIST_ENTRY(sla_ringing_station) entry;
00600 };
00601
00602
00603
00604
00605 static struct {
00606
00607 pthread_t thread;
00608 ast_cond_t cond;
00609 ast_mutex_t lock;
00610 AST_LIST_HEAD_NOLOCK(, sla_ringing_trunk) ringing_trunks;
00611 AST_LIST_HEAD_NOLOCK(, sla_ringing_station) ringing_stations;
00612 AST_LIST_HEAD_NOLOCK(, sla_failed_station) failed_stations;
00613 AST_LIST_HEAD_NOLOCK(, sla_event) event_q;
00614 unsigned int stop:1;
00615
00616
00617 unsigned int attempt_callerid:1;
00618
00619 unsigned int reload:1;
00620 } sla = {
00621 .thread = AST_PTHREADT_NULL,
00622 };
00623
00624
00625
00626 static int audio_buffers;
00627
00628
00629
00630
00631
00632
00633
00634 static char const gain_map[] = {
00635 -15,
00636 -13,
00637 -10,
00638 -6,
00639 0,
00640 0,
00641 0,
00642 6,
00643 10,
00644 13,
00645 15,
00646 };
00647
00648
00649 static int admin_exec(struct ast_channel *chan, void *data);
00650 static void *recordthread(void *args);
00651
00652 static char *istalking(int x)
00653 {
00654 if (x > 0)
00655 return "(talking)";
00656 else if (x < 0)
00657 return "(unmonitored)";
00658 else
00659 return "(not talking)";
00660 }
00661
00662 static int careful_write(int fd, unsigned char *data, int len, int block)
00663 {
00664 int res;
00665 int x;
00666
00667 while (len) {
00668 if (block) {
00669 x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
00670 res = ioctl(fd, DAHDI_IOMUX, &x);
00671 } else
00672 res = 0;
00673 if (res >= 0)
00674 res = write(fd, data, len);
00675 if (res < 1) {
00676 if (errno != EAGAIN) {
00677 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00678 return -1;
00679 } else
00680 return 0;
00681 }
00682 len -= res;
00683 data += res;
00684 }
00685
00686 return 0;
00687 }
00688
00689 static int set_talk_volume(struct ast_conf_user *user, int volume)
00690 {
00691 char gain_adjust;
00692
00693
00694
00695
00696 gain_adjust = gain_map[volume + 5];
00697
00698 return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00699 }
00700
00701 static int set_listen_volume(struct ast_conf_user *user, int volume)
00702 {
00703 char gain_adjust;
00704
00705
00706
00707
00708 gain_adjust = gain_map[volume + 5];
00709
00710 return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00711 }
00712
00713 static void tweak_volume(struct volume *vol, enum volume_action action)
00714 {
00715 switch (action) {
00716 case VOL_UP:
00717 switch (vol->desired) {
00718 case 5:
00719 break;
00720 case 0:
00721 vol->desired = 2;
00722 break;
00723 case -2:
00724 vol->desired = 0;
00725 break;
00726 default:
00727 vol->desired++;
00728 break;
00729 }
00730 break;
00731 case VOL_DOWN:
00732 switch (vol->desired) {
00733 case -5:
00734 break;
00735 case 2:
00736 vol->desired = 0;
00737 break;
00738 case 0:
00739 vol->desired = -2;
00740 break;
00741 default:
00742 vol->desired--;
00743 break;
00744 }
00745 }
00746 }
00747
00748 static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
00749 {
00750 tweak_volume(&user->talk, action);
00751
00752
00753
00754 if (!set_talk_volume(user, user->talk.desired))
00755 user->talk.actual = 0;
00756 else
00757 user->talk.actual = user->talk.desired;
00758 }
00759
00760 static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
00761 {
00762 tweak_volume(&user->listen, action);
00763
00764
00765
00766 if (!set_listen_volume(user, user->listen.desired))
00767 user->listen.actual = 0;
00768 else
00769 user->listen.actual = user->listen.desired;
00770 }
00771
00772 static void reset_volumes(struct ast_conf_user *user)
00773 {
00774 signed char zero_volume = 0;
00775
00776 ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00777 ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
00778 }
00779
00780 static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
00781 {
00782 unsigned char *data;
00783 int len;
00784 int res = -1;
00785
00786 if (!ast_check_hangup(chan))
00787 res = ast_autoservice_start(chan);
00788
00789 AST_LIST_LOCK(&confs);
00790
00791 switch(sound) {
00792 case ENTER:
00793 data = enter;
00794 len = sizeof(enter);
00795 break;
00796 case LEAVE:
00797 data = leave;
00798 len = sizeof(leave);
00799 break;
00800 default:
00801 data = NULL;
00802 len = 0;
00803 }
00804 if (data) {
00805 careful_write(conf->fd, data, len, 1);
00806 }
00807
00808 AST_LIST_UNLOCK(&confs);
00809
00810 if (!res)
00811 ast_autoservice_stop(chan);
00812 }
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828 static struct ast_conference *build_conf(char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount, const struct ast_channel *chan)
00829 {
00830 struct ast_conference *cnf;
00831 struct dahdi_confinfo dahdic = { 0, };
00832 int confno_int = 0;
00833
00834 AST_LIST_LOCK(&confs);
00835
00836 AST_LIST_TRAVERSE(&confs, cnf, list) {
00837 if (!strcmp(confno, cnf->confno))
00838 break;
00839 }
00840
00841 if (cnf || (!make && !dynamic))
00842 goto cnfout;
00843
00844
00845 if (!(cnf = ast_calloc(1, sizeof(*cnf))))
00846 goto cnfout;
00847
00848 ast_mutex_init(&cnf->playlock);
00849 ast_mutex_init(&cnf->listenlock);
00850 cnf->recordthread = AST_PTHREADT_NULL;
00851 ast_mutex_init(&cnf->recordthreadlock);
00852 cnf->announcethread = AST_PTHREADT_NULL;
00853 ast_mutex_init(&cnf->announcethreadlock);
00854 ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
00855 ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
00856 ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
00857 ast_copy_string(cnf->uniqueid, chan->uniqueid, sizeof(cnf->uniqueid));
00858
00859
00860 dahdic.confno = -1;
00861 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
00862 cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
00863 if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &dahdic)) {
00864 ast_log(LOG_WARNING, "Unable to open pseudo device\n");
00865 if (cnf->fd >= 0)
00866 close(cnf->fd);
00867 ast_free(cnf);
00868 cnf = NULL;
00869 goto cnfout;
00870 }
00871
00872 cnf->dahdiconf = dahdic.confno;
00873
00874
00875 cnf->chan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL);
00876 if (cnf->chan) {
00877 ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
00878 ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
00879 dahdic.chan = 0;
00880 dahdic.confno = cnf->dahdiconf;
00881 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
00882 if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &dahdic)) {
00883 ast_log(LOG_WARNING, "Error setting conference\n");
00884 if (cnf->chan)
00885 ast_hangup(cnf->chan);
00886 else
00887 close(cnf->fd);
00888
00889 ast_free(cnf);
00890 cnf = NULL;
00891 goto cnfout;
00892 }
00893 }
00894
00895
00896 cnf->start = time(NULL);
00897 cnf->maxusers = 0x7fffffff;
00898 cnf->isdynamic = dynamic ? 1 : 0;
00899 ast_verb(3, "Created MeetMe conference %d for conference '%s'\n", cnf->dahdiconf, cnf->confno);
00900 AST_LIST_INSERT_HEAD(&confs, cnf, list);
00901
00902
00903 if ((sscanf(cnf->confno, "%30d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
00904 conf_map[confno_int] = 1;
00905
00906 cnfout:
00907 if (cnf)
00908 ast_atomic_fetchadd_int(&cnf->refcount, refcount);
00909
00910 AST_LIST_UNLOCK(&confs);
00911
00912 return cnf;
00913 }
00914
00915
00916 static char *complete_meetmecmd(const char *line, const char *word, int pos, int state)
00917 {
00918 static char *cmds[] = {"concise", "lock", "unlock", "mute", "unmute", "kick", "list", NULL};
00919
00920 int len = strlen(word);
00921 int which = 0;
00922 struct ast_conference *cnf = NULL;
00923 struct ast_conf_user *usr = NULL;
00924 char *confno = NULL;
00925 char usrno[50] = "";
00926 char *myline, *ret = NULL;
00927
00928 if (pos == 1) {
00929 return ast_cli_complete(word, cmds, state);
00930 } else if (pos == 2) {
00931 AST_LIST_LOCK(&confs);
00932 AST_LIST_TRAVERSE(&confs, cnf, list) {
00933 if (!strncasecmp(word, cnf->confno, len) && ++which > state) {
00934 ret = cnf->confno;
00935 break;
00936 }
00937 }
00938 ret = ast_strdup(ret);
00939 AST_LIST_UNLOCK(&confs);
00940 return ret;
00941 } else if (pos == 3) {
00942
00943 if (strstr(line, "mute") || strstr(line, "kick")) {
00944 if (state == 0 && (strstr(line, "kick") || strstr(line, "mute")) && !strncasecmp(word, "all", len))
00945 return ast_strdup("all");
00946 which++;
00947 AST_LIST_LOCK(&confs);
00948
00949
00950 myline = ast_strdupa(line);
00951 if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
00952 while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
00953 ;
00954 }
00955
00956 AST_LIST_TRAVERSE(&confs, cnf, list) {
00957 if (!strcmp(confno, cnf->confno))
00958 break;
00959 }
00960
00961 if (cnf) {
00962
00963 AST_LIST_TRAVERSE(&cnf->userlist, usr, list) {
00964 snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
00965 if (!strncasecmp(word, usrno, len) && ++which > state)
00966 break;
00967 }
00968 }
00969 AST_LIST_UNLOCK(&confs);
00970 return usr ? ast_strdup(usrno) : NULL;
00971 } else if (strstr(line, "list") && (state == 0))
00972 return ast_strdup("concise");
00973 }
00974
00975 return NULL;
00976 }
00977
00978 static char *meetme_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00979 {
00980
00981 struct ast_conference *cnf;
00982 struct ast_conf_user *user;
00983 int hr, min, sec;
00984 int i = 0, total = 0;
00985 time_t now;
00986 struct ast_str *cmdline = NULL;
00987 #define MC_HEADER_FORMAT "%-14s %-14s %-10s %-8s %-8s %-6s\n"
00988 #define MC_DATA_FORMAT "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s %-6s\n"
00989
00990 switch (cmd) {
00991 case CLI_INIT:
00992 e->command = "meetme";
00993 e->usage =
00994 "Usage: meetme (un)lock|(un)mute|kick|list [concise] <confno> <usernumber>\n"
00995 " Executes a command for the conference or on a conferee\n";
00996 return NULL;
00997 case CLI_GENERATE:
00998 return complete_meetmecmd(a->line, a->word, a->pos, a->n);
00999 }
01000
01001 if (a->argc > 8)
01002 ast_cli(a->fd, "Invalid Arguments.\n");
01003
01004 for (i = 0; i < a->argc; i++) {
01005 if (strlen(a->argv[i]) > 100)
01006 ast_cli(a->fd, "Invalid Arguments.\n");
01007 }
01008
01009
01010 if (!(cmdline = ast_str_create(MAX_CONFNUM))) {
01011 return CLI_FAILURE;
01012 }
01013
01014 if (a->argc == 1 || (a->argc == 2 && !strcasecmp(a->argv[1], "concise"))) {
01015
01016 int concise = (a->argc == 2 && !strcasecmp(a->argv[1], "concise"));
01017 now = time(NULL);
01018 AST_LIST_LOCK(&confs);
01019 if (AST_LIST_EMPTY(&confs)) {
01020 if (!concise) {
01021 ast_cli(a->fd, "No active MeetMe conferences.\n");
01022 }
01023 AST_LIST_UNLOCK(&confs);
01024 ast_free(cmdline);
01025 return CLI_SUCCESS;
01026 }
01027 if (!concise) {
01028 ast_cli(a->fd, MC_HEADER_FORMAT, "Conf Num", "Parties", "Marked", "Activity", "Creation", "Locked");
01029 }
01030 AST_LIST_TRAVERSE(&confs, cnf, list) {
01031 if (cnf->markedusers == 0) {
01032 ast_str_set(&cmdline, 0, "N/A ");
01033 } else {
01034 ast_str_set(&cmdline, 0, "%4.4d", cnf->markedusers);
01035 }
01036 hr = (now - cnf->start) / 3600;
01037 min = ((now - cnf->start) % 3600) / 60;
01038 sec = (now - cnf->start) % 60;
01039 if (!concise) {
01040 ast_cli(a->fd, MC_DATA_FORMAT, cnf->confno, cnf->users, cmdline->str, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static", cnf->locked ? "Yes" : "No");
01041 } else {
01042 ast_cli(a->fd, "%s!%d!%d!%02d:%02d:%02d!%d!%d\n",
01043 cnf->confno,
01044 cnf->users,
01045 cnf->markedusers,
01046 hr, min, sec,
01047 cnf->isdynamic,
01048 cnf->locked);
01049 }
01050
01051 total += cnf->users;
01052 }
01053 AST_LIST_UNLOCK(&confs);
01054 if (!concise) {
01055 ast_cli(a->fd, "* Total number of MeetMe users: %d\n", total);
01056 }
01057 ast_free(cmdline);
01058 return CLI_SUCCESS;
01059 }
01060 if (a->argc < 3) {
01061 ast_free(cmdline);
01062 return CLI_SHOWUSAGE;
01063 }
01064
01065 ast_str_set(&cmdline, 0, "%s", a->argv[2]);
01066 if (strstr(a->argv[1], "lock")) {
01067 if (strcmp(a->argv[1], "lock") == 0) {
01068
01069 ast_str_append(&cmdline, 0, ",L");
01070 } else {
01071
01072 ast_str_append(&cmdline, 0, ",l");
01073 }
01074 } else if (strstr(a->argv[1], "mute")) {
01075 if (a->argc < 4) {
01076 ast_free(cmdline);
01077 return CLI_SHOWUSAGE;
01078 }
01079 if (strcmp(a->argv[1], "mute") == 0) {
01080
01081 if (strcmp(a->argv[3], "all") == 0) {
01082 ast_str_append(&cmdline, 0, ",N");
01083 } else {
01084 ast_str_append(&cmdline, 0, ",M,%s", a->argv[3]);
01085 }
01086 } else {
01087
01088 if (strcmp(a->argv[3], "all") == 0) {
01089 ast_str_append(&cmdline, 0, ",n");
01090 } else {
01091 ast_str_append(&cmdline, 0, ",m,%s", a->argv[3]);
01092 }
01093 }
01094 } else if (strcmp(a->argv[1], "kick") == 0) {
01095 if (a->argc < 4) {
01096 ast_free(cmdline);
01097 return CLI_SHOWUSAGE;
01098 }
01099 if (strcmp(a->argv[3], "all") == 0) {
01100
01101 ast_str_append(&cmdline, 0, ",K");
01102 } else {
01103
01104 ast_str_append(&cmdline, 0, ",k,%s", a->argv[3]);
01105 }
01106 } else if (strcmp(a->argv[1], "list") == 0) {
01107 int concise = (a->argc == 4 && (!strcasecmp(a->argv[3], "concise")));
01108
01109 if (AST_LIST_EMPTY(&confs)) {
01110 if (!concise) {
01111 ast_cli(a->fd, "No active conferences.\n");
01112 }
01113 ast_free(cmdline);
01114 return CLI_SUCCESS;
01115 }
01116
01117 AST_LIST_LOCK(&confs);
01118 AST_LIST_TRAVERSE(&confs, cnf, list) {
01119 if (strcmp(cnf->confno, a->argv[2]) == 0) {
01120 break;
01121 }
01122 }
01123 if (!cnf) {
01124 if (!concise)
01125 ast_cli(a->fd, "No such conference: %s.\n", a->argv[2]);
01126 AST_LIST_UNLOCK(&confs);
01127 ast_free(cmdline);
01128 return CLI_SUCCESS;
01129 }
01130
01131 time(&now);
01132 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
01133 hr = (now - user->jointime) / 3600;
01134 min = ((now - user->jointime) % 3600) / 60;
01135 sec = (now - user->jointime) % 60;
01136 if (!concise) {
01137 ast_cli(a->fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s %s %02d:%02d:%02d\n",
01138 user->user_no,
01139 S_OR(user->chan->cid.cid_num, "<unknown>"),
01140 S_OR(user->chan->cid.cid_name, "<no name>"),
01141 user->chan->name,
01142 user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
01143 user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
01144 user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : user->adminflags & ADMINFLAG_SELFMUTED ? "(Muted)" : "",
01145 user->adminflags & ADMINFLAG_T_REQUEST ? "(Request to Talk)" : "",
01146 istalking(user->talking), hr, min, sec);
01147 } else {
01148 ast_cli(a->fd, "%d!%s!%s!%s!%s!%s!%s!%s!%d!%02d:%02d:%02d\n",
01149 user->user_no,
01150 S_OR(user->chan->cid.cid_num, ""),
01151 S_OR(user->chan->cid.cid_name, ""),
01152 user->chan->name,
01153 user->userflags & CONFFLAG_ADMIN ? "1" : "",
01154 user->userflags & CONFFLAG_MONITOR ? "1" : "",
01155 user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED) ? "1" : "",
01156 user->adminflags & ADMINFLAG_T_REQUEST ? "1" : "",
01157 user->talking, hr, min, sec);
01158 }
01159 }
01160 if (!concise) {
01161 ast_cli(a->fd, "%d users in that conference.\n", cnf->users);
01162 }
01163 AST_LIST_UNLOCK(&confs);
01164 ast_free(cmdline);
01165 return CLI_SUCCESS;
01166 } else {
01167 ast_free(cmdline);
01168 return CLI_SHOWUSAGE;
01169 }
01170
01171 ast_debug(1, "Cmdline: %s\n", cmdline->str);
01172
01173 admin_exec(NULL, cmdline->str);
01174 ast_free(cmdline);
01175
01176 return CLI_SUCCESS;
01177 }
01178
01179 static const char *sla_hold_str(unsigned int hold_access)
01180 {
01181 const char *hold = "Unknown";
01182
01183 switch (hold_access) {
01184 case SLA_HOLD_OPEN:
01185 hold = "Open";
01186 break;
01187 case SLA_HOLD_PRIVATE:
01188 hold = "Private";
01189 default:
01190 break;
01191 }
01192
01193 return hold;
01194 }
01195
01196 static char *sla_show_trunks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01197 {
01198 const struct sla_trunk *trunk;
01199
01200 switch (cmd) {
01201 case CLI_INIT:
01202 e->command = "sla show trunks";
01203 e->usage =
01204 "Usage: sla show trunks\n"
01205 " This will list all trunks defined in sla.conf\n";
01206 return NULL;
01207 case CLI_GENERATE:
01208 return NULL;
01209 }
01210
01211 ast_cli(a->fd, "\n"
01212 "=============================================================\n"
01213 "=== Configured SLA Trunks ===================================\n"
01214 "=============================================================\n"
01215 "===\n");
01216 AST_RWLIST_RDLOCK(&sla_trunks);
01217 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
01218 struct sla_station_ref *station_ref;
01219 char ring_timeout[16] = "(none)";
01220 if (trunk->ring_timeout)
01221 snprintf(ring_timeout, sizeof(ring_timeout), "%u Seconds", trunk->ring_timeout);
01222 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01223 "=== Trunk Name: %s\n"
01224 "=== ==> Device: %s\n"
01225 "=== ==> AutoContext: %s\n"
01226 "=== ==> RingTimeout: %s\n"
01227 "=== ==> BargeAllowed: %s\n"
01228 "=== ==> HoldAccess: %s\n"
01229 "=== ==> Stations ...\n",
01230 trunk->name, trunk->device,
01231 S_OR(trunk->autocontext, "(none)"),
01232 ring_timeout,
01233 trunk->barge_disabled ? "No" : "Yes",
01234 sla_hold_str(trunk->hold_access));
01235 AST_RWLIST_RDLOCK(&sla_stations);
01236 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry)
01237 ast_cli(a->fd, "=== ==> Station name: %s\n", station_ref->station->name);
01238 AST_RWLIST_UNLOCK(&sla_stations);
01239 ast_cli(a->fd, "=== ---------------------------------------------------------\n===\n");
01240 }
01241 AST_RWLIST_UNLOCK(&sla_trunks);
01242 ast_cli(a->fd, "=============================================================\n\n");
01243
01244 return CLI_SUCCESS;
01245 }
01246
01247 static const char *trunkstate2str(enum sla_trunk_state state)
01248 {
01249 #define S(e) case e: return # e;
01250 switch (state) {
01251 S(SLA_TRUNK_STATE_IDLE)
01252 S(SLA_TRUNK_STATE_RINGING)
01253 S(SLA_TRUNK_STATE_UP)
01254 S(SLA_TRUNK_STATE_ONHOLD)
01255 S(SLA_TRUNK_STATE_ONHOLD_BYME)
01256 }
01257 return "Uknown State";
01258 #undef S
01259 }
01260
01261 static char *sla_show_stations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01262 {
01263 const struct sla_station *station;
01264
01265 switch (cmd) {
01266 case CLI_INIT:
01267 e->command = "sla show stations";
01268 e->usage =
01269 "Usage: sla show stations\n"
01270 " This will list all stations defined in sla.conf\n";
01271 return NULL;
01272 case CLI_GENERATE:
01273 return NULL;
01274 }
01275
01276 ast_cli(a->fd, "\n"
01277 "=============================================================\n"
01278 "=== Configured SLA Stations =================================\n"
01279 "=============================================================\n"
01280 "===\n");
01281 AST_RWLIST_RDLOCK(&sla_stations);
01282 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01283 struct sla_trunk_ref *trunk_ref;
01284 char ring_timeout[16] = "(none)";
01285 char ring_delay[16] = "(none)";
01286 if (station->ring_timeout) {
01287 snprintf(ring_timeout, sizeof(ring_timeout),
01288 "%u", station->ring_timeout);
01289 }
01290 if (station->ring_delay) {
01291 snprintf(ring_delay, sizeof(ring_delay),
01292 "%u", station->ring_delay);
01293 }
01294 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01295 "=== Station Name: %s\n"
01296 "=== ==> Device: %s\n"
01297 "=== ==> AutoContext: %s\n"
01298 "=== ==> RingTimeout: %s\n"
01299 "=== ==> RingDelay: %s\n"
01300 "=== ==> HoldAccess: %s\n"
01301 "=== ==> Trunks ...\n",
01302 station->name, station->device,
01303 S_OR(station->autocontext, "(none)"),
01304 ring_timeout, ring_delay,
01305 sla_hold_str(station->hold_access));
01306 AST_RWLIST_RDLOCK(&sla_trunks);
01307 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01308 if (trunk_ref->ring_timeout) {
01309 snprintf(ring_timeout, sizeof(ring_timeout),
01310 "%u", trunk_ref->ring_timeout);
01311 } else
01312 strcpy(ring_timeout, "(none)");
01313 if (trunk_ref->ring_delay) {
01314 snprintf(ring_delay, sizeof(ring_delay),
01315 "%u", trunk_ref->ring_delay);
01316 } else
01317 strcpy(ring_delay, "(none)");
01318 ast_cli(a->fd, "=== ==> Trunk Name: %s\n"
01319 "=== ==> State: %s\n"
01320 "=== ==> RingTimeout: %s\n"
01321 "=== ==> RingDelay: %s\n",
01322 trunk_ref->trunk->name,
01323 trunkstate2str(trunk_ref->state),
01324 ring_timeout, ring_delay);
01325 }
01326 AST_RWLIST_UNLOCK(&sla_trunks);
01327 ast_cli(a->fd, "=== ---------------------------------------------------------\n"
01328 "===\n");
01329 }
01330 AST_RWLIST_UNLOCK(&sla_stations);
01331 ast_cli(a->fd, "============================================================\n"
01332 "\n");
01333
01334 return CLI_SUCCESS;
01335 }
01336
01337 static struct ast_cli_entry cli_meetme[] = {
01338 AST_CLI_DEFINE(meetme_cmd, "Execute a command on a conference or conferee"),
01339 AST_CLI_DEFINE(sla_show_trunks, "Show SLA Trunks"),
01340 AST_CLI_DEFINE(sla_show_stations, "Show SLA Stations"),
01341 };
01342
01343 static void conf_flush(int fd, struct ast_channel *chan)
01344 {
01345 int x;
01346
01347
01348
01349
01350 if (chan) {
01351 struct ast_frame *f;
01352
01353
01354
01355
01356 while (ast_waitfor(chan, 1)) {
01357 f = ast_read(chan);
01358 if (f)
01359 ast_frfree(f);
01360 else
01361 break;
01362 }
01363 }
01364
01365
01366 x = DAHDI_FLUSH_ALL;
01367 if (ioctl(fd, DAHDI_FLUSH, &x))
01368 ast_log(LOG_WARNING, "Error flushing channel\n");
01369
01370 }
01371
01372
01373
01374 static int conf_free(struct ast_conference *conf)
01375 {
01376 int x;
01377 struct announce_listitem *item;
01378
01379 AST_LIST_REMOVE(&confs, conf, list);
01380 manager_event(EVENT_FLAG_CALL, "MeetmeEnd", "Meetme: %s\r\n", conf->confno);
01381
01382 if (conf->recording == MEETME_RECORD_ACTIVE) {
01383 conf->recording = MEETME_RECORD_TERMINATE;
01384 AST_LIST_UNLOCK(&confs);
01385 while (1) {
01386 usleep(1);
01387 AST_LIST_LOCK(&confs);
01388 if (conf->recording == MEETME_RECORD_OFF)
01389 break;
01390 AST_LIST_UNLOCK(&confs);
01391 }
01392 }
01393
01394 for (x = 0; x < AST_FRAME_BITS; x++) {
01395 if (conf->transframe[x])
01396 ast_frfree(conf->transframe[x]);
01397 if (conf->transpath[x])
01398 ast_translator_free_path(conf->transpath[x]);
01399 }
01400 if (conf->announcethread != AST_PTHREADT_NULL) {
01401 ast_mutex_lock(&conf->announcelistlock);
01402 conf->announcethread_stop = 1;
01403 ast_softhangup(conf->chan, AST_SOFTHANGUP_EXPLICIT);
01404 ast_cond_signal(&conf->announcelist_addition);
01405 ast_mutex_unlock(&conf->announcelistlock);
01406 pthread_join(conf->announcethread, NULL);
01407
01408 while ((item = AST_LIST_REMOVE_HEAD(&conf->announcelist, entry))) {
01409 ast_filedelete(item->namerecloc, NULL);
01410 ao2_ref(item, -1);
01411 }
01412 ast_mutex_destroy(&conf->announcelistlock);
01413 }
01414 if (conf->origframe)
01415 ast_frfree(conf->origframe);
01416 if (conf->lchan)
01417 ast_hangup(conf->lchan);
01418 if (conf->chan)
01419 ast_hangup(conf->chan);
01420 if (conf->fd >= 0)
01421 close(conf->fd);
01422 if (conf->recordingfilename) {
01423 ast_free(conf->recordingfilename);
01424 }
01425 if (conf->recordingformat) {
01426 ast_free(conf->recordingformat);
01427 }
01428 ast_mutex_destroy(&conf->playlock);
01429 ast_mutex_destroy(&conf->listenlock);
01430 ast_mutex_destroy(&conf->recordthreadlock);
01431 ast_mutex_destroy(&conf->announcethreadlock);
01432 ast_free(conf);
01433
01434 return 0;
01435 }
01436
01437 static void conf_queue_dtmf(const struct ast_conference *conf,
01438 const struct ast_conf_user *sender, struct ast_frame *f)
01439 {
01440 struct ast_conf_user *user;
01441
01442 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
01443 if (user == sender)
01444 continue;
01445 if (ast_write(user->chan, f) < 0)
01446 ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
01447 }
01448 }
01449
01450 static void sla_queue_event_full(enum sla_event_type type,
01451 struct sla_trunk_ref *trunk_ref, struct sla_station *station, int lock)
01452 {
01453 struct sla_event *event;
01454
01455 if (sla.thread == AST_PTHREADT_NULL) {
01456 return;
01457 }
01458
01459 if (!(event = ast_calloc(1, sizeof(*event))))
01460 return;
01461
01462 event->type = type;
01463 event->trunk_ref = trunk_ref;
01464 event->station = station;
01465
01466 if (!lock) {
01467 AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01468 return;
01469 }
01470
01471 ast_mutex_lock(&sla.lock);
01472 AST_LIST_INSERT_TAIL(&sla.event_q, event, entry);
01473 ast_cond_signal(&sla.cond);
01474 ast_mutex_unlock(&sla.lock);
01475 }
01476
01477 static void sla_queue_event_nolock(enum sla_event_type type)
01478 {
01479 sla_queue_event_full(type, NULL, NULL, 0);
01480 }
01481
01482 static void sla_queue_event(enum sla_event_type type)
01483 {
01484 sla_queue_event_full(type, NULL, NULL, 1);
01485 }
01486
01487
01488 static void sla_queue_event_conf(enum sla_event_type type, struct ast_channel *chan,
01489 struct ast_conference *conf)
01490 {
01491 struct sla_station *station;
01492 struct sla_trunk_ref *trunk_ref = NULL;
01493 char *trunk_name;
01494
01495 trunk_name = ast_strdupa(conf->confno);
01496 strsep(&trunk_name, "_");
01497 if (ast_strlen_zero(trunk_name)) {
01498 ast_log(LOG_ERROR, "Invalid conference name for SLA - '%s'!\n", conf->confno);
01499 return;
01500 }
01501
01502 AST_RWLIST_RDLOCK(&sla_stations);
01503 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
01504 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
01505 if (trunk_ref->chan == chan && !strcmp(trunk_ref->trunk->name, trunk_name))
01506 break;
01507 }
01508 if (trunk_ref)
01509 break;
01510 }
01511 AST_RWLIST_UNLOCK(&sla_stations);
01512
01513 if (!trunk_ref) {
01514 ast_debug(1, "Trunk not found for event!\n");
01515 return;
01516 }
01517
01518 sla_queue_event_full(type, trunk_ref, station, 1);
01519 }
01520
01521
01522 static int dispose_conf(struct ast_conference *conf)
01523 {
01524 int res = 0;
01525 int confno_int = 0;
01526
01527 AST_LIST_LOCK(&confs);
01528 if (ast_atomic_dec_and_test(&conf->refcount)) {
01529
01530 if ((sscanf(conf->confno, "%4d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
01531 conf_map[confno_int] = 0;
01532 conf_free(conf);
01533 res = 1;
01534 }
01535 AST_LIST_UNLOCK(&confs);
01536
01537 return res;
01538 }
01539
01540 static void conf_start_moh(struct ast_channel *chan, const char *musicclass)
01541 {
01542 char *original_moh;
01543
01544 ast_channel_lock(chan);
01545 original_moh = ast_strdupa(chan->musicclass);
01546 ast_string_field_set(chan, musicclass, musicclass);
01547 ast_channel_unlock(chan);
01548
01549 ast_moh_start(chan, original_moh, NULL);
01550
01551 ast_channel_lock(chan);
01552 ast_string_field_set(chan, musicclass, original_moh);
01553 ast_channel_unlock(chan);
01554 }
01555
01556 static const char *get_announce_filename(enum announcetypes type)
01557 {
01558 switch (type) {
01559 case CONF_HASLEFT:
01560 return "conf-hasleft";
01561 break;
01562 case CONF_HASJOIN:
01563 return "conf-hasjoin";
01564 break;
01565 default:
01566 return "";
01567 }
01568 }
01569
01570 static void *announce_thread(void *data)
01571 {
01572 struct announce_listitem *current;
01573 struct ast_conference *conf = data;
01574 int res = 0;
01575 char filename[PATH_MAX] = "";
01576 AST_LIST_HEAD_NOLOCK(, announce_listitem) local_list;
01577 AST_LIST_HEAD_INIT_NOLOCK(&local_list);
01578
01579 while (!conf->announcethread_stop) {
01580 ast_mutex_lock(&conf->announcelistlock);
01581 if (conf->announcethread_stop) {
01582 ast_mutex_unlock(&conf->announcelistlock);
01583 break;
01584 }
01585 if (AST_LIST_EMPTY(&conf->announcelist))
01586 ast_cond_wait(&conf->announcelist_addition, &conf->announcelistlock);
01587
01588 AST_LIST_APPEND_LIST(&local_list, &conf->announcelist, entry);
01589 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
01590
01591 ast_mutex_unlock(&conf->announcelistlock);
01592 if (conf->announcethread_stop) {
01593 break;
01594 }
01595
01596 for (res = 1; !conf->announcethread_stop && (current = AST_LIST_REMOVE_HEAD(&local_list, entry)); ao2_ref(current, -1)) {
01597 ast_log(LOG_DEBUG, "About to play %s\n", current->namerecloc);
01598 if (!ast_fileexists(current->namerecloc, NULL, NULL))
01599 continue;
01600 if ((current->confchan) && (current->confusers > 1) && !ast_check_hangup(current->confchan)) {
01601 if (!ast_streamfile(current->confchan, current->namerecloc, current->language))
01602 res = ast_waitstream(current->confchan, "");
01603 if (!res) {
01604 ast_copy_string(filename, get_announce_filename(current->announcetype), sizeof(filename));
01605 if (!ast_streamfile(current->confchan, filename, current->language))
01606 ast_waitstream(current->confchan, "");
01607 }
01608 }
01609 if (current->announcetype == CONF_HASLEFT) {
01610 ast_filedelete(current->namerecloc, NULL);
01611 }
01612 }
01613 }
01614
01615
01616 while ((current = AST_LIST_REMOVE_HEAD(&local_list, entry))) {
01617 ast_filedelete(current->namerecloc, NULL);
01618 ao2_ref(current, -1);
01619 }
01620 return NULL;
01621 }
01622
01623 static int can_write(struct ast_channel *chan, int confflags)
01624 {
01625 if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
01626 return 1;
01627 }
01628
01629 return (chan->_state == AST_STATE_UP);
01630 }
01631
01632 static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags, char *optargs[])
01633 {
01634 struct ast_conf_user *user = NULL;
01635 struct ast_conf_user *usr = NULL;
01636 int fd;
01637 struct dahdi_confinfo dahdic, dahdic_empty;
01638 struct ast_frame *f;
01639 struct ast_channel *c;
01640 struct ast_frame fr;
01641 int outfd;
01642 int ms;
01643 int nfds;
01644 int res;
01645 int retrydahdi;
01646 int origfd;
01647 int musiconhold = 0;
01648 int firstpass = 0;
01649 int lastmarked = 0;
01650 int currentmarked = 0;
01651 int ret = -1;
01652 int x;
01653 int menu_active = 0;
01654 int talkreq_manager = 0;
01655 int using_pseudo = 0;
01656 int duration = 20;
01657 int hr, min, sec;
01658 int sent_event = 0;
01659 int checked = 0;
01660 int announcement_played = 0;
01661 struct timeval now;
01662 struct ast_dsp *dsp = NULL;
01663 struct ast_app *agi_app;
01664 char *agifile;
01665 const char *agifiledefault = "conf-background.agi", *tmpvar;
01666 char meetmesecs[30] = "";
01667 char exitcontext[AST_MAX_CONTEXT] = "";
01668 char recordingtmp[AST_MAX_EXTENSION] = "";
01669 char members[10] = "";
01670 int dtmf, opt_waitmarked_timeout = 0;
01671 time_t timeout = 0;
01672 struct dahdi_bufferinfo bi;
01673 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
01674 char *buf = __buf + AST_FRIENDLY_OFFSET;
01675 char *exitkeys = NULL;
01676 unsigned int calldurationlimit = 0;
01677 long timelimit = 0;
01678 long play_warning = 0;
01679 long warning_freq = 0;
01680 const char *warning_sound = NULL;
01681 const char *end_sound = NULL;
01682 char *parse;
01683 long time_left_ms = 0;
01684 struct timeval nexteventts = { 0, };
01685 int to;
01686 int setusercount = 0;
01687
01688 if (!(user = ast_calloc(1, sizeof(*user))))
01689 return ret;
01690
01691
01692 if ((confflags & CONFFLAG_WAITMARKED) &&
01693 !ast_strlen_zero(optargs[OPT_ARG_WAITMARKED]) &&
01694 (sscanf(optargs[OPT_ARG_WAITMARKED], "%30d", &opt_waitmarked_timeout) == 1) &&
01695 (opt_waitmarked_timeout > 0)) {
01696 timeout = time(NULL) + opt_waitmarked_timeout;
01697 }
01698
01699 if ((confflags & CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) {
01700 calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]);
01701 ast_verb(3, "Setting call duration limit to %d seconds.\n", calldurationlimit);
01702 }
01703
01704 if ((confflags & CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) {
01705 char *limit_str, *warning_str, *warnfreq_str;
01706 const char *var;
01707
01708 parse = optargs[OPT_ARG_DURATION_LIMIT];
01709 limit_str = strsep(&parse, ":");
01710 warning_str = strsep(&parse, ":");
01711 warnfreq_str = parse;
01712
01713 timelimit = atol(limit_str);
01714 if (warning_str)
01715 play_warning = atol(warning_str);
01716 if (warnfreq_str)
01717 warning_freq = atol(warnfreq_str);
01718
01719 if (!timelimit) {
01720 timelimit = play_warning = warning_freq = 0;
01721 warning_sound = NULL;
01722 } else if (play_warning > timelimit) {
01723 if (!warning_freq) {
01724 play_warning = 0;
01725 } else {
01726 while (play_warning > timelimit)
01727 play_warning -= warning_freq;
01728 if (play_warning < 1)
01729 play_warning = warning_freq = 0;
01730 }
01731 }
01732
01733 ast_channel_lock(chan);
01734 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_WARNING_FILE"))) {
01735 var = ast_strdupa(var);
01736 }
01737 ast_channel_unlock(chan);
01738
01739 warning_sound = var ? var : "timeleft";
01740
01741 ast_channel_lock(chan);
01742 if ((var = pbx_builtin_getvar_helper(chan, "CONF_LIMIT_TIMEOUT_FILE"))) {
01743 var = ast_strdupa(var);
01744 }
01745 ast_channel_unlock(chan);
01746
01747 end_sound = var ? var : NULL;
01748
01749
01750 calldurationlimit = 0;
01751
01752 if (!play_warning && !end_sound && timelimit) {
01753 calldurationlimit = timelimit / 1000;
01754 timelimit = play_warning = warning_freq = 0;
01755 } else {
01756 ast_debug(2, "Limit Data for this call:\n");
01757 ast_debug(2, "- timelimit = %ld\n", timelimit);
01758 ast_debug(2, "- play_warning = %ld\n", play_warning);
01759 ast_debug(2, "- warning_freq = %ld\n", warning_freq);
01760 ast_debug(2, "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF");
01761 ast_debug(2, "- end_sound = %s\n", end_sound ? end_sound : "UNDEF");
01762 }
01763 }
01764
01765
01766 if ((confflags & CONFFLAG_KEYEXIT)) {
01767 if (!ast_strlen_zero(optargs[OPT_ARG_EXITKEYS]))
01768 exitkeys = ast_strdupa(optargs[OPT_ARG_EXITKEYS]);
01769 else
01770 exitkeys = ast_strdupa("#");
01771 }
01772
01773 if (confflags & CONFFLAG_RECORDCONF) {
01774 if (!conf->recordingfilename) {
01775 const char *var;
01776 ast_channel_lock(chan);
01777 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"))) {
01778 conf->recordingfilename = ast_strdup(var);
01779 }
01780 if ((var = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT"))) {
01781 conf->recordingformat = ast_strdup(var);
01782 }
01783 ast_channel_unlock(chan);
01784 if (!conf->recordingfilename) {
01785 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
01786 conf->recordingfilename = ast_strdup(recordingtmp);
01787 }
01788 if (!conf->recordingformat) {
01789 conf->recordingformat = ast_strdup("wav");
01790 }
01791 ast_verb(4, "Starting recording of MeetMe Conference %s into file %s.%s.\n",
01792 conf->confno, conf->recordingfilename, conf->recordingformat);
01793 }
01794 }
01795
01796 ast_mutex_lock(&conf->recordthreadlock);
01797 if ((conf->recordthread == AST_PTHREADT_NULL) && (confflags & CONFFLAG_RECORDCONF) && ((conf->lchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, "pseudo", NULL)))) {
01798 ast_set_read_format(conf->lchan, AST_FORMAT_SLINEAR);
01799 ast_set_write_format(conf->lchan, AST_FORMAT_SLINEAR);
01800 dahdic.chan = 0;
01801 dahdic.confno = conf->dahdiconf;
01802 dahdic.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
01803 if (ioctl(conf->lchan->fds[0], DAHDI_SETCONF, &dahdic)) {
01804 ast_log(LOG_WARNING, "Error starting listen channel\n");
01805 ast_hangup(conf->lchan);
01806 conf->lchan = NULL;
01807 } else {
01808 ast_pthread_create_detached_background(&conf->recordthread, NULL, recordthread, conf);
01809 }
01810 }
01811 ast_mutex_unlock(&conf->recordthreadlock);
01812
01813 ast_mutex_lock(&conf->announcethreadlock);
01814 if ((conf->announcethread == AST_PTHREADT_NULL) && !(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
01815 ast_mutex_init(&conf->announcelistlock);
01816 AST_LIST_HEAD_INIT_NOLOCK(&conf->announcelist);
01817 ast_pthread_create_background(&conf->announcethread, NULL, announce_thread, conf);
01818 }
01819 ast_mutex_unlock(&conf->announcethreadlock);
01820
01821 time(&user->jointime);
01822
01823 user->timelimit = timelimit;
01824 user->play_warning = play_warning;
01825 user->warning_freq = warning_freq;
01826 user->warning_sound = warning_sound;
01827 user->end_sound = end_sound;
01828
01829 if (calldurationlimit > 0) {
01830 time(&user->kicktime);
01831 user->kicktime = user->kicktime + calldurationlimit;
01832 }
01833
01834 if (ast_tvzero(user->start_time))
01835 user->start_time = ast_tvnow();
01836 time_left_ms = user->timelimit;
01837
01838 if (user->timelimit) {
01839 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
01840 nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000));
01841 }
01842
01843 if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
01844
01845 if (!ast_streamfile(chan, "conf-locked", chan->language))
01846 ast_waitstream(chan, "");
01847 goto outrun;
01848 }
01849
01850 ast_mutex_lock(&conf->playlock);
01851
01852 if (AST_LIST_EMPTY(&conf->userlist))
01853 user->user_no = 1;
01854 else
01855 user->user_no = AST_LIST_LAST(&conf->userlist)->user_no + 1;
01856
01857 if (rt_schedule && conf->maxusers)
01858 if (conf->users >= conf->maxusers) {
01859
01860 if (!ast_streamfile(chan, "conf-full", chan->language))
01861 ast_waitstream(chan, "");
01862 ast_mutex_unlock(&conf->playlock);
01863 user->user_no = 0;
01864 goto outrun;
01865 }
01866
01867 AST_LIST_INSERT_TAIL(&conf->userlist, user, list);
01868
01869 user->chan = chan;
01870 user->userflags = confflags;
01871 user->adminflags = (confflags & CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
01872 user->talking = -1;
01873
01874 ast_mutex_unlock(&conf->playlock);
01875
01876 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW))) {
01877 char destdir[PATH_MAX];
01878
01879 snprintf(destdir, sizeof(destdir), "%s/meetme", ast_config_AST_SPOOL_DIR);
01880
01881 if (ast_mkdir(destdir, 0777) != 0) {
01882 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", destdir, strerror(errno));
01883 goto outrun;
01884 }
01885
01886 snprintf(user->namerecloc, sizeof(user->namerecloc),
01887 "%s/meetme-username-%s-%d", destdir,
01888 conf->confno, user->user_no);
01889 if (confflags & CONFFLAG_INTROUSERNOREVIEW)
01890 res = ast_play_and_record(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL);
01891 else
01892 res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
01893 if (res == -1)
01894 goto outrun;
01895 }
01896
01897 ast_mutex_lock(&conf->playlock);
01898
01899 if (confflags & CONFFLAG_MARKEDUSER)
01900 conf->markedusers++;
01901 conf->users++;
01902 if (rt_log_members) {
01903
01904 snprintf(members, sizeof(members), "%d", conf->users);
01905 ast_realtime_require_field("meetme",
01906 "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
01907 "members", RQ_UINTEGER1, strlen(members),
01908 NULL);
01909 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
01910 }
01911 setusercount = 1;
01912
01913
01914 if (conf->users == 1)
01915 ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno);
01916
01917 ast_mutex_unlock(&conf->playlock);
01918
01919
01920 pbx_builtin_setvar_helper(chan, "MEETMEUNIQUEID", conf->uniqueid);
01921
01922 if (confflags & CONFFLAG_EXIT_CONTEXT) {
01923 ast_channel_lock(chan);
01924 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) {
01925 ast_copy_string(exitcontext, tmpvar, sizeof(exitcontext));
01926 } else if (!ast_strlen_zero(chan->macrocontext)) {
01927 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
01928 } else {
01929 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
01930 }
01931 ast_channel_unlock(chan);
01932 }
01933
01934 if (!(confflags & (CONFFLAG_QUIET | CONFFLAG_NOONLYPERSON))) {
01935 if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
01936 if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
01937 ast_waitstream(chan, "");
01938 if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
01939 if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
01940 ast_waitstream(chan, "");
01941 }
01942
01943 if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
01944 int keepplaying = 1;
01945
01946 if (conf->users == 2) {
01947 if (!ast_streamfile(chan, "conf-onlyone", chan->language)) {
01948 res = ast_waitstream(chan, AST_DIGIT_ANY);
01949 ast_stopstream(chan);
01950 if (res > 0)
01951 keepplaying = 0;
01952 else if (res == -1)
01953 goto outrun;
01954 }
01955 } else {
01956 if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
01957 res = ast_waitstream(chan, AST_DIGIT_ANY);
01958 ast_stopstream(chan);
01959 if (res > 0)
01960 keepplaying = 0;
01961 else if (res == -1)
01962 goto outrun;
01963 }
01964 if (keepplaying) {
01965 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
01966 if (res > 0)
01967 keepplaying = 0;
01968 else if (res == -1)
01969 goto outrun;
01970 }
01971 if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
01972 res = ast_waitstream(chan, AST_DIGIT_ANY);
01973 ast_stopstream(chan);
01974 if (res > 0)
01975 keepplaying = 0;
01976 else if (res == -1)
01977 goto outrun;
01978 }
01979 }
01980 }
01981
01982 if (!(confflags & CONFFLAG_NO_AUDIO_UNTIL_UP)) {
01983
01984 ast_indicate(chan, -1);
01985 }
01986
01987 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
01988 ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
01989 goto outrun;
01990 }
01991
01992 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
01993 ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
01994 goto outrun;
01995 }
01996
01997 retrydahdi = (strcasecmp(chan->tech->type, "DAHDI") || (chan->audiohooks || chan->monitor) ? 1 : 0);
01998 user->dahdichannel = !retrydahdi;
01999
02000 dahdiretry:
02001 origfd = chan->fds[0];
02002 if (retrydahdi) {
02003
02004 fd = open("/dev/dahdi/pseudo", O_RDWR | O_NONBLOCK);
02005 if (fd < 0) {
02006 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
02007 goto outrun;
02008 }
02009 using_pseudo = 1;
02010
02011 memset(&bi, 0, sizeof(bi));
02012 bi.bufsize = CONF_SIZE / 2;
02013 bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
02014 bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
02015 bi.numbufs = audio_buffers;
02016 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
02017 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
02018 close(fd);
02019 goto outrun;
02020 }
02021 x = 1;
02022 if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
02023 ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
02024 close(fd);
02025 goto outrun;
02026 }
02027 nfds = 1;
02028 } else {
02029
02030 fd = chan->fds[0];
02031 nfds = 0;
02032 }
02033 memset(&dahdic, 0, sizeof(dahdic));
02034 memset(&dahdic_empty, 0, sizeof(dahdic_empty));
02035
02036 dahdic.chan = 0;
02037 if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
02038 ast_log(LOG_WARNING, "Error getting conference\n");
02039 close(fd);
02040 goto outrun;
02041 }
02042 if (dahdic.confmode) {
02043
02044 if (!retrydahdi) {
02045 ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
02046 retrydahdi = 1;
02047 goto dahdiretry;
02048 }
02049 }
02050 memset(&dahdic, 0, sizeof(dahdic));
02051
02052 dahdic.chan = 0;
02053 dahdic.confno = conf->dahdiconf;
02054
02055 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
02056 struct announce_listitem *item;
02057 if (!(item = ao2_alloc(sizeof(*item), NULL)))
02058 return -1;
02059 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
02060 ast_copy_string(item->language, chan->language, sizeof(item->language));
02061 item->confchan = conf->chan;
02062 item->confusers = conf->users;
02063 item->announcetype = CONF_HASJOIN;
02064 ast_mutex_lock(&conf->announcelistlock);
02065 ao2_ref(item, +1);
02066 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
02067 ast_cond_signal(&conf->announcelist_addition);
02068 ast_mutex_unlock(&conf->announcelistlock);
02069
02070 while (!ast_check_hangup(conf->chan) && ao2_ref(item, 0) == 2 && !ast_safe_sleep(chan, 1000)) {
02071 ;
02072 }
02073 ao2_ref(item, -1);
02074 }
02075
02076 if (confflags & CONFFLAG_WAITMARKED && !conf->markedusers)
02077 dahdic.confmode = DAHDI_CONF_CONF;
02078 else if (confflags & CONFFLAG_MONITOR)
02079 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
02080 else if (confflags & CONFFLAG_TALKER)
02081 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
02082 else
02083 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
02084
02085 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02086 ast_log(LOG_WARNING, "Error setting conference\n");
02087 close(fd);
02088 goto outrun;
02089 }
02090 ast_debug(1, "Placed channel %s in DAHDI conf %d\n", chan->name, conf->dahdiconf);
02091
02092 if (!sent_event) {
02093 manager_event(EVENT_FLAG_CALL, "MeetmeJoin",
02094 "Channel: %s\r\n"
02095 "Uniqueid: %s\r\n"
02096 "Meetme: %s\r\n"
02097 "Usernum: %d\r\n"
02098 "CallerIDnum: %s\r\n"
02099 "CallerIDname: %s\r\n",
02100 chan->name, chan->uniqueid, conf->confno,
02101 user->user_no,
02102 S_OR(user->chan->cid.cid_num, "<unknown>"),
02103 S_OR(user->chan->cid.cid_name, "<unknown>")
02104 );
02105 sent_event = 1;
02106 }
02107
02108 if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
02109 firstpass = 1;
02110 if (!(confflags & CONFFLAG_QUIET))
02111 if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
02112 conf_play(chan, conf, ENTER);
02113 }
02114
02115 conf_flush(fd, chan);
02116
02117 if (confflags & CONFFLAG_AGI) {
02118
02119
02120
02121 ast_channel_lock(chan);
02122 if ((tmpvar = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND"))) {
02123 agifile = ast_strdupa(tmpvar);
02124 } else {
02125 agifile = ast_strdupa(agifiledefault);
02126 }
02127 ast_channel_unlock(chan);
02128
02129 if (user->dahdichannel) {
02130
02131 x = 1;
02132 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02133 }
02134
02135 agi_app = pbx_findapp("agi");
02136 if (agi_app) {
02137 ret = pbx_exec(chan, agi_app, agifile);
02138 } else {
02139 ast_log(LOG_WARNING, "Could not find application (agi)\n");
02140 ret = -2;
02141 }
02142 if (user->dahdichannel) {
02143
02144 x = 0;
02145 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02146 }
02147 } else {
02148 if (user->dahdichannel && (confflags & CONFFLAG_STARMENU)) {
02149
02150 x = 1;
02151 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
02152 }
02153 if (confflags & (CONFFLAG_OPTIMIZETALKER | CONFFLAG_MONITORTALKER) && !(dsp = ast_dsp_new())) {
02154 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
02155 res = -1;
02156 }
02157 for (;;) {
02158 int menu_was_active = 0;
02159
02160 outfd = -1;
02161 ms = -1;
02162 now = ast_tvnow();
02163
02164 if (rt_schedule) {
02165 if (now.tv_sec % 60 == 0) {
02166 if (!checked) {
02167 if (now.tv_sec >= conf->endtime) {
02168 goto outrun;
02169 }
02170
02171 if (!announcement_played && conf->endalert) {
02172 if (now.tv_sec + conf->endalert >= conf->endtime) {
02173 if (!ast_streamfile(chan, "conf-will-end-in", chan->language))
02174 ast_waitstream(chan, "");
02175 ast_say_digits(chan, (conf->endtime - now.tv_sec) / 60, "", chan->language);
02176 if (!ast_streamfile(chan, "minutes", chan->language))
02177 ast_waitstream(chan, "");
02178 announcement_played = 1;
02179 }
02180 }
02181 checked = 1;
02182
02183 }
02184 } else {
02185 checked = 0;
02186 }
02187 }
02188
02189 if (user->kicktime && (user->kicktime <= now.tv_sec))
02190 break;
02191
02192 to = -1;
02193 if (user->timelimit) {
02194 int minutes = 0, seconds = 0, remain = 0;
02195
02196 to = ast_tvdiff_ms(nexteventts, now);
02197 if (to < 0)
02198 to = 0;
02199 time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time);
02200 if (time_left_ms < to)
02201 to = time_left_ms;
02202
02203 if (time_left_ms <= 0) {
02204 if (user->end_sound) {
02205 res = ast_streamfile(chan, user->end_sound, chan->language);
02206 res = ast_waitstream(chan, "");
02207 }
02208 break;
02209 }
02210
02211 if (!to) {
02212 if (time_left_ms >= 5000) {
02213
02214 remain = (time_left_ms + 500) / 1000;
02215 if (remain / 60 >= 1) {
02216 minutes = remain / 60;
02217 seconds = remain % 60;
02218 } else {
02219 seconds = remain;
02220 }
02221
02222
02223 if (user->warning_sound && user->play_warning) {
02224 if (!strcmp(user->warning_sound, "timeleft")) {
02225
02226 res = ast_streamfile(chan, "vm-youhave", chan->language);
02227 res = ast_waitstream(chan, "");
02228 if (minutes) {
02229 res = ast_say_number(chan, minutes, AST_DIGIT_ANY, chan->language, (char *) NULL);
02230 res = ast_streamfile(chan, "queue-minutes", chan->language);
02231 res = ast_waitstream(chan, "");
02232 }
02233 if (seconds) {
02234 res = ast_say_number(chan, seconds, AST_DIGIT_ANY, chan->language, (char *) NULL);
02235 res = ast_streamfile(chan, "queue-seconds", chan->language);
02236 res = ast_waitstream(chan, "");
02237 }
02238 } else {
02239 res = ast_streamfile(chan, user->warning_sound, chan->language);
02240 res = ast_waitstream(chan, "");
02241 }
02242 }
02243 }
02244 if (user->warning_freq)
02245 nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000));
02246 else
02247 nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000));
02248 }
02249 }
02250
02251 now = ast_tvnow();
02252 if (timeout && now.tv_sec >= timeout)
02253 break;
02254
02255
02256
02257
02258 if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual)
02259 set_talk_volume(user, user->listen.desired);
02260
02261 menu_was_active = menu_active;
02262
02263 currentmarked = conf->markedusers;
02264 if (!(confflags & CONFFLAG_QUIET) &&
02265 (confflags & CONFFLAG_MARKEDUSER) &&
02266 (confflags & CONFFLAG_WAITMARKED) &&
02267 lastmarked == 0) {
02268 if (currentmarked == 1 && conf->users > 1) {
02269 ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
02270 if (conf->users - 1 == 1) {
02271 if (!ast_streamfile(chan, "conf-userwilljoin", chan->language))
02272 ast_waitstream(chan, "");
02273 } else {
02274 if (!ast_streamfile(chan, "conf-userswilljoin", chan->language))
02275 ast_waitstream(chan, "");
02276 }
02277 }
02278 if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER))
02279 if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
02280 ast_waitstream(chan, "");
02281 }
02282
02283
02284 user->userflags = confflags;
02285
02286 if (confflags & CONFFLAG_WAITMARKED) {
02287 if (currentmarked == 0) {
02288 if (lastmarked != 0) {
02289 if (!(confflags & CONFFLAG_QUIET))
02290 if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language))
02291 ast_waitstream(chan, "");
02292 if (confflags & CONFFLAG_MARKEDEXIT) {
02293 if (confflags & CONFFLAG_KICK_CONTINUE)
02294 ret = 0;
02295 break;
02296 } else {
02297 dahdic.confmode = DAHDI_CONF_CONF;
02298 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02299 ast_log(LOG_WARNING, "Error setting conference\n");
02300 close(fd);
02301 goto outrun;
02302 }
02303 }
02304 }
02305 if (!musiconhold && (confflags & CONFFLAG_MOH)) {
02306 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02307 musiconhold = 1;
02308 }
02309 } else if (currentmarked >= 1 && lastmarked == 0) {
02310
02311 timeout = 0;
02312 if (confflags & CONFFLAG_MONITOR)
02313 dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
02314 else if (confflags & CONFFLAG_TALKER)
02315 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER;
02316 else
02317 dahdic.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
02318 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02319 ast_log(LOG_WARNING, "Error setting conference\n");
02320 close(fd);
02321 goto outrun;
02322 }
02323 if (musiconhold && (confflags & CONFFLAG_MOH)) {
02324 ast_moh_stop(chan);
02325 musiconhold = 0;
02326 }
02327 if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
02328 if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
02329 ast_waitstream(chan, "");
02330 conf_play(chan, conf, ENTER);
02331 }
02332 }
02333 }
02334
02335
02336 if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
02337 if (conf->users == 1) {
02338 if (!musiconhold) {
02339 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02340 musiconhold = 1;
02341 }
02342 } else {
02343 if (musiconhold) {
02344 ast_moh_stop(chan);
02345 musiconhold = 0;
02346 }
02347 }
02348 }
02349
02350
02351 if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
02352 if (confflags & CONFFLAG_KICK_CONTINUE)
02353 ret = 0;
02354 else
02355 ret = -1;
02356 break;
02357 }
02358
02359
02360
02361
02362 if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && (dahdic.confmode & DAHDI_CONF_TALKER)) {
02363 dahdic.confmode ^= DAHDI_CONF_TALKER;
02364 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02365 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
02366 ret = -1;
02367 break;
02368 }
02369
02370 manager_event(EVENT_FLAG_CALL, "MeetmeMute",
02371 "Channel: %s\r\n"
02372 "Uniqueid: %s\r\n"
02373 "Meetme: %s\r\n"
02374 "Usernum: %i\r\n"
02375 "Status: on\r\n",
02376 chan->name, chan->uniqueid, conf->confno, user->user_no);
02377 }
02378
02379
02380 if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) && !(confflags & CONFFLAG_MONITOR) && !(dahdic.confmode & DAHDI_CONF_TALKER)) {
02381 dahdic.confmode |= DAHDI_CONF_TALKER;
02382 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02383 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
02384 ret = -1;
02385 break;
02386 }
02387
02388 manager_event(EVENT_FLAG_CALL, "MeetmeMute",
02389 "Channel: %s\r\n"
02390 "Uniqueid: %s\r\n"
02391 "Meetme: %s\r\n"
02392 "Usernum: %i\r\n"
02393 "Status: off\r\n",
02394 chan->name, chan->uniqueid, conf->confno, user->user_no);
02395 }
02396
02397 if ((user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
02398 (user->adminflags & ADMINFLAG_T_REQUEST) && !(talkreq_manager)) {
02399 talkreq_manager = 1;
02400
02401 manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest",
02402 "Channel: %s\r\n"
02403 "Uniqueid: %s\r\n"
02404 "Meetme: %s\r\n"
02405 "Usernum: %i\r\n"
02406 "Status: on\r\n",
02407 chan->name, chan->uniqueid, conf->confno, user->user_no);
02408 }
02409
02410
02411 if (!(user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) &&
02412 !(user->adminflags & ADMINFLAG_T_REQUEST) && (talkreq_manager)) {
02413 talkreq_manager = 0;
02414 manager_event(EVENT_FLAG_CALL, "MeetmeTalkRequest",
02415 "Channel: %s\r\n"
02416 "Uniqueid: %s\r\n"
02417 "Meetme: %s\r\n"
02418 "Usernum: %i\r\n"
02419 "Status: off\r\n",
02420 chan->name, chan->uniqueid, conf->confno, user->user_no);
02421 }
02422
02423
02424 if (user->adminflags & ADMINFLAG_KICKME) {
02425
02426 if (!(confflags & CONFFLAG_QUIET) &&
02427 !ast_streamfile(chan, "conf-kicked", chan->language)) {
02428 ast_waitstream(chan, "");
02429 }
02430 ret = 0;
02431 break;
02432 }
02433
02434
02435 if (ast_check_hangup(chan))
02436 break;
02437
02438 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
02439
02440 if (c) {
02441 char dtmfstr[2] = "";
02442
02443 if (c->fds[0] != origfd || (user->dahdichannel && (c->audiohooks || c->monitor))) {
02444 if (using_pseudo) {
02445
02446 close(fd);
02447 using_pseudo = 0;
02448 }
02449 ast_debug(1, "Ooh, something swapped out under us, starting over\n");
02450 retrydahdi = (strcasecmp(c->tech->type, "DAHDI") || (c->audiohooks || c->monitor) ? 1 : 0);
02451 user->dahdichannel = !retrydahdi;
02452 goto dahdiretry;
02453 }
02454 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)))
02455 f = ast_read_noaudio(c);
02456 else
02457 f = ast_read(c);
02458 if (!f)
02459 break;
02460 if (f->frametype == AST_FRAME_DTMF) {
02461 dtmfstr[0] = f->subclass;
02462 dtmfstr[1] = '\0';
02463 }
02464
02465 if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
02466 if (user->talk.actual)
02467 ast_frame_adjust_volume(f, user->talk.actual);
02468
02469 if (confflags & (CONFFLAG_OPTIMIZETALKER | CONFFLAG_MONITORTALKER)) {
02470 int totalsilence;
02471
02472 if (user->talking == -1)
02473 user->talking = 0;
02474
02475 res = ast_dsp_silence(dsp, f, &totalsilence);
02476 if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
02477 user->talking = 1;
02478 if (confflags & CONFFLAG_MONITORTALKER)
02479 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
02480 "Channel: %s\r\n"
02481 "Uniqueid: %s\r\n"
02482 "Meetme: %s\r\n"
02483 "Usernum: %d\r\n"
02484 "Status: on\r\n",
02485 chan->name, chan->uniqueid, conf->confno, user->user_no);
02486 }
02487 if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
02488 user->talking = 0;
02489 if (confflags & CONFFLAG_MONITORTALKER)
02490 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
02491 "Channel: %s\r\n"
02492 "Uniqueid: %s\r\n"
02493 "Meetme: %s\r\n"
02494 "Usernum: %d\r\n"
02495 "Status: off\r\n",
02496 chan->name, chan->uniqueid, conf->confno, user->user_no);
02497 }
02498 }
02499 if (using_pseudo) {
02500
02501
02502
02503
02504
02505
02506
02507
02508
02509
02510
02511
02512 if (user->talking && !(confflags & CONFFLAG_OPTIMIZETALKER)) {
02513 careful_write(fd, f->data.ptr, f->datalen, 0);
02514 }
02515 }
02516 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
02517 if (confflags & CONFFLAG_PASS_DTMF)
02518 conf_queue_dtmf(conf, user, f);
02519 if (ioctl(fd, DAHDI_SETCONF, &dahdic_empty)) {
02520 ast_log(LOG_WARNING, "Error setting conference\n");
02521 close(fd);
02522 ast_frfree(f);
02523 goto outrun;
02524 }
02525
02526
02527
02528
02529 if (!menu_active && user->talk.desired && !user->talk.actual)
02530 set_talk_volume(user, 0);
02531
02532 if (musiconhold) {
02533 ast_moh_stop(chan);
02534 }
02535 if ((confflags & CONFFLAG_ADMIN)) {
02536
02537 if (!menu_active) {
02538 menu_active = 1;
02539
02540 if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
02541 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02542 ast_stopstream(chan);
02543 } else
02544 dtmf = 0;
02545 } else
02546 dtmf = f->subclass;
02547 if (dtmf) {
02548 switch(dtmf) {
02549 case '1':
02550 menu_active = 0;
02551
02552
02553 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
02554 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02555 else
02556 user->adminflags |= (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED);
02557
02558 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02559 if (!ast_streamfile(chan, "conf-muted", chan->language))
02560 ast_waitstream(chan, "");
02561 } else {
02562 if (!ast_streamfile(chan, "conf-unmuted", chan->language))
02563 ast_waitstream(chan, "");
02564 }
02565 break;
02566 case '2':
02567 menu_active = 0;
02568 if (conf->locked) {
02569 conf->locked = 0;
02570 if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
02571 ast_waitstream(chan, "");
02572 } else {
02573 conf->locked = 1;
02574 if (!ast_streamfile(chan, "conf-lockednow", chan->language))
02575 ast_waitstream(chan, "");
02576 }
02577 break;
02578 case '3':
02579 menu_active = 0;
02580 usr = AST_LIST_LAST(&conf->userlist);
02581 if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
02582 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02583 ast_waitstream(chan, "");
02584 } else
02585 usr->adminflags |= ADMINFLAG_KICKME;
02586 ast_stopstream(chan);
02587 break;
02588 case '4':
02589 tweak_listen_volume(user, VOL_DOWN);
02590 break;
02591 case '6':
02592 tweak_listen_volume(user, VOL_UP);
02593 break;
02594 case '7':
02595 tweak_talk_volume(user, VOL_DOWN);
02596 break;
02597 case '8':
02598 menu_active = 0;
02599 break;
02600 case '9':
02601 tweak_talk_volume(user, VOL_UP);
02602 break;
02603 default:
02604 menu_active = 0;
02605
02606 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02607 ast_waitstream(chan, "");
02608 break;
02609 }
02610 }
02611 } else {
02612
02613 if (!menu_active) {
02614 menu_active = 1;
02615 if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
02616 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
02617 ast_stopstream(chan);
02618 } else
02619 dtmf = 0;
02620 } else
02621 dtmf = f->subclass;
02622 if (dtmf) {
02623 switch(dtmf) {
02624 case '1':
02625 menu_active = 0;
02626
02627
02628 user->adminflags ^= ADMINFLAG_SELFMUTED;
02629
02630
02631 if ((confflags & CONFFLAG_MONITOR) || (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))) {
02632 if (!ast_streamfile(chan, "conf-muted", chan->language))
02633 ast_waitstream(chan, "");
02634 } else {
02635 if (!ast_streamfile(chan, "conf-unmuted", chan->language))
02636 ast_waitstream(chan, "");
02637 }
02638 break;
02639 case '2':
02640 menu_active = 0;
02641 if (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED))
02642 user->adminflags |= ADMINFLAG_T_REQUEST;
02643
02644 if (user->adminflags & ADMINFLAG_T_REQUEST)
02645 if (!ast_streamfile(chan, "beep", chan->language))
02646 ast_waitstream(chan, "");
02647 break;
02648 case '4':
02649 tweak_listen_volume(user, VOL_DOWN);
02650 break;
02651 case '6':
02652 tweak_listen_volume(user, VOL_UP);
02653 break;
02654 case '7':
02655 tweak_talk_volume(user, VOL_DOWN);
02656 break;
02657 case '8':
02658 menu_active = 0;
02659 break;
02660 case '9':
02661 tweak_talk_volume(user, VOL_UP);
02662 break;
02663 default:
02664 menu_active = 0;
02665 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
02666 ast_waitstream(chan, "");
02667 break;
02668 }
02669 }
02670 }
02671 if (musiconhold)
02672 conf_start_moh(chan, optargs[OPT_ARG_MOH_CLASS]);
02673
02674 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02675 ast_log(LOG_WARNING, "Error setting conference\n");
02676 close(fd);
02677 ast_frfree(f);
02678 goto outrun;
02679 }
02680
02681 conf_flush(fd, chan);
02682
02683 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT) && ast_exists_extension(chan, exitcontext, dtmfstr, 1, "")) {
02684 if (confflags & CONFFLAG_PASS_DTMF)
02685 conf_queue_dtmf(conf, user, f);
02686
02687 if (!ast_goto_if_exists(chan, exitcontext, dtmfstr, 1)) {
02688 ast_debug(1, "Got DTMF %c, goto context %s\n", dtmfstr[0], exitcontext);
02689 ret = 0;
02690 ast_frfree(f);
02691 break;
02692 } else {
02693 ast_debug(2, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", dtmfstr, exitcontext);
02694 }
02695 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_KEYEXIT) && (strchr(exitkeys, f->subclass))) {
02696 pbx_builtin_setvar_helper(chan, "MEETME_EXIT_KEY", dtmfstr);
02697
02698 if (confflags & CONFFLAG_PASS_DTMF)
02699 conf_queue_dtmf(conf, user, f);
02700 ret = 0;
02701 ast_frfree(f);
02702 break;
02703 } else if ((f->frametype == AST_FRAME_DTMF_BEGIN || f->frametype == AST_FRAME_DTMF_END)
02704 && confflags & CONFFLAG_PASS_DTMF) {
02705 conf_queue_dtmf(conf, user, f);
02706 } else if ((confflags & CONFFLAG_SLA_STATION) && f->frametype == AST_FRAME_CONTROL) {
02707 switch (f->subclass) {
02708 case AST_CONTROL_HOLD:
02709 sla_queue_event_conf(SLA_EVENT_HOLD, chan, conf);
02710 break;
02711 default:
02712 break;
02713 }
02714 } else if (f->frametype == AST_FRAME_NULL) {
02715
02716 } else {
02717 ast_debug(1,
02718 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
02719 chan->name, f->frametype, f->subclass);
02720 }
02721 ast_frfree(f);
02722 } else if (outfd > -1) {
02723 res = read(outfd, buf, CONF_SIZE);
02724 if (res > 0) {
02725 memset(&fr, 0, sizeof(fr));
02726 fr.frametype = AST_FRAME_VOICE;
02727 fr.subclass = AST_FORMAT_SLINEAR;
02728 fr.datalen = res;
02729 fr.samples = res / 2;
02730 fr.data.ptr = buf;
02731 fr.offset = AST_FRIENDLY_OFFSET;
02732 if (!user->listen.actual &&
02733 ((confflags & CONFFLAG_MONITOR) ||
02734 (user->adminflags & (ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED)) ||
02735 (!user->talking && (confflags & CONFFLAG_OPTIMIZETALKER))
02736 )) {
02737 int idx;
02738 for (idx = 0; idx < AST_FRAME_BITS; idx++)
02739 if (chan->rawwriteformat & (1 << idx))
02740 break;
02741 if (idx >= AST_FRAME_BITS)
02742 goto bailoutandtrynormal;
02743 ast_mutex_lock(&conf->listenlock);
02744 if (!conf->transframe[idx]) {
02745 if (conf->origframe) {
02746 if (!conf->transpath[idx])
02747 conf->transpath[idx] = ast_translator_build_path((1 << idx), AST_FORMAT_SLINEAR);
02748 if (conf->transpath[idx]) {
02749 conf->transframe[idx] = ast_translate(conf->transpath[idx], conf->origframe, 0);
02750 if (!conf->transframe[idx])
02751 conf->transframe[idx] = &ast_null_frame;
02752 }
02753 }
02754 }
02755 if (conf->transframe[idx]) {
02756 if ((conf->transframe[idx]->frametype != AST_FRAME_NULL) &&
02757 can_write(chan, confflags)) {
02758 struct ast_frame *cur;
02759
02760
02761
02762
02763 for (cur = conf->transframe[idx]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
02764 if (ast_write(chan, cur)) {
02765 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02766 break;
02767 }
02768 }
02769 }
02770 } else {
02771 ast_mutex_unlock(&conf->listenlock);
02772 goto bailoutandtrynormal;
02773 }
02774 ast_mutex_unlock(&conf->listenlock);
02775 } else {
02776 bailoutandtrynormal:
02777 if (user->listen.actual)
02778 ast_frame_adjust_volume(&fr, user->listen.actual);
02779 if (can_write(chan, confflags) && ast_write(chan, &fr) < 0) {
02780 ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
02781 }
02782 }
02783 } else
02784 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
02785 }
02786 lastmarked = currentmarked;
02787 }
02788 }
02789
02790 if (musiconhold)
02791 ast_moh_stop(chan);
02792
02793 if (using_pseudo)
02794 close(fd);
02795 else {
02796
02797 dahdic.chan = 0;
02798 dahdic.confno = 0;
02799 dahdic.confmode = 0;
02800 if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
02801 ast_log(LOG_WARNING, "Error setting conference\n");
02802 }
02803 }
02804
02805 reset_volumes(user);
02806
02807 if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
02808 conf_play(chan, conf, LEAVE);
02809
02810 if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users > 1) {
02811 struct announce_listitem *item;
02812 if (!(item = ao2_alloc(sizeof(*item), NULL)))
02813 return -1;
02814 ast_copy_string(item->namerecloc, user->namerecloc, sizeof(item->namerecloc));
02815 ast_copy_string(item->language, chan->language, sizeof(item->language));
02816 item->confchan = conf->chan;
02817 item->confusers = conf->users;
02818 item->announcetype = CONF_HASLEFT;
02819 ast_mutex_lock(&conf->announcelistlock);
02820 AST_LIST_INSERT_TAIL(&conf->announcelist, item, entry);
02821 ast_cond_signal(&conf->announcelist_addition);
02822 ast_mutex_unlock(&conf->announcelistlock);
02823 } else if (!(confflags & CONFFLAG_QUIET) && ((confflags & CONFFLAG_INTROUSER) || (confflags & CONFFLAG_INTROUSERNOREVIEW)) && conf->users == 1) {
02824
02825 ast_filedelete(user->namerecloc, NULL);
02826 }
02827
02828 outrun:
02829 AST_LIST_LOCK(&confs);
02830
02831 if (dsp)
02832 ast_dsp_free(dsp);
02833
02834 if (user->user_no) {
02835 now = ast_tvnow();
02836 hr = (now.tv_sec - user->jointime) / 3600;
02837 min = ((now.tv_sec - user->jointime) % 3600) / 60;
02838 sec = (now.tv_sec - user->jointime) % 60;
02839
02840 if (sent_event) {
02841 manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
02842 "Channel: %s\r\n"
02843 "Uniqueid: %s\r\n"
02844 "Meetme: %s\r\n"
02845 "Usernum: %d\r\n"
02846 "CallerIDNum: %s\r\n"
02847 "CallerIDName: %s\r\n"
02848 "Duration: %ld\r\n",
02849 chan->name, chan->uniqueid, conf->confno,
02850 user->user_no,
02851 S_OR(user->chan->cid.cid_num, "<unknown>"),
02852 S_OR(user->chan->cid.cid_name, "<unknown>"),
02853 (long)(now.tv_sec - user->jointime));
02854 }
02855
02856 if (setusercount) {
02857 conf->users--;
02858 if (rt_log_members) {
02859
02860 snprintf(members, sizeof(members), "%d", conf->users);
02861 ast_realtime_require_field("meetme",
02862 "confno", strlen(conf->confno) > 7 ? RQ_UINTEGER4 : strlen(conf->confno) > 4 ? RQ_UINTEGER3 : RQ_UINTEGER2, strlen(conf->confno),
02863 "members", RQ_UINTEGER1, strlen(members),
02864 NULL);
02865 ast_update_realtime("meetme", "confno", conf->confno, "members", members, NULL);
02866 }
02867 if (confflags & CONFFLAG_MARKEDUSER)
02868 conf->markedusers--;
02869 }
02870
02871 AST_LIST_REMOVE(&conf->userlist, user, list);
02872
02873
02874 if (!conf->users)
02875 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno);
02876
02877
02878 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
02879 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
02880 }
02881 ast_free(user);
02882 AST_LIST_UNLOCK(&confs);
02883
02884 return ret;
02885 }
02886
02887 static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char *confno, int make, int dynamic,
02888 char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags,
02889 char *optargs[], int *too_early)
02890 {
02891 struct ast_variable *var;
02892 struct ast_conference *cnf;
02893
02894 *too_early = 0;
02895
02896
02897 AST_LIST_LOCK(&confs);
02898 AST_LIST_TRAVERSE(&confs, cnf, list) {
02899 if (!strcmp(confno, cnf->confno))
02900 break;
02901 }
02902 if (cnf) {
02903 cnf->refcount += refcount;
02904 }
02905 AST_LIST_UNLOCK(&confs);
02906
02907 if (!cnf) {
02908 char *pin = NULL, *pinadmin = NULL;
02909 int maxusers = 0;
02910 struct timeval now;
02911 char currenttime[19] = "";
02912 char eatime[19] = "";
02913 char useropts[32] = "";
02914 char adminopts[32] = "";
02915 struct ast_tm tm, etm;
02916 struct timeval endtime = { .tv_sec = 0 };
02917
02918 if (rt_schedule) {
02919 now = ast_tvnow();
02920
02921 ast_localtime(&now, &tm, NULL);
02922 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02923
02924 ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime);
02925
02926 var = ast_load_realtime("meetme", "confno",
02927 confno, "starttime <= ", currenttime, "endtime >= ",
02928 currenttime, NULL);
02929
02930 if (!var && fuzzystart) {
02931 now = ast_tvnow();
02932 now.tv_sec += fuzzystart;
02933
02934 ast_localtime(&now, &tm, NULL);
02935 ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
02936 var = ast_load_realtime("meetme", "confno",
02937 confno, "starttime <= ", currenttime, "endtime >= ",
02938 currenttime, NULL);
02939 }
02940
02941 if (!var && earlyalert) {
02942 now = ast_tvnow();
02943 now.tv_sec += earlyalert;
02944 ast_localtime(&now, &etm, NULL);
02945 ast_strftime(eatime, sizeof(eatime), DATE_FORMAT, &etm);
02946 var = ast_load_realtime("meetme", "confno",
02947 confno, "starttime <= ", eatime, "endtime >= ",
02948 currenttime, NULL);
02949 if (var)
02950 *too_early = 1;
02951 }
02952
02953 } else
02954 var = ast_load_realtime("meetme", "confno", confno, NULL);
02955
02956 if (!var)
02957 return NULL;
02958
02959 if (rt_schedule && *too_early) {
02960
02961 if (!ast_streamfile(chan, "conf-has-not-started", chan->language))
02962 ast_waitstream(chan, "");
02963 ast_variables_destroy(var);
02964 return NULL;
02965 }
02966
02967 while (var) {
02968 if (!strcasecmp(var->name, "pin")) {
02969 pin = ast_strdupa(var->value);
02970 } else if (!strcasecmp(var->name, "adminpin")) {
02971 pinadmin = ast_strdupa(var->value);
02972 } else if (!strcasecmp(var->name, "opts")) {
02973 ast_copy_string(useropts, var->value, sizeof(useropts));
02974 } else if (!strcasecmp(var->name, "maxusers")) {
02975 maxusers = atoi(var->value);
02976 } else if (!strcasecmp(var->name, "adminopts")) {
02977 ast_copy_string(adminopts, var->value, sizeof(adminopts));
02978 } else if (!strcasecmp(var->name, "endtime")) {
02979 union {
02980 struct ast_tm atm;
02981 struct tm tm;
02982 } t = { { 0, }, };
02983 strptime(var->value, "%Y-%m-%d %H:%M:%S", &t.tm);
02984
02985
02986
02987
02988 t.tm.tm_isdst = -1;
02989 endtime = ast_mktime(&t.atm, NULL);
02990 }
02991
02992 var = var->next;
02993 }
02994
02995 ast_variables_destroy(var);
02996
02997 cnf = build_conf(confno, pin ? pin : "", pinadmin ? pinadmin : "", make, dynamic, refcount, chan);
02998
02999 if (cnf) {
03000 cnf->maxusers = maxusers;
03001 cnf->endalert = endalert;
03002 cnf->endtime = endtime.tv_sec;
03003 }
03004 }
03005
03006 if (cnf) {
03007 if (confflags && !cnf->chan &&
03008 !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03009 ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03010 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03011 ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03012 }
03013
03014 if (confflags && !cnf->chan &&
03015 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03016 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03017 ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03018 }
03019 }
03020
03021 return cnf;
03022 }
03023
03024
03025 static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic,
03026 char *dynamic_pin, size_t pin_buf_len, int refcount, struct ast_flags *confflags)
03027 {
03028 struct ast_config *cfg;
03029 struct ast_variable *var;
03030 struct ast_flags config_flags = { 0 };
03031 struct ast_conference *cnf;
03032 char *parse;
03033 AST_DECLARE_APP_ARGS(args,
03034 AST_APP_ARG(confno);
03035 AST_APP_ARG(pin);
03036 AST_APP_ARG(pinadmin);
03037 );
03038
03039
03040 ast_debug(1, "The requested confno is '%s'?\n", confno);
03041 AST_LIST_LOCK(&confs);
03042 AST_LIST_TRAVERSE(&confs, cnf, list) {
03043 ast_debug(3, "Does conf %s match %s?\n", confno, cnf->confno);
03044 if (!strcmp(confno, cnf->confno))
03045 break;
03046 }
03047 if (cnf) {
03048 cnf->refcount += refcount;
03049 }
03050 AST_LIST_UNLOCK(&confs);
03051
03052 if (!cnf) {
03053 if (dynamic) {
03054
03055 ast_debug(1, "Building dynamic conference '%s'\n", confno);
03056 if (dynamic_pin) {
03057 if (dynamic_pin[0] == 'q') {
03058
03059 if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, pin_buf_len - 1, 0) < 0)
03060 return NULL;
03061 }
03062 cnf = build_conf(confno, dynamic_pin, "", make, dynamic, refcount, chan);
03063 } else {
03064 cnf = build_conf(confno, "", "", make, dynamic, refcount, chan);
03065 }
03066 } else {
03067
03068 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03069 if (!cfg) {
03070 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
03071 return NULL;
03072 }
03073 for (var = ast_variable_browse(cfg, "rooms"); var; var = var->next) {
03074 if (strcasecmp(var->name, "conf"))
03075 continue;
03076
03077 if (!(parse = ast_strdupa(var->value)))
03078 return NULL;
03079
03080 AST_STANDARD_APP_ARGS(args, parse);
03081 ast_debug(3, "Will conf %s match %s?\n", confno, args.confno);
03082 if (!strcasecmp(args.confno, confno)) {
03083
03084 cnf = build_conf(args.confno,
03085 S_OR(args.pin, ""),
03086 S_OR(args.pinadmin, ""),
03087 make, dynamic, refcount, chan);
03088 break;
03089 }
03090 }
03091 if (!var) {
03092 ast_debug(1, "%s isn't a valid conference\n", confno);
03093 }
03094 ast_config_destroy(cfg);
03095 }
03096 } else if (dynamic_pin) {
03097
03098
03099
03100 if (dynamic_pin[0] == 'q')
03101 dynamic_pin[0] = '\0';
03102 }
03103
03104 if (cnf) {
03105 if (confflags && !cnf->chan &&
03106 !ast_test_flag(confflags, CONFFLAG_QUIET) &&
03107 ast_test_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW)) {
03108 ast_log(LOG_WARNING, "No DAHDI channel available for conference, user introduction disabled (is chan_dahdi loaded?)\n");
03109 ast_clear_flag(confflags, CONFFLAG_INTROUSER | CONFFLAG_INTROUSERNOREVIEW);
03110 }
03111
03112 if (confflags && !cnf->chan &&
03113 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
03114 ast_log(LOG_WARNING, "No DAHDI channel available for conference, conference recording disabled (is chan_dahdi loaded?)\n");
03115 ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
03116 }
03117 }
03118
03119 return cnf;
03120 }
03121
03122
03123 static int count_exec(struct ast_channel *chan, void *data)
03124 {
03125 int res = 0;
03126 struct ast_conference *conf;
03127 int count;
03128 char *localdata;
03129 char val[80] = "0";
03130 AST_DECLARE_APP_ARGS(args,
03131 AST_APP_ARG(confno);
03132 AST_APP_ARG(varname);
03133 );
03134
03135 if (ast_strlen_zero(data)) {
03136 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
03137 return -1;
03138 }
03139
03140 if (!(localdata = ast_strdupa(data)))
03141 return -1;
03142
03143 AST_STANDARD_APP_ARGS(args, localdata);
03144
03145 conf = find_conf(chan, args.confno, 0, 0, NULL, 0, 1, NULL);
03146
03147 if (conf) {
03148 count = conf->users;
03149 dispose_conf(conf);
03150 conf = NULL;
03151 } else
03152 count = 0;
03153
03154 if (!ast_strlen_zero(args.varname)) {
03155
03156 snprintf(val, sizeof(val), "%d", count);
03157 pbx_builtin_setvar_helper(chan, args.varname, val);
03158 } else {
03159 if (chan->_state != AST_STATE_UP)
03160 ast_answer(chan);
03161 res = ast_say_number(chan, count, "", chan->language, (char *) NULL);
03162 }
03163
03164 return res;
03165 }
03166
03167
03168 static int conf_exec(struct ast_channel *chan, void *data)
03169 {
03170 int res = -1;
03171 char confno[MAX_CONFNUM] = "";
03172 int allowretry = 0;
03173 int retrycnt = 0;
03174 struct ast_conference *cnf = NULL;
03175 struct ast_flags confflags = {0}, config_flags = { 0 };
03176 int dynamic = 0;
03177 int empty = 0, empty_no_pin = 0;
03178 int always_prompt = 0;
03179 char *notdata, *info, the_pin[MAX_PIN] = "";
03180 AST_DECLARE_APP_ARGS(args,
03181 AST_APP_ARG(confno);
03182 AST_APP_ARG(options);
03183 AST_APP_ARG(pin);
03184 );
03185 char *optargs[OPT_ARG_ARRAY_SIZE] = { NULL, };
03186
03187 if (ast_strlen_zero(data)) {
03188 allowretry = 1;
03189 notdata = "";
03190 } else {
03191 notdata = data;
03192 }
03193
03194 if (chan->_state != AST_STATE_UP)
03195 ast_answer(chan);
03196
03197 info = ast_strdupa(notdata);
03198
03199 AST_STANDARD_APP_ARGS(args, info);
03200
03201 if (args.confno) {
03202 ast_copy_string(confno, args.confno, sizeof(confno));
03203 if (ast_strlen_zero(confno)) {
03204 allowretry = 1;
03205 }
03206 }
03207
03208 if (args.pin)
03209 ast_copy_string(the_pin, args.pin, sizeof(the_pin));
03210
03211 if (args.options) {
03212 ast_app_parse_options(meetme_opts, &confflags, optargs, args.options);
03213 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
03214 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && ast_strlen_zero(args.pin))
03215 strcpy(the_pin, "q");
03216
03217 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
03218 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
03219 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT | CONFFLAG_DYNAMICPIN);
03220 }
03221
03222 do {
03223 if (retrycnt > 3)
03224 allowretry = 0;
03225 if (empty) {
03226 int i;
03227 struct ast_config *cfg;
03228 struct ast_variable *var;
03229 int confno_int;
03230
03231
03232 if ((empty_no_pin) || (!dynamic)) {
03233 cfg = ast_config_load(CONFIG_FILE_NAME, config_flags);
03234 if (cfg) {
03235 var = ast_variable_browse(cfg, "rooms");
03236 while (var) {
03237 if (!strcasecmp(var->name, "conf")) {
03238 char *stringp = ast_strdupa(var->value);
03239 if (stringp) {
03240 char *confno_tmp = strsep(&stringp, "|,");
03241 int found = 0;
03242 if (!dynamic) {
03243
03244 AST_LIST_LOCK(&confs);
03245 AST_LIST_TRAVERSE(&confs, cnf, list) {
03246 if (!strcmp(confno_tmp, cnf->confno)) {
03247
03248 found = 1;
03249 break;
03250 }
03251 }
03252 AST_LIST_UNLOCK(&confs);
03253 if (!found) {
03254
03255 if ((empty_no_pin && ast_strlen_zero(stringp)) || (!empty_no_pin)) {
03256
03257
03258
03259
03260 ast_copy_string(confno, confno_tmp, sizeof(confno));
03261 break;
03262
03263 }
03264 }
03265 }
03266 }
03267 }
03268 var = var->next;
03269 }
03270 ast_config_destroy(cfg);
03271 }
03272 }
03273
03274
03275 if (ast_strlen_zero(confno) && dynamic) {
03276 AST_LIST_LOCK(&confs);
03277 for (i = 0; i < ARRAY_LEN(conf_map); i++) {
03278 if (!conf_map[i]) {
03279 snprintf(confno, sizeof(confno), "%d", i);
03280 conf_map[i] = 1;
03281 break;
03282 }
03283 }
03284 AST_LIST_UNLOCK(&confs);
03285 }
03286
03287
03288 if (ast_strlen_zero(confno)) {
03289 res = ast_streamfile(chan, "conf-noempty", chan->language);
03290 if (!res)
03291 ast_waitstream(chan, "");
03292 } else {
03293 if (sscanf(confno, "%30d", &confno_int) == 1) {
03294 if (!ast_test_flag(&confflags, CONFFLAG_QUIET)) {
03295 res = ast_streamfile(chan, "conf-enteringno", chan->language);
03296 if (!res) {
03297 ast_waitstream(chan, "");
03298 res = ast_say_digits(chan, confno_int, "", chan->language);
03299 }
03300 }
03301 } else {
03302 ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
03303 }
03304 }
03305 }
03306
03307 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
03308
03309 res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
03310 if (res < 0) {
03311
03312 confno[0] = '\0';
03313 allowretry = 0;
03314 break;
03315 }
03316 }
03317 if (!ast_strlen_zero(confno)) {
03318
03319 cnf = find_conf(chan, confno, 1, dynamic, the_pin,
03320 sizeof(the_pin), 1, &confflags);
03321 if (!cnf) {
03322 int too_early = 0;
03323 cnf = find_conf_realtime(chan, confno, 1, dynamic,
03324 the_pin, sizeof(the_pin), 1, &confflags, optargs, &too_early);
03325 if (rt_schedule && too_early)
03326 allowretry = 0;
03327 }
03328
03329 if (!cnf) {
03330 if (allowretry) {
03331 confno[0] = '\0';
03332 res = ast_streamfile(chan, "conf-invalid", chan->language);
03333 if (!res)
03334 ast_waitstream(chan, "");
03335 res = -1;
03336 }
03337 } else {
03338 if ((!ast_strlen_zero(cnf->pin) &&
03339 !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
03340 (!ast_strlen_zero(cnf->pinadmin) &&
03341 ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
03342 char pin[MAX_PIN] = "";
03343 int j;
03344
03345
03346 for (j = 0; j < 3; j++) {
03347 if (*the_pin && (always_prompt == 0)) {
03348 ast_copy_string(pin, the_pin, sizeof(pin));
03349 res = 0;
03350 } else {
03351
03352 res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
03353 }
03354 if (res >= 0) {
03355 if (!strcasecmp(pin, cnf->pin) ||
03356 (!ast_strlen_zero(cnf->pinadmin) &&
03357 !strcasecmp(pin, cnf->pinadmin))) {
03358
03359 allowretry = 0;
03360 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin))
03361 ast_set_flag(&confflags, CONFFLAG_ADMIN);
03362
03363 res = conf_run(chan, cnf, confflags.flags, optargs);
03364 break;
03365 } else {
03366
03367 if (!ast_streamfile(chan, "conf-invalidpin", chan->language)) {
03368 res = ast_waitstream(chan, AST_DIGIT_ANY);
03369 ast_stopstream(chan);
03370 }
03371 else {
03372 ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
03373 break;
03374 }
03375 if (res < 0)
03376 break;
03377 pin[0] = res;
03378 pin[1] = '\0';
03379 res = -1;
03380 if (allowretry)
03381 confno[0] = '\0';
03382 }
03383 } else {
03384
03385 res = -1;
03386 allowretry = 0;
03387
03388 break;
03389 }
03390
03391
03392 if (*the_pin && (always_prompt == 0)) {
03393 break;
03394 }
03395 }
03396 } else {
03397
03398 allowretry = 0;
03399
03400
03401 res = conf_run(chan, cnf, confflags.flags, optargs);
03402 }
03403 dispose_conf(cnf);
03404 cnf = NULL;
03405 }
03406 }
03407 } while (allowretry);
03408
03409 if (cnf)
03410 dispose_conf(cnf);
03411
03412 return res;
03413 }
03414
03415 static struct ast_conf_user *find_user(struct ast_conference *conf, char *callerident)
03416 {
03417 struct ast_conf_user *user = NULL;
03418 int cid;
03419
03420 sscanf(callerident, "%30i", &cid);
03421 if (conf && callerident) {
03422 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03423 if (cid == user->user_no)
03424 return user;
03425 }
03426 }
03427 return NULL;
03428 }
03429
03430
03431
03432 static int admin_exec(struct ast_channel *chan, void *data) {
03433 char *params;
03434 struct ast_conference *cnf;
03435 struct ast_conf_user *user = NULL;
03436 AST_DECLARE_APP_ARGS(args,
03437 AST_APP_ARG(confno);
03438 AST_APP_ARG(command);
03439 AST_APP_ARG(user);
03440 );
03441
03442 if (ast_strlen_zero(data)) {
03443 ast_log(LOG_WARNING, "MeetMeAdmin requires an argument!\n");
03444 return -1;
03445 }
03446
03447 params = ast_strdupa(data);
03448 AST_STANDARD_APP_ARGS(args, params);
03449
03450 if (!args.command) {
03451 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
03452 return -1;
03453 }
03454
03455 AST_LIST_LOCK(&confs);
03456 AST_LIST_TRAVERSE(&confs, cnf, list) {
03457 if (!strcmp(cnf->confno, args.confno))
03458 break;
03459 }
03460
03461 if (!cnf) {
03462 ast_log(LOG_WARNING, "Conference number '%s' not found!\n", args.confno);
03463 AST_LIST_UNLOCK(&confs);
03464 return 0;
03465 }
03466
03467 ast_atomic_fetchadd_int(&cnf->refcount, 1);
03468
03469 if (args.user)
03470 user = find_user(cnf, args.user);
03471
03472 switch (*args.command) {
03473 case 76:
03474 cnf->locked = 1;
03475 break;
03476 case 108:
03477 cnf->locked = 0;
03478 break;
03479 case 75:
03480 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03481 user->adminflags |= ADMINFLAG_KICKME;
03482 break;
03483 case 101:
03484 user = AST_LIST_LAST(&cnf->userlist);
03485 if (!(user->userflags & CONFFLAG_ADMIN))
03486 user->adminflags |= ADMINFLAG_KICKME;
03487 else
03488 ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
03489 break;
03490 case 77:
03491 if (user) {
03492 user->adminflags |= ADMINFLAG_MUTED;
03493 } else
03494 ast_log(LOG_NOTICE, "Specified User not found!\n");
03495 break;
03496 case 78:
03497 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
03498 if (!(user->userflags & CONFFLAG_ADMIN))
03499 user->adminflags |= ADMINFLAG_MUTED;
03500 }
03501 break;
03502 case 109:
03503 if (user) {
03504 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
03505 } else
03506 ast_log(LOG_NOTICE, "Specified User not found!\n");
03507 break;
03508 case 110:
03509 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03510 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
03511 break;
03512 case 107:
03513 if (user)
03514 user->adminflags |= ADMINFLAG_KICKME;
03515 else
03516 ast_log(LOG_NOTICE, "Specified User not found!\n");
03517 break;
03518 case 118:
03519 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03520 tweak_listen_volume(user, VOL_DOWN);
03521 break;
03522 case 86:
03523 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03524 tweak_listen_volume(user, VOL_UP);
03525 break;
03526 case 115:
03527 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03528 tweak_talk_volume(user, VOL_DOWN);
03529 break;
03530 case 83:
03531 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03532 tweak_talk_volume(user, VOL_UP);
03533 break;
03534 case 82:
03535 AST_LIST_TRAVERSE(&cnf->userlist, user, list)
03536 reset_volumes(user);
03537 break;
03538 case 114:
03539 if (user)
03540 reset_volumes(user);
03541 else
03542 ast_log(LOG_NOTICE, "Specified User not found!\n");
03543 break;
03544 case 85:
03545 if (user)
03546 tweak_listen_volume(user, VOL_UP);
03547 else
03548 ast_log(LOG_NOTICE, "Specified User not found!\n");
03549 break;
03550 case 117:
03551 if (user)
03552 tweak_listen_volume(user, VOL_DOWN);
03553 else
03554 ast_log(LOG_NOTICE, "Specified User not found!\n");
03555 break;
03556 case 84:
03557 if (user)
03558 tweak_talk_volume(user, VOL_UP);
03559 else
03560 ast_log(LOG_NOTICE, "Specified User not found!\n");
03561 break;
03562 case 116:
03563 if (user)
03564 tweak_talk_volume(user, VOL_DOWN);
03565 else
03566 ast_log(LOG_NOTICE, "Specified User not found!\n");
03567 break;
03568 }
03569
03570 AST_LIST_UNLOCK(&confs);
03571
03572 dispose_conf(cnf);
03573
03574 return 0;
03575 }
03576
03577
03578
03579 static int channel_admin_exec(struct ast_channel *chan, void *data) {
03580 char *params;
03581 struct ast_conference *conf = NULL;
03582 struct ast_conf_user *user = NULL;
03583 AST_DECLARE_APP_ARGS(args,
03584 AST_APP_ARG(channel);
03585 AST_APP_ARG(command);
03586 );
03587
03588 if (ast_strlen_zero(data)) {
03589 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires two arguments!\n");
03590 return -1;
03591 }
03592
03593 params = ast_strdupa(data);
03594 AST_STANDARD_APP_ARGS(args, params);
03595
03596 if (!args.channel) {
03597 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a channel name!\n");
03598 return -1;
03599 }
03600
03601 if (!args.command) {
03602 ast_log(LOG_WARNING, "MeetMeChannelAdmin requires a command!\n");
03603 return -1;
03604 }
03605
03606 AST_LIST_LOCK(&confs);
03607 AST_LIST_TRAVERSE(&confs, conf, list) {
03608 AST_LIST_TRAVERSE(&conf->userlist, user, list) {
03609 if (!strcmp(user->chan->name, args.channel))
03610 break;
03611 }
03612 }
03613
03614 if (!user) {
03615 ast_log(LOG_NOTICE, "Specified user (%s) not found\n", args.channel);
03616 AST_LIST_UNLOCK(&confs);
03617 return 0;
03618 }
03619
03620
03621 switch (*args.command) {
03622 case 77:
03623 user->adminflags |= ADMINFLAG_MUTED;
03624 break;
03625 case 109:
03626 user->adminflags &= ~ADMINFLAG_MUTED;
03627 break;
03628 case 107:
03629 user->adminflags |= ADMINFLAG_KICKME;
03630 break;
03631 default:
03632 ast_log(LOG_WARNING, "Unknown MeetMeChannelAdmin command '%s'\n", args.command);
03633 break;
03634 }
03635
03636 AST_LIST_UNLOCK(&confs);
03637
03638 return 0;
03639 }
03640
03641 static int meetmemute(struct mansession *s, const struct message *m, int mute)
03642 {
03643 struct ast_conference *conf;
03644 struct ast_conf_user *user;
03645 const char *confid = astman_get_header(m, "Meetme");
03646 char *userid = ast_strdupa(astman_get_header(m, "Usernum"));
03647 int userno;
03648
03649 if (ast_strlen_zero(confid)) {
03650 astman_send_error(s, m, "Meetme conference not specified");
03651 return 0;
03652 }
03653
03654 if (ast_strlen_zero(userid)) {
03655 astman_send_error(s, m, "Meetme user number not specified");
03656 return 0;
03657 }
03658
03659 userno = strtoul(userid, &userid, 10);
03660
03661 if (*userid) {
03662 astman_send_error(s, m, "Invalid user number");
03663 return 0;
03664 }
03665
03666
03667 AST_LIST_LOCK(&confs);
03668 AST_LIST_TRAVERSE(&confs, conf, list) {
03669 if (!strcmp(confid, conf->confno))
03670 break;
03671 }
03672
03673 if (!conf) {
03674 AST_LIST_UNLOCK(&confs);
03675 astman_send_error(s, m, "Meetme conference does not exist");
03676 return 0;
03677 }
03678
03679 AST_LIST_TRAVERSE(&conf->userlist, user, list)
03680 if (user->user_no == userno)
03681 break;
03682
03683 if (!user) {
03684 AST_LIST_UNLOCK(&confs);
03685 astman_send_error(s, m, "User number not found");
03686 return 0;
03687 }
03688
03689 if (mute)
03690 user->adminflags |= ADMINFLAG_MUTED;
03691 else
03692 user->adminflags &= ~(ADMINFLAG_MUTED | ADMINFLAG_SELFMUTED | ADMINFLAG_T_REQUEST);
03693
03694 AST_LIST_UNLOCK(&confs);
03695
03696 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);
03697
03698 astman_send_ack(s, m, mute ? "User muted" : "User unmuted");
03699 return 0;
03700 }
03701
03702 static int action_meetmemute(struct mansession *s, const struct message *m)
03703 {
03704 return meetmemute(s, m, 1);
03705 }
03706
03707 static int action_meetmeunmute(struct mansession *s, const struct message *m)
03708 {
03709 return meetmemute(s, m, 0);
03710 }
03711
03712 static char mandescr_meetmelist[] =
03713 "Description: Lists all users in a particular MeetMe conference.\n"
03714 "MeetmeList will follow as separate events, followed by a final event called\n"
03715 "MeetmeListComplete.\n"
03716 "Variables:\n"
03717 " *ActionId: <id>\n"
03718 " *Conference: <confno>\n";
03719
03720 static int action_meetmelist(struct mansession *s, const struct message *m)
03721 {
03722 const char *actionid = astman_get_header(m, "ActionID");
03723 const char *conference = astman_get_header(m, "Conference");
03724 char idText[80] = "";
03725 struct ast_conference *cnf;
03726 struct ast_conf_user *user;
03727 int total = 0;
03728
03729 if (!ast_strlen_zero(actionid))
03730 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
03731
03732 if (AST_LIST_EMPTY(&confs)) {
03733 astman_send_error(s, m, "No active conferences.");
03734 return 0;
03735 }
03736
03737 astman_send_listack(s, m, "Meetme user list will follow", "start");
03738
03739
03740 AST_LIST_LOCK(&confs);
03741 AST_LIST_TRAVERSE(&confs, cnf, list) {
03742
03743 if (!ast_strlen_zero(conference) && strcmp(cnf->confno, conference))
03744 continue;
03745
03746
03747 AST_LIST_TRAVERSE(&cnf->userlist, user, list) {
03748 total++;
03749 astman_append(s,
03750 "Event: MeetmeList\r\n"
03751 "%s"
03752 "Conference: %s\r\n"
03753 "UserNumber: %d\r\n"
03754 "CallerIDNum: %s\r\n"
03755 "CallerIDName: %s\r\n"
03756 "Channel: %s\r\n"
03757 "Admin: %s\r\n"
03758 "Role: %s\r\n"
03759 "MarkedUser: %s\r\n"
03760 "Muted: %s\r\n"
03761 "Talking: %s\r\n"
03762 "\r\n",
03763 idText,
03764 cnf->confno,
03765 user->user_no,
03766 S_OR(user->chan->cid.cid_num, "<unknown>"),
03767 S_OR(user->chan->cid.cid_name, "<no name>"),
03768 user->chan->name,
03769 user->userflags & CONFFLAG_ADMIN ? "Yes" : "No",
03770 user->userflags & CONFFLAG_MONITOR ? "Listen only" : user->userflags & CONFFLAG_TALKER ? "Talk only" : "Talk and listen",
03771 user->userflags & CONFFLAG_MARKEDUSER ? "Yes" : "No",
03772 user->adminflags & ADMINFLAG_MUTED ? "By admin" : user->adminflags & ADMINFLAG_SELFMUTED ? "By self" : "No",
03773 user->talking > 0 ? "Yes" : user->talking == 0 ? "No" : "Not monitored");
03774 }
03775 }
03776 AST_LIST_UNLOCK(&confs);
03777
03778 astman_append(s,
03779 "Event: MeetmeListComplete\r\n"
03780 "EventList: Complete\r\n"
03781 "ListItems: %d\r\n"
03782 "%s"
03783 "\r\n", total, idText);
03784 return 0;
03785 }
03786
03787 static void *recordthread(void *args)
03788 {
03789 struct ast_conference *cnf = args;
03790 struct ast_frame *f = NULL;
03791 int flags;
03792 struct ast_filestream *s = NULL;
03793 int res = 0;
03794 int x;
03795 const char *oldrecordingfilename = NULL;
03796
03797 if (!cnf || !cnf->lchan) {
03798 pthread_exit(0);
03799 }
03800
03801 ast_stopstream(cnf->lchan);
03802 flags = O_CREAT | O_TRUNC | O_WRONLY;
03803
03804
03805 cnf->recording = MEETME_RECORD_ACTIVE;
03806 while (ast_waitfor(cnf->lchan, -1) > -1) {
03807 if (cnf->recording == MEETME_RECORD_TERMINATE) {
03808 AST_LIST_LOCK(&confs);
03809 AST_LIST_UNLOCK(&confs);
03810 break;
03811 }
03812 if (!s && cnf->recordingfilename && (cnf->recordingfilename != oldrecordingfilename)) {
03813 s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, AST_FILE_MODE);
03814 oldrecordingfilename = cnf->recordingfilename;
03815 }
03816
03817 f = ast_read(cnf->lchan);
03818 if (!f) {
03819 res = -1;
03820 break;
03821 }
03822 if (f->frametype == AST_FRAME_VOICE) {
03823 ast_mutex_lock(&cnf->listenlock);
03824 for (x = 0; x < AST_FRAME_BITS; x++) {
03825
03826 if (cnf->transframe[x]) {
03827 ast_frfree(cnf->transframe[x]);
03828 cnf->transframe[x] = NULL;
03829 }
03830 }
03831 if (cnf->origframe)
03832 ast_frfree(cnf->origframe);
03833 cnf->origframe = ast_frdup(f);
03834 ast_mutex_unlock(&cnf->listenlock);
03835 if (s)
03836 res = ast_writestream(s, f);
03837 if (res) {
03838 ast_frfree(f);
03839 break;
03840 }
03841 }
03842 ast_frfree(f);
03843 }
03844 cnf->recording = MEETME_RECORD_OFF;
03845 if (s)
03846 ast_closestream(s);
03847
03848 pthread_exit(0);
03849 }
03850
03851
03852 static enum ast_device_state meetmestate(const char *data)
03853 {
03854 struct ast_conference *conf;
03855
03856
03857 AST_LIST_LOCK(&confs);
03858 AST_LIST_TRAVERSE(&confs, conf, list) {
03859 if (!strcmp(data, conf->confno))
03860 break;
03861 }
03862 AST_LIST_UNLOCK(&confs);
03863 if (!conf)
03864 return AST_DEVICE_INVALID;
03865
03866
03867
03868 if (!conf->users)
03869 return AST_DEVICE_NOT_INUSE;
03870
03871 return AST_DEVICE_INUSE;
03872 }
03873
03874 static void load_config_meetme(void)
03875 {
03876 struct ast_config *cfg;
03877 struct ast_flags config_flags = { 0 };
03878 const char *val;
03879
03880 if (!(cfg = ast_config_load(CONFIG_FILE_NAME, config_flags)))
03881 return;
03882
03883 audio_buffers = DEFAULT_AUDIO_BUFFERS;
03884
03885
03886 rt_schedule = 0;
03887 fuzzystart = 0;
03888 earlyalert = 0;
03889 endalert = 0;
03890
03891
03892 rt_log_members = 1;
03893
03894 if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
03895 if ((sscanf(val, "%30d", &audio_buffers) != 1)) {
03896 ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
03897 audio_buffers = DEFAULT_AUDIO_BUFFERS;
03898 } else if ((audio_buffers < DAHDI_DEFAULT_NUM_BUFS) || (audio_buffers > DAHDI_MAX_NUM_BUFS)) {
03899 ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
03900 DAHDI_DEFAULT_NUM_BUFS, DAHDI_MAX_NUM_BUFS);
03901 audio_buffers = DEFAULT_AUDIO_BUFFERS;
03902 }
03903 if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
03904 ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
03905 }
03906
03907 if ((val = ast_variable_retrieve(cfg, "general", "schedule")))
03908 rt_schedule = ast_true(val);
03909 if ((val = ast_variable_retrieve(cfg, "general", "logmembercount")))
03910 rt_log_members = ast_true(val);
03911 if ((val = ast_variable_retrieve(cfg, "general", "fuzzystart"))) {
03912 if ((sscanf(val, "%30d", &fuzzystart) != 1)) {
03913 ast_log(LOG_WARNING, "fuzzystart must be a number, not '%s'\n", val);
03914 fuzzystart = 0;
03915 }
03916 }
03917 if ((val = ast_variable_retrieve(cfg, "general", "earlyalert"))) {
03918 if ((sscanf(val, "%30d", &earlyalert) != 1)) {
03919 ast_log(LOG_WARNING, "earlyalert must be a number, not '%s'\n", val);
03920 earlyalert = 0;
03921 }
03922 }
03923 if ((val = ast_variable_retrieve(cfg, "general", "endalert"))) {
03924 if ((sscanf(val, "%30d", &endalert) != 1)) {
03925 ast_log(LOG_WARNING, "endalert must be a number, not '%s'\n", val);
03926 endalert = 0;
03927 }
03928 }
03929
03930 ast_config_destroy(cfg);
03931 }
03932
03933
03934
03935
03936 static struct sla_trunk *sla_find_trunk(const char *name)
03937 {
03938 struct sla_trunk *trunk = NULL;
03939
03940 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
03941 if (!strcasecmp(trunk->name, name))
03942 break;
03943 }
03944
03945 return trunk;
03946 }
03947
03948
03949
03950
03951 static struct sla_station *sla_find_station(const char *name)
03952 {
03953 struct sla_station *station = NULL;
03954
03955 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
03956 if (!strcasecmp(station->name, name))
03957 break;
03958 }
03959
03960 return station;
03961 }
03962
03963 static int sla_check_station_hold_access(const struct sla_trunk *trunk,
03964 const struct sla_station *station)
03965 {
03966 struct sla_station_ref *station_ref;
03967 struct sla_trunk_ref *trunk_ref;
03968
03969
03970 AST_LIST_TRAVERSE(&trunk->stations, station_ref, entry) {
03971 AST_LIST_TRAVERSE(&station_ref->station->trunks, trunk_ref, entry) {
03972 if (trunk_ref->trunk != trunk || station_ref->station == station)
03973 continue;
03974 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME &&
03975 station_ref->station->hold_access == SLA_HOLD_PRIVATE)
03976 return 1;
03977 return 0;
03978 }
03979 }
03980
03981 return 0;
03982 }
03983
03984
03985
03986
03987
03988
03989
03990
03991 static struct sla_trunk_ref *sla_find_trunk_ref_byname(const struct sla_station *station,
03992 const char *name)
03993 {
03994 struct sla_trunk_ref *trunk_ref = NULL;
03995
03996 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
03997 if (strcasecmp(trunk_ref->trunk->name, name))
03998 continue;
03999
04000 if ( (trunk_ref->trunk->barge_disabled
04001 && trunk_ref->state == SLA_TRUNK_STATE_UP) ||
04002 (trunk_ref->trunk->hold_stations
04003 && trunk_ref->trunk->hold_access == SLA_HOLD_PRIVATE
04004 && trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) ||
04005 sla_check_station_hold_access(trunk_ref->trunk, station) )
04006 {
04007 trunk_ref = NULL;
04008 }
04009
04010 break;
04011 }
04012
04013 return trunk_ref;
04014 }
04015
04016 static struct sla_station_ref *sla_create_station_ref(struct sla_station *station)
04017 {
04018 struct sla_station_ref *station_ref;
04019
04020 if (!(station_ref = ast_calloc(1, sizeof(*station_ref))))
04021 return NULL;
04022
04023 station_ref->station = station;
04024
04025 return station_ref;
04026 }
04027
04028 static struct sla_ringing_station *sla_create_ringing_station(struct sla_station *station)
04029 {
04030 struct sla_ringing_station *ringing_station;
04031
04032 if (!(ringing_station = ast_calloc(1, sizeof(*ringing_station))))
04033 return NULL;
04034
04035 ringing_station->station = station;
04036 ringing_station->ring_begin = ast_tvnow();
04037
04038 return ringing_station;
04039 }
04040
04041 static enum ast_device_state sla_state_to_devstate(enum sla_trunk_state state)
04042 {
04043 switch (state) {
04044 case SLA_TRUNK_STATE_IDLE:
04045 return AST_DEVICE_NOT_INUSE;
04046 case SLA_TRUNK_STATE_RINGING:
04047 return AST_DEVICE_RINGING;
04048 case SLA_TRUNK_STATE_UP:
04049 return AST_DEVICE_INUSE;
04050 case SLA_TRUNK_STATE_ONHOLD:
04051 case SLA_TRUNK_STATE_ONHOLD_BYME:
04052 return AST_DEVICE_ONHOLD;
04053 }
04054
04055 return AST_DEVICE_UNKNOWN;
04056 }
04057
04058 static void sla_change_trunk_state(const struct sla_trunk *trunk, enum sla_trunk_state state,
04059 enum sla_which_trunk_refs inactive_only, const struct sla_trunk_ref *exclude)
04060 {
04061 struct sla_station *station;
04062 struct sla_trunk_ref *trunk_ref;
04063
04064 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04065 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04066 if (trunk_ref->trunk != trunk || (inactive_only ? trunk_ref->chan : 0)
04067 || trunk_ref == exclude)
04068 continue;
04069 trunk_ref->state = state;
04070 ast_devstate_changed(sla_state_to_devstate(state),
04071 "SLA:%s_%s", station->name, trunk->name);
04072 break;
04073 }
04074 }
04075 }
04076
04077 struct run_station_args {
04078 struct sla_station *station;
04079 struct sla_trunk_ref *trunk_ref;
04080 ast_mutex_t *cond_lock;
04081 ast_cond_t *cond;
04082 };
04083
04084 static void answer_trunk_chan(struct ast_channel *chan)
04085 {
04086 ast_answer(chan);
04087 ast_indicate(chan, -1);
04088 }
04089
04090 static void *run_station(void *data)
04091 {
04092 struct sla_station *station;
04093 struct sla_trunk_ref *trunk_ref;
04094 struct ast_str *conf_name = ast_str_create(16);
04095 struct ast_flags conf_flags = { 0 };
04096 struct ast_conference *conf;
04097
04098 {
04099 struct run_station_args *args = data;
04100 station = args->station;
04101 trunk_ref = args->trunk_ref;
04102 ast_mutex_lock(args->cond_lock);
04103 ast_cond_signal(args->cond);
04104 ast_mutex_unlock(args->cond_lock);
04105
04106 }
04107
04108 ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1);
04109 ast_str_set(&conf_name, 0, "SLA_%s", trunk_ref->trunk->name);
04110 ast_set_flag(&conf_flags,
04111 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
04112 answer_trunk_chan(trunk_ref->chan);
04113 conf = build_conf(conf_name->str, "", "", 0, 0, 1, trunk_ref->chan);
04114 if (conf) {
04115 conf_run(trunk_ref->chan, conf, conf_flags.flags, NULL);
04116 dispose_conf(conf);
04117 conf = NULL;
04118 }
04119 trunk_ref->chan = NULL;
04120 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
04121 trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
04122 ast_str_append(&conf_name, 0, ",K");
04123 admin_exec(NULL, conf_name->str);
04124 trunk_ref->trunk->hold_stations = 0;
04125 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04126 }
04127
04128 ast_dial_join(station->dial);
04129 ast_dial_destroy(station->dial);
04130 station->dial = NULL;
04131 ast_free(conf_name);
04132
04133 return NULL;
04134 }
04135
04136 static void sla_stop_ringing_trunk(struct sla_ringing_trunk *ringing_trunk)
04137 {
04138 char buf[80];
04139 struct sla_station_ref *station_ref;
04140
04141 snprintf(buf, sizeof(buf), "SLA_%s,K", ringing_trunk->trunk->name);
04142 admin_exec(NULL, buf);
04143 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04144
04145 while ((station_ref = AST_LIST_REMOVE_HEAD(&ringing_trunk->timed_out_stations, entry)))
04146 ast_free(station_ref);
04147
04148 ast_free(ringing_trunk);
04149 }
04150
04151 static void sla_stop_ringing_station(struct sla_ringing_station *ringing_station,
04152 enum sla_station_hangup hangup)
04153 {
04154 struct sla_ringing_trunk *ringing_trunk;
04155 struct sla_trunk_ref *trunk_ref;
04156 struct sla_station_ref *station_ref;
04157
04158 ast_dial_join(ringing_station->station->dial);
04159 ast_dial_destroy(ringing_station->station->dial);
04160 ringing_station->station->dial = NULL;
04161
04162 if (hangup == SLA_STATION_HANGUP_NORMAL)
04163 goto done;
04164
04165
04166
04167
04168
04169
04170 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04171 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04172 if (ringing_trunk->trunk == trunk_ref->trunk)
04173 break;
04174 }
04175 if (!trunk_ref)
04176 continue;
04177 if (!(station_ref = sla_create_station_ref(ringing_station->station)))
04178 continue;
04179 AST_LIST_INSERT_TAIL(&ringing_trunk->timed_out_stations, station_ref, entry);
04180 }
04181
04182 done:
04183 ast_free(ringing_station);
04184 }
04185
04186 static void sla_dial_state_callback(struct ast_dial *dial)
04187 {
04188 sla_queue_event(SLA_EVENT_DIAL_STATE);
04189 }
04190
04191
04192
04193
04194 static int sla_check_timed_out_station(const struct sla_ringing_trunk *ringing_trunk,
04195 const struct sla_station *station)
04196 {
04197 struct sla_station_ref *timed_out_station;
04198
04199 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, timed_out_station, entry) {
04200 if (station == timed_out_station->station)
04201 return 1;
04202 }
04203
04204 return 0;
04205 }
04206
04207
04208
04209
04210
04211
04212
04213
04214
04215 static struct sla_ringing_trunk *sla_choose_ringing_trunk(struct sla_station *station,
04216 struct sla_trunk_ref **trunk_ref, int rm)
04217 {
04218 struct sla_trunk_ref *s_trunk_ref;
04219 struct sla_ringing_trunk *ringing_trunk = NULL;
04220
04221 AST_LIST_TRAVERSE(&station->trunks, s_trunk_ref, entry) {
04222 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04223
04224 if (s_trunk_ref->trunk != ringing_trunk->trunk)
04225 continue;
04226
04227
04228
04229 if (sla_check_timed_out_station(ringing_trunk, station))
04230 continue;
04231
04232 if (rm)
04233 AST_LIST_REMOVE_CURRENT(entry);
04234
04235 if (trunk_ref)
04236 *trunk_ref = s_trunk_ref;
04237
04238 break;
04239 }
04240 AST_LIST_TRAVERSE_SAFE_END;
04241
04242 if (ringing_trunk)
04243 break;
04244 }
04245
04246 return ringing_trunk;
04247 }
04248
04249 static void sla_handle_dial_state_event(void)
04250 {
04251 struct sla_ringing_station *ringing_station;
04252
04253 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04254 struct sla_trunk_ref *s_trunk_ref = NULL;
04255 struct sla_ringing_trunk *ringing_trunk = NULL;
04256 struct run_station_args args;
04257 enum ast_dial_result dial_res;
04258 pthread_t dont_care;
04259 ast_mutex_t cond_lock;
04260 ast_cond_t cond;
04261
04262 switch ((dial_res = ast_dial_state(ringing_station->station->dial))) {
04263 case AST_DIAL_RESULT_HANGUP:
04264 case AST_DIAL_RESULT_INVALID:
04265 case AST_DIAL_RESULT_FAILED:
04266 case AST_DIAL_RESULT_TIMEOUT:
04267 case AST_DIAL_RESULT_UNANSWERED:
04268 AST_LIST_REMOVE_CURRENT(entry);
04269 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_NORMAL);
04270 break;
04271 case AST_DIAL_RESULT_ANSWERED:
04272 AST_LIST_REMOVE_CURRENT(entry);
04273
04274 ast_mutex_lock(&sla.lock);
04275 ringing_trunk = sla_choose_ringing_trunk(ringing_station->station, &s_trunk_ref, 1);
04276 ast_mutex_unlock(&sla.lock);
04277 if (!ringing_trunk) {
04278 ast_debug(1, "Found no ringing trunk for station '%s' to answer!\n", ringing_station->station->name);
04279 break;
04280 }
04281
04282 s_trunk_ref->chan = ast_dial_answered(ringing_station->station->dial);
04283
04284 answer_trunk_chan(ringing_trunk->trunk->chan);
04285 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
04286
04287
04288
04289 args.trunk_ref = s_trunk_ref;
04290 args.station = ringing_station->station;
04291 args.cond = &cond;
04292 args.cond_lock = &cond_lock;
04293 ast_free(ringing_trunk);
04294 ast_free(ringing_station);
04295 ast_mutex_init(&cond_lock);
04296 ast_cond_init(&cond, NULL);
04297 ast_mutex_lock(&cond_lock);
04298 ast_pthread_create_detached_background(&dont_care, NULL, run_station, &args);
04299 ast_cond_wait(&cond, &cond_lock);
04300 ast_mutex_unlock(&cond_lock);
04301 ast_mutex_destroy(&cond_lock);
04302 ast_cond_destroy(&cond);
04303 break;
04304 case AST_DIAL_RESULT_TRYING:
04305 case AST_DIAL_RESULT_RINGING:
04306 case AST_DIAL_RESULT_PROGRESS:
04307 case AST_DIAL_RESULT_PROCEEDING:
04308 break;
04309 }
04310 if (dial_res == AST_DIAL_RESULT_ANSWERED) {
04311
04312 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
04313 sla_queue_event(SLA_EVENT_DIAL_STATE);
04314 break;
04315 }
04316 }
04317 AST_LIST_TRAVERSE_SAFE_END;
04318 }
04319
04320
04321
04322
04323 static int sla_check_ringing_station(const struct sla_station *station)
04324 {
04325 struct sla_ringing_station *ringing_station;
04326
04327 AST_LIST_TRAVERSE(&sla.ringing_stations, ringing_station, entry) {
04328 if (station == ringing_station->station)
04329 return 1;
04330 }
04331
04332 return 0;
04333 }
04334
04335
04336
04337
04338 static int sla_check_failed_station(const struct sla_station *station)
04339 {
04340 struct sla_failed_station *failed_station;
04341 int res = 0;
04342
04343 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.failed_stations, failed_station, entry) {
04344 if (station != failed_station->station)
04345 continue;
04346 if (ast_tvdiff_ms(ast_tvnow(), failed_station->last_try) > 1000) {
04347 AST_LIST_REMOVE_CURRENT(entry);
04348 ast_free(failed_station);
04349 break;
04350 }
04351 res = 1;
04352 }
04353 AST_LIST_TRAVERSE_SAFE_END
04354
04355 return res;
04356 }
04357
04358
04359
04360
04361 static int sla_ring_station(struct sla_ringing_trunk *ringing_trunk, struct sla_station *station)
04362 {
04363 char *tech, *tech_data;
04364 struct ast_dial *dial;
04365 struct sla_ringing_station *ringing_station;
04366 const char *cid_name = NULL, *cid_num = NULL;
04367 enum ast_dial_result res;
04368
04369 if (!(dial = ast_dial_create()))
04370 return -1;
04371
04372 ast_dial_set_state_callback(dial, sla_dial_state_callback);
04373 tech_data = ast_strdupa(station->device);
04374 tech = strsep(&tech_data, "/");
04375
04376 if (ast_dial_append(dial, tech, tech_data) == -1) {
04377 ast_dial_destroy(dial);
04378 return -1;
04379 }
04380
04381 if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_name)) {
04382 cid_name = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_name);
04383 ast_free(ringing_trunk->trunk->chan->cid.cid_name);
04384 ringing_trunk->trunk->chan->cid.cid_name = NULL;
04385 }
04386 if (!sla.attempt_callerid && !ast_strlen_zero(ringing_trunk->trunk->chan->cid.cid_num)) {
04387 cid_num = ast_strdupa(ringing_trunk->trunk->chan->cid.cid_num);
04388 ast_free(ringing_trunk->trunk->chan->cid.cid_num);
04389 ringing_trunk->trunk->chan->cid.cid_num = NULL;
04390 }
04391
04392 res = ast_dial_run(dial, ringing_trunk->trunk->chan, 1);
04393
04394 if (cid_name)
04395 ringing_trunk->trunk->chan->cid.cid_name = ast_strdup(cid_name);
04396 if (cid_num)
04397 ringing_trunk->trunk->chan->cid.cid_num = ast_strdup(cid_num);
04398
04399 if (res != AST_DIAL_RESULT_TRYING) {
04400 struct sla_failed_station *failed_station;
04401 ast_dial_destroy(dial);
04402 if (!(failed_station = ast_calloc(1, sizeof(*failed_station))))
04403 return -1;
04404 failed_station->station = station;
04405 failed_station->last_try = ast_tvnow();
04406 AST_LIST_INSERT_HEAD(&sla.failed_stations, failed_station, entry);
04407 return -1;
04408 }
04409 if (!(ringing_station = sla_create_ringing_station(station))) {
04410 ast_dial_join(dial);
04411 ast_dial_destroy(dial);
04412 return -1;
04413 }
04414
04415 station->dial = dial;
04416
04417 AST_LIST_INSERT_HEAD(&sla.ringing_stations, ringing_station, entry);
04418
04419 return 0;
04420 }
04421
04422
04423
04424 static int sla_check_inuse_station(const struct sla_station *station)
04425 {
04426 struct sla_trunk_ref *trunk_ref;
04427
04428 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04429 if (trunk_ref->chan)
04430 return 1;
04431 }
04432
04433 return 0;
04434 }
04435
04436 static struct sla_trunk_ref *sla_find_trunk_ref(const struct sla_station *station,
04437 const struct sla_trunk *trunk)
04438 {
04439 struct sla_trunk_ref *trunk_ref = NULL;
04440
04441 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
04442 if (trunk_ref->trunk == trunk)
04443 break;
04444 }
04445
04446 return trunk_ref;
04447 }
04448
04449
04450
04451
04452
04453
04454 static int sla_check_station_delay(struct sla_station *station,
04455 struct sla_ringing_trunk *ringing_trunk)
04456 {
04457 struct sla_trunk_ref *trunk_ref;
04458 unsigned int delay = UINT_MAX;
04459 int time_left, time_elapsed;
04460
04461 if (!ringing_trunk)
04462 ringing_trunk = sla_choose_ringing_trunk(station, &trunk_ref, 0);
04463 else
04464 trunk_ref = sla_find_trunk_ref(station, ringing_trunk->trunk);
04465
04466 if (!ringing_trunk || !trunk_ref)
04467 return delay;
04468
04469
04470
04471
04472 delay = trunk_ref->ring_delay;
04473 if (!delay)
04474 delay = station->ring_delay;
04475 if (!delay)
04476 return INT_MAX;
04477
04478 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04479 time_left = (delay * 1000) - time_elapsed;
04480
04481 return time_left;
04482 }
04483
04484
04485
04486
04487 static void sla_ring_stations(void)
04488 {
04489 struct sla_station_ref *station_ref;
04490 struct sla_ringing_trunk *ringing_trunk;
04491
04492
04493
04494 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04495 AST_LIST_TRAVERSE(&ringing_trunk->trunk->stations, station_ref, entry) {
04496 int time_left;
04497
04498
04499 if (sla_check_ringing_station(station_ref->station))
04500 continue;
04501
04502
04503 if (sla_check_inuse_station(station_ref->station))
04504 continue;
04505
04506
04507
04508 if (sla_check_failed_station(station_ref->station))
04509 continue;
04510
04511
04512
04513 if (sla_check_timed_out_station(ringing_trunk, station_ref->station))
04514 continue;
04515
04516
04517 time_left = sla_check_station_delay(station_ref->station, ringing_trunk);
04518 if (time_left != INT_MAX && time_left > 0)
04519 continue;
04520
04521
04522 sla_ring_station(ringing_trunk, station_ref->station);
04523 }
04524 }
04525
04526 }
04527
04528 static void sla_hangup_stations(void)
04529 {
04530 struct sla_trunk_ref *trunk_ref;
04531 struct sla_ringing_station *ringing_station;
04532
04533 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04534 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04535 struct sla_ringing_trunk *ringing_trunk;
04536 ast_mutex_lock(&sla.lock);
04537 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04538 if (trunk_ref->trunk == ringing_trunk->trunk)
04539 break;
04540 }
04541 ast_mutex_unlock(&sla.lock);
04542 if (ringing_trunk)
04543 break;
04544 }
04545 if (!trunk_ref) {
04546 AST_LIST_REMOVE_CURRENT(entry);
04547 ast_dial_join(ringing_station->station->dial);
04548 ast_dial_destroy(ringing_station->station->dial);
04549 ringing_station->station->dial = NULL;
04550 ast_free(ringing_station);
04551 }
04552 }
04553 AST_LIST_TRAVERSE_SAFE_END
04554 }
04555
04556 static void sla_handle_ringing_trunk_event(void)
04557 {
04558 ast_mutex_lock(&sla.lock);
04559 sla_ring_stations();
04560 ast_mutex_unlock(&sla.lock);
04561
04562
04563 sla_hangup_stations();
04564 }
04565
04566 static void sla_handle_hold_event(struct sla_event *event)
04567 {
04568 ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1);
04569 event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME;
04570 ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s",
04571 event->station->name, event->trunk_ref->trunk->name);
04572 sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD,
04573 INACTIVE_TRUNK_REFS, event->trunk_ref);
04574
04575 if (event->trunk_ref->trunk->active_stations == 1) {
04576
04577
04578 event->trunk_ref->trunk->on_hold = 1;
04579 ast_indicate(event->trunk_ref->trunk->chan, AST_CONTROL_HOLD);
04580 }
04581
04582 ast_softhangup(event->trunk_ref->chan, AST_CAUSE_NORMAL);
04583 event->trunk_ref->chan = NULL;
04584 }
04585
04586
04587
04588
04589
04590 static int sla_calc_trunk_timeouts(unsigned int *timeout)
04591 {
04592 struct sla_ringing_trunk *ringing_trunk;
04593 int res = 0;
04594
04595 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
04596 int time_left, time_elapsed;
04597 if (!ringing_trunk->trunk->ring_timeout)
04598 continue;
04599 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04600 time_left = (ringing_trunk->trunk->ring_timeout * 1000) - time_elapsed;
04601 if (time_left <= 0) {
04602 pbx_builtin_setvar_helper(ringing_trunk->trunk->chan, "SLATRUNK_STATUS", "RINGTIMEOUT");
04603 AST_LIST_REMOVE_CURRENT(entry);
04604 sla_stop_ringing_trunk(ringing_trunk);
04605 res = 1;
04606 continue;
04607 }
04608 if (time_left < *timeout)
04609 *timeout = time_left;
04610 }
04611 AST_LIST_TRAVERSE_SAFE_END;
04612
04613 return res;
04614 }
04615
04616
04617
04618
04619
04620 static int sla_calc_station_timeouts(unsigned int *timeout)
04621 {
04622 struct sla_ringing_trunk *ringing_trunk;
04623 struct sla_ringing_station *ringing_station;
04624 int res = 0;
04625
04626 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_stations, ringing_station, entry) {
04627 unsigned int ring_timeout = 0;
04628 int time_elapsed, time_left = INT_MAX, final_trunk_time_left = INT_MIN;
04629 struct sla_trunk_ref *trunk_ref;
04630
04631
04632
04633
04634 AST_LIST_TRAVERSE(&ringing_station->station->trunks, trunk_ref, entry) {
04635 struct sla_station_ref *station_ref;
04636 int trunk_time_elapsed, trunk_time_left;
04637
04638 AST_LIST_TRAVERSE(&sla.ringing_trunks, ringing_trunk, entry) {
04639 if (ringing_trunk->trunk == trunk_ref->trunk)
04640 break;
04641 }
04642 if (!ringing_trunk)
04643 continue;
04644
04645
04646
04647 if (!trunk_ref->ring_timeout)
04648 break;
04649
04650
04651
04652
04653 AST_LIST_TRAVERSE(&ringing_trunk->timed_out_stations, station_ref, entry) {
04654 if (station_ref->station == ringing_station->station)
04655 break;
04656 }
04657 if (station_ref)
04658 continue;
04659
04660 trunk_time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_trunk->ring_begin);
04661 trunk_time_left = (trunk_ref->ring_timeout * 1000) - trunk_time_elapsed;
04662 if (trunk_time_left > final_trunk_time_left)
04663 final_trunk_time_left = trunk_time_left;
04664 }
04665
04666
04667 if (final_trunk_time_left == INT_MIN && !ringing_station->station->ring_timeout)
04668 continue;
04669
04670
04671 if (ringing_station->station->ring_timeout) {
04672 ring_timeout = ringing_station->station->ring_timeout;
04673 time_elapsed = ast_tvdiff_ms(ast_tvnow(), ringing_station->ring_begin);
04674 time_left = (ring_timeout * 1000) - time_elapsed;
04675 }
04676
04677
04678
04679 if (final_trunk_time_left > INT_MIN && final_trunk_time_left < time_left)
04680 time_left = final_trunk_time_left;
04681
04682
04683 if (time_left <= 0) {
04684 AST_LIST_REMOVE_CURRENT(entry);
04685 sla_stop_ringing_station(ringing_station, SLA_STATION_HANGUP_TIMEOUT);
04686 res = 1;
04687 continue;
04688 }
04689
04690
04691
04692 if (time_left < *timeout)
04693 *timeout = time_left;
04694 }
04695 AST_LIST_TRAVERSE_SAFE_END;
04696
04697 return res;
04698 }
04699
04700
04701
04702
04703 static int sla_calc_station_delays(unsigned int *timeout)
04704 {
04705 struct sla_station *station;
04706 int res = 0;
04707
04708 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
04709 struct sla_ringing_trunk *ringing_trunk;
04710 int time_left;
04711
04712
04713 if (sla_check_ringing_station(station))
04714 continue;
04715
04716
04717 if (sla_check_inuse_station(station))
04718 continue;
04719
04720
04721 if (!(ringing_trunk = sla_choose_ringing_trunk(station, NULL, 0)))
04722 continue;
04723
04724 if ((time_left = sla_check_station_delay(station, ringing_trunk)) == INT_MAX)
04725 continue;
04726
04727
04728
04729
04730 if (time_left <= 0) {
04731 res = 1;
04732 continue;
04733 }
04734
04735 if (time_left < *timeout)
04736 *timeout = time_left;
04737 }
04738
04739 return res;
04740 }
04741
04742
04743
04744 static int sla_process_timers(struct timespec *ts)
04745 {
04746 unsigned int timeout = UINT_MAX;
04747 struct timeval wait;
04748 unsigned int change_made = 0;
04749
04750
04751 if (sla_calc_trunk_timeouts(&timeout))
04752 change_made = 1;
04753
04754
04755 if (sla_calc_station_timeouts(&timeout))
04756 change_made = 1;
04757
04758
04759 if (sla_calc_station_delays(&timeout))
04760 change_made = 1;
04761
04762
04763 if (change_made)
04764 sla_queue_event_nolock(SLA_EVENT_RINGING_TRUNK);
04765
04766
04767 if (timeout == UINT_MAX)
04768 return 0;
04769
04770 if (ts) {
04771 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(timeout, 1000));
04772 ts->tv_sec = wait.tv_sec;
04773 ts->tv_nsec = wait.tv_usec * 1000;
04774 }
04775
04776 return 1;
04777 }
04778
04779 static int sla_load_config(int reload);
04780
04781
04782 static void sla_check_reload(void)
04783 {
04784 struct sla_station *station;
04785 struct sla_trunk *trunk;
04786
04787 ast_mutex_lock(&sla.lock);
04788
04789 if (!AST_LIST_EMPTY(&sla.event_q) || !AST_LIST_EMPTY(&sla.ringing_trunks)
04790 || !AST_LIST_EMPTY(&sla.ringing_stations)) {
04791 ast_mutex_unlock(&sla.lock);
04792 return;
04793 }
04794
04795 AST_RWLIST_RDLOCK(&sla_stations);
04796 AST_RWLIST_TRAVERSE(&sla_stations, station, entry) {
04797 if (station->ref_count)
04798 break;
04799 }
04800 AST_RWLIST_UNLOCK(&sla_stations);
04801 if (station) {
04802 ast_mutex_unlock(&sla.lock);
04803 return;
04804 }
04805
04806 AST_RWLIST_RDLOCK(&sla_trunks);
04807 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
04808 if (trunk->ref_count)
04809 break;
04810 }
04811 AST_RWLIST_UNLOCK(&sla_trunks);
04812 if (trunk) {
04813 ast_mutex_unlock(&sla.lock);
04814 return;
04815 }
04816
04817
04818 sla_load_config(1);
04819 sla.reload = 0;
04820
04821 ast_mutex_unlock(&sla.lock);
04822 }
04823
04824 static void *sla_thread(void *data)
04825 {
04826 struct sla_failed_station *failed_station;
04827 struct sla_ringing_station *ringing_station;
04828
04829 ast_mutex_lock(&sla.lock);
04830
04831 while (!sla.stop) {
04832 struct sla_event *event;
04833 struct timespec ts = { 0, };
04834 unsigned int have_timeout = 0;
04835
04836 if (AST_LIST_EMPTY(&sla.event_q)) {
04837 if ((have_timeout = sla_process_timers(&ts)))
04838 ast_cond_timedwait(&sla.cond, &sla.lock, &ts);
04839 else
04840 ast_cond_wait(&sla.cond, &sla.lock);
04841 if (sla.stop)
04842 break;
04843 }
04844
04845 if (have_timeout)
04846 sla_process_timers(NULL);
04847
04848 while ((event = AST_LIST_REMOVE_HEAD(&sla.event_q, entry))) {
04849 ast_mutex_unlock(&sla.lock);
04850 switch (event->type) {
04851 case SLA_EVENT_HOLD:
04852 sla_handle_hold_event(event);
04853 break;
04854 case SLA_EVENT_DIAL_STATE:
04855 sla_handle_dial_state_event();
04856 break;
04857 case SLA_EVENT_RINGING_TRUNK:
04858 sla_handle_ringing_trunk_event();
04859 break;
04860 case SLA_EVENT_RELOAD:
04861 sla.reload = 1;
04862 case SLA_EVENT_CHECK_RELOAD:
04863 break;
04864 }
04865 ast_free(event);
04866 ast_mutex_lock(&sla.lock);
04867 }
04868
04869 if (sla.reload)
04870 sla_check_reload();
04871 }
04872
04873 ast_mutex_unlock(&sla.lock);
04874
04875 while ((ringing_station = AST_LIST_REMOVE_HEAD(&sla.ringing_stations, entry)))
04876 ast_free(ringing_station);
04877
04878 while ((failed_station = AST_LIST_REMOVE_HEAD(&sla.failed_stations, entry)))
04879 ast_free(failed_station);
04880
04881 return NULL;
04882 }
04883
04884 struct dial_trunk_args {
04885 struct sla_trunk_ref *trunk_ref;
04886 struct sla_station *station;
04887 ast_mutex_t *cond_lock;
04888 ast_cond_t *cond;
04889 };
04890
04891 static void *dial_trunk(void *data)
04892 {
04893 struct dial_trunk_args *args = data;
04894 struct ast_dial *dial;
04895 char *tech, *tech_data;
04896 enum ast_dial_result dial_res;
04897 char conf_name[MAX_CONFNUM];
04898 struct ast_conference *conf;
04899 struct ast_flags conf_flags = { 0 };
04900 struct sla_trunk_ref *trunk_ref = args->trunk_ref;
04901 const char *cid_name = NULL, *cid_num = NULL;
04902
04903 if (!(dial = ast_dial_create())) {
04904 ast_mutex_lock(args->cond_lock);
04905 ast_cond_signal(args->cond);
04906 ast_mutex_unlock(args->cond_lock);
04907 return NULL;
04908 }
04909
04910 tech_data = ast_strdupa(trunk_ref->trunk->device);
04911 tech = strsep(&tech_data, "/");
04912 if (ast_dial_append(dial, tech, tech_data) == -1) {
04913 ast_mutex_lock(args->cond_lock);
04914 ast_cond_signal(args->cond);
04915 ast_mutex_unlock(args->cond_lock);
04916 ast_dial_destroy(dial);
04917 return NULL;
04918 }
04919
04920 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_name)) {
04921 cid_name = ast_strdupa(trunk_ref->chan->cid.cid_name);
04922 ast_free(trunk_ref->chan->cid.cid_name);
04923 trunk_ref->chan->cid.cid_name = NULL;
04924 }
04925 if (!sla.attempt_callerid && !ast_strlen_zero(trunk_ref->chan->cid.cid_num)) {
04926 cid_num = ast_strdupa(trunk_ref->chan->cid.cid_num);
04927 ast_free(trunk_ref->chan->cid.cid_num);
04928 trunk_ref->chan->cid.cid_num = NULL;
04929 }
04930
04931 dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
04932
04933 if (cid_name)
04934 trunk_ref->chan->cid.cid_name = ast_strdup(cid_name);
04935 if (cid_num)
04936 trunk_ref->chan->cid.cid_num = ast_strdup(cid_num);
04937
04938 if (dial_res != AST_DIAL_RESULT_TRYING) {
04939 ast_mutex_lock(args->cond_lock);
04940 ast_cond_signal(args->cond);
04941 ast_mutex_unlock(args->cond_lock);
04942 ast_dial_destroy(dial);
04943 return NULL;
04944 }
04945
04946 for (;;) {
04947 unsigned int done = 0;
04948 switch ((dial_res = ast_dial_state(dial))) {
04949 case AST_DIAL_RESULT_ANSWERED:
04950 trunk_ref->trunk->chan = ast_dial_answered(dial);
04951 case AST_DIAL_RESULT_HANGUP:
04952 case AST_DIAL_RESULT_INVALID:
04953 case AST_DIAL_RESULT_FAILED:
04954 case AST_DIAL_RESULT_TIMEOUT:
04955 case AST_DIAL_RESULT_UNANSWERED:
04956 done = 1;
04957 case AST_DIAL_RESULT_TRYING:
04958 case AST_DIAL_RESULT_RINGING:
04959 case AST_DIAL_RESULT_PROGRESS:
04960 case AST_DIAL_RESULT_PROCEEDING:
04961 break;
04962 }
04963 if (done)
04964 break;
04965 }
04966
04967 if (!trunk_ref->trunk->chan) {
04968 ast_mutex_lock(args->cond_lock);
04969 ast_cond_signal(args->cond);
04970 ast_mutex_unlock(args->cond_lock);
04971 ast_dial_join(dial);
04972 ast_dial_destroy(dial);
04973 return NULL;
04974 }
04975
04976 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
04977 ast_set_flag(&conf_flags,
04978 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER |
04979 CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
04980 conf = build_conf(conf_name, "", "", 1, 1, 1, trunk_ref->trunk->chan);
04981
04982 ast_mutex_lock(args->cond_lock);
04983 ast_cond_signal(args->cond);
04984 ast_mutex_unlock(args->cond_lock);
04985
04986 if (conf) {
04987 conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
04988 dispose_conf(conf);
04989 conf = NULL;
04990 }
04991
04992
04993 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
04994
04995 trunk_ref->trunk->chan = NULL;
04996 trunk_ref->trunk->on_hold = 0;
04997
04998 ast_dial_join(dial);
04999 ast_dial_destroy(dial);
05000
05001 return NULL;
05002 }
05003
05004
05005
05006 static struct sla_trunk_ref *sla_choose_idle_trunk(const struct sla_station *station)
05007 {
05008 struct sla_trunk_ref *trunk_ref = NULL;
05009
05010 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05011 if (trunk_ref->state == SLA_TRUNK_STATE_IDLE)
05012 break;
05013 }
05014
05015 return trunk_ref;
05016 }
05017
05018 static int sla_station_exec(struct ast_channel *chan, void *data)
05019 {
05020 char *station_name, *trunk_name;
05021 struct sla_station *station;
05022 struct sla_trunk_ref *trunk_ref = NULL;
05023 char conf_name[MAX_CONFNUM];
05024 struct ast_flags conf_flags = { 0 };
05025 struct ast_conference *conf;
05026
05027 if (ast_strlen_zero(data)) {
05028 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05029 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05030 return 0;
05031 }
05032
05033 trunk_name = ast_strdupa(data);
05034 station_name = strsep(&trunk_name, "_");
05035
05036 if (ast_strlen_zero(station_name)) {
05037 ast_log(LOG_WARNING, "Invalid Arguments to SLAStation!\n");
05038 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05039 return 0;
05040 }
05041
05042 AST_RWLIST_RDLOCK(&sla_stations);
05043 station = sla_find_station(station_name);
05044 if (station)
05045 ast_atomic_fetchadd_int((int *) &station->ref_count, 1);
05046 AST_RWLIST_UNLOCK(&sla_stations);
05047
05048 if (!station) {
05049 ast_log(LOG_WARNING, "Station '%s' not found!\n", station_name);
05050 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "FAILURE");
05051 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05052 return 0;
05053 }
05054
05055 AST_RWLIST_RDLOCK(&sla_trunks);
05056 if (!ast_strlen_zero(trunk_name)) {
05057 trunk_ref = sla_find_trunk_ref_byname(station, trunk_name);
05058 } else
05059 trunk_ref = sla_choose_idle_trunk(station);
05060 AST_RWLIST_UNLOCK(&sla_trunks);
05061
05062 if (!trunk_ref) {
05063 if (ast_strlen_zero(trunk_name))
05064 ast_log(LOG_NOTICE, "No trunks available for call.\n");
05065 else {
05066 ast_log(LOG_NOTICE, "Can't join existing call on trunk "
05067 "'%s' due to access controls.\n", trunk_name);
05068 }
05069 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05070 ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05071 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05072 return 0;
05073 }
05074
05075 if (trunk_ref->state == SLA_TRUNK_STATE_ONHOLD_BYME) {
05076 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->hold_stations) == 1)
05077 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05078 else {
05079 trunk_ref->state = SLA_TRUNK_STATE_UP;
05080 ast_devstate_changed(AST_DEVICE_INUSE,
05081 "SLA:%s_%s", station->name, trunk_ref->trunk->name);
05082 }
05083 } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) {
05084 struct sla_ringing_trunk *ringing_trunk;
05085
05086 ast_mutex_lock(&sla.lock);
05087 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05088 if (ringing_trunk->trunk == trunk_ref->trunk) {
05089 AST_LIST_REMOVE_CURRENT(entry);
05090 break;
05091 }
05092 }
05093 AST_LIST_TRAVERSE_SAFE_END
05094 ast_mutex_unlock(&sla.lock);
05095
05096 if (ringing_trunk) {
05097 answer_trunk_chan(ringing_trunk->trunk->chan);
05098 sla_change_trunk_state(ringing_trunk->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05099
05100 free(ringing_trunk);
05101
05102
05103 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05104 sla_queue_event(SLA_EVENT_DIAL_STATE);
05105 }
05106 }
05107
05108 trunk_ref->chan = chan;
05109
05110 if (!trunk_ref->trunk->chan) {
05111 ast_mutex_t cond_lock;
05112 ast_cond_t cond;
05113 pthread_t dont_care;
05114 struct dial_trunk_args args = {
05115 .trunk_ref = trunk_ref,
05116 .station = station,
05117 .cond_lock = &cond_lock,
05118 .cond = &cond,
05119 };
05120 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05121
05122
05123
05124 ast_autoservice_start(chan);
05125 ast_mutex_init(&cond_lock);
05126 ast_cond_init(&cond, NULL);
05127 ast_mutex_lock(&cond_lock);
05128 ast_pthread_create_detached_background(&dont_care, NULL, dial_trunk, &args);
05129 ast_cond_wait(&cond, &cond_lock);
05130 ast_mutex_unlock(&cond_lock);
05131 ast_mutex_destroy(&cond_lock);
05132 ast_cond_destroy(&cond);
05133 ast_autoservice_stop(chan);
05134 if (!trunk_ref->trunk->chan) {
05135 ast_debug(1, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
05136 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
05137 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05138 trunk_ref->chan = NULL;
05139 ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05140 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05141 return 0;
05142 }
05143 }
05144
05145 if (ast_atomic_fetchadd_int((int *) &trunk_ref->trunk->active_stations, 1) == 0 &&
05146 trunk_ref->trunk->on_hold) {
05147 trunk_ref->trunk->on_hold = 0;
05148 ast_indicate(trunk_ref->trunk->chan, AST_CONTROL_UNHOLD);
05149 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
05150 }
05151
05152 snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
05153 ast_set_flag(&conf_flags,
05154 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
05155 ast_answer(chan);
05156 conf = build_conf(conf_name, "", "", 0, 0, 1, chan);
05157 if (conf) {
05158 conf_run(chan, conf, conf_flags.flags, NULL);
05159 dispose_conf(conf);
05160 conf = NULL;
05161 }
05162 trunk_ref->chan = NULL;
05163 if (ast_atomic_dec_and_test((int *) &trunk_ref->trunk->active_stations) &&
05164 trunk_ref->state != SLA_TRUNK_STATE_ONHOLD_BYME) {
05165 strncat(conf_name, ",K", sizeof(conf_name) - strlen(conf_name) - 1);
05166 admin_exec(NULL, conf_name);
05167 trunk_ref->trunk->hold_stations = 0;
05168 sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05169 }
05170
05171 pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "SUCCESS");
05172
05173 ast_atomic_fetchadd_int((int *) &station->ref_count, -1);
05174 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05175
05176 return 0;
05177 }
05178
05179 static struct sla_trunk_ref *create_trunk_ref(struct sla_trunk *trunk)
05180 {
05181 struct sla_trunk_ref *trunk_ref;
05182
05183 if (!(trunk_ref = ast_calloc(1, sizeof(*trunk_ref))))
05184 return NULL;
05185
05186 trunk_ref->trunk = trunk;
05187
05188 return trunk_ref;
05189 }
05190
05191 static struct sla_ringing_trunk *queue_ringing_trunk(struct sla_trunk *trunk)
05192 {
05193 struct sla_ringing_trunk *ringing_trunk;
05194
05195 if (!(ringing_trunk = ast_calloc(1, sizeof(*ringing_trunk))))
05196 return NULL;
05197
05198 ringing_trunk->trunk = trunk;
05199 ringing_trunk->ring_begin = ast_tvnow();
05200
05201 sla_change_trunk_state(trunk, SLA_TRUNK_STATE_RINGING, ALL_TRUNK_REFS, NULL);
05202
05203 ast_mutex_lock(&sla.lock);
05204 AST_LIST_INSERT_HEAD(&sla.ringing_trunks, ringing_trunk, entry);
05205 ast_mutex_unlock(&sla.lock);
05206
05207 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05208
05209 return ringing_trunk;
05210 }
05211
05212 enum {
05213 SLA_TRUNK_OPT_MOH = (1 << 0),
05214 };
05215
05216 enum {
05217 SLA_TRUNK_OPT_ARG_MOH_CLASS = 0,
05218 SLA_TRUNK_OPT_ARG_ARRAY_SIZE = 1,
05219 };
05220
05221 AST_APP_OPTIONS(sla_trunk_opts, BEGIN_OPTIONS
05222 AST_APP_OPTION_ARG('M', SLA_TRUNK_OPT_MOH, SLA_TRUNK_OPT_ARG_MOH_CLASS),
05223 END_OPTIONS );
05224
05225 static int sla_trunk_exec(struct ast_channel *chan, void *data)
05226 {
05227 char conf_name[MAX_CONFNUM];
05228 struct ast_conference *conf;
05229 struct ast_flags conf_flags = { 0 };
05230 struct sla_trunk *trunk;
05231 struct sla_ringing_trunk *ringing_trunk;
05232 AST_DECLARE_APP_ARGS(args,
05233 AST_APP_ARG(trunk_name);
05234 AST_APP_ARG(options);
05235 );
05236 char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
05237 char *conf_opt_args[OPT_ARG_ARRAY_SIZE] = { NULL, };
05238 struct ast_flags opt_flags = { 0 };
05239 char *parse;
05240
05241 if (ast_strlen_zero(data)) {
05242 ast_log(LOG_ERROR, "The SLATrunk application requires an argument, the trunk name\n");
05243 return -1;
05244 }
05245
05246 parse = ast_strdupa(data);
05247 AST_STANDARD_APP_ARGS(args, parse);
05248 if (args.argc == 2) {
05249 if (ast_app_parse_options(sla_trunk_opts, &opt_flags, opts, args.options)) {
05250 ast_log(LOG_ERROR, "Error parsing options for SLATrunk\n");
05251 return -1;
05252 }
05253 }
05254
05255 AST_RWLIST_RDLOCK(&sla_trunks);
05256 trunk = sla_find_trunk(args.trunk_name);
05257 if (trunk)
05258 ast_atomic_fetchadd_int((int *) &trunk->ref_count, 1);
05259 AST_RWLIST_UNLOCK(&sla_trunks);
05260
05261 if (!trunk) {
05262 ast_log(LOG_ERROR, "SLA Trunk '%s' not found!\n", args.trunk_name);
05263 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05264 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05265 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05266 return 0;
05267 }
05268
05269 if (trunk->chan) {
05270 ast_log(LOG_ERROR, "Call came in on %s, but the trunk is already in use!\n",
05271 args.trunk_name);
05272 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05273 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05274 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05275 return 0;
05276 }
05277
05278 trunk->chan = chan;
05279
05280 if (!(ringing_trunk = queue_ringing_trunk(trunk))) {
05281 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05282 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05283 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05284 return 0;
05285 }
05286
05287 snprintf(conf_name, sizeof(conf_name), "SLA_%s", args.trunk_name);
05288 conf = build_conf(conf_name, "", "", 1, 1, 1, chan);
05289 if (!conf) {
05290 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "FAILURE");
05291 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05292 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05293 return 0;
05294 }
05295 ast_set_flag(&conf_flags,
05296 CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER | CONFFLAG_PASS_DTMF | CONFFLAG_NO_AUDIO_UNTIL_UP);
05297
05298 if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
05299 ast_indicate(chan, -1);
05300 ast_set_flag(&conf_flags, CONFFLAG_MOH);
05301 conf_opt_args[OPT_ARG_MOH_CLASS] = opts[SLA_TRUNK_OPT_ARG_MOH_CLASS];
05302 } else
05303 ast_indicate(chan, AST_CONTROL_RINGING);
05304
05305 conf_run(chan, conf, conf_flags.flags, opts);
05306 dispose_conf(conf);
05307 conf = NULL;
05308 trunk->chan = NULL;
05309 trunk->on_hold = 0;
05310
05311 sla_change_trunk_state(trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS, NULL);
05312
05313 if (!pbx_builtin_getvar_helper(chan, "SLATRUNK_STATUS"))
05314 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "SUCCESS");
05315
05316
05317 ast_mutex_lock(&sla.lock);
05318 AST_LIST_TRAVERSE_SAFE_BEGIN(&sla.ringing_trunks, ringing_trunk, entry) {
05319 if (ringing_trunk->trunk == trunk) {
05320 AST_LIST_REMOVE_CURRENT(entry);
05321 break;
05322 }
05323 }
05324 AST_LIST_TRAVERSE_SAFE_END;
05325 ast_mutex_unlock(&sla.lock);
05326 if (ringing_trunk) {
05327 ast_free(ringing_trunk);
05328 pbx_builtin_setvar_helper(chan, "SLATRUNK_STATUS", "UNANSWERED");
05329
05330
05331 sla_queue_event(SLA_EVENT_RINGING_TRUNK);
05332 }
05333
05334 ast_atomic_fetchadd_int((int *) &trunk->ref_count, -1);
05335 sla_queue_event(SLA_EVENT_CHECK_RELOAD);
05336
05337 return 0;
05338 }
05339
05340 static enum ast_device_state sla_state(const char *data)
05341 {
05342 char *buf, *station_name, *trunk_name;
05343 struct sla_station *station;
05344 struct sla_trunk_ref *trunk_ref;
05345 enum ast_device_state res = AST_DEVICE_INVALID;
05346
05347 trunk_name = buf = ast_strdupa(data);
05348 station_name = strsep(&trunk_name, "_");
05349
05350 AST_RWLIST_RDLOCK(&sla_stations);
05351 AST_LIST_TRAVERSE(&sla_stations, station, entry) {
05352 if (strcasecmp(station_name, station->name))
05353 continue;
05354 AST_RWLIST_RDLOCK(&sla_trunks);
05355 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05356 if (!strcasecmp(trunk_name, trunk_ref->trunk->name))
05357 break;
05358 }
05359 if (!trunk_ref) {
05360 AST_RWLIST_UNLOCK(&sla_trunks);
05361 break;
05362 }
05363 res = sla_state_to_devstate(trunk_ref->state);
05364 AST_RWLIST_UNLOCK(&sla_trunks);
05365 }
05366 AST_RWLIST_UNLOCK(&sla_stations);
05367
05368 if (res == AST_DEVICE_INVALID) {
05369 ast_log(LOG_ERROR, "Could not determine state for trunk %s on station %s!\n",
05370 trunk_name, station_name);
05371 }
05372
05373 return res;
05374 }
05375
05376 static void destroy_trunk(struct sla_trunk *trunk)
05377 {
05378 struct sla_station_ref *station_ref;
05379
05380 if (!ast_strlen_zero(trunk->autocontext))
05381 ast_context_remove_extension(trunk->autocontext, "s", 1, sla_registrar);
05382
05383 while ((station_ref = AST_LIST_REMOVE_HEAD(&trunk->stations, entry)))
05384 ast_free(station_ref);
05385
05386 ast_string_field_free_memory(trunk);
05387 ast_free(trunk);
05388 }
05389
05390 static void destroy_station(struct sla_station *station)
05391 {
05392 struct sla_trunk_ref *trunk_ref;
05393
05394 if (!ast_strlen_zero(station->autocontext)) {
05395 AST_RWLIST_RDLOCK(&sla_trunks);
05396 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05397 char exten[AST_MAX_EXTENSION];
05398 char hint[AST_MAX_APP];
05399 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05400 snprintf(hint, sizeof(hint), "SLA:%s", exten);
05401 ast_context_remove_extension(station->autocontext, exten,
05402 1, sla_registrar);
05403 ast_context_remove_extension(station->autocontext, hint,
05404 PRIORITY_HINT, sla_registrar);
05405 }
05406 AST_RWLIST_UNLOCK(&sla_trunks);
05407 }
05408
05409 while ((trunk_ref = AST_LIST_REMOVE_HEAD(&station->trunks, entry)))
05410 ast_free(trunk_ref);
05411
05412 ast_string_field_free_memory(station);
05413 ast_free(station);
05414 }
05415
05416 static void sla_destroy(void)
05417 {
05418 struct sla_trunk *trunk;
05419 struct sla_station *station;
05420
05421 AST_RWLIST_WRLOCK(&sla_trunks);
05422 while ((trunk = AST_RWLIST_REMOVE_HEAD(&sla_trunks, entry)))
05423 destroy_trunk(trunk);
05424 AST_RWLIST_UNLOCK(&sla_trunks);
05425
05426 AST_RWLIST_WRLOCK(&sla_stations);
05427 while ((station = AST_RWLIST_REMOVE_HEAD(&sla_stations, entry)))
05428 destroy_station(station);
05429 AST_RWLIST_UNLOCK(&sla_stations);
05430
05431 if (sla.thread != AST_PTHREADT_NULL) {
05432 ast_mutex_lock(&sla.lock);
05433 sla.stop = 1;
05434 ast_cond_signal(&sla.cond);
05435 ast_mutex_unlock(&sla.lock);
05436 pthread_join(sla.thread, NULL);
05437 }
05438
05439
05440 ast_context_destroy(NULL, sla_registrar);
05441
05442 ast_mutex_destroy(&sla.lock);
05443 ast_cond_destroy(&sla.cond);
05444 }
05445
05446 static int sla_check_device(const char *device)
05447 {
05448 char *tech, *tech_data;
05449
05450 tech_data = ast_strdupa(device);
05451 tech = strsep(&tech_data, "/");
05452
05453 if (ast_strlen_zero(tech) || ast_strlen_zero(tech_data))
05454 return -1;
05455
05456 return 0;
05457 }
05458
05459 static int sla_build_trunk(struct ast_config *cfg, const char *cat)
05460 {
05461 struct sla_trunk *trunk;
05462 struct ast_variable *var;
05463 const char *dev;
05464
05465 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
05466 ast_log(LOG_ERROR, "SLA Trunk '%s' defined with no device!\n", cat);
05467 return -1;
05468 }
05469
05470 if (sla_check_device(dev)) {
05471 ast_log(LOG_ERROR, "SLA Trunk '%s' define with invalid device '%s'!\n",
05472 cat, dev);
05473 return -1;
05474 }
05475
05476 if (!(trunk = ast_calloc(1, sizeof(*trunk))))
05477 return -1;
05478 if (ast_string_field_init(trunk, 32)) {
05479 ast_free(trunk);
05480 return -1;
05481 }
05482
05483 ast_string_field_set(trunk, name, cat);
05484 ast_string_field_set(trunk, device, dev);
05485
05486 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
05487 if (!strcasecmp(var->name, "autocontext"))
05488 ast_string_field_set(trunk, autocontext, var->value);
05489 else if (!strcasecmp(var->name, "ringtimeout")) {
05490 if (sscanf(var->value, "%30u", &trunk->ring_timeout) != 1) {
05491 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for trunk '%s'\n",
05492 var->value, trunk->name);
05493 trunk->ring_timeout = 0;
05494 }
05495 } else if (!strcasecmp(var->name, "barge"))
05496 trunk->barge_disabled = ast_false(var->value);
05497 else if (!strcasecmp(var->name, "hold")) {
05498 if (!strcasecmp(var->value, "private"))
05499 trunk->hold_access = SLA_HOLD_PRIVATE;
05500 else if (!strcasecmp(var->value, "open"))
05501 trunk->hold_access = SLA_HOLD_OPEN;
05502 else {
05503 ast_log(LOG_WARNING, "Invalid value '%s' for hold on trunk %s\n",
05504 var->value, trunk->name);
05505 }
05506 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
05507 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
05508 var->name, var->lineno, SLA_CONFIG_FILE);
05509 }
05510 }
05511
05512 if (!ast_strlen_zero(trunk->autocontext)) {
05513 struct ast_context *context;
05514 context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
05515 if (!context) {
05516 ast_log(LOG_ERROR, "Failed to automatically find or create "
05517 "context '%s' for SLA!\n", trunk->autocontext);
05518 destroy_trunk(trunk);
05519 return -1;
05520 }
05521 if (ast_add_extension2(context, 0 , "s", 1,
05522 NULL, NULL, slatrunk_app, ast_strdup(trunk->name), ast_free_ptr, sla_registrar)) {
05523 ast_log(LOG_ERROR, "Failed to automatically create extension "
05524 "for trunk '%s'!\n", trunk->name);
05525 destroy_trunk(trunk);
05526 return -1;
05527 }
05528 }
05529
05530 AST_RWLIST_WRLOCK(&sla_trunks);
05531 AST_RWLIST_INSERT_TAIL(&sla_trunks, trunk, entry);
05532 AST_RWLIST_UNLOCK(&sla_trunks);
05533
05534 return 0;
05535 }
05536
05537 static void sla_add_trunk_to_station(struct sla_station *station, struct ast_variable *var)
05538 {
05539 struct sla_trunk *trunk;
05540 struct sla_trunk_ref *trunk_ref;
05541 struct sla_station_ref *station_ref;
05542 char *trunk_name, *options, *cur;
05543
05544 options = ast_strdupa(var->value);
05545 trunk_name = strsep(&options, ",");
05546
05547 AST_RWLIST_RDLOCK(&sla_trunks);
05548 AST_RWLIST_TRAVERSE(&sla_trunks, trunk, entry) {
05549 if (!strcasecmp(trunk->name, trunk_name))
05550 break;
05551 }
05552
05553 AST_RWLIST_UNLOCK(&sla_trunks);
05554 if (!trunk) {
05555 ast_log(LOG_ERROR, "Trunk '%s' not found!\n", var->value);
05556 return;
05557 }
05558 if (!(trunk_ref = create_trunk_ref(trunk)))
05559 return;
05560 trunk_ref->state = SLA_TRUNK_STATE_IDLE;
05561
05562 while ((cur = strsep(&options, ","))) {
05563 char *name, *value = cur;
05564 name = strsep(&value, "=");
05565 if (!strcasecmp(name, "ringtimeout")) {
05566 if (sscanf(value, "%30u", &trunk_ref->ring_timeout) != 1) {
05567 ast_log(LOG_WARNING, "Invalid ringtimeout value '%s' for "
05568 "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
05569 trunk_ref->ring_timeout = 0;
05570 }
05571 } else if (!strcasecmp(name, "ringdelay")) {
05572 if (sscanf(value, "%30u", &trunk_ref->ring_delay) != 1) {
05573 ast_log(LOG_WARNING, "Invalid ringdelay value '%s' for "
05574 "trunk '%s' on station '%s'\n", value, trunk->name, station->name);
05575 trunk_ref->ring_delay = 0;
05576 }
05577 } else {
05578 ast_log(LOG_WARNING, "Invalid option '%s' for "
05579 "trunk '%s' on station '%s'\n", name, trunk->name, station->name);
05580 }
05581 }
05582
05583 if (!(station_ref = sla_create_station_ref(station))) {
05584 ast_free(trunk_ref);
05585 return;
05586 }
05587 ast_atomic_fetchadd_int((int *) &trunk->num_stations, 1);
05588 AST_RWLIST_WRLOCK(&sla_trunks);
05589 AST_LIST_INSERT_TAIL(&trunk->stations, station_ref, entry);
05590 AST_RWLIST_UNLOCK(&sla_trunks);
05591 AST_LIST_INSERT_TAIL(&station->trunks, trunk_ref, entry);
05592 }
05593
05594 static int sla_build_station(struct ast_config *cfg, const char *cat)
05595 {
05596 struct sla_station *station;
05597 struct ast_variable *var;
05598 const char *dev;
05599
05600 if (!(dev = ast_variable_retrieve(cfg, cat, "device"))) {
05601 ast_log(LOG_ERROR, "SLA Station '%s' defined with no device!\n", cat);
05602 return -1;
05603 }
05604
05605 if (!(station = ast_calloc(1, sizeof(*station))))
05606 return -1;
05607 if (ast_string_field_init(station, 32)) {
05608 ast_free(station);
05609 return -1;
05610 }
05611
05612 ast_string_field_set(station, name, cat);
05613 ast_string_field_set(station, device, dev);
05614
05615 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
05616 if (!strcasecmp(var->name, "trunk"))
05617 sla_add_trunk_to_station(station, var);
05618 else if (!strcasecmp(var->name, "autocontext"))
05619 ast_string_field_set(station, autocontext, var->value);
05620 else if (!strcasecmp(var->name, "ringtimeout")) {
05621 if (sscanf(var->value, "%30u", &station->ring_timeout) != 1) {
05622 ast_log(LOG_WARNING, "Invalid ringtimeout '%s' specified for station '%s'\n",
05623 var->value, station->name);
05624 station->ring_timeout = 0;
05625 }
05626 } else if (!strcasecmp(var->name, "ringdelay")) {
05627 if (sscanf(var->value, "%30u", &station->ring_delay) != 1) {
05628 ast_log(LOG_WARNING, "Invalid ringdelay '%s' specified for station '%s'\n",
05629 var->value, station->name);
05630 station->ring_delay = 0;
05631 }
05632 } else if (!strcasecmp(var->name, "hold")) {
05633 if (!strcasecmp(var->value, "private"))
05634 station->hold_access = SLA_HOLD_PRIVATE;
05635 else if (!strcasecmp(var->value, "open"))
05636 station->hold_access = SLA_HOLD_OPEN;
05637 else {
05638 ast_log(LOG_WARNING, "Invalid value '%s' for hold on station %s\n",
05639 var->value, station->name);
05640 }
05641
05642 } else if (strcasecmp(var->name, "type") && strcasecmp(var->name, "device")) {
05643 ast_log(LOG_ERROR, "Invalid option '%s' specified at line %d of %s!\n",
05644 var->name, var->lineno, SLA_CONFIG_FILE);
05645 }
05646 }
05647
05648 if (!ast_strlen_zero(station->autocontext)) {
05649 struct ast_context *context;
05650 struct sla_trunk_ref *trunk_ref;
05651 context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
05652 if (!context) {
05653 ast_log(LOG_ERROR, "Failed to automatically find or create "
05654 "context '%s' for SLA!\n", station->autocontext);
05655 destroy_station(station);
05656 return -1;
05657 }
05658
05659
05660 if (ast_add_extension2(context, 0 , station->name, 1,
05661 NULL, NULL, slastation_app, ast_strdup(station->name), ast_free_ptr, sla_registrar)) {
05662 ast_log(LOG_ERROR, "Failed to automatically create extension "
05663 "for trunk '%s'!\n", station->name);
05664 destroy_station(station);
05665 return -1;
05666 }
05667 AST_RWLIST_RDLOCK(&sla_trunks);
05668 AST_LIST_TRAVERSE(&station->trunks, trunk_ref, entry) {
05669 char exten[AST_MAX_EXTENSION];
05670 char hint[AST_MAX_APP];
05671 snprintf(exten, sizeof(exten), "%s_%s", station->name, trunk_ref->trunk->name);
05672 snprintf(hint, sizeof(hint), "SLA:%s", exten);
05673
05674
05675 if (ast_add_extension2(context, 0 , exten, 1,
05676 NULL, NULL, slastation_app, ast_strdup(exten), ast_free_ptr, sla_registrar)) {
05677 ast_log(LOG_ERROR, "Failed to automatically create extension "
05678 "for trunk '%s'!\n", station->name);
05679 destroy_station(station);
05680 return -1;
05681 }
05682
05683
05684 if (ast_add_extension2(context, 0 , exten, PRIORITY_HINT,
05685 NULL, NULL, hint, NULL, NULL, sla_registrar)) {
05686 ast_log(LOG_ERROR, "Failed to automatically create hint "
05687 "for trunk '%s'!\n", station->name);
05688 destroy_station(station);
05689 return -1;
05690 }
05691 }
05692 AST_RWLIST_UNLOCK(&sla_trunks);
05693 }
05694
05695 AST_RWLIST_WRLOCK(&sla_stations);
05696 AST_RWLIST_INSERT_TAIL(&sla_stations, station, entry);
05697 AST_RWLIST_UNLOCK(&sla_stations);
05698
05699 return 0;
05700 }
05701
05702 static int sla_load_config(int reload)
05703 {
05704 struct ast_config *cfg;
05705 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
05706 const char *cat = NULL;
05707 int res = 0;
05708 const char *val;
05709
05710 if (!reload) {
05711 ast_mutex_init(&sla.lock);
05712 ast_cond_init(&sla.cond, NULL);
05713 }
05714
05715 if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags)))
05716 return 0;
05717 else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
05718 return 0;
05719
05720 if ((val = ast_variable_retrieve(cfg, "general", "attemptcallerid")))
05721 sla.attempt_callerid = ast_true(val);
05722
05723 while ((cat = ast_category_browse(cfg, cat)) && !res) {
05724 const char *type;
05725 if (!strcasecmp(cat, "general"))
05726 continue;
05727 if (!(type = ast_variable_retrieve(cfg, cat, "type"))) {
05728 ast_log(LOG_WARNING, "Invalid entry in %s defined with no type!\n",
05729 SLA_CONFIG_FILE);
05730 continue;
05731 }
05732 if (!strcasecmp(type, "trunk"))
05733 res = sla_build_trunk(cfg, cat);
05734 else if (!strcasecmp(type, "station"))
05735 res = sla_build_station(cfg, cat);
05736 else {
05737 ast_log(LOG_WARNING, "Entry in %s defined with invalid type '%s'!\n",
05738 SLA_CONFIG_FILE, type);
05739 }
05740 }
05741
05742 ast_config_destroy(cfg);
05743
05744 if (!reload && (!AST_LIST_EMPTY(&sla_stations) || !AST_LIST_EMPTY(&sla_stations)))
05745 ast_pthread_create(&sla.thread, NULL, sla_thread, NULL);
05746
05747 return res;
05748 }
05749
05750 static int acf_meetme_info_eval(char *keyword, struct ast_conference *conf)
05751 {
05752 if (!strcasecmp("lock", keyword)) {
05753 return conf->locked;
05754 } else if (!strcasecmp("parties", keyword)) {
05755 return conf->users;
05756 } else if (!strcasecmp("activity", keyword)) {
05757 time_t now;
05758 now = time(NULL);
05759 return (now - conf->start);
05760 } else if (!strcasecmp("dynamic", keyword)) {
05761 return conf->isdynamic;
05762 } else {
05763 return -1;
05764 }
05765
05766 }
05767
05768 static int acf_meetme_info(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
05769 {
05770 struct ast_conference *conf;
05771 char *parse;
05772 int result = -2;
05773 AST_DECLARE_APP_ARGS(args,
05774 AST_APP_ARG(keyword);
05775 AST_APP_ARG(confno);
05776 );
05777
05778 if (ast_strlen_zero(data)) {
05779 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires two arguments\n");
05780 return -1;
05781 }
05782
05783 parse = ast_strdupa(data);
05784 AST_STANDARD_APP_ARGS(args, parse);
05785
05786 if (ast_strlen_zero(args.keyword)) {
05787 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a keyword\n");
05788 return -1;
05789 }
05790
05791 if (ast_strlen_zero(args.confno)) {
05792 ast_log(LOG_ERROR, "Syntax: MEETME_INFO() requires a conference number\n");
05793 return -1;
05794 }
05795
05796 AST_LIST_LOCK(&confs);
05797 AST_LIST_TRAVERSE(&confs, conf, list) {
05798 if (!strcmp(args.confno, conf->confno)) {
05799 result = acf_meetme_info_eval(args.keyword, conf);
05800 break;
05801 }
05802 }
05803 AST_LIST_UNLOCK(&confs);
05804
05805 if (result > -1) {
05806 snprintf(buf, len, "%d", result);
05807 } else if (result == -1) {
05808 snprintf(buf, len, "%s %s", "Error: invalid keyword:", args.keyword);
05809 } else if (result == -2) {
05810 snprintf(buf, len, "Error: conference (%s) not found", args.confno);
05811 }
05812
05813 return 0;
05814 }
05815
05816
05817 static struct ast_custom_function meetme_info_acf = {
05818 .name = "MEETME_INFO",
05819 .synopsis = "Query a given conference of various properties.",
05820 .syntax = "MEETME_INFO(<keyword>,<confno>)",
05821 .read = acf_meetme_info,
05822 .desc =
05823 "Returns information from a given keyword. (For booleans 1-true, 0-false)\n"
05824 " Options:\n"
05825 " lock - boolean of whether the corresponding conference is locked\n"
05826 " parties - number of parties in a given conference\n"
05827 " activity - duration of conference in seconds\n"
05828 " dynamic - boolean of whether the corresponding coference is dynamic\n",
05829 };
05830
05831
05832 static int load_config(int reload)
05833 {
05834 load_config_meetme();
05835
05836 if (reload) {
05837 sla_queue_event(SLA_EVENT_RELOAD);
05838 ast_log(LOG_NOTICE, "A reload of the SLA configuration has been requested "
05839 "and will be completed when the system is idle.\n");
05840 return 0;
05841 }
05842
05843 return sla_load_config(0);
05844 }
05845
05846 static int unload_module(void)
05847 {
05848 int res = 0;
05849
05850 ast_cli_unregister_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05851 res = ast_manager_unregister("MeetmeMute");
05852 res |= ast_manager_unregister("MeetmeUnmute");
05853 res |= ast_manager_unregister("MeetmeList");
05854 res |= ast_unregister_application(app4);
05855 res |= ast_unregister_application(app3);
05856 res |= ast_unregister_application(app2);
05857 res |= ast_unregister_application(app);
05858 res |= ast_unregister_application(slastation_app);
05859 res |= ast_unregister_application(slatrunk_app);
05860
05861 ast_devstate_prov_del("Meetme");
05862 ast_devstate_prov_del("SLA");
05863
05864 sla_destroy();
05865
05866 res |= ast_custom_function_unregister(&meetme_info_acf);
05867 ast_unload_realtime("meetme");
05868
05869 return res;
05870 }
05871
05872 static int load_module(void)
05873 {
05874 int res = 0;
05875
05876 res |= load_config(0);
05877
05878 ast_cli_register_multiple(cli_meetme, ARRAY_LEN(cli_meetme));
05879 res |= ast_manager_register("MeetmeMute", EVENT_FLAG_CALL,
05880 action_meetmemute, "Mute a Meetme user");
05881 res |= ast_manager_register("MeetmeUnmute", EVENT_FLAG_CALL,
05882 action_meetmeunmute, "Unmute a Meetme user");
05883 res |= ast_manager_register2("MeetmeList", EVENT_FLAG_REPORTING,
05884 action_meetmelist, "List participants in a conference", mandescr_meetmelist);
05885 res |= ast_register_application(app4, channel_admin_exec, synopsis4, descrip4);
05886 res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
05887 res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
05888 res |= ast_register_application(app, conf_exec, synopsis, descrip);
05889 res |= ast_register_application(slastation_app, sla_station_exec,
05890 slastation_synopsis, slastation_desc);
05891 res |= ast_register_application(slatrunk_app, sla_trunk_exec,
05892 slatrunk_synopsis, slatrunk_desc);
05893
05894 res |= ast_devstate_prov_add("Meetme", meetmestate);
05895 res |= ast_devstate_prov_add("SLA", sla_state);
05896
05897 res |= ast_custom_function_register(&meetme_info_acf);
05898 ast_realtime_require_field("meetme", "confno", RQ_UINTEGER2, 3, "members", RQ_UINTEGER1, 3, NULL);
05899
05900 return res;
05901 }
05902
05903 static int reload(void)
05904 {
05905 ast_unload_realtime("meetme");
05906 return load_config(1);
05907 }
05908
05909 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "MeetMe conference bridge",
05910 .load = load_module,
05911 .unload = unload_module,
05912 .reload = reload,
05913 );
05914