Skip to content
Snippets Groups Projects
app_rpt.c 121 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			ast_safe_sleep(mychannel, ctint);
    			ast_mutex_lock(&myrpt->lock);
    			if(myrpt->unkeytocttimer < ctint)
    				myrpt->unkeytocttimer = 0;
    			else
    				myrpt->unkeytocttimer -= ctint;
    			ast_mutex_unlock(&myrpt->lock);
    		}
    	
    
    		/*
    		* Now, the carrier on the rptr rx should be gone. 
    		* If it re-appeared, then forget about sending the CT
    		*/
    		if(myrpt->keyed){
    			imdone = 1;
    			break;
    		}
    			
    
    		l = myrpt->links.next;
    		if (l != &myrpt->links)
    		{
    			ast_mutex_lock(&myrpt->lock);
    			while(l != &myrpt->links)
    			{
    				if (l->mode) hastx++;
    				l = l->next;
    			}
    			ast_mutex_unlock(&myrpt->lock);
    
    			res = telem_lookup(mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
    
    			if(res)
    				ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
    			
    		
    
    		/* if in remote cmd mode, indicate it */
    
    			if (myrpt->cmdnode[0])
    			{
    				ast_safe_sleep(mychannel,200);
    
    				res = telem_lookup(mychannel, myrpt->name, "cmdmode");
    
    				if(res)
    				 	ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
    				ast_stopstream(mychannel);
    			}
    
    		else if((ct = ast_variable_retrieve(cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
    			ct_copy = ast_strdupa(ct);
    
    			res = telem_lookup(mychannel, myrpt->name, ct_copy);
    
    			if(res)
    			 	ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);		
    		}	
    			
    
    		imdone = 1;
    		break;
    	    case REMDISC:
    		/* wait a little bit */
    
    		wait_interval(myrpt, DLY_TELEM, mychannel);
    
    		res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
    		if (!res) 
    			res = ast_waitstream(mychannel, "");
    		else
    			 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    		ast_stopstream(mychannel);
    		ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
    		res = ast_streamfile(mychannel, ((mytele->mylink.connected) ? 
    			"rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
    		break;
    	    case REMALREADY:
    		/* wait a little bit */
    
    		wait_interval(myrpt, DLY_TELEM, mychannel);
    
    		res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
    		break;
    	    case REMNOTFOUND:
    		/* wait a little bit */
    
    		wait_interval(myrpt, DLY_TELEM, mychannel);
    
    		res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
    		break;
    	    case REMGO:
    		/* wait a little bit */
    
    		wait_interval(myrpt, DLY_TELEM, mychannel);
    
    		res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
    		break;
    	    case CONNECTED:
    		/* wait a little bit */
    
    		wait_interval(myrpt, DLY_TELEM,  mychannel);
    
    		res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
    		if (!res) 
    			res = ast_waitstream(mychannel, "");
    		else
    			 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    		ast_stopstream(mychannel);
    		ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
    		res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
    		break;
    	    case CONNFAIL:
    		res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
    		if (!res) 
    			res = ast_waitstream(mychannel, "");
    		else
    			 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    		ast_stopstream(mychannel);
    		ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
    		res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
    		break;
    	    case STATUS:
    		/* wait a little bit */
    
    		wait_interval(myrpt, DLY_TELEM, mychannel);
    
    		hastx = 0;
    		linkbase.next = &linkbase;
    		linkbase.prev = &linkbase;
    		ast_mutex_lock(&myrpt->lock);
    		/* make our own list of links */
    		l = myrpt->links.next;
    		while(l != &myrpt->links)
    		{
    			m = malloc(sizeof(struct rpt_link));
    			if (!m)
    			{
    				ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
    
    Jim Dixon's avatar
    Jim Dixon committed
    				ast_mutex_lock(&myrpt->lock);
    				remque((struct qelem *)mytele);
    				ast_mutex_unlock(&myrpt->lock);
    				free(mytele);		
    				ast_hangup(mychannel);
    
    				pthread_exit(NULL);
    			}
    			memcpy(m,l,sizeof(struct rpt_link));
    			m->next = m->prev = NULL;
    			insque((struct qelem *)m,(struct qelem *)linkbase.next);
    			l = l->next;
    		}
    		ast_mutex_unlock(&myrpt->lock);
    		res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
    		if (!res) 
    			res = ast_waitstream(mychannel, "");
    		else
    			 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    		ast_stopstream(mychannel);
    		ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
    		if (!res) 
    			res = ast_waitstream(mychannel, "");
    		else
    			 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    		ast_stopstream(mychannel);
    		if (myrpt->callmode)
    		{
    			hastx = 1;
    			res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
    			if (!res) 
    				res = ast_waitstream(mychannel, "");
    			else
    				 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    			ast_stopstream(mychannel);
    		}
    		l = linkbase.next;
    		while(l != &linkbase)
    		{
    			hastx = 1;
    			res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
    			if (!res) 
    				res = ast_waitstream(mychannel, "");
    			else
    				ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    			ast_stopstream(mychannel);
    			ast_say_character_str(mychannel,l->name,NULL,mychannel->language);
    			if (!res) 
    				res = ast_waitstream(mychannel, "");
    			else
    				 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    			ast_stopstream(mychannel);
    			res = ast_streamfile(mychannel, ((l->mode) ? 
    				"rpt/tranceive" : "rpt/monitor"), mychannel->language);
    			if (!res) 
    				res = ast_waitstream(mychannel, "");
    			else
    				ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    			ast_stopstream(mychannel);
    			l = l->next;
    		}			
    		if (!hastx)
    		{
    			res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
    			if (!res) 
    				res = ast_waitstream(mychannel, "");
    			else
    				 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    			ast_stopstream(mychannel);
    		}
    		/* destroy our local link queue */
    		l = linkbase.next;
    		while(l != &linkbase)
    		{
    			m = l;
    			l = l->next;
    			remque((struct qelem *)m);
    			free(m);
    		}			
    		imdone = 1;
    		break;
    
    	    case TIMEOUT:
    		res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
    		if (!res) 
    			res = ast_waitstream(mychannel, "");
    		else
    			 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    		ast_stopstream(mychannel);
    		ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
    		res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
    		break;
    
    		
    	    case STATS_TIME:
    
    	    	wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
    
    		t = time(NULL);
    
    		/* Say the phase of the day is before the time */
    		if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
    			p = "rpt/goodmorning";
    		else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
    			p = "rpt/goodafternoon";
    		else
    			p = "rpt/goodevening";
    		if (sayfile(mychannel,p) == -1)
    		{
    			imdone = 1;
    			break;
    		}
    		/* Say the time is ... */		
    		if (sayfile(mychannel,"rpt/thetimeis") == -1)
    		{
    			imdone = 1;
    			break;
    		}
    		/* Say the time */				
    	    	res = ast_say_time(mychannel, t, "", mychannel->language);
    		if (!res) 
    			res = ast_waitstream(mychannel, "");
    		ast_stopstream(mychannel);		
    		imdone = 1;
    	    	break;
    	    case STATS_VERSION:
    		p = strstr(tdesc, "version");	
    		if(!p)
    			break;	
    		if(sscanf(p, "version %d.%d", &vmajor, &vminor) != 2)
    			break;
    
        		wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
    
    		/* Say "version" */
    		if (sayfile(mychannel,"rpt/version") == -1)
    		{
    			imdone = 1;
    			break;
    		}
    		if(!res) /* Say "X" */
    			ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
    		if (!res) 
    			res = ast_waitstream(mychannel, "");
    		ast_stopstream(mychannel);	
    		if (saycharstr(mychannel,".") == -1)
    		{
    			imdone = 1;
    			break;
    		}
    		if(!res) /* Say "Y" */
    			ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
    		if (!res){
    			res = ast_waitstream(mychannel, "");
    			ast_stopstream(mychannel);
    		}	
    		else
    			 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    		imdone = 1;
    	    	break;
    
    	    	wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
    
    	    	if(mytele->param)
    	    		saycharstr(mychannel, mytele->param);
    	    	imdone = 1;
    		break;
    
    Jim Dixon's avatar
    Jim Dixon committed
    	    case TEST_TONE:
    		imdone = 1;
    		myrpt->stopgen = 0;
    	        if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
    			break;
    	        while(mychannel->generatordata && (!myrpt->stopgen)) {
    			if (ast_safe_sleep(mychannel,1)) break;
    		    	imdone = 1;
    			}
    		break;
    
    	    default:
    	    	break;
    
    Jim Dixon's avatar
    Jim Dixon committed
    	myrpt->stopgen = 0;
    
    		if (!res) 
    			res = ast_waitstream(mychannel, "");
    		else {
    			ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    			res = 0;
    		}
    
    	ast_mutex_lock(&myrpt->lock);
    	remque((struct qelem *)mytele);
    	ast_mutex_unlock(&myrpt->lock);
    	free(mytele);		
    
    static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
    
    struct rpt_link *mylink = (struct rpt_link *) data;
    
    	tele = malloc(sizeof(struct rpt_tele));
    	if (!tele)
    
    		ast_log(LOG_WARNING, "Unable to allocate memory\n");
    
    	/* zero it out */
    	memset((char *)tele,0,sizeof(struct rpt_tele));
    	tele->rpt = myrpt;
    	tele->mode = mode;
    	ast_mutex_lock(&myrpt->lock);
    
    	if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED)){
    		memset(&tele->mylink,0,sizeof(struct rpt_link));
    		if (mylink){
    			memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
    		}
    	}
    	else if (mode == ARB_ALPHA){
    
    		strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
    
    	insque((struct qelem *)tele,(struct qelem *)myrpt->tele.next); 
    	ast_mutex_unlock(&myrpt->lock);
            pthread_attr_init(&attr);
            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    
    	ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
    
    Mark Spencer's avatar
    Mark Spencer committed
    static void *rpt_call(void *this)
    {
    ZT_CONFINFO ci;  /* conference info */
    struct	rpt *myrpt = (struct rpt *)this;
    int	res;
    
    Jim Dixon's avatar
    Jim Dixon committed
    struct	ast_frame wf;
    
    Mark Spencer's avatar
    Mark Spencer committed
    int stopped,congstarted;
    struct ast_channel *mychannel,*genchannel;
    
    	myrpt->mydtmf = 0;
    	/* allocate a pseudo-channel thru asterisk */
    
    	mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!mychannel)
    	{
    		fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
    		pthread_exit(NULL);
    	}
    	ci.chan = 0;
    
    	ci.confno = myrpt->conf; /* use the pseudo conference */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
    		| ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
    	/* first put the channel on the conference */
    	if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
    	{
    		ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
    		ast_hangup(mychannel);
    		myrpt->callmode = 0;
    		pthread_exit(NULL);
    	}
    	/* allocate a pseudo-channel thru asterisk */
    
    	genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!genchannel)
    	{
    		fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
    		ast_hangup(mychannel);
    		pthread_exit(NULL);
    	}
    	ci.chan = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
    		| ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
    	/* first put the channel on the conference */
    	if (ioctl(genchannel->fds[0],ZT_SETCONF,&ci) == -1)
    	{
    		ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
    		ast_hangup(mychannel);
    		ast_hangup(genchannel);
    		myrpt->callmode = 0;
    		pthread_exit(NULL);
    	}
    
    	if (myrpt->tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->tonezone) == -1))
    	{
    		ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone);
    		ast_hangup(mychannel);
    		ast_hangup(genchannel);
    		myrpt->callmode = 0;
    		pthread_exit(NULL);
    	}
    	if (myrpt->tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->tonezone) == -1))
    	{
    		ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->tonezone);
    		ast_hangup(mychannel);
    		ast_hangup(genchannel);
    		myrpt->callmode = 0;
    		pthread_exit(NULL);
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* start dialtone */
    	if (tone_zone_play_tone(mychannel->fds[0],ZT_TONE_DIALTONE) < 0)
    	{
    		ast_log(LOG_WARNING, "Cannot start dialtone\n");
    		ast_hangup(mychannel);
    		ast_hangup(genchannel);
    		myrpt->callmode = 0;
    		pthread_exit(NULL);
    	}
    	stopped = 0;
    	congstarted = 0;
    	while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
    	{
    
    		if ((myrpt->callmode == 1) && (myrpt->cidx > 0) && (!stopped))
    		{
    			stopped = 1;
    			/* stop dial tone */
    			tone_zone_play_tone(mychannel->fds[0],-1);
    		}
    		if ((myrpt->callmode == 4) && (!congstarted))
    		{
    			congstarted = 1;
    			/* start congestion tone */
    			tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION);
    		}
    
    Jim Dixon's avatar
    Jim Dixon committed
    		res = ast_safe_sleep(mychannel, MSWAIT);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (res < 0)
    		{
    			ast_hangup(mychannel);
    			ast_hangup(genchannel);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			myrpt->callmode = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    			pthread_exit(NULL);
    		}
    	}
    	/* stop any tone generation */
    	tone_zone_play_tone(mychannel->fds[0],-1);
    	/* end if done */
    	if (!myrpt->callmode)
    	{
    		ast_hangup(mychannel);
    		ast_hangup(genchannel);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		myrpt->callmode = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		pthread_exit(NULL);			
    	}
    
    
    	if (myrpt->ourcallerid && *myrpt->ourcallerid){
    		char *name, *loc, *instr;
    		instr = strdup(myrpt->ourcallerid);
    		if(instr){
    			ast_callerid_parse(instr, &name, &loc);
    			if(loc){
    				if(mychannel->cid.cid_num)
    					free(mychannel->cid.cid_num);
    				mychannel->cid.cid_num = strdup(loc);
    			}
    			if(name){
    				if(mychannel->cid.cid_name)
    					free(mychannel->cid.cid_name);
    				mychannel->cid.cid_name = strdup(name);
    			}
    			free(instr);
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	strncpy(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
    	strncpy(mychannel->context, myrpt->ourcontext, sizeof(mychannel->context) - 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (myrpt->acctcode)
    
    		strncpy(mychannel->accountcode, myrpt->acctcode, sizeof(mychannel->accountcode) - 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	mychannel->priority = 1;
    	ast_channel_undefer_dtmf(mychannel);
    	if (ast_pbx_start(mychannel) < 0)
    	{
    		ast_log(LOG_WARNING, "Unable to start PBX!!\n");
    		ast_hangup(mychannel);
    		ast_hangup(genchannel);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	 	myrpt->callmode = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		pthread_exit(NULL);
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	myrpt->callmode = 3;
    	while(myrpt->callmode)
    	{
    
    		if ((!mychannel->pbx) && (myrpt->callmode != 4))
    
    Mark Spencer's avatar
    Mark Spencer committed
    		{
    			myrpt->callmode = 4;
    
    Mark Spencer's avatar
    Mark Spencer committed
    			/* start congestion tone */
    			tone_zone_play_tone(genchannel->fds[0],ZT_TONE_CONGESTION);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    		if (myrpt->mydtmf)
    		{
    			wf.frametype = AST_FRAME_DTMF;
    			wf.subclass = myrpt->mydtmf;
    			wf.offset = 0;
    			wf.mallocd = 0;
    			wf.data = NULL;
    			wf.datalen = 0;
    			wf.samples = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_write(genchannel,&wf); 
    
    Mark Spencer's avatar
    Mark Spencer committed
    			myrpt->mydtmf = 0;
    		}
    
    Jim Dixon's avatar
    Jim Dixon committed
    		usleep(MSWAIT * 1000);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	tone_zone_play_tone(genchannel->fds[0],-1);
    
    	if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_hangup(genchannel);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	myrpt->callmode = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	pthread_exit(NULL);
    }
    
    
    static void send_link_dtmf(struct rpt *myrpt,char c)
    {
    char	str[300];
    struct	ast_frame wf;
    struct	rpt_link *l;
    
    
    	snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
    
    	wf.frametype = AST_FRAME_TEXT;
    	wf.subclass = 0;
    	wf.offset = 0;
    	wf.mallocd = 1;
    	wf.datalen = strlen(str) + 1;
    	wf.samples = 0;
    	l = myrpt->links.next;
    	/* first, see if our dude is there */
    	while(l != &myrpt->links)
    	{
    
    		/* if we found it, write it and were done */
    		if (!strcmp(l->name,myrpt->cmdnode))
    
    			if (l->chan) ast_write(l->chan,&wf);
    
    		}
    		l = l->next;
    	}
    	l = myrpt->links.next;
    	/* if not, give it to everyone */
    	while(l != &myrpt->links)
    	{
    
    		if (l->chan) ast_write(l->chan,&wf);
    
    /*
    * Internet linking function 
    */
    
    static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source)
    
    Jim Dixon's avatar
    Jim Dixon committed
    	char tmp[300], deststr[300] = "",modechange = 0;
    
    	struct rpt_link *l;
    	ZT_CONFINFO ci;  /* conference info */
    
    	if(!param)
    		return DC_ERROR;
    		
    			
    	if (!myrpt->enable)
    		return DC_ERROR;
    
    	if(debug)
    		printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
    		
    	switch(myatoi(param)){
    		case 1: /* Link off */
    			val = ast_variable_retrieve(cfg, NODES, digitbuf);
    			if (!val){
    				if(strlen(digitbuf) >= myrpt->longestnode)
    					return DC_ERROR;
    				break;
    			}
    			strncpy(tmp,val,sizeof(tmp) - 1);
    			s = tmp;
    			s1 = strsep(&s,",");
    			ast_mutex_lock(&myrpt->lock);
    			l = myrpt->links.next;
    			/* try to find this one in queue */
    			while(l != &myrpt->links){
    				/* if found matching string */
    				if (!strcmp(l->name, digitbuf))
    					break;
    				l = l->next;
    			}
    			if (l != &myrpt->links){ /* if found */
    
    				struct	ast_frame wf;
    
    				l->retries = MAX_RETRIES + 1;
    				l->disced = 1;
    
    				wf.frametype = AST_FRAME_TEXT;
    				wf.subclass = 0;
    				wf.offset = 0;
    				wf.mallocd = 1;
    				wf.datalen = strlen(discstr) + 1;
    				wf.samples = 0;
    				wf.data = strdup(discstr);
    				if (l->chan)
    				{
    					ast_write(l->chan,&wf);
    					if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
    					ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
    				}
    
    				rpt_telemetry(myrpt, COMPLETE, NULL);
    				return DC_COMPLETE;
    			}
    			ast_mutex_unlock(&myrpt->lock);	
    			return DC_COMPLETE;
    		case 2: /* Link Monitor */
    			val = ast_variable_retrieve(cfg, NODES, digitbuf);
    			if (!val){
    				if(strlen(digitbuf) >= myrpt->longestnode)
    					return DC_ERROR;
    				break;
    			}
    			strncpy(tmp,val,sizeof(tmp) - 1);
    			s = tmp;
    			s1 = strsep(&s,",");
    			ast_mutex_lock(&myrpt->lock);
    			l = myrpt->links.next;
    			/* try to find this one in queue */
    			while(l != &myrpt->links){
    				/* if found matching string */
    				if (!strcmp(l->name, digitbuf))
    					break;
    				l = l->next;
    			}
    			/* if found */
    			if (l != &myrpt->links) 
    			{
    				/* if already in this mode, just ignore */
    
    				if ((!l->mode) || (!l->chan)) {
    
    					ast_mutex_unlock(&myrpt->lock);
    					rpt_telemetry(myrpt,REMALREADY,NULL);
    					return DC_COMPLETE;
    					
    				}
    
    Jim Dixon's avatar
    Jim Dixon committed
    				ast_mutex_unlock(&myrpt->lock);
    
    				if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
    
    Jim Dixon's avatar
    Jim Dixon committed
    				l->retries = MAX_RETRIES + 1;
    				l->disced = 2;
    				modechange = 1;
    			} else
    				ast_mutex_unlock(&myrpt->lock);
    
    			/* establish call in monitor mode */
    			l = malloc(sizeof(struct rpt_link));
    			if (!l){
    				ast_log(LOG_WARNING, "Unable to malloc\n");
    
    Jim Dixon's avatar
    Jim Dixon committed
    				return DC_ERROR;
    
    			}
    			/* zero the silly thing */
    			memset((char *)l,0,sizeof(struct rpt_link));
    
    			snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
    
    			tele = strchr(deststr,'/');
    			if (!tele){
    				fprintf(stderr,"link2:Dial number (%s) must be in format tech/number\n",deststr);
    
    Jim Dixon's avatar
    Jim Dixon committed
    				return DC_ERROR;
    
    			}
    			*tele++ = 0;
    			l->isremote = (s && ast_true(s));
    			strncpy(l->name, digitbuf, MAXNODESTR - 1);
    
    			l->chan = ast_request(deststr,AST_FORMAT_SLINEAR,tele,NULL);
    
    Jim Dixon's avatar
    Jim Dixon committed
    			if (modechange) l->connected = 1;
    
    			if (l->chan){
    				ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
    				ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
    				l->chan->whentohangup = 0;
    				l->chan->appl = "Apprpt";
    				l->chan->data = "(Remote Rx)";
    				if (option_verbose > 2)
    					ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
    						deststr,tele,l->chan->name);
    
    				if(l->chan->cid.cid_num)
    					free(l->chan->cid.cid_num);
    				l->chan->cid.cid_num = strdup(myrpt->name);
    
    				rpt_telemetry(myrpt,CONNFAIL,l);
    
    				free(l);
    				if (option_verbose > 2)
    					ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
    						deststr,tele,l->chan->name);
    				return DC_ERROR;
    			}
    			/* allocate a pseudo-channel thru asterisk */
    
    			l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
    
    			if (!l->pchan){
    				fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
    
    Jim Dixon's avatar
    Jim Dixon committed
    				ast_hangup(l->chan);
    				free(l);
    				return DC_ERROR;
    
    			}
    			ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
    			ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
    			/* make a conference for the pseudo-one */
    			ci.chan = 0;
    			ci.confno = myrpt->conf;
    			ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
    			/* first put the channel on the conference in proper mode */
    			if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
    			{
    				ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
    
    Jim Dixon's avatar
    Jim Dixon committed
    				ast_hangup(l->chan);
    				ast_hangup(l->pchan);
    				free(l);
    				return DC_ERROR;
    
    			}
    			ast_mutex_lock(&myrpt->lock);
    			/* insert at end of queue */
    			insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
    
    			rpt_telemetry(myrpt,COMPLETE,NULL);
    			return DC_COMPLETE;
    		case 3: /* Link transceive */
    			val = ast_variable_retrieve(cfg, NODES, digitbuf);
    			if (!val){
    				if(strlen(digitbuf) >= myrpt->longestnode)
    					return DC_ERROR;
    				break;
    			}
    			strncpy(tmp,val,sizeof(tmp) - 1);
    			s = tmp;
    			s1 = strsep(&s,",");
    			ast_mutex_lock(&myrpt->lock);
    			l = myrpt->links.next;
    			/* try to find this one in queue */
    			while(l != &myrpt->links){
    				/* if found matching string */
    				if (!strcmp(l->name, digitbuf))
    					break;
    				l = l->next;
    			}
    			/* if found */
    			if (l != &myrpt->links){ 
    				/* if already in this mode, just ignore */
    
    				if ((l->mode) || (!l->chan)) {
    
    					ast_mutex_unlock(&myrpt->lock);
    					rpt_telemetry(myrpt, REMALREADY, NULL);
    					return DC_COMPLETE;
    				}
    
    Jim Dixon's avatar
    Jim Dixon committed
    				ast_mutex_unlock(&myrpt->lock);
    
    				if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
    
    Jim Dixon's avatar
    Jim Dixon committed
    				l->retries = MAX_RETRIES + 1;
    				l->disced = 2;
    				modechange = 1;
    			} else
    				ast_mutex_unlock(&myrpt->lock);
    
    			/* establish call in tranceive mode */
    			l = malloc(sizeof(struct rpt_link));
    			if (!l){
    				ast_log(LOG_WARNING, "Unable to malloc\n");
    
    Jim Dixon's avatar
    Jim Dixon committed
    				return(DC_ERROR);
    
    			}
    			/* zero the silly thing */
    			memset((char *)l,0,sizeof(struct rpt_link));
    			l->mode = 1;
    
    			l->outbound = 1;
    
    			strncpy(l->name, digitbuf, MAXNODESTR - 1);
    			l->isremote = (s && ast_true(s));
    
    Jim Dixon's avatar
    Jim Dixon committed
    			if (modechange) l->connected = 1;
    
    			snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
    
    			tele = strchr(deststr, '/');
    			if (!tele){
    				fprintf(stderr,"link3:Dial number (%s) must be in format tech/number\n",deststr);
    
    Jim Dixon's avatar
    Jim Dixon committed
    				free(l);
    				return DC_ERROR;
    
    			l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
    
    			if (l->chan){
    				ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
    				ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
    				l->chan->whentohangup = 0;
    				l->chan->appl = "Apprpt";
    				l->chan->data = "(Remote Rx)";
    				if (option_verbose > 2)
    					ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n",
    						deststr, tele, l->chan->name);
    
    				if(l->chan->cid.cid_num)
    					free(l->chan->cid.cid_num);
    				l->chan->cid.cid_num = strdup(myrpt->name);
    
    				rpt_telemetry(myrpt,CONNFAIL,l);
    
    				free(l);
    				if (option_verbose > 2)
    					ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
    						deststr,tele,l->chan->name);
    				return DC_ERROR;
    			}
    			/* allocate a pseudo-channel thru asterisk */
    
    			l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
    
    			if (!l->pchan){
    				fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
    
    Jim Dixon's avatar
    Jim Dixon committed
    				ast_hangup(l->chan);
    				free(l);
    				return DC_ERROR;
    
    			}
    			ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
    			ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
    			/* make a conference for the tx */
    			ci.chan = 0;
    			ci.confno = myrpt->conf;
    			ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
    			/* first put the channel on the conference in proper mode */
    			if (ioctl(l->pchan->fds[0], ZT_SETCONF, &ci) == -1)
    			{
    				ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
    
    Jim Dixon's avatar
    Jim Dixon committed
    				ast_hangup(l->chan);
    				ast_hangup(l->pchan);
    				free(l);
    				return DC_ERROR;
    
    			}
    			ast_mutex_lock(&myrpt->lock);
    			/* insert at end of queue */
    			insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
    
    			rpt_telemetry(myrpt,COMPLETE,NULL);
    			return DC_COMPLETE;
    		case 4: /* Enter Command Mode */
    		
    			/* if doesnt allow link cmd, or no links active, return */
     			if ((command_source != SOURCE_RPT) || (myrpt->links.next == &myrpt->links))
    				return DC_COMPLETE;
    			
    			/* if already in cmd mode, or selected self, fughetabahtit */
    			if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
    			
    				rpt_telemetry(myrpt, REMALREADY, NULL);
    				return DC_COMPLETE;
    			}
    			/* node must at least exist in list */
    			val = ast_variable_retrieve(cfg, NODES, digitbuf);
    			if (!val){
    				if(strlen(digitbuf) >= myrpt->longestnode)
    					return DC_ERROR;
    				break;
    			
    			}
    			ast_mutex_lock(&myrpt->lock);
    
    			strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
    
    			ast_mutex_unlock(&myrpt->lock);
    			rpt_telemetry(myrpt, REMGO, NULL);	
    			return DC_COMPLETE;
    			
    		case 5: /* Status */
    			rpt_telemetry(myrpt, STATUS, NULL);
    			return DC_COMPLETE;
    			
    			
    		case 6: /* All Links Off */
    			l = myrpt->links.next;
    			
    			while(l != &myrpt->links){
    
    				if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV); /* Hang 'em up */
    
    				l = l->next;
    			}
    			rpt_telemetry(myrpt, COMPLETE, NULL);
    
    	
    		default:
    			return DC_ERROR;
    			
    	}
    	
    	return DC_INDETERMINATE;
    }	
    
    /*
    * Autopatch up
    */
    
    static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source)
    {
    	pthread_attr_t attr;
    	
    		
    	if (!myrpt->enable)
    		return DC_ERROR;
    		
    	if(debug)
    		printf("@@@@ Autopatch up\n");
    
    	ast_mutex_lock(&myrpt->lock);
    	
    	/* if on call, force * into current audio stream */
    	
    	if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
    		myrpt->mydtmf = myrpt->funcchar;
    	}
    	if (myrpt->callmode){
    
    		return DC_COMPLETE;
    	}
    	myrpt->callmode = 1;
    	myrpt->cidx = 0;
    	myrpt->exten[myrpt->cidx] = 0;
    	ast_mutex_unlock(&myrpt->lock);
    	pthread_attr_init(&attr);
    	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    
    	ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
    
    	return DC_COMPLETE;
    }
    
    /*
    * Autopatch down
    */
    
    static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source)
    {
    	if (!myrpt->enable)
    		return DC_ERROR;
    	
    	if(debug)
    		printf("@@@@ Autopatch down\n");
    		
    	ast_mutex_lock(&myrpt->lock);
    	
    	if (!myrpt->callmode){
    
    		return DC_COMPLETE;
    	}
    	
    	myrpt->callmode = 0;
    	ast_mutex_unlock(&myrpt->lock);
    	rpt_telemetry(myrpt, TERM, NULL);
    	return DC_COMPLETE;
    }
    
    /*
    * Status
    */
    
    static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source)
    {
    
    	if(!param)
    		return DC_ERROR;
    		
    			
    	if (!myrpt->enable)
    		return DC_ERROR;
    
    	if(debug)
    		printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
    	
    	switch(myatoi(param)){
    		case 1: /* System ID */
    			rpt_telemetry(myrpt, ID1, NULL);
    			return DC_COMPLETE;
    		case 2: /* System Time */
    			rpt_telemetry(myrpt, STATS_TIME, NULL);
    			return DC_COMPLETE;
    		case 3: /* app_rpt.c version */
    			rpt_telemetry(myrpt, STATS_VERSION, NULL);
    		default:
    			return DC_ERROR;
    	}
    	return DC_INDETERMINATE;
    }
    
    /*