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: 137529 $")
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/devicestate.h"
00068 #include "asterisk/dial.h"
00069 #include "asterisk/causes.h"
00070
00071 #include "asterisk/dahdi_compat.h"
00072
00073 #include "enter.h"
00074 #include "leave.h"
00075
00076 #define CONFIG_FILE_NAME "meetme.conf"
00077 #define SLA_CONFIG_FILE "sla.conf"
00078
00079
00080 #define DEFAULT_AUDIO_BUFFERS 32
00081
00082 enum {
00083 ADMINFLAG_MUTED = (1 << 1),
00084 ADMINFLAG_SELFMUTED = (1 << 2),
00085 ADMINFLAG_KICKME = (1 << 3)
00086 };
00087
00088 #define MEETME_DELAYDETECTTALK 300
00089 #define MEETME_DELAYDETECTENDTALK 1000
00090
00091 #define AST_FRAME_BITS 32
00092
00093 enum volume_action {
00094 VOL_UP,
00095 VOL_DOWN
00096 };
00097
00098 enum entrance_sound {
00099 ENTER,
00100 LEAVE
00101 };
00102
00103 enum recording_state {
00104 MEETME_RECORD_OFF,
00105 MEETME_RECORD_STARTED,
00106 MEETME_RECORD_ACTIVE,
00107 MEETME_RECORD_TERMINATE
00108 };
00109
00110 #define CONF_SIZE 320
00111
00112 enum {
00113
00114 CONFFLAG_ADMIN = (1 << 0),
00115
00116 CONFFLAG_MONITOR = (1 << 1),
00117
00118 CONFFLAG_POUNDEXIT = (1 << 2),
00119
00120 CONFFLAG_STARMENU = (1 << 3),
00121
00122 CONFFLAG_TALKER = (1 << 4),
00123
00124 CONFFLAG_QUIET = (1 << 5),
00125
00126
00127 CONFFLAG_ANNOUNCEUSERCOUNT = (1 << 6),
00128
00129 CONFFLAG_AGI = (1 << 7),
00130
00131 CONFFLAG_MOH = (1 << 8),
00132
00133 CONFFLAG_MARKEDEXIT = (1 << 9),
00134
00135 CONFFLAG_WAITMARKED = (1 << 10),
00136
00137 CONFFLAG_EXIT_CONTEXT = (1 << 11),
00138
00139 CONFFLAG_MARKEDUSER = (1 << 12),
00140
00141 CONFFLAG_INTROUSER = (1 << 13),
00142
00143 CONFFLAG_RECORDCONF = (1<< 14),
00144
00145 CONFFLAG_MONITORTALKER = (1 << 15),
00146 CONFFLAG_DYNAMIC = (1 << 16),
00147 CONFFLAG_DYNAMICPIN = (1 << 17),
00148 CONFFLAG_EMPTY = (1 << 18),
00149 CONFFLAG_EMPTYNOPIN = (1 << 19),
00150 CONFFLAG_ALWAYSPROMPT = (1 << 20),
00151
00152 CONFFLAG_OPTIMIZETALKER = (1 << 21),
00153
00154
00155 CONFFLAG_NOONLYPERSON = (1 << 22),
00156
00157
00158 CONFFLAG_INTROUSERNOREVIEW = (1 << 23),
00159
00160 CONFFLAG_STARTMUTED = (1 << 24),
00161
00162 CONFFLAG_PASS_DTMF = (1 << 25),
00163
00164 CONFFLAG_SLA_STATION = (1 << 26),
00165
00166 CONFFLAG_SLA_TRUNK = (1 << 27),
00167 };
00168
00169 enum {
00170 OPT_ARG_WAITMARKED = 0,
00171 OPT_ARG_ARRAY_SIZE = 1,
00172 };
00173
00174 AST_APP_OPTIONS(meetme_opts, BEGIN_OPTIONS
00175 AST_APP_OPTION('A', CONFFLAG_MARKEDUSER ),
00176 AST_APP_OPTION('a', CONFFLAG_ADMIN ),
00177 AST_APP_OPTION('b', CONFFLAG_AGI ),
00178 AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT ),
00179 AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN ),
00180 AST_APP_OPTION('d', CONFFLAG_DYNAMIC ),
00181 AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN ),
00182 AST_APP_OPTION('e', CONFFLAG_EMPTY ),
00183 AST_APP_OPTION('F', CONFFLAG_PASS_DTMF ),
00184 AST_APP_OPTION('i', CONFFLAG_INTROUSER ),
00185 AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW ),
00186 AST_APP_OPTION('M', CONFFLAG_MOH ),
00187 AST_APP_OPTION('m', CONFFLAG_STARTMUTED ),
00188 AST_APP_OPTION('o', CONFFLAG_OPTIMIZETALKER ),
00189 AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ),
00190 AST_APP_OPTION('p', CONFFLAG_POUNDEXIT ),
00191 AST_APP_OPTION('q', CONFFLAG_QUIET ),
00192 AST_APP_OPTION('r', CONFFLAG_RECORDCONF ),
00193 AST_APP_OPTION('s', CONFFLAG_STARMENU ),
00194 AST_APP_OPTION('T', CONFFLAG_MONITORTALKER ),
00195 AST_APP_OPTION('l', CONFFLAG_MONITOR ),
00196 AST_APP_OPTION('t', CONFFLAG_TALKER ),
00197 AST_APP_OPTION_ARG('w', CONFFLAG_WAITMARKED, OPT_ARG_WAITMARKED ),
00198 AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT ),
00199 AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT ),
00200 AST_APP_OPTION('1', CONFFLAG_NOONLYPERSON ),
00201 END_OPTIONS );
00202
00203 static const char *app = "MeetMe";
00204 static const char *app2 = "MeetMeCount";
00205 static const char *app3 = "MeetMeAdmin";
00206 static const char *slastation_app = "SLAStation";
00207 static const char *slatrunk_app = "SLATrunk";
00208
00209 static const char *synopsis = "MeetMe conference bridge";
00210 static const char *synopsis2 = "MeetMe participant count";
00211 static const char *synopsis3 = "MeetMe conference Administration";
00212 static const char *slastation_synopsis = "Shared Line Appearance Station";
00213 static const char *slatrunk_synopsis = "Shared Line Appearance Trunk";
00214
00215 static const char *descrip =
00216 " MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe\n"
00217 "conference. If the conference number is omitted, the user will be prompted\n"
00218 "to enter one. User can exit the conference by hangup, or if the 'p' option\n"
00219 "is specified, by pressing '#'.\n"
00220 "Please note: The DAHDI kernel modules and at least one hardware driver (or dahdi_dummy)\n"
00221 " must be present for conferencing to operate properly. In addition, the chan_dahdi\n"
00222 " channel driver must be loaded for the 'i' and 'r' options to operate at all.\n\n"
00223 "The option string may contain zero or more of the following characters:\n"
00224 " 'a' -- set admin mode\n"
00225 " 'A' -- set marked mode\n"
00226 " 'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND}\n"
00227 " Default: conf-background.agi (Note: This does not work with\n"
00228 " non-DAHDI channels in the same conference)\n"
00229 " 'c' -- announce user(s) count on joining a conference\n"
00230 " 'd' -- dynamically add conference\n"
00231 " 'D' -- dynamically add conference, prompting for a PIN\n"
00232 " 'e' -- select an empty conference\n"
00233 " 'E' -- select an empty pinless conference\n"
00234 " 'F' -- Pass DTMF through the conference.\n"
00235 " 'i' -- announce user join/leave with review\n"
00236 " 'I' -- announce user join/leave without review\n"
00237 " 'l' -- set listen only mode (Listen only, no talking)\n"
00238 " 'm' -- set initially muted\n"
00239 " 'M' -- enable music on hold when the conference has a single caller\n"
00240 " 'o' -- set talker optimization - treats talkers who aren't speaking as\n"
00241 " being muted, meaning (a) No encode is done on transmission and\n"
00242 " (b) Received audio that is not registered as talking is omitted\n"
00243 " causing no buildup in background noise. Note that this option\n"
00244 " will be removed in 1.6 and enabled by default.\n"
00245 " 'p' -- allow user to exit the conference by pressing '#'\n"
00246 " 'P' -- always prompt for the pin even if it is specified\n"
00247 " 'q' -- quiet mode (don't play enter/leave sounds)\n"
00248 " 'r' -- Record conference (records as ${MEETME_RECORDINGFILE}\n"
00249 " using format ${MEETME_RECORDINGFORMAT}). Default filename is\n"
00250 " meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is\n"
00251 " wav.\n"
00252 " 's' -- Present menu (user or admin) when '*' is received ('send' to menu)\n"
00253 " 't' -- set talk only mode. (Talk only, no listening)\n"
00254 " 'T' -- set talker detection (sent to manager interface and meetme list)\n"
00255 " 'w[(<secs>)]'\n"
00256 " -- wait until the marked user enters the conference\n"
00257 " 'x' -- close the conference when last marked user exits\n"
00258 " 'X' -- allow user to exit the conference by entering a valid single\n"
00259 " digit extension ${MEETME_EXIT_CONTEXT} or the current context\n"
00260 " if that variable is not defined.\n"
00261 " '1' -- do not play message when first person enters\n";
00262
00263 static const char *descrip2 =
00264 " MeetMeCount(confno[|var]): Plays back the number of users in the specified\n"
00265 "MeetMe conference. If var is specified, playback will be skipped and the value\n"
00266 "will be returned in the variable. Upon app completion, MeetMeCount will hangup\n"
00267 "the channel, unless priority n+1 exists, in which case priority progress will\n"
00268 "continue.\n";
00269
00270 static const char *descrip3 =
00271 " MeetMeAdmin(confno,command[,user]): Run admin command for conference\n"
00272 " 'e' -- Eject last user that joined\n"
00273 " 'k' -- Kick one user out of conference\n"
00274 " 'K' -- Kick all users out of conference\n"
00275 " 'l' -- Unlock conference\n"
00276 " 'L' -- Lock conference\n"
00277 " 'm' -- Unmute one user\n"
00278 " 'M' -- Mute one user\n"
00279 " 'n' -- Unmute all users in the conference\n"
00280 " 'N' -- Mute all non-admin users in the conference\n"
00281 " 'r' -- Reset one user's volume settings\n"
00282 " 'R' -- Reset all users volume settings\n"
00283 " 's' -- Lower entire conference speaking volume\n"
00284 " 'S' -- Raise entire conference speaking volume\n"
00285 " 't' -- Lower one user's talk volume\n"
00286 " 'T' -- Raise one user's talk volume\n"
00287 " 'u' -- Lower one user's listen volume\n"
00288 " 'U' -- Raise one user's listen volume\n"
00289 " 'v' -- Lower entire conference listening volume\n"
00290 " 'V' -- Raise entire conference listening volume\n"
00291 "";
00292
00293 static const char *slastation_desc =
00294 " SLAStation(station):\n"
00295 "This application should be executed by an SLA station. The argument depends\n"
00296 "on how the call was initiated. If the phone was just taken off hook, then\n"
00297 "the argument \"station\" should be just the station name. If the call was\n"
00298 "initiated by pressing a line key, then the station name should be preceded\n"
00299 "by an underscore and the trunk name associated with that line button.\n"
00300 "For example: \"station1_line1\"."
00301 " On exit, this application will set the variable SLASTATION_STATUS to\n"
00302 "one of the following values:\n"
00303 " FAILURE | CONGESTION | SUCCESS\n"
00304 "";
00305
00306 static const char *slatrunk_desc =
00307 " SLATrunk(trunk):\n"
00308 "This application should be executed by an SLA trunk on an inbound call.\n"
00309 "The channel calling this application should correspond to the SLA trunk\n"
00310 "with the name \"trunk\" that is being passed as an argument.\n"
00311 " On exit, this application will set the variable SLATRUNK_STATUS to\n"
00312 "one of the following values:\n"
00313 " FAILURE | SUCCESS | UNANSWERED | RINGTIMEOUT\n"
00314 "";
00315
00316 #define MAX_CONFNUM 80
00317 #define MAX_PIN 80
00318
00319
00320 struct ast_conference {
00321 ast_mutex_t playlock;
00322 ast_mutex_t listenlock;
00323 char confno[MAX_CONFNUM];
00324 struct ast_channel *chan;
00325 struct ast_channel *lchan;
00326 int fd;
00327 int zapconf;
00328 int users;
00329 int markedusers;
00330 time_t start;
00331 int refcount;
00332 enum recording_state recording:2;
00333 unsigned int isdynamic:1;
00334 unsigned int locked:1;
00335 pthread_t recordthread;
00336 ast_mutex_t recordthreadlock;
00337 pthread_attr_t attr;
00338 const char *recordingfilename;
00339 const char *recordingformat;
00340 char pin[MAX_PIN];
00341 char pinadmin[MAX_PIN];
00342 struct ast_frame *transframe[32];
00343 struct ast_frame *origframe;
00344 struct ast_trans_pvt *transpath[32];
00345 AST_LIST_HEAD_NOLOCK(, ast_conf_user) userlist;
00346 AST_LIST_ENTRY(ast_conference) list;
00347 };
00348
00349 static AST_LIST_HEAD_STATIC(confs, ast_conference);
00350
00351 static unsigned int conf_map[1024] = {0, };
00352
00353 struct volume {
00354 int desired;
00355 int actual;
00356 };
00357
00358 struct ast_conf_user {
00359 int user_no;
00360 int userflags;
00361 int adminflags;
00362 struct ast_channel *chan;
00363 int talking;
00364 int zapchannel;
00365 char usrvalue[50];
00366 char namerecloc[PATH_MAX];
00367 time_t jointime;
00368 struct volume talk;
00369 struct volume listen;
00370 AST_LIST_ENTRY(ast_conf_user) list;
00371 };
00372
00373 enum sla_which_trunk_refs {
00374 ALL_TRUNK_REFS,
00375 INACTIVE_TRUNK_REFS,
00376 };
00377
00378 enum sla_trunk_state {
00379 SLA_TRUNK_STATE_IDLE,
00380 SLA_TRUNK_STATE_RINGING,
00381 SLA_TRUNK_STATE_UP,
00382 SLA_TRUNK_STATE_ONHOLD,
00383 SLA_TRUNK_STATE_ONHOLD_BYME,
00384 };
00385
00386 enum sla_hold_access {
00387
00388
00389 SLA_HOLD_OPEN,
00390
00391
00392 SLA_HOLD_PRIVATE,
00393 };
00394
00395 struct sla_trunk_ref;
00396
00397 struct sla_station {
00398 AST_RWLIST_ENTRY(sla_station) entry;
00399 AST_DECLARE_STRING_FIELDS(
00400 AST_STRING_FIELD(name);
00401 AST_STRING_FIELD(device);
00402 AST_STRING_FIELD(autocontext);
00403 );
00404 AST_LIST_HEAD_NOLOCK(, sla_trunk_ref) trunks;
00405 struct ast_dial *dial;
00406
00407
00408
00409 unsigned int ring_timeout;
00410
00411
00412
00413 unsigned int ring_delay;
00414
00415
00416 unsigned int hold_access:1;
00417 };
00418
00419 struct sla_station_ref {
00420 AST_LIST_ENTRY(sla_station_ref) entry;
00421 struct sla_station *station;
00422 };
00423
00424 struct sla_trunk {
00425 AST_RWLIST_ENTRY(sla_trunk) entry;
00426 AST_DECLARE_STRING_FIELDS(
00427 AST_STRING_FIELD(name);
00428 AST_STRING_FIELD(device);
00429 AST_STRING_FIELD(autocontext);
00430 );
00431 AST_LIST_HEAD_NOLOCK(, sla_station_ref) stations;
00432
00433 unsigned int num_stations;
00434
00435 unsigned int active_stations;
00436
00437 unsigned int hold_stations;
00438 struct ast_channel *chan;
00439 unsigned int ring_timeout;
00440
00441
00442 unsigned int barge_disabled:1;
00443
00444
00445 unsigned int hold_access:1;
00446
00447
00448 unsigned int on_hold:1;
00449 };
00450
00451 struct sla_trunk_ref {
00452 AST_LIST_ENTRY(sla_trunk_ref) entry;
00453 struct sla_trunk *trunk;
00454 enum sla_trunk_state state;
00455 struct ast_channel *chan;
00456
00457
00458
00459 unsigned int ring_timeout;
00460
00461
00462
00463 unsigned int ring_delay;
00464 };
00465
00466 static AST_RWLIST_HEAD_STATIC(sla_stations, sla_station);
00467 static AST_RWLIST_HEAD_STATIC(sla_trunks, sla_trunk);
00468
00469 static const char sla_registrar[] = "SLA";
00470
00471
00472 enum sla_event_type {
00473
00474 SLA_EVENT_HOLD,
00475
00476 SLA_EVENT_DIAL_STATE,
00477
00478 SLA_EVENT_RINGING_TRUNK,
00479 };
00480
00481 struct sla_event {
00482 enum sla_event_type type;
00483 struct sla_station *station;
00484 struct sla_trunk_ref *trunk_ref;
00485 AST_LIST_ENTRY(sla_event) entry;
00486 };
00487
00488
00489
00490 struct sla_failed_station {
00491 struct sla_station *station;
00492 struct timeval last_try;
00493 AST_LIST_ENTRY(sla_failed_station) entry;
00494 };
00495
00496
00497 struct sla_ringing_trunk {
00498 struct sla_trunk *trunk;
00499
00500 struct timeval ring_begin;
00501 AST_LIST_HEAD_NOLOCK(, sla_station_ref) timed_out_stations;
00502 AST_LIST_ENTRY(sla_ringing_trunk) entry;
00503 };
00504
00505 enum sla_station_hangup {
00506 SLA_STATION_HANGUP_NORMAL,
00507 SLA_STATION_HANGUP_TIMEOUT,
00508 };
00509
00510
00511 struct sla_ringing_station {
00512 struct sla_station *station;
00513
00514 struct timeval ring_begin;
00515 AST_LIST_ENTRY(sla_ringing_station) entry;
00516 };
00517
00518
00519
00520
00521 static struct {
00522
00523 pthread_t thread;
00524 ast_cond_t cond;
00525 ast_mutex_t lock;
00526 AST_LIST_HEAD_NOLOCK(, sla_ringing_trunk) ringing_trunks;
00527 AST_LIST_HEAD_NOLOCK(, sla_ringing_station) ringing_stations;
00528 AST_LIST_HEAD_NOLOCK(, sla_failed_station) failed_stations;
00529 AST_LIST_HEAD_NOLOCK(, sla_event) event_q;
00530 unsigned int stop:1;
00531
00532
00533 unsigned int attempt_callerid:1;
00534 } sla = {
00535 .thread = AST_PTHREADT_NULL,
00536 };
00537
00538
00539
00540 static int audio_buffers;
00541
00542
00543
00544
00545
00546
00547
00548 static char const gain_map[] = {
00549 -15,
00550 -13,
00551 -10,
00552 -6,
00553 0,
00554 0,
00555 0,
00556 6,
00557 10,
00558 13,
00559 15,
00560 };
00561
00562
00563 static int admin_exec(struct ast_channel *chan, void *data);
00564 static void *recordthread(void *args);
00565
00566 static char *istalking(int x)
00567 {
00568 if (x > 0)
00569 return "(talking)";
00570 else if (x < 0)
00571 return "(unmonitored)";
00572 else
00573 return "(not talking)";
00574 }
00575
00576 static int careful_write(int fd, unsigned char *data, int len, int block)
00577 {
00578 int res;
00579 int x;
00580
00581 while (len) {
00582 if (block) {
00583 x = DAHDI_IOMUX_WRITE | DAHDI_IOMUX_SIGEVENT;
00584 res = ioctl(fd, DAHDI_IOMUX, &x);
00585 } else
00586 res = 0;
00587 if (res >= 0)
00588 res = write(fd, data, len);
00589 if (res < 1) {
00590 if (errno != EAGAIN) {
00591 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00592 return -1;
00593 } else
00594 return 0;
00595 }
00596 len -= res;
00597 data += res;
00598 }
00599
00600 return 0;
00601 }
00602
00603 static int set_talk_volume(struct ast_conf_user *user, int volume)
00604 {
00605 char gain_adjust;
00606
00607
00608
00609
00610 gain_adjust = gain_map[volume + 5];
00611
00612 return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00613 }
00614
00615 static int set_listen_volume(struct ast_conf_user *user, int volume)
00616 {
00617 char gain_adjust;
00618
00619
00620
00621
00622 gain_adjust = gain_map[volume + 5];
00623
00624 return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00625 }
00626
00627 static void tweak_volume(struct volume *vol, enum volume_action action)
00628 {
00629 switch (action) {
00630 case VOL_UP:
00631 switch (vol->desired) {
00632 case 5:
00633 break;
00634 case 0:
00635 vol->desired = 2;
00636 break;
00637 case -2:
00638 vol->desired = 0;
00639 break;
00640 default:
00641 vol->desired++;
00642 break;
00643 }
00644 break;
00645 case VOL_DOWN:
00646 switch (vol->desired) {
00647 case -5:
00648 break;
00649 case 2:
00650 vol->desired = 0;
00651 break;
00652 case 0:
00653 vol->desired = -2;
00654 break;
00655 default:
00656 vol->desired--;
00657 break;
00658 }
00659 }
00660 }
00661
00662 static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
00663 {
00664 tweak_volume(&user->talk, action);
00665
00666
00667
00668 if (!set_talk_volume(user, user->talk.desired))
00669 user->talk.actual = 0;
00670 else
00671 user->talk.actual = user->talk.desired;
00672 }
00673
00674 static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
00675 {
00676 tweak_volume(&user->listen, action);
00677
00678
00679
00680 if (!set_listen_volume(user, user->listen.desired))
00681 user->listen.actual = 0;
00682 else
00683 user->listen.actual = user->listen.desired;
00684 }
00685
00686 static void reset_volumes(struct ast_conf_user *user)
00687 {
00688 signed char zero_volume = 0;
00689
00690 ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00691 ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
00692 }
00693
00694 static void conf_play(struct ast_channel *chan, struct ast_conference *conf, enum entrance_sound sound)
00695 {
00696 unsigned char *data;
00697 int len;
00698 int res = -1;
00699
00700 if (!chan->_softhangup)
00701 res = ast_autoservice_start(chan);
00702
00703 AST_LIST_LOCK(&confs);
00704
00705 switch(sound) {
00706 case ENTER:
00707 data = enter;
00708 len = sizeof(enter);
00709 break;
00710 case LEAVE:
00711 data = leave;
00712 len = sizeof(leave);
00713 break;
00714 default:
00715 data = NULL;
00716 len = 0;
00717 }
00718 if (data) {
00719 careful_write(conf->fd, data, len, 1);
00720 }
00721
00722 AST_LIST_UNLOCK(&confs);
00723
00724 if (!res)
00725 ast_autoservice_stop(chan);
00726 }
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741 static struct ast_conference *build_conf(char *confno, char *pin, char *pinadmin, int make, int dynamic, int refcount)
00742 {
00743 struct ast_conference *cnf;
00744 struct dahdi_confinfo ztc = { 0, };
00745 int confno_int = 0;
00746
00747 AST_LIST_LOCK(&confs);
00748
00749 AST_LIST_TRAVERSE(&confs, cnf, list) {
00750 if (!strcmp(confno, cnf->confno))
00751 break;
00752 }
00753
00754 if (cnf || (!make && !dynamic))
00755 goto cnfout;
00756
00757
00758 if (!(cnf = ast_calloc(1, sizeof(*cnf))))
00759 goto cnfout;
00760
00761 ast_mutex_init(&cnf->playlock);
00762 ast_mutex_init(&cnf->listenlock);
00763 cnf->recordthread = AST_PTHREADT_NULL;
00764 ast_mutex_init(&cnf->recordthreadlock);
00765 ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
00766 ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
00767 ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
00768
00769
00770 ztc.confno = -1;
00771 ztc.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
00772 #ifdef HAVE_ZAPTEL
00773 cnf->fd = open("/dev/zap/pseudo", O_RDWR);
00774 #else
00775 cnf->fd = open("/dev/dahdi/pseudo", O_RDWR);
00776 #endif
00777 if (cnf->fd < 0 || ioctl(cnf->fd, DAHDI_SETCONF, &ztc)) {
00778 ast_log(LOG_WARNING, "Unable to open pseudo device\n");
00779 if (cnf->fd >= 0)
00780 close(cnf->fd);
00781 free(cnf);
00782 cnf = NULL;
00783 goto cnfout;
00784 }
00785
00786 cnf->zapconf = ztc.confno;
00787
00788
00789 cnf->chan = ast_request(dahdi_chan_name, AST_FORMAT_SLINEAR, "pseudo", NULL);
00790 if (cnf->chan) {
00791 ast_set_read_format(cnf->chan, AST_FORMAT_SLINEAR);
00792 ast_set_write_format(cnf->chan, AST_FORMAT_SLINEAR);
00793 ztc.chan = 0;
00794 ztc.confno = cnf->zapconf;
00795 ztc.confmode = DAHDI_CONF_CONFANN | DAHDI_CONF_CONFANNMON;
00796 if (ioctl(cnf->chan->fds[0], DAHDI_SETCONF, &ztc)) {
00797 ast_log(LOG_WARNING, "Error setting conference\n");
00798 if (cnf->chan)
00799 ast_hangup(cnf->chan);
00800 else
00801 close(cnf->fd);
00802 free(cnf);
00803 cnf = NULL;
00804 goto cnfout;
00805 }
00806 }
00807
00808
00809 cnf->start = time(NULL);
00810 cnf->isdynamic = dynamic ? 1 : 0;
00811 if (option_verbose > 2)
00812 ast_verbose(VERBOSE_PREFIX_3 "Created MeetMe conference %d for conference '%s'\n", cnf->zapconf, cnf->confno);
00813 AST_LIST_INSERT_HEAD(&confs, cnf, list);
00814
00815
00816 if ((sscanf(cnf->confno, "%d", &confno_int) == 1) && (confno_int >= 0 && confno_int < 1024))
00817 conf_map[confno_int] = 1;
00818
00819 cnfout:
00820 if (cnf)
00821 ast_atomic_fetchadd_int(&cnf->refcount, refcount);
00822
00823 AST_LIST_UNLOCK(&confs);
00824
00825 return cnf;
00826 }
00827
00828 static int meetme_cmd(int fd, int argc, char **argv)
00829 {
00830
00831 struct ast_conference *cnf;
00832 struct ast_conf_user *user;
00833 int hr, min, sec;
00834 int i = 0, total = 0;
00835 time_t now;
00836 char *header_format = "%-14s %-14s %-10s %-8s %-8s\n";
00837 char *data_format = "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s\n";
00838 char cmdline[1024] = "";
00839
00840 if (argc > 8)
00841 ast_cli(fd, "Invalid Arguments.\n");
00842
00843 for (i = 0; i < argc; i++) {
00844 if (strlen(argv[i]) > 100)
00845 ast_cli(fd, "Invalid Arguments.\n");
00846 }
00847 if (argc == 1) {
00848
00849 now = time(NULL);
00850 AST_LIST_LOCK(&confs);
00851 if (AST_LIST_EMPTY(&confs)) {
00852 ast_cli(fd, "No active MeetMe conferences.\n");
00853 AST_LIST_UNLOCK(&confs);
00854 return RESULT_SUCCESS;
00855 }
00856 ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation");
00857 AST_LIST_TRAVERSE(&confs, cnf, list) {
00858 if (cnf->markedusers == 0)
00859 strcpy(cmdline, "N/A ");
00860 else
00861 snprintf(cmdline, sizeof(cmdline), "%4.4d", cnf->markedusers);
00862 hr = (now - cnf->start) / 3600;
00863 min = ((now - cnf->start) % 3600) / 60;
00864 sec = (now - cnf->start) % 60;
00865
00866 ast_cli(fd, data_format, cnf->confno, cnf->users, cmdline, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static");
00867
00868 total += cnf->users;
00869 }
00870 AST_LIST_UNLOCK(&confs);
00871 ast_cli(fd, "* Total number of MeetMe users: %d\n", total);
00872 return RESULT_SUCCESS;
00873 }
00874 if (argc < 3)
00875 return RESULT_SHOWUSAGE;
00876 ast_copy_string(cmdline, argv[2], sizeof(cmdline));
00877 if (strstr(argv[1], "lock")) {
00878 if (strcmp(argv[1], "lock") == 0) {
00879
00880 strncat(cmdline, "|L", sizeof(cmdline) - strlen(cmdline) - 1);
00881 } else {
00882
00883 strncat(cmdline, "|l", sizeof(cmdline) - strlen(cmdline) - 1);
00884 }
00885 } else if (strstr(argv[1], "mute")) {
00886 if (argc < 4)
00887 return RESULT_SHOWUSAGE;
00888 if (strcmp(argv[1], "mute") == 0) {
00889
00890 if (strcmp(argv[3], "all") == 0) {
00891 strncat(cmdline, "|N", sizeof(cmdline) - strlen(cmdline) - 1);
00892 } else {
00893 strncat(cmdline, "|M|", sizeof(cmdline) - strlen(cmdline) - 1);
00894 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00895 }
00896 } else {
00897
00898 if (strcmp(argv[3], "all") == 0) {
00899 strncat(cmdline, "|n", sizeof(cmdline) - strlen(cmdline) - 1);
00900 } else {
00901 strncat(cmdline, "|m|", sizeof(cmdline) - strlen(cmdline) - 1);
00902 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00903 }
00904 }
00905 } else if (strcmp(argv[1], "kick") == 0) {
00906 if (argc < 4)
00907 return RESULT_SHOWUSAGE;
00908 if (strcmp(argv[3], "all") == 0) {
00909
00910 strncat(cmdline, "|K", sizeof(cmdline) - strlen(cmdline) - 1);
00911 } else {
00912
00913 strncat(cmdline, "|k|", sizeof(cmdline) - strlen(cmdline) - 1);
00914 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00915 }
00916 } else if(strcmp(argv[1], "list") == 0) {
00917 int concise = ( 4 == argc && ( !strcasecmp(argv[3], "concise") ) );
00918
00919 if (AST_LIST_EMPTY(&confs)) {
00920 if ( !concise )
00921 ast_cli(fd, "No active conferences.\n");
00922 return RESULT_SUCCESS;
00923 }
00924
00925 AST_LIST_LOCK(&confs);
00926 AST_LIST_TRAVERSE(&confs, cnf, list) {
00927 if (strcmp(cnf->confno, argv[2]) == 0)
00928 break;
00929 }
00930 if (!cnf) {
00931 if ( !concise )
00932 ast_cli(fd, "No such conference: %s.\n",argv[2]);
00933 AST_LIST_UNLOCK(&confs);
00934 return