示例#1
0
static int checkMax(struct ast_channel *chan, struct roomdetails *dtmfmatch)
{
	int res=0;
    	struct ast_app *app;
	char getvar[30]="AstVar";
	char roomno[30]="";
	char maxusers[30]="";
	char currentusers[30]="";
	char prompt[50]="";
	char arg[255]="";

    	strcpy(maxusers,dtmfmatch->maxusers);
	strcpy(roomno,dtmfmatch->roomno);
    	strcat(arg,roomno);
    	strcat(arg,",");
	strcat(arg,getvar);

	if(!(app = pbx_findapp(ConfAppCount))) {
		ast_log(LOG_WARNING, "Invalid participant count application: %s\n", ConfAppCount);
		return -1;
	}
 	res = pbx_exec(chan, app, arg);
   	strcpy(currentusers, pbx_builtin_getvar_helper(chan, getvar));
	if(atoi(currentusers) < atoi(maxusers)){
	ast_log(LOG_NOTICE, "Currentusers: %i\n", atoi(currentusers));
		if(atoi(currentusers)>0){
			strcpy(prompt,"conf-thereare");
			if (!ast_streamfile(chan, "conf-thereare", chan->language)){
				res = ast_waitstream(chan,"");
				ast_stopstream(chan);
				
				if (!ast_say_number(chan, (atoi(currentusers)), AST_DIGIT_ANY, chan->language, (char *) NULL)){
					res = ast_waitstream(chan,"");
					ast_stopstream(chan);
				}
				if (!ast_streamfile(chan, "conf-otherinparty", chan->language)){
					res = ast_waitstream(chan,"");
					ast_stopstream(chan);
				}
			}
		}
		res=1;
	}
	else{
        	ast_log(LOG_NOTICE, "Maximum users exeeded, Current users in room: %s\n",currentusers);
        	strcpy(prompt, "conf-locked");
        	if (!ast_streamfile(chan, prompt, chan->language)){
        		res = ast_waitstream(chan,"");
			ast_stopstream(chan);
		}
		res=-1;
	}
	return res;
}
示例#2
0
int getConf(struct ast_channel *chan, struct userkeyin dtmfinput, struct roomdetails *dtmfmatch)
{
	char *prompt;
	/* char *invalid;*/

	int res=0, retry=0, skip=0;

	if (ast_strlen_zero(dtmfinput.inroom)){
		strcpy(dtmfinput.inroom, "");
	} else {
		skip = 1;	
		retry = 2;
	}
	
	 while (retry++ < 3){ 
		if(!skip){
			prompt = "conf-getconfno";
        		if(ast_app_getdata(chan, prompt, dtmfinput.inroom, sizeof(dtmfinput.inroom) - 2, 0) < 0)
				return -1;
			res = ast_waitstream(chan,"");
		}
 		res = roomQuery(dtmfinput, dtmfmatch);
		if(res==1 || res==2)
			break;
		if(res == -2){
			prompt = "conf-has-not-started";
			if (!ast_streamfile(chan, prompt, chan->language)){
				res = ast_waitstream(chan,"");
				ast_stopstream(chan);
			}
			res = -1;
			break;
		}
		prompt = "conf-invalid";
		if (!ast_streamfile(chan, prompt, chan->language)){
			res = ast_waitstream(chan,"");
			ast_stopstream(chan);
		}
	}

	if(retry>=2 && (res < 1 && !skip)){
		prompt = "vm-goodbye";
		if (!ast_streamfile(chan, prompt, chan->language)){
			res = ast_waitstream(chan,"");
			ast_stopstream(chan);
		}
		res = -1;
	}
	return res;
}
示例#3
0
int getPass(struct ast_channel *chan, struct userkeyin dtmfinput, struct roomdetails *dtmfmatch)
{
	char *prompt;
	/* char *invalid; */
	int res = 0, retry=0;

        prompt = "agent-pass";
        if(ast_app_getdata(chan, prompt, dtmfinput.inpass, sizeof(dtmfinput.inpass) - 2, 0) < 0)
		return -1;
        res = ast_waitstream(chan,"");
        res = passQuery(dtmfinput, dtmfmatch);

        while (retry++ < 2 && res !=1){
		    prompt = "auth-incorrect";
		    if(ast_app_getdata(chan, prompt, dtmfinput.inpass, sizeof(dtmfinput.inpass) - 2, 0) < 0)
			return -1;
		    res = ast_waitstream(chan,"");
			res = passQuery(dtmfinput, dtmfmatch);
				if(res==1)
					break;
		}

       if(retry>1 && res != 1){
			prompt = "vm-goodbye";
			if (!ast_streamfile(chan, prompt, chan->language)){
				res = ast_waitstream(chan,"");
				ast_stopstream(chan);
			}
			res = -1;
        }
	return res;
}
示例#4
0
static int play_and_wait(struct ast_channel *chan, char *file, char *digits)
{
	int res = -1;
	if (!ast_streamfile(chan, file, chan->language)) {
		res = ast_waitstream(chan, digits);
	}
	return res;
}
示例#5
0
int ast_play_and_wait(struct ast_channel *chan, char *fn)
{
    int d;
    d = ast_streamfile(chan, fn, chan->language);
    if (d)
        return d;
    d = ast_waitstream(chan, AST_DIGIT_ANY);
    ast_stopstream(chan);
    return d;
}
示例#6
0
static int saywords(struct ast_channel *chan, char *word1, char *word2, char *word5, int num)
{
	/* Put this in a separate proc because it's bound to change */
	int d = 0;

	if (num > 0) {
		if (num % 1000 == 1) {
			ast_streamfile(chan, word1, chan->language);
			d = ast_waitstream(chan,"");
		} else if (((num % 10) >= 2) && ((num % 10) <= 4 ) && ((num % 100) < 10 || (num % 100) > 20)) {
			ast_streamfile(chan, word2, chan->language);
			d = ast_waitstream(chan, "");
		} else {
			ast_streamfile(chan, word5, chan->language);
			d = ast_waitstream(chan, "");
		}
	}

	return d;
}
示例#7
0
static int s_streamwait3(const say_args_t *a, const char *fn)
{
	int res = ast_streamfile(a->chan, fn, a->language);
	if (res) {
		ast_log(LOG_WARNING, "Unable to play message %s\n", fn);
		return res;
	}
	res = (a->audiofd  > -1 && a->ctrlfd > -1) ?
	ast_waitstream_full(a->chan, a->ints, a->audiofd, a->ctrlfd) :
	ast_waitstream(a->chan, a->ints);
	ast_stopstream(a->chan);
	return res;  
}
示例#8
0
static int _play_file(struct ast_channel* chan, char* filename) {
	int res;

	ast_stopstream(chan);
	res = ast_streamfile(chan, filename, chan->language);

	if(!res)
		res = ast_waitstream(chan, AST_DIGIT_ANY);
	else
		res = 0;

	ast_stopstream(chan);

	return res;
}
示例#9
0
int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
{
    int res,to,fto;
    if (prompt) {
        res = ast_streamfile(c, prompt, c->language);
        if (res < 0)
            return res;
    }
    fto = 6000;
    to = 2000;
    if (timeout > 0) fto = to = timeout;
    if (timeout < 0) fto = to = 1000000000;
    res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
    return res;
}
示例#10
0
/* set timeout to 0 for "standard" timeouts. Set timeout to -1 for
   "ludicrous time" (essentially never times out) */
int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
{
    int res,to,fto;
    /* XXX Merge with full version? XXX */
    if (maxlen)
        s[0] = '\0';
    if (prompt) {
        res = ast_streamfile(c, prompt, c->language);
        if (res < 0)
            return res;
    }
    fto = c->pbx ? c->pbx->rtimeout * 1000 : 6000;
    to = c->pbx ? c->pbx->dtimeout * 1000 : 2000;

    if (timeout > 0) fto = to = timeout;
    if (timeout < 0) fto = to = 1000000000;
    res = ast_readstring(c, s, maxlen, to, fto, "#");
    return res;
}
示例#11
0
static int enterConf(struct ast_channel *chan, struct roomdetails *dtmfmatch)
{
        int res=0;
        /* char *prompt; */
	char prompt[50]="";
        struct ast_app *app;
	char arg2[255]="";
	char roomno2[80]="";
	char roomtype2[30]="";
	char recordfile[100]="conf-recordings/";

        strcpy(roomno2,dtmfmatch->roomno);
	strcpy(roomtype2,dtmfmatch->roomtype);
	strcpy(arg2, roomno2);

	strcat(arg2, ",");
	strcat(arg2, roomtype2);
	strcat(arg2, ",");

	strcat(recordfile, dtmfmatch->roomno);
	strcat(recordfile, "-");
	strcat(recordfile, dtmfmatch->bookid);

        ast_log(LOG_NOTICE, "Roomtype: %s\n", arg2);
	pbx_builtin_setvar_helper(chan, "MEETME_RECORDINGFILE", recordfile);
  
	if(strchr(dtmfmatch->aFlags, 'r'))
	{
		strcpy(prompt,"conf-call-recorded");
		if (!ast_streamfile(chan, prompt, chan->language)){
			res = ast_waitstream(chan,"");
			ast_stopstream(chan);
		}
	}
        if(!(app=pbx_findapp(ConfApp))){
		ast_log(LOG_WARNING, "Invalid conferencing application: %s\n", ConfApp);
		return -1;
	}
        res = pbx_exec(chan, app, arg2);

	return 1;
}
示例#12
0
文件: app_page.c 项目: OPSF/uClinux
static int page_exec(struct ast_channel *chan, void *data)
{
	struct ast_module_user *u;
	char *options, *tech, *resource, *tmp;
	char meetmeopts[88], originator[AST_CHANNEL_NAME];
	struct ast_flags flags = { 0 };
	unsigned int confid = ast_random();
	struct ast_app *app;
	int res = 0, pos = 0, i = 0;
	struct ast_dial *dials[MAX_DIALS];

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "This application requires at least one argument (destination(s) to page)\n");
		return -1;
	}

	u = ast_module_user_add(chan);

	if (!(app = pbx_findapp("MeetMe"))) {
		ast_log(LOG_WARNING, "There is no MeetMe application available!\n");
		ast_module_user_remove(u);
		return -1;
	};

	options = ast_strdupa(data);

	ast_copy_string(originator, chan->name, sizeof(originator));
	if ((tmp = strchr(originator, '-')))
		*tmp = '\0';

	tmp = strsep(&options, "|");
	if (options)
		ast_app_parse_options(page_opts, &flags, NULL, options);

	snprintf(meetmeopts, sizeof(meetmeopts), "MeetMe|%ud|%s%sqxdw(5)", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "m"),
		(ast_test_flag(&flags, PAGE_RECORD) ? "r" : "") );

	/* Go through parsing/calling each device */
	while ((tech = strsep(&tmp, "&"))) {
		struct ast_dial *dial = NULL;

		/* don't call the originating device */
		if (!strcasecmp(tech, originator))
			continue;

		/* If no resource is available, continue on */
		if (!(resource = strchr(tech, '/'))) {
			ast_log(LOG_WARNING, "Incomplete destination '%s' supplied.\n", tech);
			continue;
		}

		*resource++ = '\0';

		/* Create a dialing structure */
		if (!(dial = ast_dial_create())) {
			ast_log(LOG_WARNING, "Failed to create dialing structure.\n");
			continue;
		}

		/* Append technology and resource */
		ast_dial_append(dial, tech, resource);

		/* Set ANSWER_EXEC as global option */
		ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, meetmeopts);

		/* Run this dial in async mode */
		ast_dial_run(dial, chan, 1);

		/* Put in our dialing array */
		dials[pos++] = dial;
	}

	if (!ast_test_flag(&flags, PAGE_QUIET)) {
		res = ast_streamfile(chan, "beep", chan->language);
		if (!res)
			res = ast_waitstream(chan, "");
	}

	if (!res) {
		snprintf(meetmeopts, sizeof(meetmeopts), "%ud|A%s%sqxd", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "t"), 
			(ast_test_flag(&flags, PAGE_RECORD) ? "r" : "") );
		pbx_exec(chan, app, meetmeopts);
	}

	/* Go through each dial attempt cancelling, joining, and destroying */
	for (i = 0; i < pos; i++) {
		struct ast_dial *dial = dials[i];

		/* We have to wait for the async thread to exit as it's possible Meetme won't throw them out immediately */
		ast_dial_join(dial);

		/* Hangup all channels */
		ast_dial_hangup(dial);

		/* Destroy dialing structure */
		ast_dial_destroy(dial);
	}

	ast_module_user_remove(u);

	return -1;
}
/* play name of mailbox owner.
 * returns:  -1 for bad or missing extension
 *           '1' for selected entry from directory
 *           '*' for skipped entry from directory
 */
static int play_mailbox_owner(struct ast_channel *chan, char *context, char *dialcontext, char *ext, char *name, int fromappvm) {
	int res = 0;
	int loop = 3;
	char fn[256];
	char fn2[256];

	/* Check for the VoiceMail2 greeting first */
	snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/greet",
		(char *)ast_config_AST_SPOOL_DIR, context, ext);
#ifdef USE_ODBC_STORAGE
	retrieve_file(fn);
#endif

	/* Otherwise, check for an old-style Voicemail greeting */
	snprintf(fn2, sizeof(fn2), "%s/vm/%s/greet",
		(char *)ast_config_AST_SPOOL_DIR, ext);
#ifdef USE_ODBC_STORAGE
	retrieve_file(fn2);
