Skip to content
Snippets Groups Projects
app_rpt.c 176 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
    	for(i = 0; i < 20 ; i++){
    		flags =  ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT; 
    		res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
    		if(flags & ZT_IOMUX_WRITEEMPTY)
    			break;
    		if( ast_safe_sleep(chan, 50)){
    			res = -1;
    			break;
    		}
    	}
    		
    
    static int sayfile(struct ast_channel *mychannel,char *fname)
    {
    int	res;
    
    	res = ast_streamfile(mychannel, fname, mychannel->language);
    	if (!res) 
    		res = ast_waitstream(mychannel, "");
    	else
    		 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    	ast_stopstream(mychannel);
    	return res;
    }
    
    static int saycharstr(struct ast_channel *mychannel,char *str)
    {
    int	res;
    
    	res = ast_say_character_str(mychannel,str,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);
    	return res;
    }
    
    
    static int saynum(struct ast_channel *mychannel, int num)
    {
    	int res;
    	res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
    	if(!res)
    		res = ast_waitstream(mychannel, "");
    	else
    		ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    	ast_stopstream(mychannel);
    	return res;
    }
    
    
    
    /* Retrieve an int from a config file */
                                                                                    
    static int retrieve_astcfgint(char *category, char *name, int min, int max, int defl)
    {
            char *var;
            int ret;
                                                                                    
            var = ast_variable_retrieve(cfg, category, name);
            if(var){
                    ret = myatoi(var);
                    if(ret < min)
                            ret = min;
                    if(ret > max)
                            ret = max;
            }
            else
                    ret = defl;
            return ret;
    }
    
    static int telem_any(struct ast_channel *chan, char *entry)
    {
    	int res;
    	char c;
    	
    	static int morsespeed;
    	static int morsefreq;
    	static int morseampl;
    	static int morseidfreq = 0;
    	static int morseidampl;
    	static char mcat[] = MORSE;
    	
    	res = 0;
    	
    	if(!morseidfreq){ /* Get the morse parameters if not already loaded */
    		morsespeed = retrieve_astcfgint( mcat, "speed", 5, 20, 20);
            	morsefreq = retrieve_astcfgint( mcat, "frequency", 300, 3000, 800);
            	morseampl = retrieve_astcfgint( mcat, "amplitude", 200, 8192, 4096);
    		morseidampl = retrieve_astcfgint( mcat, "idamplitude", 200, 8192, 2048);
    		morseidfreq = retrieve_astcfgint( mcat, "idfrequency", 300, 3000, 330);	
    	}
    	
    	/* Is it a file, or a tone sequence? */
    			
    	if(entry[0] == '|'){
    		c = entry[1];
    		if((c >= 'a')&&(c <= 'z'))
    			c -= 0x20;
    	
    		switch(c){
    			case 'I': /* Morse ID */
    				res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
    				break;
    			
    			case 'M': /* Morse Message */
    				res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
    				break;
    			
    			case 'T': /* Tone sequence */
    				res = send_tone_telemetry(chan, entry + 2);
    				break;
    			default:
    				res = -1;
    		}
    	}
    	else
    		res = sayfile(chan, entry); /* File */
    	return res;
    }
    
    /*
    * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
    *
    * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
    */
    
    
    static int telem_lookup(struct ast_channel *chan, char *node, char *name)
    
    	/* Retrieve the section name for telemetry from the node section */
    	
    	telemetry = ast_variable_retrieve(cfg, node, TELEMETRY);
    	if(telemetry){
    		telemetry_save = ast_strdupa(telemetry);
    		if(!telemetry_save){
    			ast_log(LOG_WARNING,"ast_strdupa() failed in telem_lookup()\n");
    			return res;
    		}
    		entry = ast_variable_retrieve(cfg, telemetry_save, name);
    	}
    	
    
    	/* Try to look up the telemetry name */
    	
    	if(!entry){
    		/* Telemetry name wasn't found in the config file, use the default */
    		for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
    			if(!strcasecmp(tele_defs[i].name, name))
    				entry = tele_defs[i].value;
    		}
    	}
    	if(entry)	
    		telem_any(chan, entry);
    	else{
    		ast_log(LOG_WARNING, "Telemetry name not found: %s\n", name);
    		res = -1;
    	}
    	return res;
    }
    
    
    /*
    * Retrieve a wait interval
    */
    
    static int get_wait_interval(struct rpt *myrpt, int type)
    {
            int interval;
            char *wait_times;
            char *wait_times_save;
                                                                                                                      
            wait_times_save = NULL;
            wait_times = ast_variable_retrieve(cfg, myrpt->name, "wait_times");
                                                                                                                      
            if(wait_times){
                    wait_times_save = ast_strdupa(wait_times);
                    if(!wait_times_save){
                            ast_log(LOG_WARNING, "Out of memory in wait_interval()\n");
                            wait_times = NULL;
                    }
            }
                                                                                                                      
            switch(type){
                    case DLY_TELEM:
                            if(wait_times)
                                    interval = retrieve_astcfgint(wait_times_save, "telemwait", 500, 5000, 1000);
                            else
                                    interval = 1000;
                            break;
                                                                                                                      
                    case DLY_ID:
                            if(wait_times)
                                    interval = retrieve_astcfgint(wait_times_save, "idwait",250,5000,500);
                            else
                                    interval = 500;
                            break;
                                                                                                                      
                    case DLY_UNKEY:
                            if(wait_times)
                                    interval = retrieve_astcfgint(wait_times_save, "unkeywait",500,5000,1000);
                            else
                                    interval = 1000;
                            break;
                                                                                                                      
                    case DLY_CALLTERM:
                            if(wait_times)
                                    interval = retrieve_astcfgint(wait_times_save, "calltermwait",500,5000,1500);
                            else
                                    interval = 1500;
                            break;
                                                                                                                      
                    default:
                            return 0;
            }
    	return interval;
    }                                                                                                                  
    
    
    
    static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
    
    	if((interval = get_wait_interval(myrpt, type)))
    		ast_safe_sleep(chan,interval);
    
    static void *rpt_tele_thread(void *this)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    ZT_CONFINFO ci;  /* conference info */
    
    int	res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
    
    struct	rpt_tele *mytele = (struct rpt_tele *)this;
    
    struct	rpt *myrpt;
    struct	rpt_link *l,*m,linkbase;
    struct	ast_channel *mychannel;
    
    int vmajor, vminor;
    
    char *p,*ct,*ct_copy,*ident, *nodename;
    
    time_t t;
    struct tm localtm;
    
    
    	/* get a pointer to myrpt */
    	myrpt = mytele->rpt;
    
    
    	/* Snag copies of a few key myrpt variables */
    
    	rpt_mutex_lock(&myrpt->lock);
    	insque((struct qelem *)mytele, (struct qelem *)myrpt->tele.next); /* Moved from rpt_telemetry() */
    
    	nodename = ast_strdupa(myrpt->name);
    	ident = ast_strdupa(myrpt->ident);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* allocate a pseudo-channel thru asterisk */
    
    	mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
    	if (!mychannel)
    
    Mark Spencer's avatar
    Mark Spencer committed
    	{
    		fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
    
    		ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
    		rpt_mutex_unlock(&myrpt->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		pthread_exit(NULL);
    	}
    
    	mytele->chan = mychannel; /* Save a copy of the channel so we can access it externally if need be */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* make a conference for the tx */
    	ci.chan = 0;
    
    	/* If there's an ID queued, or tail message queued, */
    	/* only connect the ID audio to the local tx conference so */
    	/* linked systems can't hear it */
    
    	ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
    		(mytele->mode == TAILMSG)) ?
    		 	myrpt->txconf : myrpt->conf);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ci.confmode = ZT_CONF_CONFANN;
    	/* first put the channel on the conference in announce mode */
    	if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
    	{
    		ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
    
    		rpt_mutex_unlock(&myrpt->lock);
    		ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
    
    Mark Spencer's avatar
    Mark Spencer committed
    		pthread_exit(NULL);
    	}
    	ast_stopstream(mychannel);
    
    		wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
    
    	    case TAILMSG:
    		res = ast_streamfile(mychannel, myrpt->tailmessages[myrpt->tailmessagen], mychannel->language); 
    		break;
    
    		
    	    case IDTALKOVER:
    	    	p = ast_variable_retrieve(cfg, nodename, "idtalkover");
    	    	if(p)
    			res = telem_any(mychannel, p); 
    		imdone=1;	
    	    	break;
    	    		
    
    	    case PROC:
    		/* wait a little bit longer */
    
    		wait_interval(myrpt, DLY_TELEM, mychannel);
    
    		res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
    		break;
    	    case TERM:
    		/* wait a little bit longer */
    
    		wait_interval(myrpt, DLY_CALLTERM, mychannel);
    
    		res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
    		break;
    	    case COMPLETE:
    		/* wait a little bit */
    
    		wait_interval(myrpt, DLY_TELEM, mychannel);
    
    		res = telem_lookup(mychannel, myrpt->name, "functcomplete");
    
    	    case MACRO_NOTFOUND:
    		/* wait a little bit */
    		wait_interval(myrpt, DLY_TELEM, mychannel);
    		res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
    		break;
    	    case MACRO_BUSY:
    		/* wait a little bit */
    		wait_interval(myrpt, DLY_TELEM, mychannel);
    		res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
    		break;
    
    		* Reset the Unkey to CT timer
    		*/
    
    		x = get_wait_interval(myrpt, DLY_UNKEY);
    
    		myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
    
    
    		/*
    		* If there's one already queued, don't do another
    
    		*/
    
    		tlist = myrpt->tele.next;
    		unkeys_queued = 0;
                    if (tlist != &myrpt->tele)
                    {
    
                            while(tlist != &myrpt->tele){
                                    if (tlist->mode == UNKEY) unkeys_queued++;
                                    tlist = tlist->next;
                            }
    
    		/* Wait for the telemetry timer to expire */
    		/* Periodically check the timer since it can be re-initialized above */
    		while(myrpt->unkeytocttimer)
    		{
    			int ctint;
    			if(myrpt->unkeytocttimer > 100)
    				ctint = 100;
    			else
    				ctint = myrpt->unkeytocttimer;
    			ast_safe_sleep(mychannel, ctint);
    
    			if(myrpt->unkeytocttimer < ctint)
    				myrpt->unkeytocttimer = 0;
    			else
    				myrpt->unkeytocttimer -= ctint;
    
    		}
    	
    		/*
    		* 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;
    		}
    			
    
    		haslink = 0;
    
    		l = myrpt->links.next;
    		if (l != &myrpt->links)
    		{
    
    				{
    					l = l->next;
    					continue;
    				}
    				haslink = 1;
    
    				if (l->mode) {
    					hastx++;
    					if (l->isremote) hasremote++;
    				}
    
    			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);		
    		}	
    
    		if (hasremote && (!myrpt->cmdnode[0]))
    		{
    			/* set for all to hear */
    			ci.chan = 0;
    			ci.confno = myrpt->conf;
    			ci.confmode = ZT_CONF_CONFANN;
    			/* first put the channel on the conference in announce mode */
    			if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
    			{
    				ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
    
    				remque((struct qelem *)mytele);
    
    				rpt_mutex_unlock(&myrpt->lock);
    				ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
    
    				free(mytele);		
    				ast_hangup(mychannel);
    				pthread_exit(NULL);
    			}
    			if((ct = ast_variable_retrieve(cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
    				ast_safe_sleep(mychannel,200);
    				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;
    
    		/* make our own list of links */
    		l = myrpt->links.next;
    		while(l != &myrpt->links)
    		{
    
    			{
    				l = l->next;
    				continue;
    
    			}
    			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
    				remque((struct qelem *)mytele);
    
    				rpt_mutex_unlock(&myrpt->lock);
    				ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
    
    Jim Dixon's avatar
    Jim Dixon committed
    				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;
    		}
    
    		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;
    
    	    case REV_PATCH:
    	    	wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
    	    	if(mytele->param) {
    
    			/* Parts of this section taken from app_parkandannounce */
    			char *tpl_working, *tpl_current;
    			char *tmp[100], *myparm;
    			int looptemp=0,i=0, dres = 0;
    	
    
    			tpl_working = strdupa(mytele->param);
    			myparm = strsep(&tpl_working,",");
    			tpl_current=strsep(&tpl_working, ":");
    
    			while(tpl_current && looptemp < sizeof(tmp)) {
    				tmp[looptemp]=tpl_current;
    				looptemp++;
    				tpl_current=strsep(&tpl_working,":");
    			}
    
    			for(i=0; i<looptemp; i++) {
    				if(!strcmp(tmp[i], "PARKED")) {
    					ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
    				} else if(!strcmp(tmp[i], "NODE")) {
    					ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
    				} else {
    					dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
    					if(!dres) {
    						dres = ast_waitstream(mychannel, "");
    					} else {
    						ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
    						dres = 0;
    					}
    				}
    			}
    		}
    	    	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;
    		}
    
    	if (mytele->mode == TAILMSG)
    	{
    		if (!res)
    		{
    			myrpt->tailmessagen++;
    			if(myrpt->tailmessagen >= myrpt->tailmessagemax) myrpt->tailmessagen = 0;
    		}
    		else
    		{
    			myrpt->tmsgtimer = myrpt->tailsquashedtime;
    		}
    	}
    
    #ifdef  APP_RPT_LOCK_DEBUG
    	{
    		struct lockthread *t;
    
    		sleep(5);
    		ast_mutex_lock(&locklock);
    		t = get_lockthread(pthread_self());
    		if (t) memset(t,0,sizeof(struct lockthread));
    		ast_mutex_unlock(&locklock);
    	}			
    #endif
    
    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));
    
    	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) || (mode == REV_PATCH)) {
    
    		strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
    
            pthread_attr_init(&attr);
            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    
    	res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
    	if(res < 0)
    		ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
    
    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);
    	if (!mychannel)
    
    Mark Spencer's avatar
    Mark Spencer committed
    	{
    		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);
    	if (!genchannel)
    
    Mark Spencer's avatar
    Mark Spencer committed
    	{
    		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)
    
    		ast_string_field_set(mychannel, accountcode, myrpt->acctcode);
    
    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);
    	}