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