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