#endif

	if (ast_fileexists(fn, NULL, chan->language) > 0) {
		res = ast_streamfile(chan, fn, chan->language);
		if (!res) {
			res = ast_waitstream(chan, AST_DIGIT_ANY);
		}
		ast_stopstream(chan);
	} else if (ast_fileexists(fn2, NULL, chan->language) > 0) {
		res = ast_streamfile(chan, fn2, chan->language);
		if (!res) {
			res = ast_waitstream(chan, AST_DIGIT_ANY);
		}
		ast_stopstream(chan);
	} else {
		res = ast_say_character_str(chan, !ast_strlen_zero(name) ? name : ext,
					AST_DIGIT_ANY, chan->language);
	}
#ifdef USE_ODBC_STORAGE
	ast_filedelete(fn, NULL);	
	ast_filedelete(fn2, NULL);	
#endif

	while (loop) {
		if (!res) {
			res = ast_streamfile(chan, "dir-instr", chan->language);
		}
		if (!res) {
			res = ast_waitstream(chan, AST_DIGIT_ANY);
		}
		if (!res) {
			res = ast_waitfordigit(chan, 3000);
		}
		ast_stopstream(chan);
	
		if (res > -1) {
			switch (res) {
				case '1':
					/* Name selected */
					loop = 0;
					if (fromappvm) {
						/* We still want to set the exten */
						ast_copy_string(chan->exten, ext, sizeof(chan->exten));
					} else {
						if (ast_goto_if_exists(chan, dialcontext, ext, 1)) {
							ast_log(LOG_WARNING,
								"Can't find extension '%s' in context '%s'.  "
								"Did you pass the wrong context to Directory?\n",
								ext, dialcontext);
							res = -1;
						}
					}
					break;
	
				case '*':   
					/* Skip to next match in list */
					loop = 0;
					break;
	
				default:
					/* Not '1', or '*', so decrement number of tries */
					res = 0;
					loop--;
					break;
			} /* end switch */
		} /* end if */
		else {
			/* User hungup, so jump out now */
			loop = 0;
		}
	} /* end while */

	return(res);
}
示例#14
0
static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct ast_config *ucfg, char *context, char *dialcontext, char digit, int last, int readext, int fromappvm)
{
	/* Read in the first three digits..  "digit" is the first digit, already read */
	char ext[NUMDIGITS + 1], *cat;
	char name[80] = "";
	struct ast_variable *v;
	int res;
	int found=0;
	int lastuserchoice = 0;
	char *start, *conv, *stringp = NULL;
	const char *pos;
	int breakout = 0;

	if (ast_strlen_zero(context)) {
		ast_log(LOG_WARNING,
			"Directory must be called with an argument "
			"(context in which to interpret extensions)\n");
		return -1;
	}
	if (digit == '0') {
		if (!ast_goto_if_exists(chan, dialcontext, "o", 1) ||
		    (!ast_strlen_zero(chan->macrocontext) &&
		     !ast_goto_if_exists(chan, chan->macrocontext, "o", 1))) {
			return 0;
		} else {
			ast_log(LOG_WARNING, "Can't find extension 'o' in current context.  "
				"Not Exiting the Directory!\n");
			res = 0;
		}
	}	
	if (digit == '*') {
		if (!ast_goto_if_exists(chan, dialcontext, "a", 1) ||
		    (!ast_strlen_zero(chan->macrocontext) &&
		     !ast_goto_if_exists(chan, chan->macrocontext, "a", 1))) {
			return 0;
		} else {
			ast_log(LOG_WARNING, "Can't find extension 'a' in current context.  "
				"Not Exiting the Directory!\n");
			res = 0;
		}
	}	
	memset(ext, 0, sizeof(ext));
	ext[0] = digit;
	res = 0;
	if (ast_readstring(chan, ext + 1, NUMDIGITS - 1, 3000, 3000, "#") < 0) res = -1;
	if (!res) {
		/* Search for all names which start with those digits */
		v = ast_variable_browse(cfg, context);
		while(v && !res) {
			/* Find all candidate extensions */
			while(v) {
				/* Find a candidate extension */
				start = strdup(v->value);
				if (start && !strcasestr(start, "hidefromdir=yes")) {
					stringp=start;
					strsep(&stringp, ",");
					pos = strsep(&stringp, ",");
					if (pos) {
						ast_copy_string(name, pos, sizeof(name));
						/* Grab the last name */
						if (last && strrchr(pos,' '))
							pos = strrchr(pos, ' ') + 1;
						conv = convert(pos);
						if (conv) {
							if (!strncmp(conv, ext, strlen(ext))) {
								/* Match! */
								found++;
								free(conv);
								free(start);
								break;
							}
							free(conv);
						}
					}
					free(start);
				}
				v = v->next;
			}

			if (v) {
				/* We have a match -- play a greeting if they have it */
				res = play_mailbox_owner(chan, context, dialcontext, v->name, name, readext, fromappvm);
				switch (res) {
					case -1:
						/* user pressed '1' but extension does not exist, or
						 * user hungup
						 */
						lastuserchoice = 0;
						break;
					case '1':
						/* user pressed '1' and extensions exists;
						   play_mailbox_owner will already have done
						   a goto() on the channel
						 */
						lastuserchoice = res;
						break;
					case '*':
						/* user pressed '*' to skip something found */
						lastuserchoice = res;
						res = 0;
						break;
					default:
						break;
				}
				v = v->next;
			}
		}

		if (!res && ucfg) {
			/* Search users.conf for all names which start with those digits */
			for (cat = ast_category_browse(ucfg, NULL); cat && !res ; cat = ast_category_browse(ucfg, cat)) {
				if (!strcasecmp(cat, "general"))
					continue;
				if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory")))
					continue;
				
				/* Find all candidate extensions */
				if ((pos = ast_variable_retrieve(ucfg, cat, "fullname"))) {
					ast_copy_string(name, pos, sizeof(name));
					/* Grab the last name */
					if (last && strrchr(pos,' '))
						pos = strrchr(pos, ' ') + 1;
					conv = convert(pos);
					if (conv) {
						if (!strcmp(conv, ext)) {
							/* Match! */
							found++;
							/* We have a match -- play a greeting if they have it */
							res = play_mailbox_owner(chan, context, dialcontext, cat, name, readext, fromappvm);
							switch (res) {
							case -1:
								/* user pressed '1' but extension does not exist, or
								 * user hungup
								 */
								lastuserchoice = 0;
								breakout = 1;
								break;
							case '1':
								/* user pressed '1' and extensions exists;
								   play_mailbox_owner will already have done
								   a goto() on the channel
								 */
								lastuserchoice = res;
								breakout = 1;
								break;
							case '*':
								/* user pressed '*' to skip something found */
								lastuserchoice = res;
								breakout = 0;
								res = 0;
								break;
							default:
								breakout = 1;
								break;
							}
							free(conv);
							if (breakout)
								break;
						}
						else
							free(conv);
					}
				}
			}
		}
			
		if (lastuserchoice != '1') {
			res = ast_streamfile(chan, found ? "dir-nomore" : "dir-nomatch", chan->language);
			if (!res)
				res = 1;
			return res;
		}
		return 0;
	}
	return res;
}
示例#15
0
static void *dialstring(void *string)
{
	struct ast_channel *channel;
	char *bufptr,*destptr;
	int  ms=10000;		/* ms affects number of rings */
	int  cnt=0,first;
	char tech[256];
	char tele[256];
	char filename[256];
	int  answered=0;

	for(first=0, bufptr=(char *)string, destptr=tech; *bufptr&&cnt<256; cnt++){
		if(*bufptr=='/' && !first) {
			*destptr=0;
			destptr=tele;
			first=1;
		}
		else if(*bufptr==',') {
			*destptr=0;
			destptr=filename;
		} else {
			*destptr=*bufptr;
			destptr++;
		}
		bufptr++;
	} 
	*destptr=0;
	ast_log(LOG_DEBUG, "Printing string arg: %s Eos\n", (char *)string);
	if(strlen(tech)+strlen(tele)+strlen(filename) > 256) {
		ast_log(LOG_ERROR, "Autodial:Error string too long\n");
		free(string);
		pthread_exit(NULL);
	}
	ast_log(LOG_DEBUG, "Autodial Tech %s(%d) Tele %s(%d) Filename %s(%d)\n",tech, (int)strlen(tech), tele, (int)strlen(tele), filename, (int)strlen(filename));

	channel=ast_request(tech,AST_FORMAT_SLINEAR,tele);
	if(channel!=NULL){
		ast_call(channel,tele,10000);
	} else {
		ast_log(LOG_ERROR, "Autodial:Sorry unable to obtain channel\n");
		free(string);
		pthread_exit(NULL);
	}
	if(channel->_state==AST_STATE_UP)
		ast_log(LOG_DEBUG, "Autodial:Line is Up\n");
	while(ms>0){
		struct ast_frame *f;

		ms=ast_waitfor(channel,ms);
		f=ast_read(channel);
		if(!f){
			ast_log(LOG_DEBUG, "Autodial:Hung Up\n");
			break;
		}
		if (f->frametype==AST_FRAME_CONTROL) {
			if (f->subclass==AST_CONTROL_ANSWER) {
				ast_log(LOG_DEBUG, "Autodial:Phone Answered\n");
				if (channel->_state==AST_STATE_UP) {
					char res;

					ast_streamfile(channel,filename,0);
					/* Press Five for snooze */
					res=ast_waitstream(channel, "37");
					if(res=='3'){
						answered=1;
						set_snooze_alarm((char *)string,60);
						ast_streamfile(channel,"demo-thanks",0);
						ast_waitstream(channel, "");
					}
					else if(res=='7'){
						answered=1;
						ast_streamfile(channel,"demo-thanks",0);
						ast_waitstream(channel, "");
					}
					ast_stopstream(channel);
					ms=0;
				}
			}
			else if (f->subclass==AST_CONTROL_RINGING)
				ast_log(LOG_DEBUG, "Autodial:Phone Ringing end\n");
		}
		ast_frfree(f);
	}
	if(!answered)
		set_snooze_alarm((char *) string, 5);
	free(string);
	ast_hangup(channel);
	ast_log(LOG_DEBUG, "Autodial:Hung up channel\n");
	pthread_exit(NULL);
	return NULL;
}
示例#16
0
static int auth_exec(struct ast_channel *chan, void *data)
{
	int res=0;
	int retries;
	struct localuser *u;
	char password[256]="";
	char passwd[256];
	char *opts;
	char *prompt;
	if (!data || ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "Authenticate requires an argument(password)\n");
		return -1;
	}
	LOCAL_USER_ADD(u);
	if (chan->_state != AST_STATE_UP) {
		res = ast_answer(chan);
		if (res) {
			LOCAL_USER_REMOVE(u);
			return -1;
		}
	}
	strncpy(password, data, sizeof(password) - 1);
	opts=strchr(password, '|');
	if (opts) {
		*opts = 0;
		opts++;
	} else
		opts = "";
	/* Start asking for password */
	prompt = "agent-pass";
	for (retries = 0; retries < 3; retries++) {
		res = ast_app_getdata(chan, prompt, passwd, sizeof(passwd) - 2, 0);
		if (res < 0)
			break;
		res = 0;
		if (password[0] == '/') {
			if (strchr(opts, 'd')) {
				char tmp[256];
				/* Compare against a database key */
				if (!ast_db_get(password + 1, passwd, tmp, sizeof(tmp))) {
					/* It's a good password */
					if (strchr(opts, 'r')) {
						ast_db_del(password + 1, passwd);
					}
					break;
				}
			} else {
				/* Compare against a file */
				FILE *f;
				f = fopen(password, "r");
				if (f) {
					char buf[256] = "";
					while(!feof(f)) {
						fgets(buf, sizeof(buf), f);
						if (!feof(f) && !ast_strlen_zero(buf)) {
							buf[strlen(buf) - 1] = '\0';
							if (!ast_strlen_zero(buf) && !strcmp(passwd, buf))
								break;
						}
					}
					fclose(f);
					if (!ast_strlen_zero(buf) && !strcmp(passwd, buf))
						break;
				} else 
					ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", password, strerror(errno));
			}
		} else {
			/* Compare against a fixed password */
			if (!strcmp(passwd, password)) 
				break;
		}
		prompt="auth-incorrect";
	}
	if ((retries < 3) && !res) {
		if (strchr(opts, 'a')) 
			ast_cdr_setaccount(chan, passwd);
		res = ast_streamfile(chan, "auth-thankyou", chan->language);
		if (!res)
			res = ast_waitstream(chan, "");
	} else {
		if (!res)
			res = ast_streamfile(chan, "vm-goodbye", chan->language);
		if (!res)
			res = ast_waitstream(chan, "");
		res = -1;
	}
	LOCAL_USER_REMOVE(u);
	return res;
}
示例#17
0
static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
		       int volfactor, const int fd, const char *mygroup, const char *spec,
		       const char *exten, const char *context)
{
	char nameprefix[AST_NAME_STRLEN];
	char peer_name[AST_NAME_STRLEN + 5];
	signed char zero_volume = 0;
	int waitms;
	int res;
	char *ptr;
	int num;
	int num_spyed_upon = 1;
	struct chanspy_ds chanspy_ds = { 0, };

	ast_mutex_init(&chanspy_ds.lock);

	snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1));

	if (chan->_state != AST_STATE_UP)
		ast_answer(chan);

	ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */

	waitms = 100;

	for (;;) {
		struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
		struct ast_channel *prev = NULL, *peer = NULL;

		if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
			res = ast_streamfile(chan, "beep", chan->language);
			if (!res)
				res = ast_waitstream(chan, "");
			else if (res < 0) {
				ast_clear_flag(chan, AST_FLAG_SPYING);
				break;
			}
		}

		res = ast_waitfordigit(chan, waitms);
		if (res < 0) {
			ast_clear_flag(chan, AST_FLAG_SPYING);
			break;
		}
				
		/* reset for the next loop around, unless overridden later */
		waitms = 100;
		num_spyed_upon = 0;

		for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
		     peer_chanspy_ds;
			 chanspy_ds_free(peer_chanspy_ds), prev = peer,
		     peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 
			 	next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
			const char *group;
			int igrp = !mygroup;
			char *groups[25];
			int num_groups = 0;
			char dup_group[512];
			int x;
			char *s;

			peer = peer_chanspy_ds->chan;

			ast_mutex_unlock(&peer_chanspy_ds->lock);

			if (peer == prev) {
				ast_channel_unlock(peer);
				chanspy_ds_free(peer_chanspy_ds);
				break;
			}

			if (ast_check_hangup(chan)) {
				ast_channel_unlock(peer);
				chanspy_ds_free(peer_chanspy_ds);
				break;
			}

			if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
				ast_channel_unlock(peer);
				continue;
			}

			if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
				ast_channel_unlock(peer);
				continue;
			}

			if (mygroup) {
				if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
					ast_copy_string(dup_group, group, sizeof(dup_group));
					num_groups = ast_app_separate_args(dup_group, ':', groups,
									   sizeof(groups) / sizeof(groups[0]));
				}
				
				for (x = 0; x < num_groups; x++) {
					if (!strcmp(mygroup, groups[x])) {
						igrp = 1;
						break;
					}
				}
			}
			
			if (!igrp) {
				ast_channel_unlock(peer);
				continue;
			}

			strcpy(peer_name, "spy-");
			strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
			ptr = strchr(peer_name, '/');
			*ptr++ = '\0';
			
			for (s = peer_name; s < ptr; s++)
				*s = tolower(*s);

			/* We have to unlock the peer channel here to avoid a deadlock.
			 * So, when we need to dereference it again, we have to lock the 
			 * datastore and get the pointer from there to see if the channel 
			 * is still valid. */
			ast_channel_unlock(peer);

			if (!ast_test_flag(flags, OPTION_QUIET)) {
				if (ast_fileexists(peer_name, NULL, NULL) != -1) {
					res = ast_streamfile(chan, peer_name, chan->language);
					if (!res)
						res = ast_waitstream(chan, "");
					if (res) {
						chanspy_ds_free(peer_chanspy_ds);
						break;
					}
				} else
					res = ast_say_character_str(chan, peer_name, "", chan->language);
				if ((num = atoi(ptr))) 
					ast_say_digits(chan, atoi(ptr), "", chan->language);
			}
			
			res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags);
			num_spyed_upon++;	

			if (res == -1) {
				chanspy_ds_free(peer_chanspy_ds);
				break;
			} else if (res > 1 && spec) {
				struct ast_channel *next;

				snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);

				if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
					peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
					next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
				} else {
					/* stay on this channel, if it is still valid */

					ast_mutex_lock(&peer_chanspy_ds->lock);
					if (peer_chanspy_ds->chan) {
						ast_channel_lock(peer_chanspy_ds->chan);
						next_chanspy_ds = peer_chanspy_ds;
						peer_chanspy_ds = NULL;
					} else {
						/* the channel is gone */
						ast_mutex_unlock(&peer_chanspy_ds->lock);
						next_chanspy_ds = NULL;
					}
				}

				peer = NULL;
			}
		}
		if (res == -1 || ast_check_hangup(chan))
			break;
	}
	
	ast_clear_flag(chan, AST_FLAG_SPYING);

	ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);

	ast_mutex_lock(&chanspy_ds.lock);
	ast_mutex_unlock(&chanspy_ds.lock);
	ast_mutex_destroy(&chanspy_ds.lock);

	return res;
}
示例#18
0
int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence)
{
    int d = 0;
    char *fmts;
    char comment[256];
    int x, fmtcnt=1, res=-1,outmsg=0;
    struct ast_frame *f;
    struct ast_filestream *others[MAX_OTHER_FORMATS];
    struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
    char *sfmt[MAX_OTHER_FORMATS];
    char *stringp=NULL;
    time_t start, end;
    struct ast_dsp *sildet;   	/* silence detector dsp */
    int totalsilence = 0;
    int dspsilence = 0;
    int gotsilence = 0;		/* did we timeout for silence? */
    int rfmt=0;
    char prependfile[80];

    if (silencethreshold < 0)
        silencethreshold = global_silence_threshold;

    if (maxsilence < 0)
        maxsilence = global_maxsilence;

    /* barf if no pointer passed to store duration in */
    if (duration == NULL) {
        ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
        return -1;
    }

    ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
    snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);

    if (playfile || beep) {
        if (!beep)
            d = ast_play_and_wait(chan, playfile);
        if (d > -1)
            d = ast_streamfile(chan, "beep",chan->language);
        if (!d)
            d = ast_waitstream(chan,"");
        if (d < 0)
            return -1;
    }
    strncpy(prependfile, recordfile, sizeof(prependfile) -1);
    strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);

    fmts = ast_strdupa(fmt);

    stringp=fmts;
    strsep(&stringp, "|");
    ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
    sfmt[0] = ast_strdupa(fmts);

    while((fmt = strsep(&stringp, "|"))) {
        if (fmtcnt > MAX_OTHER_FORMATS - 1) {
            ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
            break;
        }
        sfmt[fmtcnt++] = ast_strdupa(fmt);
    }

    time(&start);
    end=start;  /* pre-initialize end to be same as start in case we never get into loop */
    for (x=0; x<fmtcnt; x++) {
        others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
        ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing:  %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
        if (!others[x]) {
            break;
        }
    }

    sildet = ast_dsp_new(); /* Create the silence detector */
    if (!sildet) {
        ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
        return -1;
    }
    ast_dsp_set_threshold(sildet, silencethreshold);

    if (maxsilence > 0) {
        rfmt = chan->readformat;
        res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
        if (res < 0) {
            ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
            return -1;
        }
    }

    if (x == fmtcnt) {
        /* Loop forever, writing the packets we read to the writer(s), until
           we read a # or get a hangup */
        f = NULL;
        for(;;) {
            res = ast_waitfor(chan, 2000);
            if (!res) {
                ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
                /* Try one more time in case of masq */
                res = ast_waitfor(chan, 2000);
                if (!res) {
                    ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
                    res = -1;
                }
            }

            if (res < 0) {
                f = NULL;
                break;
            }
            f = ast_read(chan);
            if (!f)
                break;
            if (f->frametype == AST_FRAME_VOICE) {
                /* write each format */
                for (x=0; x<fmtcnt; x++) {
                    if (!others[x])
                        break;
                    res = ast_writestream(others[x], f);
                }

                /* Silence Detection */
                if (maxsilence > 0) {
                    dspsilence = 0;
                    ast_dsp_silence(sildet, f, &dspsilence);
                    if (dspsilence)
                        totalsilence = dspsilence;
                    else
                        totalsilence = 0;

                    if (totalsilence > maxsilence) {
                        /* Ended happily with silence */
                        if (option_verbose > 2)
                            ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
                        ast_frfree(f);
                        gotsilence = 1;
                        outmsg=2;
                        break;
                    }
                }
                /* Exit on any error */
                if (res) {
                    ast_log(LOG_WARNING, "Error writing frame\n");
                    ast_frfree(f);
                    break;
                }
            } else if (f->frametype == AST_FRAME_VIDEO) {
                /* Write only once */
                ast_writestream(others[0], f);
            } else if (f->frametype == AST_FRAME_DTMF) {
                /* stop recording with any digit */
                if (option_verbose > 2)
                    ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
                res = 't';
                outmsg = 2;
                ast_frfree(f);
                break;
            }
            if (maxtime) {
                time(&end);
                if (maxtime < (end - start)) {
                    if (option_verbose > 2)
                        ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
                    res = 't';
                    outmsg=2;
                    ast_frfree(f);
                    break;
                }
            }
            ast_frfree(f);
        }
        if (end == start) time(&end);
        if (!f) {
            if (option_verbose > 2)
                ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
            res = -1;
            outmsg=1;
#if 0
            /* delete all the prepend files */
            for (x=0; x<fmtcnt; x++) {
                if (!others[x])
                    break;
                ast_closestream(others[x]);
                ast_filedelete(prependfile, sfmt[x]);
            }
#endif
        }
    } else {
        ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]);
    }
    *duration = end - start;
