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