Skip to content
Snippets Groups Projects
app_rpt.c 199 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	case GOSUB_NOTFOUND:
    		/* wait a little bit */
    		wait_interval(myrpt, DLY_TELEM, mychannel);
    		res = ast_streamfile(mychannel, "rpt/gosub_notfound", mychannel->language);
    		break;
    
    		/* wait a little bit */
    		wait_interval(myrpt, DLY_TELEM, mychannel);
    		res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
    		break;
    
    	case GOSUB_BUSY:
    		/* wait a little bit */
    		wait_interval(myrpt, DLY_TELEM, mychannel);
    		res = ast_streamfile(mychannel, "rpt/gosub_busy", mychannel->language);
    		break;
    
    	case UNKEY:
    		if (myrpt->patchnoct && myrpt->callmode) { /* If no CT during patch configured, then don't send one */
    
    		* 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
    
    		if (tlist != &myrpt->tele) {
    			rpt_mutex_lock(&myrpt->lock);
    			while (tlist != &myrpt->tele) {
    				if (tlist->mode == UNKEY)
    					unkeys_queued++;
    				tlist = tlist->next;
    			}
    			rpt_mutex_unlock(&myrpt->lock);
    		}
    		if (unkeys_queued > 1) {
    
    		/* Wait for the telemetry timer to expire */
    		/* Periodically check the timer since it can be re-initialized above */
    
    				ctint = 100;
    			else
    				ctint = myrpt->unkeytocttimer;
    			ast_safe_sleep(mychannel, 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
    		*/
    
    		
    		rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
    		myrpt->dailykerchunks++;
    		myrpt->totalkerchunks++;
    		rpt_mutex_unlock(&myrpt->lock);
    	
    
    		haslink = 0;
    
    			while (l != &myrpt->links) {
    				if (l->name[0] == '0') {
    
    					l = l->next;
    					continue;
    				}
    				haslink = 1;
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    			res = telem_lookup(myrpt, mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
    
    				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(myrpt, 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(myrpt->cfg, myrpt->name, "unlinkedct"))) { /* Unlinked Courtesy Tone */
    			res = telem_lookup(myrpt, mychannel, myrpt->name, ct);
    			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);
    
    				ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode); /*@@@@@@@@@@@*/
    				ast_free(mytele);
    
    				ast_hangup(mychannel);
    				pthread_exit(NULL);
    			}
    
    			if ((ct = ast_variable_retrieve(myrpt->cfg, myrpt->name, "remotect"))) { /* Unlinked Courtesy Tone */
    				ast_safe_sleep(mychannel, 200);
    				res = telem_lookup(myrpt, mychannel, myrpt->name, ct);
    				if (res)
    
    				 	ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);		
    			}	
    		}
    
    			/* set for all to hear */
    			ci.chan = 0;
    			ci.confno = myrpt->txconf;
    			ci.confmode = ZT_CONF_CONFANN;
    			/* first put the channel on the conference in announce mode */
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    			if (ioctl(mychannel->fds[0], ZT_SETCONF, &ci) == -1) {
    
    				ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
    				rpt_mutex_lock(&myrpt->lock);
    				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); /*@@@@@@@@@@@*/
    				ast_free(mytele);		
    
    			snprintf(mystr, sizeof(mystr), "%04x", myrpt->lastunit);
    
    			ast_say_character_str(mychannel, mystr, NULL, mychannel->language);
    
    		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;
    
    		wait_interval(myrpt, DLY_TELEM, mychannel);
    
    		res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
    		break;
    
    		wait_interval(myrpt, DLY_TELEM, mychannel);
    
    		res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
    		break;
    
    		wait_interval(myrpt, DLY_TELEM, mychannel);
    
    		res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
    		break;
    
    		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;
    
    		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;
    
    		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) {
    			if (l->name[0] == '0') {
    
    				l = l->next;
    				continue;
    
    				ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
    
    Jim Dixon's avatar
    Jim Dixon committed
    				remque((struct qelem *)mytele);
    
    				ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode); /*@@@@@@@@@@@*/
    				ast_free(mytele);
    
    Jim Dixon's avatar
    Jim Dixon committed
    				ast_hangup(mychannel);
    
    			memcpy(m, l, sizeof(struct rpt_link));
    
    			insque((struct qelem *)m, (struct qelem *)linkbase.next);
    
    		res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
    
    			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);
    
    			hastx = 1;
    			res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
    
    				res = ast_waitstream(mychannel, "");
    			else
    				 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    			ast_stopstream(mychannel);
    		}
    		l = linkbase.next;
    
    			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;
    		}			
    
    			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;
    
    			m = l;
    			l = l->next;
    			remque((struct qelem *)m);
    
    	case LASTNODEKEY: /* Identify last node which keyed us up */
    
    			p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
    		else
    			p = NULL;
    		rpt_mutex_unlock(&myrpt->lock);
    
    			imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
    			break;
    		}
    		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, p, 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);
    		imdone = 1;
    		break;		
    
    
    		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 */
    
    		tv = ast_tvnow();
    		ast_localtime(&tv, &localtm, 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";
    
    			imdone = 1;
    			break;
    		}
    		/* Say the time is ... */		
    
    		if (sayfile(mychannel, "rpt/thetimeis") == -1) {
    
    			imdone = 1;
    			break;
    		}
    		/* Say the time */				
    
    		res = ast_say_time(mychannel, tv.tv_sec, "", mychannel->language);
    
    		if (!res) 
    			res = ast_waitstream(mychannel, "");
    		ast_stopstream(mychannel);		
    		imdone = 1;
    	    	break;
    
    	case STATS_VERSION:
    		wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
    
    		/* Say "version" */
    
    		if (sayfile(mychannel, "rpt/version") == -1) {
    
    			imdone = 1;
    			break;
    		}
    
    			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;
    		}
    
    			ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
    
    			res = ast_waitstream(mychannel, "");
    			ast_stopstream(mychannel);
    
    			 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
    		imdone = 1;
    
    	case ARB_ALPHA:
    		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;
    
    			tpl_working = ast_strdupa(mytele->param);
    			myparm = strsep(&tpl_working, ",");
    			tpl_current = strsep(&tpl_working, ":");
    
    			while (tpl_current && looptemp < sizeof(tmp)) {
    				tmp[looptemp] = tpl_current;
    
    				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);
    
    						dres = ast_waitstream(mychannel, "");
    					} else {
    						ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
    						dres = 0;
    					}
    				}
    			}
    		}
    
    Jim Dixon's avatar
    Jim Dixon committed
    		imdone = 1;
    		myrpt->stopgen = 0;
    
    		if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
    
    Jim Dixon's avatar
    Jim Dixon committed
    			break;
    
    		while (mychannel->generatordata && (!myrpt->stopgen)) {
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    			if (ast_safe_sleep(mychannel, 1)) break;
    
    Jim Dixon's avatar
    Jim Dixon committed
    		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) {
    
    			if (myrpt->tailmessagen >= myrpt->p.tailmsg.argc)
    				myrpt->tailmessagen = 0;
    		} else {
    
    			myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
    
    	sleep(5);
    	ast_mutex_lock(&locklock);
    	t = get_lockthread(pthread_self());
    	if (t)
    		memset(t, 0, sizeof(struct lockthread));
    	ast_mutex_unlock(&locklock);
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    static void rpt_telemetry(struct rpt *myrpt, int mode, void *data)
    
    	struct rpt_tele *tele;
    	struct rpt_link *mylink = (struct rpt_link *) data;
    	int res;
    
    		ast_log(LOG_WARNING, "Unable to allocate memory\n");
    
    	if ((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED)) {
    		if (mylink) {
    			memcpy(&tele->mylink, mylink, sizeof(struct rpt_link));
    
    	} else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
    		ast_copy_string(tele->param, (char *) data, sizeof(tele->param));
    
    	insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
    
    	res = ast_pthread_create_detached(&tele->threadid, NULL, rpt_tele_thread, (void *) tele);
    
    		rpt_mutex_lock(&myrpt->lock);
    		remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
    		rpt_mutex_unlock(&myrpt->lock);	
    
    		ast_log(LOG_WARNING, "Could not create telemetry thread: %s\n", 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;
    	struct ast_frame wf;
    	int stopped, congstarted, dialtimer, lastcidx, aborted;
    	struct ast_channel *mychannel, *genchannel;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	myrpt->mydtmf = 0;
    	/* allocate a pseudo-channel thru asterisk */
    
    	mychannel = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
    	if (!mychannel) {
    		ast_log(LOG_ERROR, "rpt: unable to obtain pseudo channel\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		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) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		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) {
    		ast_log(LOG_ERROR, "rpt: unable to obtain pseudo channel\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		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) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		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->p.tonezone && (tone_zone_set_zone(mychannel->fds[0], myrpt->p.tonezone) == -1)) {
    		ast_log(LOG_WARNING, "Unable to set tone zone %s\n", myrpt->p.tonezone);
    
    		ast_hangup(mychannel);
    		ast_hangup(genchannel);
    		myrpt->callmode = 0;
    		pthread_exit(NULL);
    	}
    
    	if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0], myrpt->p.tonezone) == -1)) {
    		ast_log(LOG_WARNING, "Unable to set tone zone %s\n", myrpt->p.tonezone);
    
    		ast_hangup(mychannel);
    		ast_hangup(genchannel);
    		myrpt->callmode = 0;
    		pthread_exit(NULL);
    	}
    
    	/* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
    
    	if ((!myrpt->patchquiet) && (tone_zone_play_tone(mychannel->fds[0], ZT_TONE_DIALTONE) < 0)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		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->patchdialtime) && (myrpt->callmode == 1) && (myrpt->cidx != lastcidx)) {
    
    		if ((myrpt->patchdialtime) && (dialtimer >= myrpt->patchdialtime)) { 
    
    			rpt_mutex_lock(&myrpt->lock);
    			aborted = 1;
    			myrpt->callmode = 0;
    			rpt_mutex_unlock(&myrpt->lock);
    			break;
    		}
    	
    
    		if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			stopped = 1;
    			/* stop dial tone */
    
    			tone_zone_play_tone(mychannel->fds[0], -1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    		if (myrpt->callmode == 4) {
    			if (!congstarted) {
    
    				congstarted = 1;
    				/* start congestion tone */
    
    				tone_zone_play_tone(mychannel->fds[0], ZT_TONE_CONGESTION);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    Jim Dixon's avatar
    Jim Dixon committed
    		res = ast_safe_sleep(mychannel, MSWAIT);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			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
    	}
    	/* stop any tone generation */
    
    	tone_zone_play_tone(mychannel->fds[0], -1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* end if done */
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_hangup(mychannel);
    		ast_hangup(genchannel);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		myrpt->callmode = 0;
    
    		if ((!myrpt->patchquiet) && aborted)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		pthread_exit(NULL);			
    	}
    
    	if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid) {
    
    		instr = ast_strdup(myrpt->p.ourcallerid);
    		if (instr) {
    
    			ast_callerid_parse(instr, &name, &loc);
    
    			if (loc) {
    				if (mychannel->cid.cid_num)
    					ast_free(mychannel->cid.cid_num);
    				mychannel->cid.cid_num = ast_strdup(loc);
    
    			if (name) {
    				if (mychannel->cid.cid_name)
    					ast_free(mychannel->cid.cid_name);
    				mychannel->cid.cid_name = ast_strdup(name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten));
    	ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context));
    
    		ast_copy_string((char *)mychannel->accountcode, myrpt->p.acctcode, sizeof(mychannel->accountcode));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	mychannel->priority = 1;
    	ast_channel_undefer_dtmf(mychannel);
    
    	if (ast_pbx_start(mychannel) < 0) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		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;
    
    	/* set appropriate conference for the pseudo */
    	ci.chan = 0;
    	ci.confno = myrpt->conf;
    	ci.confmode = (myrpt->p.duplex == 2) ? ZT_CONF_CONFANNMON :
    		(ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
    	/* first put the channel on the conference in announce mode */
    
    	if (ioctl(myrpt->pchannel->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);
    	}
    
    	while (myrpt->callmode) {
    		if ((!mychannel->pbx) && (myrpt->callmode != 4)) {
    			if (myrpt->patchfarenddisconnect) { /* If patch is setup for far end disconnect */
    
    					rpt_mutex_unlock(&myrpt->lock);
    					rpt_telemetry(myrpt, TERM, NULL);
    					rpt_mutex_lock(&myrpt->lock);
    				}
    
    			} else { /* Send congestion until patch is downed by command */
    
    				myrpt->callmode = 4;
    				rpt_mutex_unlock(&myrpt->lock);
    				/* start congestion tone */
    
    				tone_zone_play_tone(genchannel->fds[0], ZT_TONE_CONGESTION);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    			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
    			myrpt->mydtmf = 0;
    		}
    
    Jim Dixon's avatar
    Jim Dixon committed
    		usleep(MSWAIT * 1000);
    
    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;
    
    	/* set appropriate conference for the pseudo */
    	ci.chan = 0;
    	ci.confno = myrpt->conf;
    	ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON :
    		(ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
    	/* first put the channel on the conference in announce mode */
    
    	if (ioctl(myrpt->pchannel->fds[0], ZT_SETCONF, &ci) == -1) {
    
    		ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	pthread_exit(NULL);
    }
    
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    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 (l->name[0] == '0') {
    
    			l = l->next;
    			continue;
    		}
    
    		/* if we found it, write it and were done */
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    		if (!strcmp(l->name, myrpt->cmdnode)) {
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    				ast_write(l->chan, &wf);
    
    		}
    		l = l->next;
    	}
    	l = myrpt->links.next;
    	/* if not, give it to everyone */
    
    	while (l != &myrpt->links) {
    		wf.data = ast_strdup(str);
    		if (l->chan)
    			ast_write(l->chan, &wf);
    
    static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
    
    	char *s, *tele;
    	char deststr[300] = "", modechange = 0;
    
    	ZT_CONFINFO ci;  /* conference info */
    
    	AST_DECLARE_APP_ARGS(args,
    		AST_APP_ARG(s1);
    		AST_APP_ARG(s2); /* XXX Never used.  Scratch? XXX */
    	);
    
    	ast_copy_string(digitbuf, digits, sizeof(digitbuf));
    
    	ast_debug(1, "@@@@ ilink param = %s, digitbuf = %s\n", S_OR(param, "(null)"), digitbuf);
    
    
    	switch (myatoi(param)) {
    	case 1: /* Link off */
    		if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
    			strcpy(digitbuf, myrpt->lastlinknode);
    		val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
    		if (!val) {
    			if (strlen(digitbuf) >= myrpt->longestnode)
    				return DC_ERROR;
    			break;
    		}
    		rpt_mutex_lock(&myrpt->lock);
    		l = myrpt->links.next;
    		/* try to find this one in queue */
    		while (l != &myrpt->links) {
    			if (l->name[0] == '0') {
    
    			/* if found matching string */
    			if (!strcmp(l->name, digitbuf))
    
    			l = l->next;
    		}
    		if (l != &myrpt->links) { /* if found */
    			struct ast_frame wf;
    			ast_copy_string(myrpt->lastlinknode, digitbuf, MAXNODESTR);
    			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 = ast_strdup(discstr);
    			if (l->chan) {
    				ast_write(l->chan, &wf);
    				if (ast_safe_sleep(l->chan, 250) == -1)
    
    				ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
    
    			rpt_telemetry(myrpt, COMPLETE, NULL);
    			return DC_COMPLETE;
    		}
    		rpt_mutex_unlock(&myrpt->lock);	
    		return DC_COMPLETE;
    	case 2: /* Link Monitor */
    		if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
    			strcpy(digitbuf, myrpt->lastlinknode);
    		val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
    		if (!val) {
    			if (strlen(digitbuf) >= myrpt->longestnode)
    				return DC_ERROR;
    			break;
    		}
    		s = ast_strdupa(val);
    
    		rpt_mutex_lock(&myrpt->lock);
    		l = myrpt->links.next;
    		/* try to find this one in queue */
    		while (l != &myrpt->links) {
    			if (l->name[0] == '0') {
    
    			/* 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)) {
    
    				rpt_telemetry(myrpt, REMALREADY, NULL);
    				return DC_COMPLETE;
    
    			reconnects = l->reconnects;
    			rpt_mutex_unlock(&myrpt->lock);
    			if (l->chan)
    				ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
    			l->retries = MAX_RETRIES + 1;
    			l->disced = 2;
    			modechange = 1;
    		} else
    			rpt_mutex_unlock(&myrpt->lock);
    		ast_copy_string(myrpt->lastlinknode, digitbuf, MAXNODESTR);
    		/* establish call in monitor mode */
    
    		if (!l) {
    			ast_log(LOG_WARNING, "Unable to malloc\n");
    			return DC_ERROR;
    		}
    		snprintf(deststr, sizeof(deststr), "IAX2/%s", args.s1);
    		tele = strchr(deststr, '/');
    		if (!tele) {
    			ast_log(LOG_ERROR, "link2:Dial number (%s) must be in format tech/number\n", deststr);
    			return DC_ERROR;
    		}
    		*tele++ = 0;
    		l->isremote = (s && ast_true(s));
    		ast_copy_string(l->name, digitbuf, MAXNODESTR);
    		l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele, NULL);
    		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)";
    
    			ast_verb(3, "rpt (remote) initiating call to %s/%s on %s\n",
    
    					deststr, tele, l->chan->name);
    			if (l->chan->cid.cid_num)
    				ast_free(l->chan->cid.cid_num);
    			l->chan->cid.cid_num = ast_strdup(myrpt->name);
    			ast_call(l->chan, tele, 0);
    		} else {
    			rpt_telemetry(myrpt, CONNFAIL, l);
    			ast_free(l);
    
    			ast_verb(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) {
    			ast_log(LOG_ERROR, "rpt:Sorry unable to obtain pseudo channel\n");
    			ast_hangup(l->chan);
    			ast_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");
    			ast_hangup(l->chan);
    			ast_hangup(l->pchan);
    			ast_free(l);
    			return DC_ERROR;
    		}
    		rpt_mutex_lock(&myrpt->lock);
    		l->reconnects = reconnects;
    		/* insert at end of queue */
    		insque((struct qelem *)l, (struct qelem *)myrpt->links.next);
    		rpt_mutex_unlock(&myrpt->lock);
    		rpt_telemetry(myrpt, COMPLETE, NULL);
    		return DC_COMPLETE;
    	case 3: /* Link transceive */
    		if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    			strcpy(digitbuf, myrpt->lastlinknode);
    
    		val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
    		if (!val) {
    			if (strlen(digitbuf) >= myrpt->longestnode)
    
    Jim Dixon's avatar
    Jim Dixon committed
    				return DC_ERROR;
    
    		rpt_mutex_lock(&myrpt->lock);
    		l = myrpt->links.next;
    		/* try to find this one in queue */
    		while (l != &myrpt->links) {
    			if (l->name[0] == '0') {
    				l = l->next;
    				continue;