#if 0
    if (outmsg > 1) {
#else
    if (outmsg) {
#endif
        struct ast_frame *fr;
        for (x=0; x<fmtcnt; x++) {
            snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
            realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
            if (!others[x] || !realfiles[x])
                break;
            if (totalsilence)
                ast_stream_rewind(others[x], totalsilence-200);
            else
                ast_stream_rewind(others[x], 200);
            ast_truncstream(others[x]);
            /* add the original file too */
            while ((fr = ast_readframe(realfiles[x]))) {
                ast_writestream(others[x],fr);
            }
            ast_closestream(others[x]);
            ast_closestream(realfiles[x]);
            ast_filerename(prependfile, recordfile, sfmt[x]);
#if 0
            ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
#endif
            ast_filedelete(prependfile, sfmt[x]);
        }
    }
    if (rfmt) {
        if (ast_set_read_format(chan, rfmt)) {
            ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
        }
    }
    if (outmsg) {
        if (outmsg > 1) {
            /* Let them know it worked */
            ast_streamfile(chan, "auth-thankyou", chan->language);
            ast_waitstream(chan, "");
        }
    }
    return res;
}

int ast_lock_path(const char *path)
{
    char *s;
    char *fs;
    int res;
    int fd;
    time_t start;
    s = alloca(strlen(path) + 10);
    fs = alloca(strlen(path) + 20);
    if (!fs || !s) {
        ast_log(LOG_WARNING, "Out of memory!\n");
        return -1;
    }
    snprintf(fs, strlen(path) + 19, "%s/%s-%08x", path, ".lock", rand());
    fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
    if (fd < 0) {
        fprintf(stderr, "Unable to create lock file: %s\n", strerror(errno));
        return -1;
    }
    close(fd);
    snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
    time(&start);
    while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
        usleep(1);
    if (res < 0) {
        ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
    }
    unlink(fs);
    ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
    return res;
}
示例#19
0
static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
	int volfactor, const int fd, const char *mygroup, const char *myenforced,
	const char *spec, const char *exten, const char *context)
{
	char nameprefix[AST_NAME_STRLEN];
	char peer_name[AST_NAME_STRLEN + 5];
	char exitcontext[AST_MAX_CONTEXT] = "";
	signed char zero_volume = 0;
	int waitms;
	int res;
	char *ptr;
	int num;
	int num_spyed_upon = 1;
	struct chanspy_ds chanspy_ds;

	if (ast_test_flag(flags, OPTION_EXIT)) {
		const char *c;
		if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT")))
			ast_copy_string(exitcontext, c, sizeof(exitcontext));
		else if (!ast_strlen_zero(chan->macrocontext))
			ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
		else
			ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
	}

	ast_mutex_init(&chanspy_ds.lock);

	snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1));

	if (chan->_state != AST_STATE_UP)
		ast_answer(chan);

	ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */

	waitms = 100;

	for (;;) {
		struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
		struct ast_channel *prev = NULL, *peer = NULL;

		if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
			res = ast_streamfile(chan, "beep", chan->language);
			if (!res)
				res = ast_waitstream(chan, "");
			else if (res < 0) {
				ast_clear_flag(chan, AST_FLAG_SPYING);
				break;
			}
			if (!ast_strlen_zero(exitcontext)) {
				char tmp[2];
				tmp[0] = res;
				tmp[1] = '\0';
				if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
					goto exit;
				else
					ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
			}
		}

		res = ast_waitfordigit(chan, waitms);
		if (res < 0) {
			ast_clear_flag(chan, AST_FLAG_SPYING);
			break;
		}
		if (!ast_strlen_zero(exitcontext)) {
			char tmp[2];
			tmp[0] = res;
			tmp[1] = '\0';
			if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
				goto exit;
			else
				ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
		}

		/* reset for the next loop around, unless overridden later */
		waitms = 100;
		num_spyed_upon = 0;

		for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
		     peer_chanspy_ds;
			 chanspy_ds_free(peer_chanspy_ds), prev = peer,
		     peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 
			 	next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
			const char *group;
			int igrp = !mygroup;
			char *groups[25];
			int num_groups = 0;
			char dup_group[512];
			int x;
			char *s;
			char *buffer;
			char *end;
			char *ext;
			char *form_enforced;
			int ienf = !myenforced;

			peer = peer_chanspy_ds->chan;

			ast_mutex_unlock(&peer_chanspy_ds->lock);

			if (peer == prev) {
				ast_channel_unlock(peer);
				chanspy_ds_free(peer_chanspy_ds);
				break;
			}

			if (ast_check_hangup(chan)) {
				ast_channel_unlock(peer);
				chanspy_ds_free(peer_chanspy_ds);
				break;
			}

			if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
				ast_channel_unlock(peer);
				continue;
			}

			if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
				ast_channel_unlock(peer);
				continue;
			}

			if (mygroup) {
				if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
					ast_copy_string(dup_group, group, sizeof(dup_group));
					num_groups = ast_app_separate_args(dup_group, ':', groups,
						ARRAY_LEN(groups));
				}

				for (x = 0; x < num_groups; x++) {
					if (!strcmp(mygroup, groups[x])) {
						igrp = 1;
						break;
					}
				}
			}

			if (!igrp) {
				ast_channel_unlock(peer);
				continue;
			}

			if (myenforced) {

				/* We don't need to allocate more space than just the
				length of (peer->name) for ext as we will cut the
				channel name's ending before copying into ext */

				ext = alloca(strlen(peer->name));

				form_enforced = alloca(strlen(myenforced) + 3);

				strcpy(form_enforced, ":");
				strcat(form_enforced, myenforced);
				strcat(form_enforced, ":");

				buffer = ast_strdupa(peer->name);
				
				if ((end = strchr(buffer, '-'))) {
					*end++ = ':';
					*end = '\0';
				}

				strcpy(ext, ":");
				strcat(ext, buffer);

				if (strcasestr(form_enforced, ext))
					ienf = 1;
			}

			if (!ienf)
				continue;

			strcpy(peer_name, "spy-");
			strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
			ptr = strchr(peer_name, '/');
			*ptr++ = '\0';

			for (s = peer_name; s < ptr; s++)
				*s = tolower(*s);
			/* We have to unlock the peer channel here to avoid a deadlock.
			 * So, when we need to dereference it again, we have to lock the 
			 * datastore and get the pointer from there to see if the channel 
			 * is still valid. */
			ast_channel_unlock(peer);

			if (!ast_test_flag(flags, OPTION_QUIET)) {
				if (ast_fileexists(peer_name, NULL, NULL) != -1) {
					res = ast_streamfile(chan, peer_name, chan->language);
					if (!res)
						res = ast_waitstream(chan, "");
					if (res) {
						chanspy_ds_free(peer_chanspy_ds);
						break;
					}
				} else
					res = ast_say_character_str(chan, peer_name, "", chan->language);
				if ((num = atoi(ptr)))
					ast_say_digits(chan, atoi(ptr), "", chan->language);
			}

			res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext);
			num_spyed_upon++;	

			if (res == -1) {
				chanspy_ds_free(peer_chanspy_ds);
				goto exit;
			} else if (res == -2) {
				res = 0;
				chanspy_ds_free(peer_chanspy_ds);
				goto exit;
			} else if (res > 1 && spec) {
				struct ast_channel *next;

				snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);

				if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
					peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
					next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
				} else {
					/* stay on this channel, if it is still valid */

					ast_mutex_lock(&peer_chanspy_ds->lock);
					if (peer_chanspy_ds->chan) {
						ast_channel_lock(peer_chanspy_ds->chan);
						next_chanspy_ds = peer_chanspy_ds;
						peer_chanspy_ds = NULL;
					} else {
						/* the channel is gone */
						ast_mutex_unlock(&peer_chanspy_ds->lock);
						next_chanspy_ds = NULL;
					}
				}

				peer = NULL;
			}
		}
		if (res == -1 || ast_check_hangup(chan))
			break;
	}
