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