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