exit:

	ast_clear_flag(chan, AST_FLAG_SPYING);

	ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);

	ast_mutex_lock(&chanspy_ds.lock);
	ast_mutex_unlock(&chanspy_ds.lock);
	ast_mutex_destroy(&chanspy_ds.lock);

	return res;
}
static int directory_exec(struct ast_channel *chan, void *data)
{
	int res = 0;
	struct localuser *u;
	struct ast_config *cfg;
	int last = 1;
	int fromappvm = 0;
	char *context, *dialcontext, *dirintro, *options;

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n");
		return -1;
	}

	LOCAL_USER_ADD(u);

	context = ast_strdupa(data);
	dialcontext = strchr(context, '|');
	if (dialcontext) {
		*dialcontext = '\0';
		dialcontext++;
		options = strchr(dialcontext, '|');
		if (options) {
			*options = '\0';
			options++; 
			if (strchr(options, 'f'))
				last = 0;
			if (strchr(options, 'v'))
				fromappvm = 1;
		}
	} else	
		dialcontext = context;

	cfg = realtime_directory(context);
	if (!cfg) {
		LOCAL_USER_REMOVE(u);
		return -1;
	}

	dirintro = ast_variable_retrieve(cfg, context, "directoryintro");
	if (ast_strlen_zero(dirintro))
		dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
	if (ast_strlen_zero(dirintro)) {
		if (last)
			dirintro = "dir-intro";	
		else
			dirintro = "dir-intro-fn";
	}

	if (chan->_state != AST_STATE_UP) 
		res = ast_answer(chan);

	for (;;) {
		if (!res)
			res = ast_streamfile(chan, dirintro, chan->language);
		if (!res)
			res = ast_waitstream(chan, AST_DIGIT_ANY);
		ast_stopstream(chan);
		if (!res)
			res = ast_waitfordigit(chan, 5000);
		if (res > 0) {
			res = do_directory(chan, cfg, context, dialcontext, res, last, fromappvm);
			if (res > 0) {
				res = ast_waitstream(chan, AST_DIGIT_ANY);
				ast_stopstream(chan);
				if (res >= 0) {
					continue;
				}
			}
		}
		break;
	}
	ast_config_destroy(cfg);
	LOCAL_USER_REMOVE(u);
	return res;
}
示例#21
0
static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags)
{
	struct ast_conference *prev=NULL, *cur;
	struct ast_conf_user *user = malloc(sizeof(struct ast_conf_user));
	int fd;
	struct zt_confinfo ztc;
	struct ast_frame *f;
	struct ast_channel *c;
	struct ast_frame fr;
	int outfd;
	int ms;
	int nfds;
	int res;
	int flags;
	int retryzap;
	int origfd;
	int musiconhold = 0;
	int firstpass = 0;
	int origquiet;
	int ret = -1;
	int x;
	int menu_active = 0;
	int using_pseudo = 0;

	struct ast_app *app;
	char *agifile;
	char *agifiledefault = "conf-background.agi";
	char meetmesecs[30] = "";
	char exitcontext[AST_MAX_EXTENSION] = "";
	int dtmf;

	ZT_BUFFERINFO bi;
	char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
	char *buf = __buf + AST_FRIENDLY_OFFSET;
	
	if (!user) {
		ast_log(LOG_ERROR, "Out of memory\n");
		return(ret);
	}
	memset(user, 0, sizeof(struct ast_conf_user));

	user->user_no = 0; /* User number 0 means starting up user! (dead - not in the list!) */

	time(&user->jointime);

	if (conf->locked) {
		/* Sorry, but this confernce is locked! */	
		if (!ast_streamfile(chan, "conf-locked", chan->language))
			ast_waitstream(chan, "");
		goto outrun;
	}
	conf->users++;
	if (confflags & CONFFLAG_MARKEDUSER)
		conf->markedusers++;
      
   	ast_mutex_lock(&conflock);
	if (conf->firstuser == NULL) {
		/* Fill the first new User struct */
		user->user_no = 1;
		user->nextuser = NULL;
		user->prevuser = NULL;
		conf->firstuser = user;
		conf->lastuser = user;
	} else {
		/* Fill the new user struct */	
		user->user_no = conf->lastuser->user_no + 1; 
		user->prevuser = conf->lastuser;
		user->nextuser = NULL;
		if (conf->lastuser->nextuser != NULL) {
			ast_log(LOG_WARNING, "Error in User Management!\n");
			ast_mutex_unlock(&conflock);
			goto outrun;
		} else {
			conf->lastuser->nextuser = user;
			conf->lastuser = user;
		}
	}
	user->chan = chan;
	user->userflags = confflags;
	user->adminflags = 0;
	ast_mutex_unlock(&conflock);
	origquiet = confflags & CONFFLAG_QUIET;
	if (confflags & CONFFLAG_EXIT_CONTEXT) {
		if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) 
			strncpy(exitcontext, agifile, sizeof(exitcontext) - 1);
		else if (!ast_strlen_zero(chan->macrocontext)) 
			strncpy(exitcontext, chan->macrocontext, sizeof(exitcontext) - 1);
		else
			strncpy(exitcontext, chan->context, sizeof(exitcontext) - 1);
	}
	while((confflags & CONFFLAG_WAITMARKED) && (conf->markedusers == 0)) {
		confflags &= ~CONFFLAG_QUIET;
		confflags |= origquiet;
		/* XXX Announce that we're waiting on the conference lead to join */
		if (!(confflags & CONFFLAG_QUIET)) {
			res = ast_streamfile(chan, "vm-dialout", chan->language);
			if (!res)
				res = ast_waitstream(chan, "");
		} else
			res = 0;
		/* If we're waiting with hold music, set to silent mode */
		if (!res) {
			confflags |= CONFFLAG_QUIET;
			ast_moh_start(chan, NULL);
			res = ast_safe_sleep_conditional(chan, 60000, confnonzero, conf);
			ast_moh_stop(chan);
		}
		if (res < 0) {
			ast_log(LOG_DEBUG, "Got hangup on '%s' already\n", chan->name);
			goto outrun;
		}
	}
	
	if (!(confflags & CONFFLAG_QUIET) && conf->users == 1) {
		if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) {
			if (ast_waitstream(chan, "") < 0)
				goto outrun;
		} else
			goto outrun;
	}

	/* Set it into linear mode (write) */
	if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
		ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
		goto outrun;
	}

	/* Set it into linear mode (read) */
	if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
		ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
		goto outrun;
	}
	ast_indicate(chan, -1);
	retryzap = strcasecmp(chan->type, "Zap");
