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 #include <stdlib.h>
00027 #include <stdio.h>
00028 #include <string.h>
00029 #include <unistd.h>
00030 #include <errno.h>
00031 #include <sys/ioctl.h>
00032 #ifdef __linux__
00033 #include <linux/zaptel.h>
00034 #else
00035 #include <zaptel.h>
00036 #endif
00037
00038 #include "asterisk.h"
00039
00040 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 33545 $")
00041
00042 #include "asterisk/lock.h"
00043 #include "asterisk/file.h"
00044 #include "asterisk/logger.h"
00045 #include "asterisk/channel.h"
00046 #include "asterisk/pbx.h"
00047 #include "asterisk/module.h"
00048 #include "asterisk/config.h"
00049 #include "asterisk/app.h"
00050 #include "asterisk/dsp.h"
00051 #include "asterisk/musiconhold.h"
00052 #include "asterisk/manager.h"
00053 #include "asterisk/options.h"
00054 #include "asterisk/cli.h"
00055 #include "asterisk/say.h"
00056 #include "asterisk/utils.h"
00057
00058 static const char *tdesc = "MeetMe conference bridge";
00059
00060 static const char *app = "MeetMe";
00061 static const char *app2 = "MeetMeCount";
00062 static const char *app3 = "MeetMeAdmin";
00063
00064 static const char *synopsis = "MeetMe conference bridge";
00065 static const char *synopsis2 = "MeetMe participant count";
00066 static const char *synopsis3 = "MeetMe conference Administration";
00067
00068 static const char *descrip =
00069 " MeetMe([confno][,[options][,pin]]): Enters the user into a specified MeetMe conference.\n"
00070 "If the conference number is omitted, the user will be prompted to enter\n"
00071 "one. \n"
00072 "User can exit the conference by hangup, or if the 'p' option is specified, by pressing '#'.\n"
00073 "Please note: The Zaptel kernel modules and at least one hardware driver (or ztdummy)\n"
00074 " must be present for conferencing to operate properly. In addition, the chan_zap\n"
00075 " channel driver must be loaded for the 'i' and 'r' options to operate at all.\n\n"
00076 "The option string may contain zero or more of the following characters:\n"
00077 " 'a' -- set admin mode\n"
00078 " 'A' -- set marked mode\n"
00079 " 'b' -- run AGI script specified in ${MEETME_AGI_BACKGROUND}\n"
00080 " Default: conf-background.agi\n"
00081 " (Note: This does not work with non-Zap channels in the same conference)\n"
00082 " 'c' -- announce user(s) count on joining a conference\n"
00083 " 'd' -- dynamically add conference\n"
00084 " 'D' -- dynamically add conference, prompting for a PIN\n"
00085 " 'e' -- select an empty conference\n"
00086 " 'E' -- select an empty pinless conference\n"
00087 " 'i' -- announce user join/leave\n"
00088 " 'm' -- set monitor only mode (Listen only, no talking)\n"
00089 " 'M' -- enable music on hold when the conference has a single caller\n"
00090 " 'p' -- allow user to exit the conference by pressing '#'\n"
00091 " 'P' -- always prompt for the pin even if it is specified\n"
00092 " 'q' -- quiet mode (don't play enter/leave sounds)\n"
00093 " 'r' -- Record conference (records as ${MEETME_RECORDINGFILE}\n"
00094 " using format ${MEETME_RECORDINGFORMAT}). Default filename is\n"
00095 " meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is wav.\n"
00096 " 's' -- Present menu (user or admin) when '*' is received ('send' to menu)\n"
00097 " 't' -- set talk only mode. (Talk only, no listening)\n"
00098 " 'T' -- set talker detection (sent to manager interface and meetme list)\n"
00099 " 'w' -- wait until the marked user enters the conference\n"
00100 " 'x' -- close the conference when last marked user exits\n"
00101 " 'X' -- allow user to exit the conference by entering a valid single\n"
00102 " digit extension ${MEETME_EXIT_CONTEXT} or the current context\n"
00103 " if that variable is not defined.\n";
00104
00105 static const char *descrip2 =
00106 " MeetMeCount(confno[|var]): Plays back the number of users in the specified\n"
00107 "MeetMe conference. If var is specified, playback will be skipped and the value\n"
00108 "will be returned in the variable. Upon app completion, MeetMeCount will hangup the\n"
00109 "channel, unless priority n+1 exists, in which case priority progress will continue.\n"
00110 "A ZAPTEL INTERFACE MUST BE INSTALLED FOR CONFERENCING FUNCTIONALITY.\n";
00111
00112 static const char *descrip3 =
00113 " MeetMeAdmin(confno,command[,user]): Run admin command for conference\n"
00114 " 'e' -- Eject last user that joined\n"
00115 " 'k' -- Kick one user out of conference\n"
00116 " 'K' -- Kick all users out of conference\n"
00117 " 'l' -- Unlock conference\n"
00118 " 'L' -- Lock conference\n"
00119 " 'm' -- Unmute conference\n"
00120 " 'M' -- Mute conference\n"
00121 " 'n' -- Unmute entire conference (except admin)\n"
00122 " 'N' -- Mute entire conference (except admin)\n"
00123 "";
00124
00125 #define CONFIG_FILE_NAME "meetme.conf"
00126
00127 STANDARD_LOCAL_USER;
00128
00129 LOCAL_USER_DECL;
00130
00131 static struct ast_conference {
00132 char confno[AST_MAX_EXTENSION];
00133 struct ast_channel *chan;
00134 int fd;
00135 int zapconf;
00136 int users;
00137 int markedusers;
00138 struct ast_conf_user *firstuser;
00139 struct ast_conf_user *lastuser;
00140 time_t start;
00141 int recording;
00142 int isdynamic;
00143 int locked;
00144 pthread_t recordthread;
00145 pthread_attr_t attr;
00146 char *recordingfilename;
00147 char *recordingformat;
00148 char pin[AST_MAX_EXTENSION];
00149 char pinadmin[AST_MAX_EXTENSION];
00150 struct ast_conference *next;
00151 } *confs;
00152
00153 struct volume {
00154 int desired;
00155 int actual;
00156 };
00157
00158 struct ast_conf_user {
00159 int user_no;
00160 struct ast_conf_user *prevuser;
00161 struct ast_conf_user *nextuser;
00162 int userflags;
00163 int adminflags;
00164 struct ast_channel *chan;
00165 int talking;
00166 int zapchannel;
00167 char usrvalue[50];
00168 char namerecloc[PATH_MAX];
00169 time_t jointime;
00170 struct volume talk;
00171 struct volume listen;
00172 };
00173
00174 static int audio_buffers;
00175
00176
00177
00178 #define DEFAULT_AUDIO_BUFFERS 32
00179
00180 #define ADMINFLAG_MUTED (1 << 1)
00181 #define ADMINFLAG_KICKME (1 << 2)
00182 #define MEETME_DELAYDETECTTALK 300
00183 #define MEETME_DELAYDETECTENDTALK 1000
00184
00185 enum volume_action {
00186 VOL_UP,
00187 VOL_DOWN,
00188 };
00189
00190 AST_MUTEX_DEFINE_STATIC(conflock);
00191
00192 static int admin_exec(struct ast_channel *chan, void *data);
00193
00194 static void *recordthread(void *args);
00195
00196 #include "enter.h"
00197 #include "leave.h"
00198
00199 #define ENTER 0
00200 #define LEAVE 1
00201
00202 #define MEETME_RECORD_OFF 0
00203 #define MEETME_RECORD_ACTIVE 1
00204 #define MEETME_RECORD_TERMINATE 2
00205
00206 #define CONF_SIZE 320
00207
00208 #define CONFFLAG_ADMIN (1 << 1)
00209 #define CONFFLAG_MONITOR (1 << 2)
00210 #define CONFFLAG_POUNDEXIT (1 << 3)
00211 #define CONFFLAG_STARMENU (1 << 4)
00212 #define CONFFLAG_TALKER (1 << 5)
00213 #define CONFFLAG_QUIET (1 << 6)
00214 #define CONFFLAG_ANNOUNCEUSERCOUNT (1 << 7)
00215 #define CONFFLAG_AGI (1 << 8)
00216 #define CONFFLAG_MOH (1 << 9)
00217 #define CONFFLAG_MARKEDEXIT (1 << 10)
00218 #define CONFFLAG_WAITMARKED (1 << 11)
00219 #define CONFFLAG_EXIT_CONTEXT (1 << 12)
00220 #define CONFFLAG_MARKEDUSER (1 << 13)
00221 #define CONFFLAG_INTROUSER (1 << 14)
00222 #define CONFFLAG_RECORDCONF (1<< 15)
00223 #define CONFFLAG_MONITORTALKER (1 << 16)
00224 #define CONFFLAG_DYNAMIC (1 << 17)
00225 #define CONFFLAG_DYNAMICPIN (1 << 18)
00226 #define CONFFLAG_EMPTY (1 << 19)
00227 #define CONFFLAG_EMPTYNOPIN (1 << 20)
00228 #define CONFFLAG_ALWAYSPROMPT (1 << 21)
00229
00230
00231 AST_APP_OPTIONS(meetme_opts, {
00232 AST_APP_OPTION('a', CONFFLAG_ADMIN ),
00233 AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT ),
00234 AST_APP_OPTION('T', CONFFLAG_MONITORTALKER ),
00235 AST_APP_OPTION('i', CONFFLAG_INTROUSER ),
00236 AST_APP_OPTION('m', CONFFLAG_MONITOR ),
00237 AST_APP_OPTION('p', CONFFLAG_POUNDEXIT ),
00238 AST_APP_OPTION('s', CONFFLAG_STARMENU ),
00239 AST_APP_OPTION('t', CONFFLAG_TALKER ),
00240 AST_APP_OPTION('q', CONFFLAG_QUIET ),
00241 AST_APP_OPTION('M', CONFFLAG_MOH ),
00242 AST_APP_OPTION('x', CONFFLAG_MARKEDEXIT ),
00243 AST_APP_OPTION('X', CONFFLAG_EXIT_CONTEXT ),
00244 AST_APP_OPTION('A', CONFFLAG_MARKEDUSER ),
00245 AST_APP_OPTION('b', CONFFLAG_AGI ),
00246 AST_APP_OPTION('w', CONFFLAG_WAITMARKED ),
00247 AST_APP_OPTION('r', CONFFLAG_RECORDCONF ),
00248 AST_APP_OPTION('d', CONFFLAG_DYNAMIC ),
00249 AST_APP_OPTION('D', CONFFLAG_DYNAMICPIN ),
00250 AST_APP_OPTION('e', CONFFLAG_EMPTY ),
00251 AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN ),
00252 AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ),
00253 });
00254
00255 static char *istalking(int x)
00256 {
00257 if (x > 0)
00258 return "(talking)";
00259 else if (x < 0)
00260 return "(unmonitored)";
00261 else
00262 return "(not talking)";
00263 }
00264
00265 static int careful_write(int fd, unsigned char *data, int len, int block)
00266 {
00267 int res;
00268 int x;
00269
00270 while (len) {
00271 if (block) {
00272 x = ZT_IOMUX_WRITE | ZT_IOMUX_SIGEVENT;
00273 res = ioctl(fd, ZT_IOMUX, &x);
00274 } else
00275 res = 0;
00276 if (res >= 0)
00277 res = write(fd, data, len);
00278 if (res < 1) {
00279 if (errno != EAGAIN) {
00280 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00281 return -1;
00282 } else
00283 return 0;
00284 }
00285 len -= res;
00286 data += res;
00287 }
00288
00289 return 0;
00290 }
00291
00292
00293
00294
00295
00296
00297
00298 static signed char gain_map[] = {
00299 -15,
00300 -13,
00301 -10,
00302 -6,
00303 0,
00304 0,
00305 0,
00306 6,
00307 10,
00308 13,
00309 15,
00310 };
00311
00312 static int set_talk_volume(struct ast_conf_user *user, int volume)
00313 {
00314 signed char gain_adjust;
00315
00316
00317
00318
00319 gain_adjust = gain_map[volume + 5];
00320
00321 return ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00322 }
00323
00324 static int set_listen_volume(struct ast_conf_user *user, int volume)
00325 {
00326 signed char gain_adjust;
00327
00328
00329
00330
00331 gain_adjust = gain_map[volume + 5];
00332
00333 return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
00334 }
00335
00336 static void tweak_volume(struct volume *vol, enum volume_action action)
00337 {
00338 switch (action) {
00339 case VOL_UP:
00340 switch (vol->desired) {
00341 case 5:
00342 break;
00343 case 0:
00344 vol->desired = 2;
00345 break;
00346 case -2:
00347 vol->desired = 0;
00348 break;
00349 default:
00350 vol->desired++;
00351 break;
00352 }
00353 break;
00354 case VOL_DOWN:
00355 switch (vol->desired) {
00356 case -5:
00357 break;
00358 case 2:
00359 vol->desired = 0;
00360 break;
00361 case 0:
00362 vol->desired = -2;
00363 break;
00364 default:
00365 vol->desired--;
00366 break;
00367 }
00368 }
00369 }
00370
00371 static void tweak_talk_volume(struct ast_conf_user *user, enum volume_action action)
00372 {
00373 tweak_volume(&user->talk, action);
00374
00375
00376
00377 if (!set_talk_volume(user, user->talk.desired))
00378 user->talk.actual = 0;
00379 else
00380 user->talk.actual = user->talk.desired;
00381 }
00382
00383 static void tweak_listen_volume(struct ast_conf_user *user, enum volume_action action)
00384 {
00385 tweak_volume(&user->listen, action);
00386
00387
00388
00389 if (!set_listen_volume(user, user->listen.desired))
00390 user->listen.actual = 0;
00391 else
00392 user->listen.actual = user->listen.desired;
00393 }
00394
00395 static void reset_volumes(struct ast_conf_user *user)
00396 {
00397 signed char zero_volume = 0;
00398
00399 ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00400 ast_channel_setoption(user->chan, AST_OPTION_RXGAIN, &zero_volume, sizeof(zero_volume), 0);
00401 }
00402
00403 static void conf_play(struct ast_channel *chan, struct ast_conference *conf, int sound)
00404 {
00405 unsigned char *data;
00406 int len;
00407 int res = -1;
00408
00409 if (!chan->_softhangup)
00410 res = ast_autoservice_start(chan);
00411
00412 ast_mutex_lock(&conflock);
00413
00414 switch(sound) {
00415 case ENTER:
00416 data = enter;
00417 len = sizeof(enter);
00418 break;
00419 case LEAVE:
00420 data = leave;
00421 len = sizeof(leave);
00422 break;
00423 default:
00424 data = NULL;
00425 len = 0;
00426 }
00427 if (data)
00428 careful_write(conf->fd, data, len, 1);
00429
00430 ast_mutex_unlock(&conflock);
00431
00432 if (!res)
00433 ast_autoservice_stop(chan);
00434 }
00435
00436 static struct ast_conference *build_conf(char *confno, char *pin, char *pinadmin, int make, int dynamic)
00437 {
00438 struct ast_conference *cnf;
00439 struct zt_confinfo ztc;
00440
00441 ast_mutex_lock(&conflock);
00442
00443 for (cnf = confs; cnf; cnf = cnf->next) {
00444 if (!strcmp(confno, cnf->confno))
00445 break;
00446 }
00447
00448 if (!cnf && (make || dynamic)) {
00449
00450 cnf = calloc(1, sizeof(*cnf));
00451 if (cnf) {
00452 ast_copy_string(cnf->confno, confno, sizeof(cnf->confno));
00453 ast_copy_string(cnf->pin, pin, sizeof(cnf->pin));
00454 ast_copy_string(cnf->pinadmin, pinadmin, sizeof(cnf->pinadmin));
00455 cnf->markedusers = 0;
00456 cnf->chan = ast_request("zap", AST_FORMAT_ULAW, "pseudo", NULL);
00457 if (cnf->chan) {
00458 cnf->fd = cnf->chan->fds[0];
00459 } else {
00460 ast_log(LOG_WARNING, "Unable to open pseudo channel - trying device\n");
00461 cnf->fd = open("/dev/zap/pseudo", O_RDWR);
00462 if (cnf->fd < 0) {
00463 ast_log(LOG_WARNING, "Unable to open pseudo device\n");
00464 free(cnf);
00465 cnf = NULL;
00466 goto cnfout;
00467 }
00468 }
00469 memset(&ztc, 0, sizeof(ztc));
00470
00471 ztc.chan = 0;
00472 ztc.confno = -1;
00473 ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
00474 if (ioctl(cnf->fd, ZT_SETCONF, &ztc)) {
00475 ast_log(LOG_WARNING, "Error setting conference\n");
00476 if (cnf->chan)
00477 ast_hangup(cnf->chan);
00478 else
00479 close(cnf->fd);
00480 free(cnf);
00481 cnf = NULL;
00482 goto cnfout;
00483 }
00484
00485 cnf->start = time(NULL);
00486 cnf->zapconf = ztc.confno;
00487 cnf->isdynamic = dynamic;
00488 cnf->firstuser = NULL;
00489 cnf->lastuser = NULL;
00490 cnf->locked = 0;
00491 if (option_verbose > 2)
00492 ast_verbose(VERBOSE_PREFIX_3 "Created MeetMe conference %d for conference '%s'\n", cnf->zapconf, cnf->confno);
00493 cnf->next = confs;
00494 confs = cnf;
00495 } else
00496 ast_log(LOG_WARNING, "Out of memory\n");
00497 }
00498 cnfout:
00499 ast_mutex_unlock(&conflock);
00500 return cnf;
00501 }
00502
00503 static int confs_show(int fd, int argc, char **argv)
00504 {
00505 ast_cli(fd, "Deprecated! Please use 'meetme' instead.\n");
00506
00507 return RESULT_SUCCESS;
00508 }
00509
00510 static char show_confs_usage[] =
00511 "Deprecated! Please use 'meetme' instead.\n";
00512
00513 static struct ast_cli_entry cli_show_confs = {
00514 { "show", "conferences", NULL }, confs_show,
00515 "Show status of conferences", show_confs_usage, NULL };
00516
00517 static int conf_cmd(int fd, int argc, char **argv) {
00518
00519 struct ast_conference *cnf;
00520 struct ast_conf_user *user;
00521 int hr, min, sec;
00522 int i = 0, total = 0;
00523 time_t now;
00524 char *header_format = "%-14s %-14s %-10s %-8s %-8s\n";
00525 char *data_format = "%-12.12s %4.4d %4.4s %02d:%02d:%02d %-8s\n";
00526 char cmdline[1024] = "";
00527
00528 if (argc > 8)
00529 ast_cli(fd, "Invalid Arguments.\n");
00530
00531 for (i = 0; i < argc; i++) {
00532 if (strlen(argv[i]) > 100)
00533 ast_cli(fd, "Invalid Arguments.\n");
00534 }
00535 if (argc == 1) {
00536
00537 now = time(NULL);
00538 cnf = confs;
00539 if (!cnf) {
00540 ast_cli(fd, "No active MeetMe conferences.\n");
00541 return RESULT_SUCCESS;
00542 }
00543 ast_cli(fd, header_format, "Conf Num", "Parties", "Marked", "Activity", "Creation");
00544 while(cnf) {
00545 if (cnf->markedusers == 0)
00546 strcpy(cmdline, "N/A ");
00547 else
00548 snprintf(cmdline, sizeof(cmdline), "%4.4d", cnf->markedusers);
00549 hr = (now - cnf->start) / 3600;
00550 min = ((now - cnf->start) % 3600) / 60;
00551 sec = (now - cnf->start) % 60;
00552
00553 ast_cli(fd, data_format, cnf->confno, cnf->users, cmdline, hr, min, sec, cnf->isdynamic ? "Dynamic" : "Static");
00554
00555 total += cnf->users;
00556 cnf = cnf->next;
00557 }
00558 ast_cli(fd, "* Total number of MeetMe users: %d\n", total);
00559 return RESULT_SUCCESS;
00560 }
00561 if (argc < 3)
00562 return RESULT_SHOWUSAGE;
00563 ast_copy_string(cmdline, argv[2], sizeof(cmdline));
00564 if (strstr(argv[1], "lock")) {
00565 if (strcmp(argv[1], "lock") == 0) {
00566
00567 strncat(cmdline, "|L", sizeof(cmdline) - strlen(cmdline) - 1);
00568 } else {
00569
00570 strncat(cmdline, "|l", sizeof(cmdline) - strlen(cmdline) - 1);
00571 }
00572 } else if (strstr(argv[1], "mute")) {
00573 if (argc < 4)
00574 return RESULT_SHOWUSAGE;
00575 if (strcmp(argv[1], "mute") == 0) {
00576
00577 if (strcmp(argv[3], "all") == 0) {
00578 strncat(cmdline, "|N", sizeof(cmdline) - strlen(cmdline) - 1);
00579 } else {
00580 strncat(cmdline, "|M|", sizeof(cmdline) - strlen(cmdline) - 1);
00581 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00582 }
00583 } else {
00584
00585 if (strcmp(argv[3], "all") == 0) {
00586 strncat(cmdline, "|n", sizeof(cmdline) - strlen(cmdline) - 1);
00587 } else {
00588 strncat(cmdline, "|m|", sizeof(cmdline) - strlen(cmdline) - 1);
00589 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00590 }
00591 }
00592 } else if (strcmp(argv[1], "kick") == 0) {
00593 if (argc < 4)
00594 return RESULT_SHOWUSAGE;
00595 if (strcmp(argv[3], "all") == 0) {
00596
00597 strncat(cmdline, "|K", sizeof(cmdline) - strlen(cmdline) - 1);
00598 } else {
00599
00600 strncat(cmdline, "|k|", sizeof(cmdline) - strlen(cmdline) - 1);
00601 strncat(cmdline, argv[3], sizeof(cmdline) - strlen(cmdline) - 1);
00602 }
00603 } else if(strcmp(argv[1], "list") == 0) {
00604
00605 if (!confs) {
00606 ast_cli(fd, "No active conferences.\n");
00607 return RESULT_SUCCESS;
00608 }
00609 cnf = confs;
00610
00611 while(cnf) {
00612 if (strcmp(cnf->confno, argv[2]) == 0)
00613 break;
00614 if (cnf->next) {
00615 cnf = cnf->next;
00616 } else {
00617 ast_cli(fd, "No such conference: %s.\n",argv[2]);
00618 return RESULT_SUCCESS;
00619 }
00620 }
00621
00622 for (user = cnf->firstuser; user; user = user->nextuser)
00623 ast_cli(fd, "User #: %-2.2d %12.12s %-20.20s Channel: %s %s %s %s %s\n",
00624 user->user_no,
00625 user->chan->cid.cid_num ? user->chan->cid.cid_num : "<unknown>",
00626 user->chan->cid.cid_name ? user->chan->cid.cid_name : "<no name>",
00627 user->chan->name,
00628 user->userflags & CONFFLAG_ADMIN ? "(Admin)" : "",
00629 user->userflags & CONFFLAG_MONITOR ? "(Listen only)" : "",
00630 user->adminflags & ADMINFLAG_MUTED ? "(Admin Muted)" : "",
00631 istalking(user->talking));
00632 ast_cli(fd,"%d users in that conference.\n",cnf->users);
00633
00634 return RESULT_SUCCESS;
00635 } else
00636 return RESULT_SHOWUSAGE;
00637 ast_log(LOG_DEBUG, "Cmdline: %s\n", cmdline);
00638 admin_exec(NULL, cmdline);
00639
00640 return 0;
00641 }
00642
00643 static char *complete_confcmd(char *line, char *word, int pos, int state) {
00644 #define CONF_COMMANDS 6
00645 int which = 0, x = 0;
00646 struct ast_conference *cnf = NULL;
00647 struct ast_conf_user *usr = NULL;
00648 char *confno = NULL;
00649 char usrno[50] = "";
00650 char cmds[CONF_COMMANDS][20] = {"lock", "unlock", "mute", "unmute", "kick", "list"};
00651 char *myline;
00652
00653 if (pos == 1) {
00654
00655 for (x = 0;x < CONF_COMMANDS; x++) {
00656 if (!strncasecmp(cmds[x], word, strlen(word))) {
00657 if (++which > state) {
00658 return strdup(cmds[x]);
00659 }
00660 }
00661 }
00662 } else if (pos == 2) {
00663
00664 ast_mutex_lock(&conflock);
00665 cnf = confs;
00666 while(cnf) {
00667 if (!strncasecmp(word, cnf->confno, strlen(word))) {
00668 if (++which > state)
00669 break;
00670 }
00671 cnf = cnf->next;
00672 }
00673 ast_mutex_unlock(&conflock);
00674 return cnf ? strdup(cnf->confno) : NULL;
00675 } else if (pos == 3) {
00676
00677 if (strstr(line, "mute") || strstr(line, "kick")) {
00678 if ((state == 0) && (strstr(line, "kick") || strstr(line,"mute")) && !(strncasecmp(word, "all", strlen(word)))) {
00679 return strdup("all");
00680 }
00681 which++;
00682 ast_mutex_lock(&conflock);
00683
00684
00685 myline = ast_strdupa(line);
00686 if (strsep(&myline, " ") && strsep(&myline, " ") && !confno) {
00687 while((confno = strsep(&myline, " ")) && (strcmp(confno, " ") == 0))
00688 ;
00689 }
00690
00691 for (cnf = confs; cnf; cnf = cnf->next) {
00692 if (!strcmp(confno, cnf->confno))
00693 break;
00694 }
00695
00696 if (cnf) {
00697
00698 for (usr = cnf->firstuser; usr; usr = usr->nextuser) {
00699 snprintf(usrno, sizeof(usrno), "%d", usr->user_no);
00700 if (!strncasecmp(word, usrno, strlen(word))) {
00701 if (++which > state)
00702 break;
00703 }
00704 }
00705 }
00706 ast_mutex_unlock(&conflock);
00707 return usr ? strdup(usrno) : NULL;
00708 }
00709 }
00710
00711 return NULL;
00712 }
00713
00714 static char conf_usage[] =
00715 "Usage: meetme (un)lock|(un)mute|kick|list <confno> <usernumber>\n"
00716 " Executes a command for the conference or on a conferee\n";
00717
00718 static struct ast_cli_entry cli_conf = {
00719 {"meetme", NULL, NULL }, conf_cmd,
00720 "Execute a command on a conference or conferee", conf_usage, complete_confcmd};
00721
00722 static void conf_flush(int fd, struct ast_channel *chan)
00723 {
00724 int x;
00725
00726
00727
00728
00729 if (chan) {
00730 struct ast_frame *f;
00731
00732
00733
00734
00735 while (ast_waitfor(chan, 1)) {
00736 f = ast_read(chan);
00737 if (f)
00738 ast_frfree(f);
00739 else
00740 break;
00741 }
00742 }
00743
00744
00745 x = ZT_FLUSH_ALL;
00746 if (ioctl(fd, ZT_FLUSH, &x))
00747 ast_log(LOG_WARNING, "Error flushing channel\n");
00748
00749 }
00750
00751
00752
00753 static int conf_free(struct ast_conference *conf)
00754 {
00755 struct ast_conference *prev = NULL, *cur = confs;
00756
00757 while (cur) {
00758 if (cur == conf) {
00759 if (prev)
00760 prev->next = conf->next;
00761 else
00762 confs = conf->next;
00763 break;
00764 }
00765 prev = cur;
00766 cur = cur->next;
00767 }
00768
00769 if (!cur)
00770 ast_log(LOG_WARNING, "Conference not found\n");
00771
00772 if (conf->recording == MEETME_RECORD_ACTIVE) {
00773 conf->recording = MEETME_RECORD_TERMINATE;
00774 ast_mutex_unlock(&conflock);
00775 while (1) {
00776 ast_mutex_lock(&conflock);
00777 if (conf->recording == MEETME_RECORD_OFF)
00778 break;
00779 ast_mutex_unlock(&conflock);
00780 }
00781 }
00782
00783 if (conf->chan)
00784 ast_hangup(conf->chan);
00785 else
00786 close(conf->fd);
00787
00788 free(conf);
00789
00790 return 0;
00791 }
00792
00793 static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags)
00794 {
00795 struct ast_conf_user *user = calloc(1, sizeof(*user));
00796 struct ast_conf_user *usr = NULL;
00797 int fd;
00798 struct zt_confinfo ztc, ztc_empty;
00799 struct ast_frame *f;
00800 struct ast_channel *c;
00801 struct ast_frame fr;
00802 int outfd;
00803 int ms;
00804 int nfds;
00805 int res;
00806 int flags;
00807 int retryzap;
00808 int origfd;
00809 int musiconhold = 0;
00810 int firstpass = 0;
00811 int lastmarked = 0;
00812 int currentmarked = 0;
00813 int ret = -1;
00814 int x;
00815 int menu_active = 0;
00816 int using_pseudo = 0;
00817 int duration=20;
00818 struct ast_dsp *dsp=NULL;
00819 struct ast_app *app;
00820 char *agifile;
00821 char *agifiledefault = "conf-background.agi";
00822 char meetmesecs[30] = "";
00823 char exitcontext[AST_MAX_CONTEXT] = "";
00824 char recordingtmp[AST_MAX_EXTENSION] = "";
00825 int dtmf;
00826 ZT_BUFFERINFO bi;
00827 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
00828 char *buf = __buf + AST_FRIENDLY_OFFSET;
00829
00830 if (!user) {
00831 ast_log(LOG_ERROR, "Out of memory\n");
00832 return ret;
00833 }
00834
00835 if (confflags & CONFFLAG_RECORDCONF && conf->recording !=MEETME_RECORD_ACTIVE) {
00836 conf->recordingfilename = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE");
00837 if (!conf->recordingfilename) {
00838 snprintf(recordingtmp, sizeof(recordingtmp), "meetme-conf-rec-%s-%s", conf->confno, chan->uniqueid);
00839 conf->recordingfilename = ast_strdupa(recordingtmp);
00840 }
00841 conf->recordingformat = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT");
00842 if (!conf->recordingformat) {
00843 snprintf(recordingtmp, sizeof(recordingtmp), "wav");
00844 conf->recordingformat = ast_strdupa(recordingtmp);
00845 }
00846 pthread_attr_init(&conf->attr);
00847 pthread_attr_setdetachstate(&conf->attr, PTHREAD_CREATE_DETACHED);
00848 ast_verbose(VERBOSE_PREFIX_4 "Starting recording of MeetMe Conference %s into file %s.%s.\n",
00849 conf->confno, conf->recordingfilename, conf->recordingformat);
00850 ast_pthread_create(&conf->recordthread, &conf->attr, recordthread, conf);
00851 }
00852
00853 time(&user->jointime);
00854
00855 if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) {
00856
00857 if (!ast_streamfile(chan, "conf-locked", chan->language))
00858 ast_waitstream(chan, "");
00859 goto outrun;
00860 }
00861
00862 if (confflags & CONFFLAG_MARKEDUSER)
00863 conf->markedusers++;
00864
00865 ast_mutex_lock(&conflock);
00866 if (!conf->firstuser) {
00867
00868 user->user_no = 1;
00869 conf->firstuser = user;
00870 conf->lastuser = user;
00871 } else {
00872
00873 user->user_no = conf->lastuser->user_no + 1;
00874 user->prevuser = conf->lastuser;
00875 if (conf->lastuser->nextuser) {
00876 ast_log(LOG_WARNING, "Error in User Management!\n");
00877 ast_mutex_unlock(&conflock);
00878 goto outrun;
00879 } else {
00880 conf->lastuser->nextuser = user;
00881 conf->lastuser = user;
00882 }
00883 }
00884
00885 user->chan = chan;
00886 user->userflags = confflags;
00887 user->adminflags = 0;
00888 user->talking = -1;
00889 conf->users++;
00890 ast_mutex_unlock(&conflock);
00891
00892 if (confflags & CONFFLAG_EXIT_CONTEXT) {
00893 if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT")))
00894 ast_copy_string(exitcontext, agifile, sizeof(exitcontext));
00895 else if (!ast_strlen_zero(chan->macrocontext))
00896 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
00897 else
00898 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
00899 }
00900
00901 if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_INTROUSER)) {
00902 snprintf(user->namerecloc, sizeof(user->namerecloc),
00903 "%s/meetme/meetme-username-%s-%d", ast_config_AST_SPOOL_DIR,
00904 conf->confno, user->user_no);
00905 res = ast_record_review(chan, "vm-rec-name", user->namerecloc, 10, "sln", &duration, NULL);
00906 if (res == -1)
00907 goto outrun;
00908 }
00909
00910 if (!(confflags & CONFFLAG_QUIET)) {
00911 if (conf->users == 1 && !(confflags & CONFFLAG_WAITMARKED))
00912 if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
00913 ast_waitstream(chan, "");
00914 if ((confflags & CONFFLAG_WAITMARKED) && conf->markedusers == 0)
00915 if (!ast_streamfile(chan, "conf-waitforleader", chan->language))
00916 ast_waitstream(chan, "");
00917 }
00918
00919 if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_ANNOUNCEUSERCOUNT) && conf->users > 1) {
00920 int keepplaying = 1;
00921
00922 if (conf->users == 2) {
00923 if (!ast_streamfile(chan,"conf-onlyone",chan->language)) {
00924 res = ast_waitstream(chan, AST_DIGIT_ANY);
00925 if (res > 0)
00926 keepplaying=0;
00927 else if (res == -1)
00928 goto outrun;
00929 }
00930 } else {
00931 if (!ast_streamfile(chan, "conf-thereare", chan->language)) {
00932 res = ast_waitstream(chan, AST_DIGIT_ANY);
00933 if (res > 0)
00934 keepplaying=0;
00935 else if (res == -1)
00936 goto outrun;
00937 }
00938 if (keepplaying) {
00939 res = ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
00940 if (res > 0)
00941 keepplaying=0;
00942 else if (res == -1)
00943 goto outrun;
00944 }
00945 if (keepplaying && !ast_streamfile(chan, "conf-otherinparty", chan->language)) {
00946 res = ast_waitstream(chan, AST_DIGIT_ANY);
00947 if (res > 0)
00948 keepplaying=0;
00949 else if (res == -1)
00950 goto outrun;
00951 }
00952 }
00953 }
00954
00955 ast_indicate(chan, -1);
00956
00957 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00958 ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
00959 goto outrun;
00960 }
00961
00962 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
00963 ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
00964 goto outrun;
00965 }
00966
00967 retryzap = strcasecmp(chan->type, "Zap");
00968 user->zapchannel = !retryzap;
00969
00970 zapretry:
00971 origfd = chan->fds[0];
00972 if (retryzap) {
00973 fd = open("/dev/zap/pseudo", O_RDWR);
00974 if (fd < 0) {
00975 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
00976 goto outrun;
00977 }
00978 using_pseudo = 1;
00979
00980 flags = fcntl(fd, F_GETFL);
00981 if (flags < 0) {
00982 ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
00983 close(fd);
00984 goto outrun;
00985 }
00986 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
00987 ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
00988 close(fd);
00989 goto outrun;
00990 }
00991
00992 memset(&bi, 0, sizeof(bi));
00993 bi.bufsize = CONF_SIZE/2;
00994 bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
00995 bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
00996 bi.numbufs = audio_buffers;
00997 if (ioctl(fd, ZT_SET_BUFINFO, &bi)) {
00998 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
00999 close(fd);
01000 goto outrun;
01001 }
01002 x = 1;
01003 if (ioctl(fd, ZT_SETLINEAR, &x)) {
01004 ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
01005 close(fd);
01006 goto outrun;
01007 }
01008 nfds = 1;
01009 } else {
01010
01011 fd = chan->fds[0];
01012 nfds = 0;
01013 }
01014 memset(&ztc, 0, sizeof(ztc));
01015 memset(&ztc_empty, 0, sizeof(ztc_empty));
01016
01017 ztc.chan = 0;
01018 if (ioctl(fd, ZT_GETCONF, &ztc)) {
01019 ast_log(LOG_WARNING, "Error getting conference\n");
01020 close(fd);
01021 goto outrun;
01022 }
01023 if (ztc.confmode) {
01024
01025 if (!retryzap) {
01026 ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
01027 retryzap = 1;
01028 goto zapretry;
01029 }
01030 }
01031 memset(&ztc, 0, sizeof(ztc));
01032
01033 ztc.chan = 0;
01034 ztc.confno = conf->zapconf;
01035
01036 ast_mutex_lock(&conflock);
01037
01038 if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_INTROUSER) && conf->users > 1) {
01039 if (conf->chan && ast_fileexists(user->namerecloc, NULL, NULL)) {
01040 if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
01041 ast_waitstream(conf->chan, "");
01042 if (!ast_streamfile(conf->chan, "conf-hasjoin", chan->language))
01043 ast_waitstream(conf->chan, "");
01044 }
01045 }
01046
01047 if (confflags & CONFFLAG_MONITOR)
01048 ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
01049 else if (confflags & CONFFLAG_TALKER)
01050 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
01051 else
01052 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
01053
01054 if (ioctl(fd, ZT_SETCONF, &ztc)) {
01055 ast_log(LOG_WARNING, "Error setting conference\n");
01056 close(fd);
01057 ast_mutex_unlock(&conflock);
01058 goto outrun;
01059 }
01060 ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf);
01061
01062 manager_event(EVENT_FLAG_CALL, "MeetmeJoin",
01063 "Channel: %s\r\n"
01064 "Uniqueid: %s\r\n"
01065 "Meetme: %s\r\n"
01066 "Usernum: %d\r\n",
01067 chan->name, chan->uniqueid, conf->confno, user->user_no);
01068
01069 if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
01070 firstpass = 1;
01071 if (!(confflags & CONFFLAG_QUIET))
01072 if (!(confflags & CONFFLAG_WAITMARKED) || ((confflags & CONFFLAG_MARKEDUSER) && (conf->markedusers >= 1)))
01073 conf_play(chan, conf, ENTER);
01074 }
01075
01076 ast_mutex_unlock(&conflock);
01077
01078 conf_flush(fd, chan);
01079
01080 if (confflags & CONFFLAG_AGI) {
01081
01082
01083
01084 agifile = pbx_builtin_getvar_helper(chan, "MEETME_AGI_BACKGROUND");
01085 if (!agifile)
01086 agifile = agifiledefault;
01087
01088 if (user->zapchannel) {
01089
01090 x = 1;
01091 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
01092 }
01093
01094 app = pbx_findapp("agi");
01095 if (app) {
01096 ret = pbx_exec(chan, app, agifile, 1);
01097 } else {
01098 ast_log(LOG_WARNING, "Could not find application (agi)\n");
01099 ret = -2;
01100 }
01101 if (user->zapchannel) {
01102
01103 x = 0;
01104 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
01105 }
01106 } else {
01107 if (user->zapchannel && (confflags & CONFFLAG_STARMENU)) {
01108
01109 x = 1;
01110 ast_channel_setoption(chan, AST_OPTION_TONE_VERIFY, &x, sizeof(char), 0);
01111 }
01112 if (confflags & CONFFLAG_MONITORTALKER && !(dsp = ast_dsp_new())) {
01113 ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
01114 res = -1;
01115 }
01116 for(;;) {
01117 int menu_was_active = 0;
01118
01119 outfd = -1;
01120 ms = -1;
01121
01122
01123
01124
01125 if (!menu_active && menu_was_active && user->listen.desired && !user->listen.actual)
01126 set_talk_volume(user, user->listen.desired);
01127
01128 menu_was_active = menu_active;
01129
01130 currentmarked = conf->markedusers;
01131 if (!(confflags & CONFFLAG_QUIET) &&
01132 (confflags & CONFFLAG_MARKEDUSER) &&
01133 (confflags & CONFFLAG_WAITMARKED) &&
01134 lastmarked == 0) {
01135 if (currentmarked == 1 && conf->users > 1) {
01136 ast_say_number(chan, conf->users - 1, AST_DIGIT_ANY, chan->language, (char *) NULL);
01137 if (conf->users - 1 == 1) {
01138 if (!ast_streamfile(chan, "conf-userwilljoin", chan->language))
01139 ast_waitstream(chan, "");
01140 } else {
01141 if (!ast_streamfile(chan, "conf-userswilljoin", chan->language))
01142 ast_waitstream(chan, "");
01143 }
01144 }
01145 if (conf->users == 1 && ! (confflags & CONFFLAG_MARKEDUSER))
01146 if (!ast_streamfile(chan, "conf-onlyperson", chan->language))
01147 ast_waitstream(chan, "");
01148 }
01149
01150 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
01151
01152
01153 user->userflags = confflags;
01154
01155 if (confflags & CONFFLAG_WAITMARKED) {
01156 if(currentmarked == 0) {
01157 if (lastmarked != 0) {
01158 if (!(confflags & CONFFLAG_QUIET))
01159 if (!ast_streamfile(chan, "conf-leaderhasleft", chan->language))
01160 ast_waitstream(chan, "");
01161 if(confflags & CONFFLAG_MARKEDEXIT)
01162 break;
01163 else {
01164 ztc.confmode = ZT_CONF_CONF;
01165 if (ioctl(fd, ZT_SETCONF, &ztc)) {
01166 ast_log(LOG_WARNING, "Error setting conference\n");
01167 close(fd);
01168 goto outrun;
01169 }
01170 }
01171 }
01172 if (musiconhold == 0 && (confflags & CONFFLAG_MOH)) {
01173 ast_moh_start(chan, NULL);
01174 musiconhold = 1;
01175 } else {
01176 ztc.confmode = ZT_CONF_CONF;
01177 if (ioctl(fd, ZT_SETCONF, &ztc)) {
01178 ast_log(LOG_WARNING, "Error setting conference\n");
01179 close(fd);
01180 goto outrun;
01181 }
01182 }
01183 } else if(currentmarked >= 1 && lastmarked == 0) {
01184 if (confflags & CONFFLAG_MONITOR)
01185 ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
01186 else if (confflags & CONFFLAG_TALKER)
01187 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
01188 else
01189 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
01190 if (ioctl(fd, ZT_SETCONF, &ztc)) {
01191 ast_log(LOG_WARNING, "Error setting conference\n");
01192 close(fd);
01193 goto outrun;
01194 }
01195 if (musiconhold && (confflags & CONFFLAG_MOH)) {
01196 ast_moh_stop(chan);
01197 musiconhold = 0;
01198 }
01199 if ( !(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MARKEDUSER)) {
01200 if (!ast_streamfile(chan, "conf-placeintoconf", chan->language))
01201 ast_waitstream(chan, "");
01202 conf_play(chan, conf, ENTER);
01203 }
01204 }
01205 }
01206
01207
01208 if ((confflags & CONFFLAG_MOH) && !(confflags & CONFFLAG_WAITMARKED)) {
01209 if (conf->users == 1) {
01210 if (musiconhold == 0) {
01211 ast_moh_start(chan, NULL);
01212 musiconhold = 1;
01213 }
01214 } else {
01215 if (musiconhold) {
01216 ast_moh_stop(chan);
01217 musiconhold = 0;
01218 }
01219 }
01220 }
01221
01222
01223 if (currentmarked == 0 && lastmarked != 0 && (confflags & CONFFLAG_MARKEDEXIT)) {
01224 ret = -1;
01225 break;
01226 }
01227
01228
01229 if (user->adminflags) {
01230
01231 if ((user->adminflags & ADMINFLAG_MUTED) && (ztc.confmode & ZT_CONF_TALKER)) {
01232 ztc.confmode ^= ZT_CONF_TALKER;
01233 if (ioctl(fd, ZT_SETCONF, &ztc)) {
01234 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
01235 ret = -1;
01236 break;
01237 }
01238 }
01239 if (!(user->adminflags & ADMINFLAG_MUTED) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
01240 ztc.confmode |= ZT_CONF_TALKER;
01241 if (ioctl(fd, ZT_SETCONF, &ztc)) {
01242 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
01243 ret = -1;
01244 break;
01245 }
01246 }
01247 if (user->adminflags & ADMINFLAG_KICKME) {
01248
01249 if (!ast_streamfile(chan, "conf-kicked", chan->language))
01250 ast_waitstream(chan, "");
01251 ret = 0;
01252 break;
01253 }
01254 } else if (!(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
01255 ztc.confmode |= ZT_CONF_TALKER;
01256 if (ioctl(fd, ZT_SETCONF, &ztc)) {
01257 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
01258 ret = -1;
01259 break;
01260 }
01261 }
01262
01263 if (c) {
01264 if (c->fds[0] != origfd) {
01265 if (using_pseudo) {
01266
01267 close(fd);
01268 using_pseudo = 0;
01269 }
01270 ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
01271 retryzap = strcasecmp(c->type, "Zap");
01272 user->zapchannel = !retryzap;
01273 goto zapretry;
01274 }
01275 f = ast_read(c);
01276 if (!f)
01277 break;
01278 if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
01279 if (user->talk.actual)
01280 ast_frame_adjust_volume(f, user->talk.actual);
01281
01282 if (confflags & CONFFLAG_MONITORTALKER) {
01283 int totalsilence;
01284
01285 if (user->talking == -1)
01286 user->talking = 0;
01287
01288 res = ast_dsp_silence(dsp, f, &totalsilence);
01289 if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) {
01290 user->talking = 1;
01291 manager_event(EVENT_FLAG_CALL, "MeetmeTalking",
01292 "Channel: %s\r\n"
01293 "Uniqueid: %s\r\n"
01294 "Meetme: %s\r\n"
01295 "Usernum: %d\r\n",
01296 chan->name, chan->uniqueid, conf->confno, user->user_no);
01297 }
01298 if (user->talking && totalsilence > MEETME_DELAYDETECTENDTALK) {
01299 user->talking = 0;
01300 manager_event(EVENT_FLAG_CALL, "MeetmeStopTalking",
01301 "Channel: %s\r\n"
01302 "Uniqueid: %s\r\n"
01303 "Meetme: %s\r\n"
01304 "Usernum: %d\r\n",
01305 chan->name, chan->uniqueid, conf->confno, user->user_no);
01306 }
01307 }
01308 if (using_pseudo) {
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321 careful_write(fd, f->data, f->datalen, 0);
01322 }
01323 } else if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) {
01324 char tmp[2];
01325
01326 tmp[0] = f->subclass;
01327 tmp[1] = '\0';
01328 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
01329 ret = 0;
01330 ast_frfree(f);
01331 break;
01332 } else if (option_debug > 1)
01333 ast_log(LOG_DEBUG, "Exit by single digit did not work in meetme. Extension %s does not exist in context %s\n", tmp, exitcontext);
01334 } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
01335 ret = 0;
01336 ast_frfree(f);
01337 break;
01338 } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
01339 if (ioctl(fd, ZT_SETCONF, &ztc_empty)) {
01340 ast_log(LOG_WARNING, "Error setting conference\n");
01341 close(fd);
01342 ast_frfree(f);
01343 goto outrun;
01344 }
01345
01346
01347
01348
01349 if (!menu_active && user->talk.desired && !user->talk.actual)
01350 set_talk_volume(user, 0);
01351
01352 if (musiconhold) {
01353 ast_moh_stop(chan);
01354 }
01355 if ((confflags & CONFFLAG_ADMIN)) {
01356
01357 if (!menu_active) {
01358 menu_active = 1;
01359
01360 if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) {
01361 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
01362 ast_stopstream(chan);
01363 } else
01364 dtmf = 0;
01365 } else
01366 dtmf = f->subclass;
01367 if (dtmf) {
01368 switch(dtmf) {
01369 case '1':
01370 menu_active = 0;
01371 if (ztc.confmode & ZT_CONF_TALKER) {
01372 ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
01373 confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER;
01374 } else {
01375 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
01376 confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER;
01377 }
01378 if (ioctl(fd, ZT_SETCONF, &ztc)) {
01379 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
01380 ret = -1;
01381 break;
01382 }
01383 if (ztc.confmode & ZT_CONF_TALKER) {
01384 if (!ast_streamfile(chan, "conf-unmuted", chan->language))
01385 ast_waitstream(chan, "");
01386 } else {
01387 if (!ast_streamfile(chan, "conf-muted", chan->language))
01388 ast_waitstream(chan, "");
01389 }
01390 break;
01391 case '2':
01392 menu_active = 0;
01393 if (conf->locked) {
01394 conf->locked = 0;
01395 if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
01396 ast_waitstream(chan, "");
01397 } else {
01398 conf->locked = 1;
01399 if (!ast_streamfile(chan, "conf-lockednow", chan->language))
01400 ast_waitstream(chan, "");
01401 }
01402 break;
01403 case '3':
01404 menu_active = 0;
01405 usr = conf->lastuser;
01406 if ((usr->chan->name == chan->name)||(usr->userflags & CONFFLAG_ADMIN)) {
01407 if(!ast_streamfile(chan, "conf-errormenu", chan->language))
01408 ast_waitstream(chan, "");
01409 } else
01410 usr->adminflags |= ADMINFLAG_KICKME;
01411 ast_stopstream(chan);
01412 break;
01413 case '4':
01414 tweak_listen_volume(user, VOL_DOWN);
01415 break;
01416 case '6':
01417 tweak_listen_volume(user, VOL_UP);
01418 break;
01419 case '7':
01420 tweak_talk_volume(user, VOL_DOWN);
01421 break;
01422 case '8':
01423 menu_active = 0;
01424 break;
01425 case '9':
01426 tweak_talk_volume(user, VOL_UP);
01427 break;
01428 default:
01429 menu_active = 0;
01430
01431 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
01432 ast_waitstream(chan, "");
01433 break;
01434 }
01435 }
01436 } else {
01437
01438 if (!menu_active) {
01439 menu_active = 1;
01440 if (!ast_streamfile(chan, "conf-usermenu", chan->language)) {
01441 dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
01442 ast_stopstream(chan);
01443 } else
01444 dtmf = 0;
01445 } else
01446 dtmf = f->subclass;
01447 if (dtmf) {
01448 switch(dtmf) {
01449 case '1':
01450 menu_active = 0;
01451 if (ztc.confmode & ZT_CONF_TALKER) {
01452 ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
01453 confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER;
01454 } else if (!(user->adminflags & ADMINFLAG_MUTED)) {
01455 ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
01456 confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER;
01457 }
01458 if (ioctl(fd, ZT_SETCONF, &ztc)) {
01459 ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
01460 ret = -1;
01461 break;
01462 }
01463 if (ztc.confmode & ZT_CONF_TALKER) {
01464 if (!ast_streamfile(chan, "conf-unmuted", chan->language))
01465 ast_waitstream(chan, "");
01466 } else {
01467 if (!ast_streamfile(chan, "conf-muted", chan->language))
01468 ast_waitstream(chan, "");
01469 }
01470 break;
01471 case '4':
01472 tweak_listen_volume(user, VOL_DOWN);
01473 break;
01474 case '6':
01475 tweak_listen_volume(user, VOL_UP);
01476 break;
01477 case '7':
01478 tweak_talk_volume(user, VOL_DOWN);
01479 break;
01480 case '8':
01481 menu_active = 0;
01482 break;
01483 case '9':
01484 tweak_talk_volume(user, VOL_UP);
01485 break;
01486 default:
01487 menu_active = 0;
01488 if (!ast_streamfile(chan, "conf-errormenu", chan->language))
01489 ast_waitstream(chan, "");
01490 break;
01491 }
01492 }
01493 }
01494 if (musiconhold)
01495 ast_moh_start(chan, NULL);
01496
01497 if (ioctl(fd, ZT_SETCONF, &ztc)) {
01498 ast_log(LOG_WARNING, "Error setting conference\n");
01499 close(fd);
01500 ast_frfree(f);
01501 goto outrun;
01502 }
01503
01504 conf_flush(fd, chan);
01505 } else if (option_debug) {
01506 ast_log(LOG_DEBUG,
01507 "Got unrecognized frame on channel %s, f->frametype=%d,f->subclass=%d\n",
01508 chan->name, f->frametype, f->subclass);
01509 }
01510 ast_frfree(f);
01511 } else if (outfd > -1) {
01512 res = read(outfd, buf, CONF_SIZE);
01513 if (res > 0) {
01514 memset(&fr, 0, sizeof(fr));
01515 fr.frametype = AST_FRAME_VOICE;
01516 fr.subclass = AST_FORMAT_SLINEAR;
01517 fr.datalen = res;
01518 fr.samples = res/2;
01519 fr.data = buf;
01520 fr.offset = AST_FRIENDLY_OFFSET;
01521 if (user->listen.actual)
01522 ast_frame_adjust_volume(&fr, user->listen.actual);
01523 if (ast_write(chan, &fr) < 0) {
01524 ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
01525 }
01526 } else
01527 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
01528 }
01529 lastmarked = currentmarked;
01530 }
01531 }
01532
01533 if (musiconhold)
01534 ast_moh_stop(chan);
01535
01536 if (using_pseudo)
01537 close(fd);
01538 else {
01539
01540 ztc.chan = 0;
01541 ztc.confno = 0;
01542 ztc.confmode = 0;
01543 if (ioctl(fd, ZT_SETCONF, &ztc)) {
01544 ast_log(LOG_WARNING, "Error setting conference\n");
01545 }
01546 }
01547
01548 reset_volumes(user);
01549
01550 ast_mutex_lock(&conflock);
01551 if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
01552 conf_play(chan, conf, LEAVE);
01553
01554 if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_INTROUSER)) {
01555 if (ast_fileexists(user->namerecloc, NULL, NULL)) {
01556 if ((conf->chan) && (conf->users > 1)) {
01557 if (!ast_streamfile(conf->chan, user->namerecloc, chan->language))
01558 ast_waitstream(conf->chan, "");
01559 if (!ast_streamfile(conf->chan, "conf-hasleft", chan->language))
01560 ast_waitstream(conf->chan, "");
01561 }
01562 ast_filedelete(user->namerecloc, NULL);
01563 }
01564 }
01565 ast_mutex_unlock(&conflock);
01566
01567 outrun:
01568 ast_mutex_lock(&conflock);
01569
01570 if (confflags & CONFFLAG_MONITORTALKER && dsp)
01571 ast_dsp_free(dsp);
01572
01573 if (user->user_no) {
01574 manager_event(EVENT_FLAG_CALL, "MeetmeLeave",
01575 "Channel: %s\r\n"
01576 "Uniqueid: %s\r\n"
01577 "Meetme: %s\r\n"
01578 "Usernum: %d\r\n",
01579 chan->name, chan->uniqueid, conf->confno, user->user_no);
01580 conf->users--;
01581 if (confflags & CONFFLAG_MARKEDUSER)
01582 conf->markedusers--;
01583 if (!conf->users) {
01584
01585 conf_free(conf);
01586 } else {
01587
01588 if (user == conf->firstuser) {
01589 if (user->nextuser) {
01590
01591 user->nextuser->prevuser = NULL;
01592 } else {
01593
01594 conf->lastuser = NULL;
01595 }
01596
01597 conf->firstuser = user->nextuser;
01598 } else if (user == conf->lastuser){
01599 if (user->prevuser)
01600 user->prevuser->nextuser = NULL;
01601 else
01602 ast_log(LOG_ERROR, "Bad bad bad! We're the last, not the first, but nobody before us??\n");
01603 conf->lastuser = user->prevuser;
01604 } else {
01605 if (user->nextuser)
01606 user->nextuser->prevuser = user->prevuser;
01607 else
01608 ast_log(LOG_ERROR, "Bad! Bad! Bad! user->nextuser is NULL but we're not the end!\n");
01609 if (user->prevuser)
01610 user->prevuser->nextuser = user->nextuser;
01611 else
01612 ast_log(LOG_ERROR, "Bad! Bad! Bad! user->prevuser is NULL but we're not the beginning!\n");
01613 }
01614 }
01615
01616 snprintf(meetmesecs, sizeof(meetmesecs), "%d", (int) (time(NULL) - user->jointime));
01617 pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
01618 }
01619 free(user);
01620 ast_mutex_unlock(&conflock);
01621
01622 return ret;
01623 }
01624
01625 static struct ast_conference *find_conf(struct ast_channel *chan, char *confno, int make, int dynamic, char *dynamic_pin,
01626 struct ast_flags *confflags)
01627 {
01628 struct ast_config *cfg;
01629 struct ast_variable *var;
01630 struct ast_conference *cnf;
01631
01632
01633 ast_mutex_lock(&conflock);
01634 for (cnf = confs; cnf; cnf = cnf->next) {
01635 if (!strcmp(confno, cnf->confno))
01636 break;
01637 }
01638 ast_mutex_unlock(&conflock);
01639
01640 if (!cnf) {
01641 if (dynamic) {
01642
01643 ast_log(LOG_DEBUG, "Building dynamic conference '%s'\n", confno);
01644 if (dynamic_pin) {
01645 if (dynamic_pin[0] == 'q') {
01646
01647 if (ast_app_getdata(chan, "conf-getpin", dynamic_pin, AST_MAX_EXTENSION - 1, 0) < 0)
01648 return NULL;
01649 }
01650 cnf = build_conf(confno, dynamic_pin, "", make, dynamic);
01651 } else {
01652 cnf = build_conf(confno, "", "", make, dynamic);
01653 }
01654 } else {
01655
01656 cfg = ast_config_load(CONFIG_FILE_NAME);
01657 if (!cfg) {
01658 ast_log(LOG_WARNING, "No %s file :(\n", CONFIG_FILE_NAME);
01659 return NULL;
01660 }
01661 var = ast_variable_browse(cfg, "rooms");
01662 while (var) {
01663 if (!strcasecmp(var->name, "conf")) {
01664
01665 char *pin, *pinadmin, *conf;
01666
01667 if ((pinadmin = ast_strdupa(var->value))) {
01668 conf = strsep(&pinadmin, "|,");
01669 pin = strsep(&pinadmin, "|,");
01670 if (!strcasecmp(conf, confno)) {
01671
01672 if (pin)
01673 if (pinadmin)
01674 cnf = build_conf(confno, pin, pinadmin, make, dynamic);
01675 else
01676 cnf = build_conf(confno, pin, "", make, dynamic);
01677 else
01678 if (pinadmin)
01679 cnf = build_conf(confno, "", pinadmin, make, dynamic);
01680 else
01681 cnf = build_conf(confno, "", "", make, dynamic);
01682 break;
01683 }
01684 }
01685 }
01686 var = var->next;
01687 }
01688 if (!var) {
01689 ast_log(LOG_DEBUG, "%s isn't a valid conference\n", confno);
01690 }
01691 ast_config_destroy(cfg);
01692 }
01693 } else if (dynamic_pin) {
01694
01695
01696
01697 if (dynamic_pin[0] == 'q')
01698 dynamic_pin[0] = '\0';
01699 }
01700
01701 if (cnf) {
01702 if (confflags && !cnf->chan &&
01703 !ast_test_flag(confflags, CONFFLAG_QUIET) &&
01704 ast_test_flag(confflags, CONFFLAG_INTROUSER)) {
01705 ast_log(LOG_WARNING, "No Zap channel available for conference, user introduction disabled (is chan_zap loaded?)\n");
01706 ast_clear_flag(confflags, CONFFLAG_INTROUSER);
01707 }
01708
01709 if (confflags && !cnf->chan &&
01710 ast_test_flag(confflags, CONFFLAG_RECORDCONF)) {
01711 ast_log(LOG_WARNING, "No Zap channel available for conference, conference recording disabled (is chan_zap loaded?)\n");
01712 ast_clear_flag(confflags, CONFFLAG_RECORDCONF);
01713 }
01714 }
01715
01716 return cnf;
01717 }
01718
01719
01720 static int count_exec(struct ast_channel *chan, void *data)
01721 {
01722 struct localuser *u;
01723 int res = 0;
01724 struct ast_conference *conf;
01725 int count;
01726 char *confnum, *localdata;
01727 char val[80] = "0";
01728
01729 if (ast_strlen_zero(data)) {
01730 ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
01731 return -1;
01732 }
01733
01734 LOCAL_USER_ADD(u);
01735
01736 localdata = ast_strdupa(data);
01737 if (!localdata) {
01738 ast_log(LOG_ERROR, "Out of memory!\n");
01739 LOCAL_USER_REMOVE(u);
01740 return -1;
01741 }
01742
01743 confnum = strsep(&localdata,"|");
01744 conf = find_conf(chan, confnum, 0, 0, NULL, NULL);
01745 if (conf)
01746 count = conf->users;
01747 else
01748 count = 0;
01749
01750 if (!ast_strlen_zero(localdata)){
01751
01752 snprintf(val, sizeof(val), "%d",count);
01753 pbx_builtin_setvar_helper(chan, localdata, val);
01754 } else {
01755 if (chan->_state != AST_STATE_UP)
01756 ast_answer(chan);
01757 res = ast_say_number(chan, count, "", chan->language, (char *) NULL);
01758 }
01759 LOCAL_USER_REMOVE(u);
01760
01761 return res;
01762 }
01763
01764
01765 static int conf_exec(struct ast_channel *chan, void *data)
01766 {
01767 int res=-1;
01768 struct localuser *u;
01769 char confno[AST_MAX_EXTENSION] = "";
01770 int allowretry = 0;
01771 int retrycnt = 0;
01772 struct ast_conference *cnf;
01773 struct ast_flags confflags = {0};
01774 int dynamic = 0;
01775 int empty = 0, empty_no_pin = 0;
01776 int always_prompt = 0;
01777 char *notdata, *info, *inflags = NULL, *inpin = NULL, the_pin[AST_MAX_EXTENSION] = "";
01778
01779 LOCAL_USER_ADD(u);
01780
01781 if (ast_strlen_zero(data)) {
01782 allowretry = 1;
01783 notdata = "";
01784 } else {
01785 notdata = data;
01786 }
01787
01788 if (chan->_state != AST_STATE_UP)
01789 ast_answer(chan);
01790
01791 info = ast_strdupa(notdata);
01792
01793 if (info) {
01794 char *tmp = strsep(&info, "|");
01795 ast_copy_string(confno, tmp, sizeof(confno));
01796 if (ast_strlen_zero(confno)) {
01797 allowretry = 1;
01798 }
01799 }
01800 if (info)
01801 inflags = strsep(&info, "|");
01802 if (info)
01803 inpin = strsep(&info, "|");
01804 if (inpin)
01805 ast_copy_string(the_pin, inpin, sizeof(the_pin));
01806
01807 if (inflags) {
01808 ast_app_parse_options(meetme_opts, &confflags, NULL, inflags);
01809 dynamic = ast_test_flag(&confflags, CONFFLAG_DYNAMIC | CONFFLAG_DYNAMICPIN);
01810 if (ast_test_flag(&confflags, CONFFLAG_DYNAMICPIN) && !inpin)
01811 strcpy(the_pin, "q");
01812
01813 empty = ast_test_flag(&confflags, CONFFLAG_EMPTY | CONFFLAG_EMPTYNOPIN);
01814 empty_no_pin = ast_test_flag(&confflags, CONFFLAG_EMPTYNOPIN);
01815 always_prompt = ast_test_flag(&confflags, CONFFLAG_ALWAYSPROMPT);
01816 }
01817
01818 do {
01819 if (retrycnt > 3)
01820 allowretry = 0;
01821 if (empty) {
01822 int i, map[1024] = { 0, };
01823 struct ast_config *cfg;
01824 struct ast_variable *var;
01825 int confno_int;
01826
01827 ast_mutex_lock(&conflock);
01828 for (cnf = confs; cnf; cnf = cnf->next) {
01829 if (sscanf(cnf->confno, "%d", &confno_int) == 1) {
01830
01831 if (confno_int >= 0 && confno_int < 1024)
01832 map[confno_int]++;
01833 }
01834 }
01835 ast_mutex_unlock(&conflock);
01836
01837
01838 if ((empty_no_pin) || (!dynamic)) {
01839 cfg = ast_config_load(CONFIG_FILE_NAME);
01840 if (cfg) {
01841 var = ast_variable_browse(cfg, "rooms");
01842 while (var) {
01843 if (!strcasecmp(var->name, "conf")) {
01844 char *stringp = ast_strdupa(var->value);
01845 if (stringp) {
01846 char *confno_tmp = strsep(&stringp, "|,");
01847 int found = 0;
01848 if (sscanf(confno_tmp, "%d", &confno_int) == 1) {
01849 if ((confno_int >= 0) && (confno_int < 1024)) {
01850 if (stringp && empty_no_pin) {
01851 map[confno_int]++;
01852 }
01853 }
01854 }
01855 if (!dynamic) {
01856
01857 ast_mutex_lock(&conflock);
01858 cnf = confs;
01859 while (cnf) {
01860 if (!strcmp(confno_tmp, cnf->confno)) {
01861
01862 found = 1;
01863 break;
01864 }
01865 cnf = cnf->next;
01866 }
01867 ast_mutex_unlock(&conflock);
01868 if (!found) {
01869
01870 if ((empty_no_pin && ((!stringp) || (stringp && (stringp[0] == '\0')))) || (!empty_no_pin)) {
01871
01872
01873
01874
01875 ast_copy_string(confno, confno_tmp, sizeof(confno));
01876 break;
01877
01878 }
01879 }
01880 }
01881 } else {
01882 ast_log(LOG_ERROR, "Out of memory\n");
01883 }
01884 }
01885 var = var->next;
01886 }
01887 ast_config_destroy(cfg);
01888 }
01889 }
01890
01891
01892 if (ast_strlen_zero(confno) && dynamic) {
01893 for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
01894 if (!map[i]) {
01895 snprintf(confno, sizeof(confno), "%d", i);
01896 break;
01897 }
01898 }
01899 }
01900
01901
01902 if (ast_strlen_zero(confno)) {
01903 res = ast_streamfile(chan, "conf-noempty", chan->language);
01904 if (!res)
01905 ast_waitstream(chan, "");
01906 } else {
01907 if (sscanf(confno, "%d", &confno_int) == 1) {
01908 res = ast_streamfile(chan, "conf-enteringno", chan->language);
01909 if (!res) {
01910 ast_waitstream(chan, "");
01911 res = ast_say_digits(chan, confno_int, "", chan->language);
01912 }
01913 } else {
01914 ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
01915 }
01916 }
01917 }
01918
01919 while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
01920
01921 res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
01922 if (res < 0) {
01923
01924 confno[0] = '\0';
01925 allowretry = 0;
01926 break;
01927 }
01928 }
01929 if (!ast_strlen_zero(confno)) {
01930
01931 cnf = find_conf(chan, confno, 1, dynamic, the_pin, &confflags);
01932 if (!cnf) {
01933 res = ast_streamfile(chan, "conf-invalid", chan->language);
01934 if (!res)
01935 ast_waitstream(chan, "");
01936 res = -1;
01937 if (allowretry)
01938 confno[0] = '\0';
01939 } else {
01940 if ((!ast_strlen_zero(cnf->pin) &&
01941 !ast_test_flag(&confflags, CONFFLAG_ADMIN)) ||
01942 (!ast_strlen_zero(cnf->pinadmin) &&
01943 ast_test_flag(&confflags, CONFFLAG_ADMIN))) {
01944 char pin[AST_MAX_EXTENSION]="";
01945 int j;
01946
01947
01948 for (j = 0; j < 3; j++) {
01949 if (*the_pin && (always_prompt == 0)) {
01950 ast_copy_string(pin, the_pin, sizeof(pin));
01951 res = 0;
01952 } else {
01953
01954 res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
01955 }
01956 if (res >= 0) {
01957 if (!strcasecmp(pin, cnf->pin) ||
01958 (!ast_strlen_zero(cnf->pinadmin) &&
01959 !strcasecmp(pin, cnf->pinadmin))) {
01960
01961 allowretry = 0;
01962 if (!ast_strlen_zero(cnf->pinadmin) && !strcasecmp(pin, cnf->pinadmin))
01963 ast_set_flag(&confflags, CONFFLAG_ADMIN);
01964
01965 res = conf_run(chan, cnf, confflags.flags);
01966 break;
01967 } else {
01968
01969 if (!ast_streamfile(chan, "conf-invalidpin", chan->language))
01970 res = ast_waitstream(chan, AST_DIGIT_ANY);
01971 else {
01972 ast_log(LOG_WARNING, "Couldn't play invalid pin msg!\n");
01973 break;
01974 }
01975 if (res < 0)
01976 break;
01977 pin[0] = res;
01978 pin[1] = '\0';
01979 res = -1;
01980 if (allowretry)
01981 confno[0] = '\0';
01982 }
01983 } else {
01984
01985 res = -1;
01986 allowretry = 0;
01987
01988 ast_mutex_lock(&conflock);
01989 if (!cnf->users) {
01990 conf_free(cnf);
01991 }
01992 ast_mutex_unlock(&conflock);
01993 break;
01994 }
01995
01996
01997 if (*the_pin && (always_prompt==0)) {
01998 break;
01999 }
02000 }
02001 } else {
02002
02003 allowretry = 0;
02004
02005
02006 res = conf_run(chan, cnf, confflags.flags);
02007 }
02008 }
02009 }
02010 } while (allowretry);
02011
02012 LOCAL_USER_REMOVE(u);
02013
02014 return res;
02015 }
02016
02017 static struct ast_conf_user* find_user(struct ast_conference *conf, char *callerident)
02018 {
02019 struct ast_conf_user *user = NULL;
02020 int cid;
02021
02022 if (!conf || !callerident) {
02023 return NULL;
02024 }
02025
02026 sscanf(callerident, "%i", &cid);
02027
02028 user = conf->firstuser;
02029 while (user) {
02030 if (user->user_no == cid)
02031 break;
02032 user = user->nextuser;
02033 }
02034
02035 return user;
02036 }
02037
02038
02039
02040 static int admin_exec(struct ast_channel *chan, void *data) {
02041 char *params, *command = NULL, *caller = NULL, *conf = NULL;
02042 struct ast_conference *cnf;
02043 struct ast_conf_user *user = NULL;
02044 struct localuser *u;
02045
02046 LOCAL_USER_ADD(u);
02047
02048 ast_mutex_lock(&conflock);
02049
02050 if (!ast_strlen_zero(data)) {
02051 params = ast_strdupa((char *) data);
02052 conf = strsep(¶ms, "|");
02053 command = strsep(¶ms, "|");
02054 caller = strsep(¶ms, "|");
02055
02056 if (!command) {
02057 ast_log(LOG_WARNING, "MeetmeAdmin requires a command!\n");
02058 ast_mutex_unlock(&conflock);
02059 LOCAL_USER_REMOVE(u);
02060 return -1;
02061 }
02062 for (cnf = confs; cnf; cnf = cnf->next) {
02063 if (!strcmp(cnf->confno, conf))
02064 break;
02065 }
02066
02067 if (caller)
02068 user = find_user(cnf, caller);
02069
02070 if (cnf) {
02071 switch((int) (*command)) {
02072 case 76:
02073 cnf->locked = 1;
02074 break;
02075 case 108:
02076 cnf->locked = 0;
02077 break;
02078 case 75:
02079 user = cnf->firstuser;
02080 while(user) {
02081 user->adminflags |= ADMINFLAG_KICKME;
02082 if (user->nextuser) {
02083 user = user->nextuser;
02084 } else {
02085 break;
02086 }
02087 }
02088 break;
02089 case 101:
02090 user = cnf->lastuser;
02091 if (!(user->userflags & CONFFLAG_ADMIN)) {
02092 user->adminflags |= ADMINFLAG_KICKME;
02093 break;
02094 } else
02095 ast_log(LOG_NOTICE, "Not kicking last user, is an Admin!\n");
02096 break;
02097 case 77:
02098 if (user) {
02099 user->adminflags |= ADMINFLAG_MUTED;
02100 } else {
02101 ast_log(LOG_NOTICE, "Specified User not found!\n");
02102 }
02103 break;
02104 case 78:
02105 user = cnf->firstuser;
02106 while(user) {
02107 if (user && !(user->userflags & CONFFLAG_ADMIN))
02108 user->adminflags |= ADMINFLAG_MUTED;
02109 if (user->nextuser) {
02110 user = user->nextuser;
02111 } else {
02112 break;
02113 }
02114 }
02115 break;
02116 case 109:
02117 if (user && (user->adminflags & ADMINFLAG_MUTED)) {
02118 user->adminflags ^= ADMINFLAG_MUTED;
02119 } else {
02120 ast_log(LOG_NOTICE, "Specified User not found or he muted himself!\n");
02121 }
02122 break;
02123 case 110:
02124 user = cnf->firstuser;
02125 while(user) {
02126 if (user && (user-> adminflags & ADMINFLAG_MUTED)) {
02127 user->adminflags ^= ADMINFLAG_MUTED;
02128 }
02129 if (user->nextuser) {
02130 user = user->nextuser;
02131 } else {
02132 break;
02133 }
02134 }
02135 break;
02136 case 107:
02137 if (user) {
02138 user->adminflags |= ADMINFLAG_KICKME;
02139 } else {
02140 ast_log(LOG_NOTICE, "Specified User not found!\n");
02141 }
02142 break;
02143 }
02144 } else {
02145 ast_log(LOG_NOTICE, "Conference Number not found\n");
02146 }
02147 }
02148 ast_mutex_unlock(&conflock);
02149
02150 LOCAL_USER_REMOVE(u);
02151
02152 return 0;
02153 }
02154
02155 static void *recordthread(void *args)
02156 {
02157 struct ast_conference *cnf = args;
02158 struct ast_frame *f=NULL;
02159 int flags;
02160 struct ast_filestream *s;
02161 int res=0;
02162
02163 if (!cnf || !cnf->chan) {
02164 pthread_exit(0);
02165 }
02166 ast_stopstream(cnf->chan);
02167 flags = O_CREAT|O_TRUNC|O_WRONLY;
02168 s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, 0644);
02169
02170 if (s) {
02171 cnf->recording = MEETME_RECORD_ACTIVE;
02172 while (ast_waitfor(cnf->chan, -1) > -1) {
02173 f = ast_read(cnf->chan);
02174 if (!f) {
02175 res = -1;
02176 break;
02177 }
02178 if (f->frametype == AST_FRAME_VOICE) {
02179 res = ast_writestream(s, f);
02180 if (res) {
02181 ast_frfree(f);
02182 break;
02183 }
02184 }
02185 ast_frfree(f);
02186 if (cnf->recording == MEETME_RECORD_TERMINATE) {
02187 ast_mutex_lock(&conflock);
02188 ast_mutex_unlock(&conflock);
02189 break;
02190 }
02191 }
02192 cnf->recording = MEETME_RECORD_OFF;
02193 ast_closestream(s);
02194 }
02195 pthread_exit(0);
02196 }
02197
02198 static void load_config(void)
02199 {
02200 struct ast_config *cfg;
02201 char *val;
02202
02203 audio_buffers = DEFAULT_AUDIO_BUFFERS;
02204
02205 if (!(cfg = ast_config_load(CONFIG_FILE_NAME)))
02206 return;
02207
02208 if ((val = ast_variable_retrieve(cfg, "general", "audiobuffers"))) {
02209 if ((sscanf(val, "%d", &audio_buffers) != 1)) {
02210 ast_log(LOG_WARNING, "audiobuffers setting must be a number, not '%s'\n", val);
02211 audio_buffers = DEFAULT_AUDIO_BUFFERS;
02212 } else if ((audio_buffers < ZT_DEFAULT_NUM_BUFS) || (audio_buffers > ZT_MAX_NUM_BUFS)) {
02213 ast_log(LOG_WARNING, "audiobuffers setting must be between %d and %d\n",
02214 ZT_DEFAULT_NUM_BUFS, ZT_MAX_NUM_BUFS);
02215 audio_buffers = DEFAULT_AUDIO_BUFFERS;
02216 }
02217 if (audio_buffers != DEFAULT_AUDIO_BUFFERS)
02218 ast_log(LOG_NOTICE, "Audio buffers per channel set to %d\n", audio_buffers);
02219 }
02220
02221 ast_config_destroy(cfg);
02222 }
02223
02224 int unload_module(void)
02225 {
02226 int res;
02227
02228 res = ast_cli_unregister(&cli_show_confs);
02229 res |= ast_cli_unregister(&cli_conf);
02230 res |= ast_unregister_application(app3);
02231 res |= ast_unregister_application(app2);
02232 res |= ast_unregister_application(app);
02233
02234 STANDARD_HANGUP_LOCALUSERS;
02235
02236 return res;
02237 }
02238
02239 int load_module(void)
02240 {
02241 int res;
02242
02243 load_config();
02244
02245 res = ast_cli_register(&cli_show_confs);
02246 res |= ast_cli_register(&cli_conf);
02247 res |= ast_register_application(app3, admin_exec, synopsis3, descrip3);
02248 res |= ast_register_application(app2, count_exec, synopsis2, descrip2);
02249 res |= ast_register_application(app, conf_exec, synopsis, descrip);
02250
02251 return res;
02252 }
02253
02254 int reload(void)
02255 {
02256 load_config();
02257
02258 return 0;
02259 }
02260
02261 char *description(void)
02262 {
02263 return (char *) tdesc;
02264 }
02265
02266 int usecount(void)
02267 {
02268 int res;
02269
02270 STANDARD_USECOUNT(res);
02271
02272 return res;
02273 }
02274
02275 char *key()
02276 {
02277 return ASTERISK_GPL_KEY;
02278 }
02279