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