zapretry:
	origfd = chan->fds[0];
	if (retryzap) {
		fd = open("/dev/zap/pseudo", O_RDWR);
		if (fd < 0) {
			ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
			goto outrun;
		}
		using_pseudo = 1;
		/* Make non-blocking */
		flags = fcntl(fd, F_GETFL);
		if (flags < 0) {
			ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
			close(fd);
			goto outrun;
		}
		if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
			ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
			close(fd);
			goto outrun;
		}
		/* Setup buffering information */
		memset(&bi, 0, sizeof(bi));
		bi.bufsize = CONF_SIZE/2;
		bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
		bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
		bi.numbufs = 4;
		if (ioctl(fd, ZT_SET_BUFINFO, &bi)) {
			ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
			close(fd);
			goto outrun;
		}
		x = 1;
		if (ioctl(fd, ZT_SETLINEAR, &x)) {
			ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
			close(fd);
			goto outrun;
		}
		nfds = 1;
	} else {
		/* XXX Make sure we're not running on a pseudo channel XXX */
		fd = chan->fds[0];
		nfds = 0;
	}
	memset(&ztc, 0, sizeof(ztc));
	/* Check to see if we're in a conference... */
	ztc.chan = 0;	
	if (ioctl(fd, ZT_GETCONF, &ztc)) {
		ast_log(LOG_WARNING, "Error getting conference\n");
		close(fd);
		goto outrun;
	}
	if (ztc.confmode) {
		/* Whoa, already in a conference...  Retry... */
		if (!retryzap) {
			ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
			retryzap = 1;
			goto zapretry;
		}
	}
	memset(&ztc, 0, sizeof(ztc));
	/* Add us to the conference */
	ztc.chan = 0;	
	ztc.confno = conf->zapconf;
	if (confflags & CONFFLAG_MONITOR)
		ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
	else if (confflags & CONFFLAG_TALKER)
		ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
	else 
		ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;

	if (ioctl(fd, ZT_SETCONF, &ztc)) {
		ast_log(LOG_WARNING, "Error setting conference\n");
		close(fd);
		goto outrun;
	}
	ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf);

	manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 
			"Channel: %s\r\n"
			"Uniqueid: %s\r\n"
			"Meetme: %s\r\n"
			"Usernum: %i\r\n",
			chan->name, chan->uniqueid, conf->confno, user->user_no);

	if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
		firstpass = 1;
		if (!(confflags & CONFFLAG_QUIET))
			conf_play(conf, ENTER);
	}

	if (confflags & CONFFLAG_AGI) {

		/* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
		  or use default filename of conf-background.agi */

		agifile = pbx_builtin_getvar_helper(chan,"MEETME_AGI_BACKGROUND");
		if (!agifile)
			agifile = agifiledefault;

		if (!strcasecmp(chan->type,"Zap")) {
			/*  Set CONFMUTE mode on Zap channel to mute DTMF tones */
			x = 1;
			ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
		}
		/* Find a pointer to the agi app and execute the script */
		app = pbx_findapp("agi");
		if (app) {
			ret = pbx_exec(chan, app, agifile, 1);
		} else {
			ast_log(LOG_WARNING, "Could not find application (agi)\n");
			ret = -2;
		}
		if (!strcasecmp(chan->type,"Zap")) {
			/*  Remove CONFMUTE mode on Zap channel */
			x = 0;
			ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
		}
	} else {
		if (!strcasecmp(chan->type,"Zap") && (confflags & CONFFLAG_STARMENU)) {
			/*  Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */
			x = 1;
			ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
		}	
		for(;;) {
			outfd = -1;
			ms = -1;
			c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
			
			/* Update the struct with the actual confflags */
			user->userflags = confflags;
			
			/* trying to add moh for single person conf */
			if (confflags & CONFFLAG_MOH) {
				if (conf->users == 1) {
					if (musiconhold == 0) {
						ast_moh_start(chan, NULL);
						musiconhold = 1;
					} 
				} else {
					if (musiconhold) {
						ast_moh_stop(chan);
						musiconhold = 0;
					}
				}
			}
			
			/* Leave if the last marked user left */
			if (conf->markedusers == 0 && confflags & CONFFLAG_MARKEDEXIT) {
				ret = -1;
				break;
			}
	
			/* Check if the admin changed my modes */
			if (user->adminflags) {			
				/* Set the new modes */
				if ((user->adminflags & ADMINFLAG_MUTED) && (ztc.confmode & ZT_CONF_TALKER)) {
					ztc.confmode ^= ZT_CONF_TALKER;
					if (ioctl(fd, ZT_SETCONF, &ztc)) {
						ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
						ret = -1;
						break;
					}
				}
				if (!(user->adminflags & ADMINFLAG_MUTED) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
					ztc.confmode |= ZT_CONF_TALKER;
					if (ioctl(fd, ZT_SETCONF, &ztc)) {
						ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
						ret = -1;
						break;
					}
				}
				if (user->adminflags & ADMINFLAG_KICKME) {
					//You have been kicked.
					if (!ast_streamfile(chan, "conf-kicked", chan->language))
						ast_waitstream(chan, "");
					ret = 0;
					break;
				}
			} else if (!(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
				ztc.confmode |= ZT_CONF_TALKER;
				if (ioctl(fd, ZT_SETCONF, &ztc)) {
					ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
					ret = -1;
					break;
				}
			}

			if (c) {
				if (c->fds[0] != origfd) {
					if (using_pseudo) {
						/* Kill old pseudo */
						close(fd);
					}
					ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
					retryzap = 0;
					using_pseudo = 0;
					goto zapretry;
				}
				f = ast_read(c);
				if (!f) 
					break;
				if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) {
					char tmp[2];
					tmp[0] = f->subclass;
					tmp[1] = '\0';
					if (ast_exists_extension(chan, exitcontext, tmp, 1, chan->callerid)) {
						strncpy(chan->context, exitcontext, sizeof(chan->context) - 1);
						strncpy(chan->exten, tmp, sizeof(chan->exten) - 1);
						chan->priority = 0;
						ret = 0;
						break;
					}
				} else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
					ret = 0;
					break;
				} else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
					if (musiconhold) {
			   			ast_moh_stop(chan);
					}
					if ((confflags & CONFFLAG_ADMIN)) {
						/* Admin menu */
						if (!menu_active) {
							menu_active = 1;
							/* Record this sound! */
							if (!ast_streamfile(chan, "conf-adminmenu", chan->language))
								dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
							else
								dtmf = 0;
						} else 
							dtmf = f->subclass;
						if (dtmf) {
							switch(dtmf) {
								case '1': /* Un/Mute */
									menu_active = 0;
		 							if (ztc.confmode & ZT_CONF_TALKER) {
	 						       		ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
	 						       		confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER;
									} else {
										ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
										confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER;
									}
									if (ioctl(fd, ZT_SETCONF, &ztc)) {
										ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
										ret = -1;
										break;
									}
									if (ztc.confmode & ZT_CONF_TALKER) {
										if (!ast_streamfile(chan, "conf-unmuted", chan->language))
											ast_waitstream(chan, "");
									} else {
										if (!ast_streamfile(chan, "conf-muted", chan->language))
											ast_waitstream(chan, "");
									}
									break;
								case '2': /* Un/Lock the Conference */
									menu_active = 0;
									if (conf->locked) {
										conf->locked = 0;
										if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
											ast_waitstream(chan, "");
									} else {
										conf->locked = 1;
										if (!ast_streamfile(chan, "conf-lockednow", chan->language))
											ast_waitstream(chan, "");
									}
									break;
								default:
									menu_active = 0;
									/* Play an error message! */
									if (!ast_streamfile(chan, "conf-errormenu", chan->language))
										ast_waitstream(chan, "");
									break;
							}
						}
					} else {
						/* User menu */
						if (!menu_active) {
							menu_active = 1;
							/* Record this sound! */
							if (!ast_streamfile(chan, "conf-usermenu", chan->language))
								dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
							else
								dtmf = 0;
						} else 
							dtmf = f->subclass;
						if (dtmf) {
							switch(dtmf) {
								case '1': /* Un/Mute */
									menu_active = 0;
		 							if (ztc.confmode & ZT_CONF_TALKER) {
	 						       		ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
	 						       		confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER;
									} else if (!(user->adminflags & ADMINFLAG_MUTED)) {
										ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
										confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER;
									}
									if (ioctl(fd, ZT_SETCONF, &ztc)) {
										ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
										ret = -1;
										break;
									}
									if (ztc.confmode & ZT_CONF_TALKER) {
										if (!ast_streamfile(chan, "conf-unmuted", chan->language))
											ast_waitstream(chan, "");
									} else {
										if (!ast_streamfile(chan, "conf-muted", chan->language))
											ast_waitstream(chan, "");
									}
									break;
								default:
									menu_active = 0;
									/* Play an error message! */
									if (!ast_streamfile(chan, "conf-errormenu", chan->language))
										ast_waitstream(chan, "");
									break;
							}
						}
					}
					if (musiconhold) {
			   			ast_moh_start(chan, NULL);
					}
				} else if (using_pseudo) {
					if (f->frametype == AST_FRAME_VOICE) {
						if (f->subclass == AST_FORMAT_SLINEAR) {
							/* Carefully write */
							careful_write(fd, f->data, f->datalen);
						} else
							ast_log(LOG_WARNING, "Huh?  Got a non-linear (%d) frame in the conference\n", f->subclass);
					}
				}
				ast_frfree(f);
			} else if (outfd > -1) {
				res = read(outfd, buf, CONF_SIZE);
				if (res > 0) {
					memset(&fr, 0, sizeof(fr));
					fr.frametype = AST_FRAME_VOICE;
					fr.subclass = AST_FORMAT_SLINEAR;
					fr.datalen = res;
					fr.samples = res/2;
					fr.data = buf;
					fr.offset = AST_FRIENDLY_OFFSET;
					if (ast_write(chan, &fr) < 0) {
						ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
						/* break; */
					}
				} else 
					ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
			}
		}
	}
	if (using_pseudo)
		close(fd);
	else {
		/* Take out of conference */
		/* Add us to the conference */
		ztc.chan = 0;	
		ztc.confno = 0;
		ztc.confmode = 0;
		if (ioctl(fd, ZT_SETCONF, &ztc)) {
			ast_log(LOG_WARNING, "Error setting conference\n");
		}
	}
	if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
		conf_play(conf, LEAVE);

