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