Skip to content
Snippets Groups Projects
app_rpt.c 199 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			/* 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_mutex_unlock(&myrpt->lock);
    
    				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
    
    		ast_copy_string(myrpt->lastlinknode, digitbuf, MAXNODESTR);
    		/* establish call in tranceive mode */
    
    		if (!l) {
    			ast_log(LOG_WARNING, "Unable to malloc\n");
    			return DC_ERROR;
    		}
    		l->mode = 1;
    		l->outbound = 1;
    		ast_copy_string(l->name, digitbuf, MAXNODESTR);
    		l->isremote = (s && ast_true(s));
    		if (modechange)
    			l->connected = 1;
    		snprintf(deststr, sizeof(deststr), "IAX2/%s", args.s1);
    		tele = strchr(deststr, '/');
    		if (!tele) {
    			ast_log(LOG_ERROR, "link3:Dial number (%s) must be in format tech/number\n", deststr);
    			ast_free(l);
    			return DC_ERROR;
    		}
    		*tele++ = 0;
    		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)";
    
    			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, 999);
    		} 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 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");
    			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 4: /* Enter Command Mode */
    		/* if doesnt allow link cmd, or no links active, return */
     		if (((command_source != SOURCE_RPT) &&
    			 (command_source != SOURCE_PHONE) &&
    			 (command_source != SOURCE_DPHONE)) ||
    			(myrpt->links.next == &myrpt->links))
    
    		/* if already in cmd mode, or selected self, fughetabahtit */
    		if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))) {
    			rpt_telemetry(myrpt, REMALREADY, NULL);
    
    		}
    		if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    			strcpy(digitbuf, myrpt->lastlinknode);
    
    		/* node must at least exist in list */
    		val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
    		if (!val) {
    			if (strlen(digitbuf) >= myrpt->longestnode)
    				return DC_ERROR;
    
    		}
    		rpt_mutex_lock(&myrpt->lock);
    		strcpy(myrpt->lastlinknode, digitbuf);
    		ast_copy_string(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode));
    		rpt_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) { /* This code is broke and needs to be changed to work with the reconnect kludge */
    			if (l->chan)
    				ast_softhangup(l->chan, AST_SOFTHANGUP_DEV); /* Hang 'em up */
    			l = l->next;
    		}
    		rpt_telemetry(myrpt, COMPLETE, NULL);
    		break;
    	case 7: /* Identify last node which keyed us up */
    		rpt_telemetry(myrpt, LASTNODEKEY, NULL);
    		break;
    	default:
    		return DC_ERROR;
    
    static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
    
    	AST_DECLARE_APP_ARGS(params,
    		AST_APP_ARG(list)[20];
    	);
    
    
    	static char *keywords[] = {
    	"context",
    	"dialtime",
    	"farenddisconnect",
    	"noct",
    	"quiet",
    	NULL
    	};
    
    		/* Set defaults */
    		myrpt->patchnoct = 0;
    		myrpt->patchdialtime = 0;
    		myrpt->patchfarenddisconnect = 0;
    		myrpt->patchquiet = 0;
    
    		ast_copy_string(myrpt->patchcontext, myrpt->p.ourcontext, sizeof(myrpt->patchcontext));
    
    			for (i = 0; i < params.argc; i++) {
    				index = matchkeyword(params.list[i], &value, keywords);
    				if (value)
    
    				switch (index) {
    				case 1: /* context */
    					ast_copy_string(myrpt->patchcontext, value, sizeof(myrpt->patchcontext)) ;
    					break;
    				case 2: /* dialtime */
    					myrpt->patchdialtime = atoi(value);
    					break;
    				case 3: /* farenddisconnect */
    					myrpt->patchfarenddisconnect = atoi(value);
    					break;
    				case 4:	/* noct */
    					myrpt->patchnoct = atoi(value);
    					break;
    				case 5: /* quiet */
    					myrpt->patchquiet = atoi(value);
    					break;
    				default:
    					break;
    
    	/* if on call, force * into current audio stream */
    	
    
    	if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) {
    
    		return DC_COMPLETE;
    	}
    	myrpt->callmode = 1;
    	myrpt->cidx = 0;
    	myrpt->exten[myrpt->cidx] = 0;
    
    	ast_pthread_create_detached(&myrpt->rpt_call_thread, NULL, rpt_call, (void *) myrpt);
    
    static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
    
    	ast_debug(1, "@@@@ Autopatch down\n");
    
    	rpt_telemetry(myrpt, TERM, NULL);
    	return DC_COMPLETE;
    }
    
    /*
    * Status
    */
    
    
    static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
    
    	ast_debug(1, "@@@@ 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;
    
    /*
    *  Macro-oni (without Salami)
    */
    
    static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
    {
    
    
    	const char *val;
    	int	i;
    	struct ast_channel *mychannel;
    
    
    	if ((!myrpt->remote) && (!myrpt->enable))
    		return DC_ERROR;
    
    
    	ast_debug(1, "@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
    
    	if (ast_strlen_zero(digitbuf)) /* needs 1 digit */
    
    	for (i = 0; i < digitbuf[i]; i++) {
    		if ((digitbuf[i] < '0') || (digitbuf[i] > '9'))
    
    	if (*digitbuf == '0')
    		val = myrpt->p.startupmacro;
    	else
    		val = ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
    
    		rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
    		return DC_COMPLETE;
    	}			
    	rpt_mutex_lock(&myrpt->lock);
    
    	if ((sizeof(myrpt->macrobuf) - strlen(myrpt->macrobuf)) < strlen(val)) {
    
    		rpt_mutex_unlock(&myrpt->lock);
    		rpt_telemetry(myrpt, MACRO_BUSY, NULL);
    		return DC_ERROR;
    	}
    	myrpt->macrotimer = MACROTIME;
    
    	strncat(myrpt->macrobuf, val, sizeof(myrpt->macrobuf) - 1);
    
    	rpt_mutex_unlock(&myrpt->lock);
    	return DC_COMPLETE;	
    }
    
    
    /*
    *  Gosub
    */
    
    static int function_gosub(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
    {
    
    	const char *val;
    	int	i;
    	struct ast_channel *mychannel;
    
    	if ((!myrpt->remote) && (!myrpt->enable))
    		return DC_ERROR;
    
    	if (debug) 
    		ast_log(LOG_DEBUG, "@@@@ gosub param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
    	
    	mychannel = myrpt->remchannel;
    
    	if (ast_strlen_zero(digitbuf)) /* needs 1 digit */
    		return DC_INDETERMINATE;
    			
    	for (i = 0; i < digitbuf[i]; i++) {
    		if ((digitbuf[i] < '0') || (digitbuf[i] > '9'))
    			return DC_ERROR;
    	}
       
    	if (*digitbuf == '0')
    		val = myrpt->p.startupgosub;
    	else
    		val = ast_variable_retrieve(myrpt->cfg, myrpt->p.gosub, digitbuf);
    	/* param was 1 for local buf */
    	if (!val) {
    		rpt_telemetry(myrpt, GOSUB_NOTFOUND, NULL);
    		return DC_COMPLETE;
    	}			
    	rpt_mutex_lock(&myrpt->lock);
    	if ((sizeof(myrpt->gosubbuf) - strlen(myrpt->gosubbuf)) < strlen(val)) {
    		rpt_mutex_unlock(&myrpt->lock);
    		rpt_telemetry(myrpt, GOSUB_BUSY, NULL);
    		return DC_ERROR;
    	}
    	myrpt->gosubtimer = GOSUBTIME;
    	strncat(myrpt->gosubbuf, val, sizeof(myrpt->gosubbuf) - 1);
    	rpt_mutex_unlock(&myrpt->lock);
    	return DC_COMPLETE;	
    }
    
    
    static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
    
    	switch(myatoi(param)) {
    	case 1: /* System reset */
    		ast_cli_command(STDERR_FILENO, "restart now"); /* A little less drastic than what was previously here. */
    		return DC_COMPLETE;
    	case 2:
    		myrpt->enable = 1;
    		rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
    		return DC_COMPLETE;
    	case 3:
    		myrpt->enable = 0;
    		return DC_COMPLETE;
    	case 4: /* test tone on */
    		rpt_telemetry(myrpt, TEST_TONE, NULL);
    		return DC_COMPLETE;
    	case 5: /* Disgorge variables to log for debug purposes */
    		myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
    		return DC_COMPLETE;
    	case 6: /* Simulate COR being activated (phone only) */
    		if (command_source != SOURCE_PHONE)
    			return DC_INDETERMINATE;
    		return DC_DOKEY;	
    	}	
    	return DC_INDETERMINATE;
    }
    
    * Collect digits one by one until something matches
    
    static int collect_function_digits(struct rpt *myrpt, char *digits, int command_source, struct rpt_link *mylink)
    
    	char function_table_name[30] = "";
    	struct ast_variable *vp;
    
    	AST_DECLARE_APP_ARGS(args,
    		AST_APP_ARG(action);
    		AST_APP_ARG(param);
    	);
    
    	ast_debug(1, "@@@@ Digits collected: %s, source: %d\n", digits, command_source);
    
    	if (command_source == SOURCE_DPHONE) {
    
    		if (!myrpt->p.dphone_functions)
    			return DC_INDETERMINATE;
    		ast_copy_string(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name));
    	} else if (command_source == SOURCE_PHONE) {
    		if (!myrpt->p.phone_functions)
    			return DC_INDETERMINATE;
    		ast_copy_string(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name));
    	} else if (command_source == SOURCE_LNK)
    		ast_copy_string(function_table_name, myrpt->p.link_functions, sizeof(function_table_name));
    
    		ast_copy_string(function_table_name, myrpt->p.functions, sizeof(function_table_name));
    
    	for (vp = ast_variable_browse(myrpt->cfg, function_table_name); vp; vp = vp->next) {
    		if (!strncasecmp(vp->name, digits, strlen(vp->name)))
    
    		if (command_source == SOURCE_LNK)
    			n = myrpt->link_longestfunc;
    		else if (command_source == SOURCE_PHONE)
    			n = myrpt->phone_longestfunc;
    		else if (command_source == SOURCE_DPHONE)
    			n = myrpt->dphone_longestfunc;
    
    		if (strlen(digits) >= n)
    
    			return DC_ERROR;
    		else
    			return DC_INDETERMINATE;
    
    	/* Found a match, retrieve value part and parse */
    
    	ast_debug(1, "@@@@ action: %s, param = %s\n", args.action, S_OR(args.param, "(null)"));
    
    	for (i = 0; i < (sizeof(function_table) / sizeof(struct function_table_tag)); i++) {
    		if (!strncasecmp(args.action, function_table[i].action, strlen(args.action)))
    
    	ast_debug(1, "@@@@ table index i = %d\n", i);
    
    	if (i == (sizeof(function_table) / sizeof(struct function_table_tag))) {
    
    		/* Error, action not in table */
    		return DC_ERROR;
    	}
    
    	if (function_table[i].function == NULL) {
    
    		/* Error, function undefined */
    
    		ast_debug(1, "@@@@ NULL for action: %s\n", args.action);
    
    		return DC_ERROR;
    	}
    	functiondigits = digits + strlen(vp->name);
    
    	return (*function_table[i].function)(myrpt, args.param, functiondigits, command_source, mylink);
    
    static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink, char *str)
    
    	char cmd[300] = "", dest[300], src[300], c;
    	int	seq, res;
    	struct rpt_link *l;
    	struct ast_frame wf;
    
    
    	wf.frametype = AST_FRAME_TEXT;
    	wf.subclass = 0;
    	wf.offset = 0;
    	wf.mallocd = 1;
    	wf.datalen = strlen(str) + 1;
    	wf.samples = 0;
    
    	if (!strcmp(str, discstr)) {
    		mylink->disced = 1;
    
    		mylink->retries = MAX_RETRIES + 1;
    
    		ast_softhangup(mylink->chan, AST_SOFTHANGUP_DEV);
    
    	if (sscanf(str, "%s %s %s %d %c", cmd, dest, src, &seq, &c) != 5) {
    		ast_log(LOG_WARNING, "Unable to parse link string %s\n", str);
    		return;
    	}
    	if (strcmp(cmd, "D")) {
    		ast_log(LOG_WARNING, "Unable to parse link string %s\n", str);
    
    	if (dest[0] == '0') {
    		strcpy(dest, myrpt->name);
    	}
    
    	/* if not for me, redistribute to all links */
    
    		l = myrpt->links.next;
    		/* see if this is one in list */
    
    		while (l != &myrpt->links) {
    			if (l->name[0] == '0') {
    
    				l = l->next;
    				continue;
    			}
    
    			/* dont send back from where it came */
    
    			if ((l == mylink) || (!strcmp(l->name, mylink->name))) {
    
    			/* if it is, send it and we're done */
    
    				if (strcmp(l->name, src)) {
    					wf.data = ast_strdup(str);
    					if (l->chan)
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    						ast_write(l->chan, &wf);
    
    			l = l->next;
    		}
    		l = myrpt->links.next;
    		/* otherwise, send it to all of em */
    
    		while (l != &myrpt->links) {
    			if (l->name[0] == '0') {
    
    				l = l->next;
    				continue;
    			}
    
    			/* dont send back from where it came */
    
    			if ((l == mylink) || (!strcmp(l->name, mylink->name))) {
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    			if (strcmp(l->name, src)) {
    
    				wf.data = ast_strdup(str);
    				if (l->chan)
    					ast_write(l->chan, &wf);
    
    	if (c == myrpt->p.endchar)
    		myrpt->stopgen = 1;
    	if (myrpt->callmode == 1) {
    
    		myrpt->exten[myrpt->cidx++] = c;
    		myrpt->exten[myrpt->cidx] = 0;
    		/* if this exists */
    
    		if (ast_exists_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
    
    		if (!ast_canmatch_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
    
    			/* call has failed, inform user */
    			myrpt->callmode = 4;
    		}
    	}
    
    	if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) {
    
    		myrpt->rem_dtmfidx = 0;
    		myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
    		time(&myrpt->rem_dtmf_time);
    
    	} else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0)) {
    
    		if (myrpt->rem_dtmfidx < MAXDTMF) {
    
    			myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
    			myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
    
    			ast_copy_string(cmd, myrpt->rem_dtmfbuf, sizeof(cmd));
    
    			res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
    
    			switch (res) {
    			case DC_INDETERMINATE:
    				break;
    			case DC_REQ_FLUSH:
    				myrpt->rem_dtmfidx = 0;
    				myrpt->rem_dtmfbuf[0] = 0;
    				break;
    			case DC_COMPLETE:
    				myrpt->totalexecdcommands++;
    				myrpt->dailyexecdcommands++;
    				ast_copy_string(myrpt->lastdtmfcommand, cmd, MAXDTMF);
    				myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
    				myrpt->rem_dtmfbuf[0] = 0;
    				myrpt->rem_dtmfidx = -1;
    				myrpt->rem_dtmf_time = 0;
    				break;
    			case DC_ERROR:
    			default:
    				myrpt->rem_dtmfbuf[0] = 0;
    				myrpt->rem_dtmfidx = -1;
    				myrpt->rem_dtmf_time = 0;
    				break;
    
    static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink, char c)
    
    	if (c == myrpt->p.endchar) {
    		if (mylink->lastrx) {
    
    			myrpt->cmdnode[0] = 0;
    			myrpt->dtmfidx = -1;
    			myrpt->dtmfbuf[0] = 0;
    
    			rpt_telemetry(myrpt, COMPLETE, NULL);
    
    		myrpt->exten[myrpt->cidx++] = c;
    		myrpt->exten[myrpt->cidx] = 0;
    		/* if this exists */
    
    		if (ast_exists_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
    
    		if (!ast_canmatch_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
    
    			/* call has failed, inform user */
    			myrpt->callmode = 4;
    		}
    	}
    
    	if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) {
    
    		myrpt->rem_dtmfidx = 0;
    		myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
    		time(&myrpt->rem_dtmf_time);
    
    	} else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0)) {
    
    		if (myrpt->rem_dtmfidx < MAXDTMF) {
    
    			myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
    			myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
    			
    
    			ast_copy_string(cmd, myrpt->rem_dtmfbuf, sizeof(cmd));
    			switch(mylink->phonemode) {
    		    case 1:
    
    				res = collect_function_digits(myrpt, cmd, 
    					SOURCE_PHONE, mylink);
    				break;
    
    				res = collect_function_digits(myrpt, cmd, 
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    					SOURCE_DPHONE, mylink);
    
    				res = collect_function_digits(myrpt, cmd, 
    					SOURCE_LNK, mylink);
    				break;
    			}
    
    			rpt_mutex_lock(&myrpt->lock);
    
    			switch(res) {
    			case DC_INDETERMINATE:
    				break;
    			case DC_DOKEY:
    				mylink->lastrx = 1;
    				break;
    			case DC_REQ_FLUSH:
    				myrpt->rem_dtmfidx = 0;
    				myrpt->rem_dtmfbuf[0] = 0;
    				break;
    			case DC_COMPLETE:
    				myrpt->totalexecdcommands++;
    				myrpt->dailyexecdcommands++;
    				ast_copy_string(myrpt->lastdtmfcommand, cmd, MAXDTMF);
    				myrpt->rem_dtmfbuf[0] = 0;
    				myrpt->rem_dtmfidx = -1;
    				myrpt->rem_dtmf_time = 0;
    				break;
    			case DC_ERROR:
    			default:
    				myrpt->rem_dtmfbuf[0] = 0;
    				myrpt->rem_dtmfidx = -1;
    				myrpt->rem_dtmf_time = 0;
    				break;
    
    /* Doug Hall RBI-1 serial data definitions:
     *
     * Byte 0: Expansion external outputs 
     * Byte 1: 
     *	Bits 0-3 are BAND as follows:
     *	Bits 4-5 are POWER bits as follows:
     *		00 - Low Power
     *		01 - Hi Power
     *		02 - Med Power
     *	Bits 6-7 are always set
     * Byte 2:
     *	Bits 0-3 MHZ in BCD format
     *	Bits 4-5 are offset as follows:
     *		00 - minus
     *		01 - plus
     *		02 - simplex
     *		03 - minus minus (whatever that is)
     *	Bit 6 is the 0/5 KHZ bit
     *	Bit 7 is always set
     * Byte 3:
     *	Bits 0-3 are 10 KHZ in BCD format
     *	Bits 4-7 are 100 KHZ in BCD format
     * Byte 4: PL Tone code and encode/decode enable bits
     *	Bits 0-5 are PL tone code (comspec binary codes)
     *	Bit 6 is encode enable/disable
     *	Bit 7 is decode enable/disable
     */
    
    /* take the frequency from the 10 mhz digits (and up) and convert it
       to a band number */
    
    static int rbi_mhztoband(char *str)
    
    
    	i = atoi(str) / 10; /* get the 10's of mhz */
    
    /* take a PL frequency and turn it into a code */
    static int rbi_pltocode(char *str)
    
    Jim Dixon's avatar
    Jim Dixon committed
    
    
    static void rbi_out_parallel(struct rpt *myrpt, unsigned char *data)
    {
    	int i, j;
    	unsigned char od, d;
    
    	for (i = 0; i < 5; i++) {
    		od = *data++; 
    		for (j = 0; j < 8; j++) {
    			d = od & 1;
    			outb(d, myrpt->p.iobase);
    			usleep(15);
    			od >>= 1;
    			outb(d | 2, myrpt->p.iobase);
    			usleep(30);
    			outb(d, myrpt->p.iobase);
    			usleep(10);
    		}
    	}
    
    static void rbi_out(struct rpt *myrpt, unsigned char *data)
    
    
    	r.radpar = ZT_RADPAR_REMMODE;
    	r.data = ZT_RADPAR_REM_RBI1;
    	/* if setparam ioctl fails, its probably not a pciradio card */
    
    	if (ioctl(myrpt->rxchannel->fds[0], ZT_RADIO_SETPARAM, &r) == -1) {
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    		rbi_out_parallel(myrpt, data);
    
    		return;
    	}
    	r.radpar = ZT_RADPAR_REMCOMMAND;
    
    	memcpy(&r.data, data, 5);
    	if (ioctl(myrpt->rxchannel->fds[0], ZT_RADIO_SETPARAM, &r) == -1) {
    		ast_log(LOG_WARNING, "Cannot send RBI command for channel %s\n", myrpt->rxchannel->name);
    
    static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, char *rxbuf, int rxmaxbytes, int asciiflag)
    
    	char *buf = alloca(30 + txbytes * 3);
    	int len;
    	ast_copy_string(buf, "String output was: ", 30 + txbytes * 3);
    	len = strlen(buf);
    	for (i = 0; i < txbytes; i++)
    		len += snprintf(buf + len, 30 + txbytes * 3 - len, "%02X ", (unsigned char) txbuf[i]);
    	strcat(buf + len, "\n");
    	ast_debug(1, "%s", buf);
    
    
    	prm.radpar = ZT_RADPAR_REMMODE;
    	if (asciiflag)
    		prm.data = ZT_RADPAR_REM_SERIAL_ASCII;
    	else
    		prm.data = ZT_RADPAR_REM_SERIAL;
    	if (ioctl(myrpt->rxchannel->fds[0], ZT_RADIO_SETPARAM, &prm) == -1)
    		return -1;
    	prm.radpar = ZT_RADPAR_REMCOMMAND;
    	prm.data = rxmaxbytes;
    	memcpy(prm.buf, txbuf, txbytes);
    	prm.index = txbytes;
    	if (ioctl(myrpt->rxchannel->fds[0], ZT_RADIO_SETPARAM, &prm) == -1)
    		return -1;
    	if (rxbuf) {
    		*rxbuf = 0;
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    		memcpy(rxbuf, prm.buf, prm.index);
    
    	char tmp[MAXREMSTR] = "", *s;
    	unsigned char rbicmd[5];
    	int	band, txoffset = 0, txpower = 0, txpl;
    
    	if (strncmp(myrpt->remote, remote_rig_rbi, 3))
    		return(0);
    	ast_copy_string(tmp, myrpt->freq, sizeof(tmp));
    	s = strchr(tmp, '.');