outrun:
	ast_mutex_lock(&conflock);
	if (user->user_no) { /* Only cleanup users who really joined! */
		manager_event(EVENT_FLAG_CALL, "MeetmeLeave", 
			"Channel: %s\r\n"
			"Uniqueid: %s\r\n"
			"Meetme: %s\r\n"
			"Usernum: %i\r\n",
			chan->name, chan->uniqueid, conf->confno, user->user_no);
		prev = NULL;
		conf->users--;
		if (confflags & CONFFLAG_MARKEDUSER) 
			conf->markedusers--;
		cur = confs;
		if (!conf->users) {
			/* No more users -- close this one out */
			while(cur) {
				if (cur == conf) {
					if (prev)
						prev->next = conf->next;
					else
						confs = conf->next;
					break;
				}
				prev = cur;
				cur = cur->next;
			}
			if (!cur) 
				ast_log(LOG_WARNING, "Conference not found\n");
			if (conf->chan)
				ast_hangup(conf->chan);
			else
				close(conf->fd);
			free(conf);
		} else {
			/* Remove the user struct */ 
			if (user == conf->firstuser) {
				if (user->nextuser) {
					/* There is another entry */
					user->nextuser->prevuser = NULL;
				} else {
					/* We are the only entry */
					conf->lastuser = NULL;
				}
				/* In either case */
				conf->firstuser = user->nextuser;
			} else if (user == conf->lastuser){
				if (user->prevuser)
					user->prevuser->nextuser = NULL;
				else
					ast_log(LOG_ERROR, "Bad bad bad!  We're the last, not the first, but nobody before us??\n");
				conf->lastuser = user->prevuser;
			} else {
				if (user->nextuser)
					user->nextuser->prevuser = user->prevuser;
				else
					ast_log(LOG_ERROR, "Bad! Bad! Bad! user->nextuser is NULL but we're not the end!\n");
				if (user->prevuser)
					user->prevuser->nextuser = user->nextuser;
				else
					ast_log(LOG_ERROR, "Bad! Bad! Bad! user->prevuser is NULL but we're not the beginning!\n");
			}
		}
		/* Return the number of seconds the user was in the conf */
		snprintf(meetmesecs, sizeof(meetmesecs), "%i", (int) (time(NULL) - user->jointime));
		pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
	}
	free(user);
	ast_mutex_unlock(&conflock);
	return ret;
}
示例#22
0
static int chanspy_exec(struct ast_channel *chan, void *data)
{
	struct localuser *u;
	struct ast_channel *peer=NULL, *prev=NULL;
	char name[AST_NAME_STRLEN],
		peer_name[AST_NAME_STRLEN + 5],
		*args,
		*ptr = NULL,
		*options = NULL,
		*spec = NULL,
		*argv[5],
		*mygroup = NULL,
		*recbase = NULL;
	int res = -1,
		volfactor = 0,
		silent = 0,
		argc = 0,
		bronly = 0,
		chosen = 0,
		count=0,
		waitms = 100,
		num = 0,
		oldrf = 0,
		oldwf = 0,
		fd = 0;
	struct ast_flags flags;
	signed char zero_volume = 0;

	if (!(args = ast_strdupa((char *)data))) {
		ast_log(LOG_ERROR, "Out of memory!\n");
		return -1;
	}

	LOCAL_USER_ADD(u);

	oldrf = chan->readformat;
	oldwf = chan->writeformat;
	if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
		ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
		LOCAL_USER_REMOVE(u);
		return -1;
	}
	
	if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
		LOCAL_USER_REMOVE(u);
		return -1;
	}

	ast_answer(chan);

	ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */

	if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
		spec = argv[0];
		if ( argc > 1) {
			options = argv[1];
		}
		if (ast_strlen_zero(spec) || !strcmp(spec, "all")) {
			spec = NULL;
		}
	}
	
	if (options) {
		char *opts[OPT_ARG_ARRAY_SIZE];
		ast_app_parse_options(chanspy_opts, &flags, opts, options);
		if (ast_test_flag(&flags, OPTION_GROUP)) {
			mygroup = opts[OPT_ARG_GROUP];
		}
		if (ast_test_flag(&flags, OPTION_RECORD)) {
			if (!(recbase = opts[OPT_ARG_RECORD])) {
				recbase = "chanspy";
			}
		}
		silent = ast_test_flag(&flags, OPTION_QUIET);
		bronly = ast_test_flag(&flags, OPTION_BRIDGED);
		if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
			int vol;

			if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
				ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
			else
				volfactor = vol;
			}
	}
	else 
		ast_clear_flag(&flags, AST_FLAGS_ALL);

	if (recbase) {
		char filename[512];
		snprintf(filename,sizeof(filename),"%s/%s.%d.raw",ast_config_AST_MONITOR_DIR, recbase, (int)time(NULL));
		if ((fd = open(filename, O_CREAT | O_WRONLY, O_TRUNC, 0644)) <= 0) {
			ast_log(LOG_WARNING, "Cannot open %s for recording\n", filename);
			fd = 0;
		}
	}

	for(;;) {
		if (!silent) {
			res = ast_streamfile(chan, "beep", chan->language);
			if (!res)
				res = ast_waitstream(chan, "");
			if (res < 0) {
				ast_clear_flag(chan, AST_FLAG_SPYING);
				break;
			}
		}

		count = 0;
		res = ast_waitfordigit(chan, waitms);
		if (res < 0) {
			ast_clear_flag(chan, AST_FLAG_SPYING);
			break;
		}
				
		peer = local_channel_walk(NULL);
		prev=NULL;
		while(peer) {
			if (peer != chan) {
				char *group = NULL;
				int igrp = 1;

				if (peer == prev && !chosen) {
					break;
				}
				chosen = 0;
				group = pbx_builtin_getvar_helper(peer, "SPYGROUP");
				if (mygroup) {
					if (!group || strcmp(mygroup, group)) {
						igrp = 0;
					}
				}
				
				if (igrp && (!spec || ((strlen(spec) <= strlen(peer->name) &&
							!strncasecmp(peer->name, spec, strlen(spec)))))) {
					if (peer && (!bronly || ast_bridged_channel(peer)) &&
					    !ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) {
						int x = 0;
						strncpy(peer_name, "spy-", 5);
						strncpy(peer_name + strlen(peer_name), peer->name, AST_NAME_STRLEN);
						ptr = strchr(peer_name, '/');
						*ptr = '\0';
						ptr++;
						for (x = 0 ; x < strlen(peer_name) ; x++) {
							if (peer_name[x] == '/') {
								break;
							}
							peer_name[x] = tolower(peer_name[x]);
						}

						if (!silent) {
							if (ast_fileexists(peer_name, NULL, NULL) != -1) {
								res = ast_streamfile(chan, peer_name, chan->language);
								if (!res)
									res = ast_waitstream(chan, "");
								if (res)
									break;
							} else
								res = ast_say_character_str(chan, peer_name, "", chan->language);
							if ((num=atoi(ptr))) 
								ast_say_digits(chan, atoi(ptr), "", chan->language);
						}
						count++;
						prev = peer;
						res = channel_spy(chan, peer, &volfactor, fd);
						if (res == -1) {
							break;
						} else if (res > 1 && spec) {
							snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res);
							if ((peer = local_get_channel_begin_name(name))) {
								chosen = 1;
							}
							continue;
						}
					}
				}
			}
			if ((peer = local_channel_walk(peer)) == NULL) {
				break;
			}
		}
		waitms = count ? 100 : 5000;
	}
	

	if (fd > 0) {
		close(fd);
	}

	if (oldrf && ast_set_read_format(chan, oldrf) < 0) {
		ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
	}
	
	if (oldwf && ast_set_write_format(chan, oldwf) < 0) {
		ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
	}

	ast_clear_flag(chan, AST_FLAG_SPYING);

	ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);

	ALL_DONE(u, res);
}
示例#23
0
int ast_control_streamfile(struct ast_channel *chan, char *file, char *fwd, char *rev, char *stop, char *pause, int skipms)
{
    struct timeval started, ended;
    long elapsed = 0,last_elapsed =0;
    char *breaks=NULL;
    char *end=NULL;
    int blen=2;
    int res=0;

    if (stop)
        blen += strlen(stop);
    if (pause)
        blen += strlen(pause);

    if (blen > 2) {
        breaks = alloca(blen + 1);
        breaks[0] = '\0';
        strcat(breaks, stop);
        strcat(breaks, pause);
    }
    if (chan->_state != AST_STATE_UP)
        res = ast_answer(chan);

    if (chan)
        ast_stopstream(chan);


    if (file) {
        if ((end = strchr(file,':'))) {
            if (!strcasecmp(end, ":end")) {
                *end = '\0';
                end++;
            }
        }
    }

    for (;;) {
        gettimeofday(&started,NULL);

        if (chan)
            ast_stopstream(chan);
        res = ast_streamfile(chan, file, chan->language);
        if (!res) {
            if (end) {
                ast_seekstream(chan->stream, 0, SEEK_END);
                end=NULL;
            }
            res = 1;
            if (elapsed) {
                ast_stream_fastforward(chan->stream, elapsed);
                last_elapsed = elapsed - 200;
            }
            if (res)
                res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
            else
                break;
        }

        if (res < 1)
            break;

        if (pause != NULL && strchr(pause, res)) {
            gettimeofday(&ended, NULL);
            elapsed = (((ended.tv_sec * 1000) + ended.tv_usec / 1000) - ((started.tv_sec * 1000) + started.tv_usec / 1000) + last_elapsed);
            for(;;) {
                if (chan)
                    ast_stopstream(chan);
                res = ast_waitfordigit(chan, 1000);
                if (res == 0)
                    continue;
                else if (res == -1 || strchr(pause, res) || (stop && strchr(stop, res)))
                    break;
            }
            if (res == *pause) {
                res = 0;
                continue;
            }
        }
        if (res == -1)
            break;

        /* if we get one of our stop chars, return it to the calling function */
        if (stop && strchr(stop, res)) {
            /* res = 0; */
            break;
        }
    }
    if (chan)
        ast_stopstream(chan);

    return res;
}
示例#24
0
/*--- conf_exec: The meetme() application */
static int conf_exec(struct ast_channel *chan, void *data)
{
	int res=-1;
	struct localuser *u;
	char confno[AST_MAX_EXTENSION] = "";
	int allowretry = 0;
	int retrycnt = 0;
	struct ast_conference *cnf;
	int confflags = 0;
	int dynamic = 0;
	int empty = 0, empty_no_pin = 0;
	char *notdata, *info, *inflags = NULL, *inpin = NULL, the_pin[AST_MAX_EXTENSION] = "";

	if (!data || ast_strlen_zero(data)) {
		allowretry = 1;
		notdata = "";
	} else {
		notdata = data;
	}
	LOCAL_USER_ADD(u);
	if (chan->_state != AST_STATE_UP)
		ast_answer(chan);

	info = ast_strdupa((char *)notdata);

	if (info) {
		char *tmp = strsep(&info, "|");
		strncpy(confno, tmp, sizeof(confno) - 1);
		if (ast_strlen_zero(confno)) {
			allowretry = 1;
		}
	}
	if (info)
		inflags = strsep(&info, "|");
	if (info)
		inpin = strsep(&info, "|");
	if (inpin)
		strncpy(the_pin, inpin, sizeof(the_pin) - 1);

	if (inflags) {
		if (strchr(inflags, 'a'))
			confflags |= CONFFLAG_ADMIN;
		if (strchr(inflags, 'm'))
			confflags |= CONFFLAG_MONITOR;
		if (strchr(inflags, 'p'))
			confflags |= CONFFLAG_POUNDEXIT;
		if (strchr(inflags, 's'))
			confflags |= CONFFLAG_STARMENU;
		if (strchr(inflags, 't'))
			confflags |= CONFFLAG_TALKER;
		if (strchr(inflags, 'q'))
			confflags |= CONFFLAG_QUIET;
		if (strchr(inflags, 'M'))
			confflags |= CONFFLAG_MOH;
		if (strchr(inflags, 'x'))
			confflags |= CONFFLAG_MARKEDEXIT;
		if (strchr(inflags, 'X'))
			confflags |= CONFFLAG_EXIT_CONTEXT;
		if (strchr(inflags, 'A'))
			confflags |= CONFFLAG_MARKEDUSER;
		if (strchr(inflags, 'b'))
			confflags |= CONFFLAG_AGI;
		if (strchr(inflags, 'w'))
			confflags |= CONFFLAG_WAITMARKED;
		if (strchr(inflags, 'd'))
			dynamic = 1;
		if (strchr(inflags, 'D')) {
			dynamic = 1;
			if (! inpin) {
				strncpy(the_pin, "q", sizeof(the_pin) - 1);
			}
		}
		if (strchr(inflags, 'e'))
			empty = 1;
		if (strchr(inflags, 'E')) {
			empty = 1;
			empty_no_pin = 1;
		}
	}

	do {
		if (retrycnt > 3)
			allowretry = 0;
		if (empty) {
			int i, map[1024];
			struct ast_config *cfg;
			struct ast_variable *var;
			int confno_int;

			memset(map, 0, sizeof(map));

			ast_mutex_lock(&conflock);
			cnf = confs;
			while (cnf) {
				if (sscanf(cnf->confno, "%d", &confno_int) == 1) {
					/* Disqualify in use conference */
					if (confno_int >= 0 && confno_int < 1024)
						map[confno_int]++;
				}
				cnf = cnf->next;
			}
			ast_mutex_unlock(&conflock);

			/* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
			if ((empty_no_pin) || (!dynamic)) {
				cfg = ast_load("meetme.conf");
				if (cfg) {
					var = ast_variable_browse(cfg, "rooms");
					while(var) {
						if (!strcasecmp(var->name, "conf")) {
							char *stringp = ast_strdupa(var->value);
							if (stringp) {
								char *confno_tmp = strsep(&stringp, "|,");
								int found = 0;
								if (sscanf(confno_tmp, "%d", &confno_int) == 1) {
									if ((confno_int >= 0) && (confno_int < 1024)) {
										if (stringp && empty_no_pin) {
											map[confno_int]++;
										}
									}
								}
								if (! dynamic) {
									/* For static:  run through the list and see if this conference is empty */
									ast_mutex_lock(&conflock);
									cnf = confs;
									while (cnf) {
										if (!strcmp(confno_tmp, cnf->confno)) {
											/* The conference exists, therefore it's not empty */
											found = 1;
											break;
										}
										cnf = cnf->next;
									}
									ast_mutex_unlock(&conflock);
									if (!found) {
										/* At this point, we have a confno_tmp (static conference) that is empty */
										if ((empty_no_pin && ((!stringp) || (stringp && (stringp[0] == '\0')))) || (!empty_no_pin)) {
										/* Case 1:  empty_no_pin and pin is nonexistant (NULL)
										 * Case 2:  empty_no_pin and pin is blank (but not NULL)
										 * Case 3:  not empty_no_pin
										 */
											strncpy(confno, confno_tmp, sizeof(confno) - 1);
											break;
											/* XXX the map is not complete (but we do have a confno) */
										}
									}
								}
							} else {
								ast_log(LOG_ERROR, "Out of memory\n");
							}
						}
						var = var->next;
					}
					ast_destroy(cfg);
				}
			}
			/* Select first conference number not in use */
			if (ast_strlen_zero(confno) && dynamic) {
				for (i=0;i<1024;i++) {
					if (!map[i]) {
						snprintf(confno, sizeof(confno), "%d", i);
						break;
					}
				}
			}

			/* Not found? */
			if (ast_strlen_zero(confno)) {
				res = ast_streamfile(chan, "conf-noempty", chan->language);
				if (!res)
					ast_waitstream(chan, "");
			} else {
				if (sscanf(confno, "%d", &confno_int) == 1) {
					res = ast_streamfile(chan, "conf-enteringno", chan->language);
					if (!res) {
						ast_waitstream(chan, "");
						res = ast_say_digits(chan, confno_int, "", chan->language);
					}
				} else {
					ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
				}
			}
		}
		while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
			/* Prompt user for conference number */
			res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
			if (res < 0) {
				/* Don't try to validate when we catch an error */
				confno[0] = '\0';
				allowretry = 0;
				break;
			}
		}
		if (!ast_strlen_zero(confno)) {
			/* Check the validity of the conference */
			cnf = find_conf(chan, confno, 1, dynamic, the_pin);
			if (!cnf) {
				res = ast_streamfile(chan, "conf-invalid", chan->language);
				if (!res)
					ast_waitstream(chan, "");
				res = -1;
				if (allowretry)
					confno[0] = '\0';
			} else {
				if (!ast_strlen_zero(cnf->pin)) {
					char pin[AST_MAX_EXTENSION]="";
					int j;

					/* Allow the pin to be retried up to 3 times */
					for (j=0; j<3; j++) {
						if (*the_pin) {
							strncpy(pin, the_pin, sizeof(pin) - 1);
							res = 0;
						} else {
							/* Prompt user for pin if pin is required */
							res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
						}
						if (res >= 0) {
							if (!strcasecmp(pin, cnf->pin)) {
								/* Pin correct */
								allowretry = 0;
								/* Run the conference */
								res = conf_run(chan, cnf, confflags);
								break;
							} else {
								/* Pin invalid */
								res = ast_streamfile(chan, "conf-invalidpin", chan->language);
								if (!res)
									ast_waitstream(chan, AST_DIGIT_ANY);
								if (res < 0)
									break;
								pin[0] = res;
								pin[1] = '\0';
								res = -1;
								if (allowretry)
									confno[0] = '\0';
							}
						} else {
							res = -1;
							allowretry = 0;
							break;
						}

						/* Don't retry pin with a static pin */
						if (*the_pin) {
							break;
						}
					}
				} else {
					/* No pin required */
					allowretry = 0;

					/* Run the conference */
					res = conf_run(chan, cnf, confflags);
				}
			}
		}
	} while (allowretry);
	/* Do the conference */
	LOCAL_USER_REMOVE(u);
	return res;
}
示例#25
0
int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path)
{
    char *fmts;
    int d;
    char comment[256];
    int x, fmtcnt=1, res=-1,outmsg=0;
    struct ast_frame *f;
    struct ast_filestream *others[MAX_OTHER_FORMATS];
    char *sfmt[MAX_OTHER_FORMATS];
    char *stringp=NULL;
    time_t start, end;
    struct ast_dsp *sildet=NULL;   	/* silence detector dsp */
    int totalsilence = 0;
    int dspsilence = 0;
    int gotsilence = 0;		/* did we timeout for silence? */
    int rfmt=0;

    if (silencethreshold < 0)
        silencethreshold = global_silence_threshold;

    if (maxsilence < 0)
        maxsilence = global_maxsilence;

    /* barf if no pointer passed to store duration in */
    if (duration == NULL) {
        ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
        return -1;
    }

    ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
    snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);

    if (playfile) {
        d = ast_play_and_wait(chan, playfile);
        if (d > -1)
            d = ast_streamfile(chan, "beep",chan->language);
        if (!d)
            d = ast_waitstream(chan,"");
        if (d < 0)
            return -1;
    }

    fmts = ast_strdupa(fmt);

    stringp=fmts;
    strsep(&stringp, "|");
    ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
    sfmt[0] = ast_strdupa(fmts);

    while((fmt = strsep(&stringp, "|"))) {
        if (fmtcnt > MAX_OTHER_FORMATS - 1) {
            ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
            break;
        }
        sfmt[fmtcnt++] = ast_strdupa(fmt);
    }

    time(&start);
    end=start;  /* pre-initialize end to be same as start in case we never get into loop */
    for (x=0; x<fmtcnt; x++) {
        others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
        ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing:  %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);

        if (!others[x]) {
            break;
        }
    }

    if (path)
        ast_unlock_path(path);


    if (maxsilence > 0) {
        sildet = ast_dsp_new(); /* Create the silence detector */
        if (!sildet) {
            ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
            return -1;
        }
        ast_dsp_set_threshold(sildet, silencethreshold);
        rfmt = chan->readformat;
        res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
        if (res < 0) {
            ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
            ast_dsp_free(sildet);
            return -1;
        }
    }

    if (x == fmtcnt) {
        /* Loop forever, writing the packets we read to the writer(s), until
           we read a # or get a hangup */
        f = NULL;
        for(;;) {
            res = ast_waitfor(chan, 2000);
            if (!res) {
                ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
                /* Try one more time in case of masq */
                res = ast_waitfor(chan, 2000);
                if (!res) {
                    ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
                    res = -1;
                }
            }

            if (res < 0) {
                f = NULL;
                break;
            }
            f = ast_read(chan);
            if (!f)
                break;
            if (f->frametype == AST_FRAME_VOICE) {
                /* write each format */
                for (x=0; x<fmtcnt; x++) {
                    res = ast_writestream(others[x], f);
                }

                /* Silence Detection */
                if (maxsilence > 0) {
                    dspsilence = 0;
                    ast_dsp_silence(sildet, f, &dspsilence);
                    if (dspsilence)
                        totalsilence = dspsilence;
                    else
                        totalsilence = 0;

                    if (totalsilence > maxsilence) {
                        /* Ended happily with silence */
                        if (option_verbose > 2)
                            ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
                        ast_frfree(f);
                        gotsilence = 1;
                        outmsg=2;
                        break;
                    }
                }
                /* Exit on any error */
                if (res) {
                    ast_log(LOG_WARNING, "Error writing frame\n");
                    ast_frfree(f);
                    break;
                }
            } else if (f->frametype == AST_FRAME_VIDEO) {
                /* Write only once */
                ast_writestream(others[0], f);
            } else if (f->frametype == AST_FRAME_DTMF) {
                if (f->subclass == '#') {
                    if (option_verbose > 2)
                        ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
                    res = '#';
                    outmsg = 2;
                    ast_frfree(f);
                    break;
                }
            }
            if (f->subclass == '0') {
                /* Check for a '0' during message recording also, in case caller wants operator */
                if (option_verbose > 2)
                    ast_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass);
                res = '0';
                outmsg = 0;
                ast_frfree(f);
                break;
            }
            if (maxtime) {
                time(&end);
                if (maxtime < (end - start)) {
                    if (option_verbose > 2)
                        ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
                    outmsg = 2;
                    res = 't';
                    ast_frfree(f);
                    break;
                }
            }
            ast_frfree(f);
        }
        if (end == start) time(&end);
        if (!f) {
            if (option_verbose > 2)
                ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
            res = -1;
            outmsg=1;
        }
    } else {
        ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
    }

    *duration = end - start;

    for (x=0; x<fmtcnt; x++) {
        if (!others[x])
            break;
        if (res > 0) {
            if (totalsilence)
                ast_stream_rewind(others[x], totalsilence-200);
            else
                ast_stream_rewind(others[x], 200);
        }
        ast_truncstream(others[x]);
        ast_closestream(others[x]);
    }
    if (rfmt) {
        if (ast_set_read_format(chan, rfmt)) {
            ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
        }
    }
    if (outmsg > 1) {
        /* Let them know recording is stopped */
        if(!ast_streamfile(chan, "auth-thankyou", chan->language))
            ast_waitstream(chan, "");
    }
    if (sildet)
        ast_dsp_free(sildet);
    return res;
}
static int nv_background_detect_exec(struct ast_channel *chan, const char *data)
{
	int res = 0;
	char tmp[256] = "\0";
	char *p = NULL;
	char *filename = NULL;
	char *options = NULL;
	char *silstr = NULL;
	char *minstr = NULL;
	char *maxstr = NULL;
	struct ast_frame *fr = NULL;
	struct ast_frame *fr2 = NULL;
	int notsilent = 0;
	struct timeval start = {0, 0}, end = {0, 0};
	int sildur = 1000;
	int mindur = 100;
	int maxdur = -1;
	int skipanswer = 0;
	int noextneeded = 0;
	int ignoredtmf = 0;
	int ignorefax = 0;
	int ignoretalk = 0;
	int x = 0;
	struct ast_format* origrformat = NULL;
	int features = 0;
	struct ast_dsp *dsp = NULL;
	struct ast_format_cap *cap;
	struct ast_format linearFormat;
	
	/* linear format capabilities */
	ast_format_set(&linearFormat, AST_FORMAT_SLINEAR, 0);
	cap = ast_format_cap_alloc_nolock();
	ast_format_cap_add(cap, &linearFormat);
	/* done */
	
	pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "");
	pbx_builtin_setvar_helper(chan, "FAXEXTEN", "");
	pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "");
	pbx_builtin_setvar_helper(chan, "TALK_DETECTED", "");
	
	if (!data || ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "NVBackgroundDetect requires an argument (filename)\n");
		return -1;
	}	
	
	strncpy(tmp, data, sizeof(tmp)-1);
	p = tmp;
	
	filename = strsep(&p, ",");
	options = strsep(&p, ",");
	silstr = strsep(&p, ",");
	minstr = strsep(&p, ",");	
	maxstr = strsep(&p, ",");	
	
	if (options) {
		if (strchr(options, 'n'))
			skipanswer = 1;
		if (strchr(options, 'x'))
			noextneeded = 1;
		if (strchr(options, 'd'))
			ignoredtmf = 1;
		if (strchr(options, 'f'))
			ignorefax = 1;
		if (strchr(options, 't'))
			ignoretalk = 1;
	}
	
	if (silstr) {
		if ((sscanf(silstr, "%d", &x) == 1) && (x > 0))
			sildur = x;
	}
	
	if (minstr) {
		if ((sscanf(minstr, "%d", &x) == 1) && (x > 0))
			mindur = x;
	}
	
	if (maxstr) {
		if ((sscanf(maxstr, "%d", &x) == 1) && (x > 0))
			maxdur = x;
	}
	
	ast_log(LOG_DEBUG, "Preparing detect of '%s' (sildur=%dms, mindur=%dms, maxdur=%dms)\n", tmp, sildur, mindur, maxdur);
						
	//	LOCAL_USER_ADD(u);
	if (ast_channel_state(chan) != AST_STATE_UP && !skipanswer) {
		/* Otherwise answer unless we're supposed to send this while on-hook */
		res = ast_answer(chan);
	}
	if (!res) {
		origrformat = ast_channel_readformat(chan); //chan->readformat;
		
// 		if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR))) 
// 			ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
		
		if ((res = ast_set_read_format_from_cap(chan, cap)) ){
			ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
		}
		
		
		
	}
	if (!(dsp = ast_dsp_new())) {
		ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
		res = -1;
	}

	if (dsp) {	
		if (!ignoretalk)
			; /* features |= DSP_FEATURE_SILENCE_SUPPRESS; */
		if (!ignorefax)
			features |= DSP_FEATURE_FAX_DETECT;
		//if (!ignoredtmf)
			features |= DSP_FEATURE_DIGIT_DETECT;
			
		ast_dsp_set_threshold(dsp, 256);
		ast_dsp_set_features(dsp, features | DSP_DIGITMODE_RELAXDTMF);
		ast_dsp_set_digitmode(dsp, DSP_DIGITMODE_DTMF);
	}
	
	if (!res) {
		ast_stopstream(chan);
// 		res = ast_streamfile(chan, tmp, chan->language);
		res = ast_streamfile(chan, tmp, ast_channel_language(chan));
		if (!res) {
// 			while(chan->stream) {
			while( ast_channel_stream(chan) ) {
// 				res = ast_sched_wait(chan->sched);
				res = ast_sched_wait( ast_channel_sched(chan) );
// 				if ((res < 0) && !chan->timingfunc) {
				if ((res < 0) && !ast_channel_timingfunc(chan)) {
					res = 0;
					break;
				}
				if (res < 0)
					res = 1000;
				res = ast_waitfor(chan, res);
				if (res < 0) {
// 					ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name);
					ast_log(LOG_WARNING, "Waitfor failed on %s\n", ast_channel_name(chan));
					break;
				} else if (res > 0) {
					fr = ast_read(chan);
					if (!fr) {
						ast_log(LOG_DEBUG, "Got hangup\n");
						res = -1;
						break;
					}
					
					fr2 = ast_dsp_process(chan, dsp, fr);
					if (!fr2) {
						ast_log(LOG_WARNING, "Bad DSP received (what happened!!)\n");
						fr2 = fr;
					} 
					
					if (fr2->frametype == AST_FRAME_DTMF) {
// 						if (fr2->subclass == 'f' && !ignorefax) {
						if (fr2->subclass.integer == 'f' && !ignorefax) {
							/* Fax tone -- Handle and return NULL */
// 							ast_log(LOG_DEBUG, "Fax detected on %s\n", chan->name);
							ast_log(LOG_DEBUG, "Fax detected on %s\n", ast_channel_name(chan));
// 							if (strcmp(chan->exten, "fax")) {
							if (strcmp(ast_channel_exten(chan), "fax")) {
								ast_log(LOG_NOTICE, "Redirecting %s to fax extension\n", ast_channel_name(chan));
								pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "1");
// 								pbx_builtin_setvar_helper(chan,"FAXEXTEN",chan->exten);
								pbx_builtin_setvar_helper(chan,"FAXEXTEN", ast_channel_exten(chan));
// 								if (ast_exists_extension(chan, chan->context, "fax", 1, chan->CALLERID_FIELD)) {
								if (ast_exists_extension(chan, ast_channel_context(chan), "fax", 1, ast_channel_caller(chan)->id.number.str)) {
									/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
// 									strncpy(chan->exten, "fax", sizeof(chan->exten)-1);
// 									chan->priority = 0;
									ast_channel_exten_set(chan, "fax");
									ast_channel_priority_set(chan, 0);
								} else
									ast_log(LOG_WARNING, "Fax detected, but no fax extension\n");
							} else
								ast_log(LOG_WARNING, "Already in a fax extension, not redirecting\n");

							res = 0;
							ast_frfree(fr);
							break;
						} else if (!ignoredtmf) {
							ast_log(LOG_DEBUG, "DTMF detected on %s\n", ast_channel_name(chan));
							char t[2];
// 							t[0] = fr2->subclass;
							t[0] = fr2->subclass.integer;
							t[1] = '\0';
// 							if (noextneeded || ast_canmatch_extension(chan, chan->context, t, 1, chan->CALLERID_FIELD)) {
							if (noextneeded || ast_canmatch_extension(chan, ast_channel_context(chan), t, 1, ast_channel_caller(chan)->id.number.str)) {
								pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "1");
								/* They entered a valid extension, or might be anyhow */
								if (noextneeded) {
									ast_log(LOG_NOTICE, "DTMF received (not matching to exten)\n");
									res = 0;
								} else {
									ast_log(LOG_NOTICE, "DTMF received (matching to exten)\n");
// 									res = fr2->subclass;
									res = fr2->subclass.integer;
								}
								ast_frfree(fr);
								break;
							} else
								ast_log(LOG_DEBUG, "Valid extension requested and DTMF did not match\n");
						}
// 					} else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR) && !ignoretalk) {
					} else if ((fr->frametype == AST_FRAME_VOICE) && ( ast_format_cap_iscompatible(cap, &fr->subclass.format)) && !ignoretalk) {
						int totalsilence;
						int ms;
						res = ast_dsp_silence(dsp, fr, &totalsilence);
						if (res && (totalsilence > sildur)) {
							/* We've been quiet a little while */
							if (notsilent) {
								/* We had heard some talking */
								gettimeofday(&end, NULL);
								ms = (end.tv_sec - start.tv_sec) * 1000;
								ms += (end.tv_usec - start.tv_usec) / 1000;
								ms -= sildur;
								if (ms < 0)
									ms = 0;
								if ((ms > mindur) && ((maxdur < 0) || (ms < maxdur))) {
									char ms_str[10];
									ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms);
// 									ast_log(LOG_NOTICE, "Redirecting %s to talk extension\n", chan->name);
									ast_log(LOG_NOTICE, "Redirecting %s to talk extension\n", ast_channel_name(chan));

									/* Save detected talk time (in milliseconds) */ 
									sprintf(ms_str, "%d", ms);	
									pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);
									
// 									if (ast_exists_extension(chan, chan->context, "talk", 1, chan->CALLERID_FIELD)) {
									if (ast_exists_extension(chan, ast_channel_context(chan), "talk", 1, ast_channel_caller(chan)->id.number.str)) {
// 										strncpy(chan->exten, "talk", sizeof(chan->exten) - 1);
// 										chan->priority = 0;
										ast_channel_exten_set(chan, "talk");
										ast_channel_priority_set(chan, 0);
									} else
										ast_log(LOG_WARNING, "Talk detected, but no talk extension\n");
									res = 0;
									ast_frfree(fr);
									break;
								} else
									ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms);
								notsilent = 0;
							}
						} else {
							if (!notsilent) {
								/* Heard some audio, mark the begining of the token */
								gettimeofday(&start, NULL);
								ast_log(LOG_DEBUG, "Start of voice token!\n");
								notsilent = 1;
							}
						}						
					}
					ast_frfree(fr);
				}
