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