// 				ast_sched_runq(chan->sched);
				ast_sched_runq( ast_channel_sched(chan) );
			}
			ast_stopstream(chan);
		} else {
// 			ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
			ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", ast_channel_name(chan), (char *)data);
			res = 0;
		}
	} else
// 		ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
		ast_log(LOG_WARNING, "Could not answer channel '%s'\n", ast_channel_name(chan));
	
	if (res > -1) {
		if (origrformat && ast_set_read_format(chan, origrformat)) {
// 			ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", chan->name, ast_getformatname(origrformat));
			ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", ast_channel_name(chan), ast_getformatname(origrformat));
		}
	}
	
	if (dsp)
		ast_dsp_free(dsp);
	
	//	LOCAL_USER_REMOVE(u);
	
	ast_format_cap_destroy(cap);
	return res;
}
示例#27
0
int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec)
{
    int res;
    struct ast_filestream *writer;
    int rfmt;
    int totalms=0, total;

    struct ast_frame *f;
    struct ast_dsp *sildet;
    /* Play prompt if requested */
    if (prompt) {
        res = ast_streamfile(c, prompt, c->language);
        if (res < 0)
            return res;
        res = ast_waitstream(c,"");
        if (res < 0)
            return res;
    }
    rfmt = c->readformat;
    res = ast_set_read_format(c, AST_FORMAT_SLINEAR);
    if (res < 0) {
        ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
        return -1;
    }
    sildet = ast_dsp_new();
    if (!sildet) {
        ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
        return -1;
    }
    writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666);
    if (!writer) {
        ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt);
        ast_dsp_free(sildet);
        return -1;
    }
    for(;;) {
        if ((res = ast_waitfor(c, 2000)) < 0) {
            ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt);
            break;
        }
        if (res) {
            f = ast_read(c);
            if (!f) {
                ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt);
                break;
            }
            if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
                /* Ended happily with DTMF */
                ast_frfree(f);
                break;
            } else if (f->frametype == AST_FRAME_VOICE) {
                ast_dsp_silence(sildet, f, &total);
                if (total > silence) {
                    /* Ended happily with silence */
                    ast_frfree(f);
                    break;
                }
                totalms += f->samples / 8;
                if (totalms > maxsec * 1000) {
                    /* Ended happily with too much stuff */
                    ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec);
                    ast_frfree(f);
                    break;
                }
            }
            ast_frfree(f);
        }
    }
    res = ast_set_read_format(c, rfmt);
    if (res)
        ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name);
    ast_dsp_free(sildet);
    ast_closestream(writer);
    return 0;
}
示例#28
0
static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
	int volfactor, const int fd, struct spy_dtmf_options *user_options,
	const char *mygroup, const char *myenforced, const char *spec, const char *exten,
	const char *context, const char *mailbox, const char *name_context)
{
	char nameprefix[AST_NAME_STRLEN];
	char peer_name[AST_NAME_STRLEN + 5];
	char exitcontext[AST_MAX_CONTEXT] = "";
	signed char zero_volume = 0;
	int waitms;
	int res;
	char *ptr;
	int num;
	int num_spyed_upon = 1;
	struct ast_channel_iterator *iter = NULL;

	if (ast_test_flag(flags, OPTION_EXIT)) {
		const char *c;
		ast_channel_lock(chan);
		if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
			ast_copy_string(exitcontext, c, sizeof(exitcontext));
		} else if (!ast_strlen_zero(chan->macrocontext)) {
			ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
		} else {
			ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
		}
		ast_channel_unlock(chan);
	}

	if (chan->_state != AST_STATE_UP)
		ast_answer(chan);

	ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */

	waitms = 100;

	for (;;) {
		struct ast_autochan *autochan = NULL, *next_autochan = NULL;
		struct ast_channel *prev = NULL;

		if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
			res = ast_streamfile(chan, "beep", chan->language);
			if (!res)
				res = ast_waitstream(chan, "");
			else if (res < 0) {
				ast_clear_flag(chan, AST_FLAG_SPYING);
				break;
			}
			if (!ast_strlen_zero(exitcontext)) {
				char tmp[2];
				tmp[0] = res;
				tmp[1] = '\0';
				if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
					goto exit;
				else
					ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
			}
		}

		/* Set up the iterator we'll be using during this call */
		if (!ast_strlen_zero(spec)) {
			iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
		} else if (!ast_strlen_zero(exten)) {
			iter = ast_channel_iterator_by_exten_new(exten, context);
		} else {
			iter = ast_channel_iterator_all_new();
		}

		if (!iter) {
			return -1;
		}

		res = ast_waitfordigit(chan, waitms);
		if (res < 0) {
			ast_clear_flag(chan, AST_FLAG_SPYING);
			break;
		}
		if (!ast_strlen_zero(exitcontext)) {
			char tmp[2];
			tmp[0] = res;
			tmp[1] = '\0';
			if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
				goto exit;
			else
				ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
		}

		/* reset for the next loop around, unless overridden later */
		waitms = 100;
		num_spyed_upon = 0;

		for (autochan = next_channel(iter, autochan, chan);
		     autochan;
			 prev = autochan->chan, ast_autochan_destroy(autochan),
		     autochan = next_autochan ? next_autochan : 
				next_channel(iter, autochan, chan), next_autochan = NULL) {
			int igrp = !mygroup;
			int ienf = !myenforced;
			char *s;

			if (autochan->chan == prev) {
				ast_autochan_destroy(autochan);
				break;
			}

			if (ast_check_hangup(chan)) {
				ast_autochan_destroy(autochan);
				break;
			}

			if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) {
				continue;
			}

			if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) {
				continue;
			}

			if (mygroup) {
				int num_groups = 0;
				int num_mygroups = 0;
				char dup_group[512];
				char dup_mygroup[512];
				char *groups[NUM_SPYGROUPS];
				char *mygroups[NUM_SPYGROUPS];
				const char *group = NULL;
				int x;
				int y;
				ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
				num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
					ARRAY_LEN(mygroups));

				/* Before dahdi scan was part of chanspy, it would use the "GROUP" variable 
				 * rather than "SPYGROUP", this check is done to preserve expected behavior */
				if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
					group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
				} else {
					group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
				}

				if (!ast_strlen_zero(group)) {
					ast_copy_string(dup_group, group, sizeof(dup_group));
					num_groups = ast_app_separate_args(dup_group, ':', groups,
						ARRAY_LEN(groups));
				}

				for (y = 0; y < num_mygroups; y++) {
					for (x = 0; x < num_groups; x++) {
						if (!strcmp(mygroups[y], groups[x])) {
							igrp = 1;
							break;
						}
					}
				}
			}

			if (!igrp) {
				continue;
			}
			if (myenforced) {
				char ext[AST_CHANNEL_NAME + 3];
				char buffer[512];
				char *end;

				snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);

				ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1);
				if ((end = strchr(ext, '-'))) {
					*end++ = ':';
					*end = '\0';
				}

				ext[0] = ':';

				if (strcasestr(buffer, ext)) {
					ienf = 1;
				}
			}

			if (!ienf) {
				continue;
			}

			strcpy(peer_name, "spy-");
			strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1);
			ptr = strchr(peer_name, '/');
			*ptr++ = '\0';
			ptr = strsep(&ptr, "-");

			for (s = peer_name; s < ptr; s++)
				*s = tolower(*s);

			if (!ast_test_flag(flags, OPTION_QUIET)) {
				if (ast_test_flag(flags, OPTION_NAME)) {
					const char *local_context = S_OR(name_context, "default");
					const char *local_mailbox = S_OR(mailbox, ptr);
					res = ast_app_sayname(chan, local_mailbox, local_context);
				}
				if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
					if (!ast_test_flag(flags, OPTION_NOTECH)) {
						if (ast_fileexists(peer_name, NULL, NULL) > 0) {
							res = ast_streamfile(chan, peer_name, chan->language);
							if (!res) {
								res = ast_waitstream(chan, "");
							}
							if (res) {
								ast_autochan_destroy(autochan);
								break;
							}
						} else {
							res = ast_say_character_str(chan, peer_name, "", chan->language);
						}
					}
					if ((num = atoi(ptr)))
						ast_say_digits(chan, atoi(ptr), "", chan->language);
				}
			}

			res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
			num_spyed_upon++;

			if (res == -1) {
				ast_autochan_destroy(autochan);
				goto exit;
			} else if (res == -2) {
				res = 0;
				ast_autochan_destroy(autochan);
				goto exit;
			} else if (res > 1 && spec) {
				struct ast_channel *next;

				snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);

				if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
					next_autochan = ast_autochan_setup(next);
					next = ast_channel_unref(next);
				} else {
					/* stay on this channel, if it is still valid */
					if (!ast_check_hangup(autochan->chan)) {
						next_autochan = ast_autochan_setup(autochan->chan);
					} else {
						/* the channel is gone */
						next_autochan = NULL;
					}
				}
			} else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
				goto exit;
			}
		}

		iter = ast_channel_iterator_destroy(iter);

		if (res == -1 || ast_check_hangup(chan))
			break;
		if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
			break;
		}
	}
exit:

	ast_clear_flag(chan, AST_FLAG_SPYING);

	ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);

	return res;
}
static int record_exec(struct ast_channel *chan, void *data)
{
	int res = 0;
	int count = 0;
	int percentflag = 0;
	char *filename, *ext = NULL, *silstr, *maxstr, *options;
	char *vdata, *p;
	int i = 0;
	char tmp[256];

	struct ast_filestream *s = '\0';
	struct localuser *u;
	struct ast_frame *f = NULL;
	
	struct ast_dsp *sildet = NULL;   	/* silence detector dsp */
	int totalsilence = 0;
	int dspsilence = 0;
	int silence = 0;		/* amount of silence to allow */
	int gotsilence = 0;		/* did we timeout for silence? */
	int maxduration = 0;		/* max duration of recording in milliseconds */
	int gottimeout = 0;		/* did we timeout for maxduration exceeded? */
	int option_skip = 0;
	int option_noanswer = 0;
	int option_append = 0;
	int terminator = '#';
	int option_quiet = 0;
	int rfmt = 0;
	int flags;
	int waitres;
	struct ast_silence_generator *silgen = NULL;
	
	/* The next few lines of code parse out the filename and header from the input string */
	if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */
		ast_log(LOG_WARNING, "Record requires an argument (filename)\n");
		return -1;
	}

	LOCAL_USER_ADD(u);

	/* Yay for strsep being easy */
	vdata = ast_strdupa(data);
	if (!vdata) {
		ast_log(LOG_ERROR, "Out of memory\n");
		LOCAL_USER_REMOVE(u);
		return -1;
	}

	p = vdata;
	filename = strsep(&p, "|");
	silstr = strsep(&p, "|");
	maxstr = strsep(&p, "|");	
	options = strsep(&p, "|");
	
	if (filename) {
		if (strstr(filename, "%d"))
			percentflag = 1;
		ext = strrchr(filename, '.'); /* to support filename with a . in the filename, not format */
		if (!ext)
			ext = strchr(filename, ':');
		if (ext) {
			*ext = '\0';
			ext++;
		}
	}
	if (!ext) {
		ast_log(LOG_WARNING, "No extension specified to filename!\n");
		LOCAL_USER_REMOVE(u);
		return -1;
	}
	if (silstr) {
		if ((sscanf(silstr, "%d", &i) == 1) && (i > -1)) {
			silence = i * 1000;
		} else if (!ast_strlen_zero(silstr)) {
			ast_log(LOG_WARNING, "'%s' is not a valid silence duration\n", silstr);
		}
	}
	
	if (maxstr) {
		if ((sscanf(maxstr, "%d", &i) == 1) && (i > -1))
			/* Convert duration to milliseconds */
			maxduration = i * 1000;
		else if (!ast_strlen_zero(maxstr))
			ast_log(LOG_WARNING, "'%s' is not a valid maximum duration\n", maxstr);
	}
	if (options) {
		/* Retain backwards compatibility with old style options */
		if (!strcasecmp(options, "skip"))
			option_skip = 1;
		else if (!strcasecmp(options, "noanswer"))
			option_noanswer = 1;
		else {
			if (strchr(options, 's'))
				option_skip = 1;
			if (strchr(options, 'n'))
				option_noanswer = 1;
			if (strchr(options, 'a'))
				option_append = 1;
			if (strchr(options, 't'))
				terminator = '*';
			if (strchr(options, 'q'))
				option_quiet = 1;
		}
	}
	
	/* done parsing */
	
	/* these are to allow the use of the %d in the config file for a wild card of sort to
	  create a new file with the inputed name scheme */
	if (percentflag) {
		do {
			snprintf(tmp, sizeof(tmp), filename, count);
			count++;
		} while ( ast_fileexists(tmp, ext, chan->language) != -1 );
		pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp);
	} else
		strncpy(tmp, filename, sizeof(tmp)-1);
	/* end of routine mentioned */
	
	
	
	if (chan->_state != AST_STATE_UP) {
		if (option_skip) {
			/* At the user's option, skip if the line is not up */
			LOCAL_USER_REMOVE(u);
			return 0;
		} else if (!option_noanswer) {
			/* Otherwise answer unless we're supposed to record while on-hook */
			res = ast_answer(chan);
		}
	}
	
	if (res) {
		ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
		goto out;
	}
	
	if (!option_quiet) {
		/* Some code to play a nice little beep to signify the start of the record operation */
		res = ast_streamfile(chan, "beep", chan->language);
		if (!res) {
			res = ast_waitstream(chan, "");
		} else {
			ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", chan->name);
		}
		ast_stopstream(chan);
	}
		
	/* The end of beep code.  Now the recording starts */
		
	if (silence > 0) {
		rfmt = chan->readformat;
		res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
		if (res < 0) {
			ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
			LOCAL_USER_REMOVE(u);
			return -1;
		}
		sildet = ast_dsp_new();
		if (!sildet) {
			ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
			LOCAL_USER_REMOVE(u);
			return -1;
		}
		ast_dsp_set_threshold(sildet, 256);
	} 
		
		
	flags = option_append ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY;
	s = ast_writefile( tmp, ext, NULL, flags , 0, 0644);
		
	if (!s) {
		ast_log(LOG_WARNING, "Could not create file %s\n", filename);
		goto out;
	}

	if (option_transmit_silence_during_record)
		silgen = ast_channel_start_silence_generator(chan);
	
	/* Request a video update */
	ast_indicate(chan, AST_CONTROL_VIDUPDATE);
	
	if (maxduration <= 0)
		maxduration = -1;
	
	while ((waitres = ast_waitfor(chan, maxduration)) > -1) {
		if (maxduration > 0) {
			if (waitres == 0) {
				gottimeout = 1;
				break;
			}
			maxduration = waitres;
		}
		
		f = ast_read(chan);
		if (!f) {
			res = -1;
			break;
		}
		if (f->frametype == AST_FRAME_VOICE) {
			res = ast_writestream(s, f);
			
			if (res) {
				ast_log(LOG_WARNING, "Problem writing frame\n");
				ast_frfree(f);
				break;
			}
			
			if (silence > 0) {
				dspsilence = 0;
				ast_dsp_silence(sildet, f, &dspsilence);
				if (dspsilence) {
					totalsilence = dspsilence;
				} else {
					totalsilence = 0;
				}
				if (totalsilence > silence) {
					/* Ended happily with silence */
					ast_frfree(f);
					gotsilence = 1;
					break;
				}
			}
		} else if (f->frametype == AST_FRAME_VIDEO) {
			res = ast_writestream(s, f);
			
			if (res) {
				ast_log(LOG_WARNING, "Problem writing frame\n");
				ast_frfree(f);
				break;
			}
		} else if ((f->frametype == AST_FRAME_DTMF) &&
		    (f->subclass == terminator)) {
			ast_frfree(f);
			break;
		}
		ast_frfree(f);
	}
	if (!f) {
		ast_log(LOG_DEBUG, "Got hangup\n");
		res = -1;
	}
			
	if (gotsilence) {
		ast_stream_rewind(s, silence-1000);
		ast_truncstream(s);
	} else if (!gottimeout) {
		/* Strip off the last 1/4 second of it */
		ast_stream_rewind(s, 250);
		ast_truncstream(s);
	}
	ast_closestream(s);

	if (silgen)
		ast_channel_stop_silence_generator(chan, silgen);
	
 out:
	if ((silence > 0) && rfmt) {
		res = ast_set_read_format(chan, rfmt);
		if (res)
			ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
		if (sildet)
			ast_dsp_free(sildet);
	}

	LOCAL_USER_REMOVE(u);

	return res;
}