Newer
Older
/* 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
rpt_mutex_unlock(&myrpt->lock);
ast_copy_string(myrpt->lastlinknode, digitbuf, MAXNODESTR);
/* establish call in tranceive mode */
Tilghman Lesher
committed
l = ast_calloc(1, sizeof(*l));
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
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",
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
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))
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;
}
if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
/* 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;
Jim Dixon
committed
break;
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
}
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;
}
return DC_INDETERMINATE;
}
/*
* Autopatch up
*/
static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
{
int i, index;
Jim Dixon
committed
char *value = NULL;
AST_DECLARE_APP_ARGS(params,
AST_APP_ARG(list)[20];
);
Jim Dixon
committed
static char *keywords[] = {
"context",
"dialtime",
"farenddisconnect",
"noct",
"quiet",
NULL
};
if (!myrpt->enable)
return DC_ERROR;
ast_debug(1, "@@@@ Autopatch up\n");
if (!myrpt->callmode) {
Jim Dixon
committed
/* 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));
Jim Dixon
committed
if (param) {
Jim Dixon
committed
/* Process parameter list */
char *tmp = ast_strdupa(param);
Mark Michelson
committed
AST_STANDARD_APP_ARGS(params, tmp);
for (i = 0; i < params.argc; i++) {
index = matchkeyword(params.list[i], &value, keywords);
if (value)
Jim Dixon
committed
value = skipchars(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;
Jim Dixon
committed
}
}
}
}
rpt_mutex_lock(&myrpt->lock);
Jim Dixon
committed
/* if on call, force * into current audio stream */
if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) {
Jim Dixon
committed
myrpt->mydtmf = myrpt->p.funcchar;
}
if (myrpt->callmode) {
rpt_mutex_unlock(&myrpt->lock);
return DC_COMPLETE;
}
myrpt->callmode = 1;
myrpt->cidx = 0;
myrpt->exten[myrpt->cidx] = 0;
rpt_mutex_unlock(&myrpt->lock);
Russell Bryant
committed
ast_pthread_create_detached(&myrpt->rpt_call_thread, NULL, rpt_call, (void *) myrpt);
return DC_COMPLETE;
}
/*
* Autopatch down
*/
static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
{
if (!myrpt->enable)
return DC_ERROR;
ast_debug(1, "@@@@ Autopatch down\n");
rpt_mutex_lock(&myrpt->lock);
if (!myrpt->callmode) {
rpt_mutex_unlock(&myrpt->lock);
return DC_COMPLETE;
}
myrpt->callmode = 0;
rpt_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, struct rpt_link *mylink)
{
if (!param)
return DC_ERROR;
if (!myrpt->enable)
return DC_ERROR;
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;
}
/* Never reached */
return DC_INDETERMINATE;
}
/*
* 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);
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.startupmacro;
else
val = ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
/* param was 1 for local buf */
if (!val) {
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;
}
Steve Murphy
committed
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
/*
* 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;
}
/*
* COP - Control operator
*/
static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
{
if (!param)
return DC_ERROR;
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
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)
{
int i;
char *stringp, *functiondigits;
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));
else
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)))
break;
}
if (!vp) {
int n;
n = myrpt->longestfunc;
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 */
stringp = ast_strdupa(vp->value);
Mark Michelson
committed
AST_STANDARD_APP_ARGS(args, stringp);
ast_debug(1, "@@@@ action: %s, param = %s\n", args.action, S_OR(args.param, "(null)"));
/* Look up the action */
for (i = 0; i < (sizeof(function_table) / sizeof(struct function_table_tag)); i++) {
if (!strncasecmp(args.action, function_table[i].action, strlen(args.action)))
break;
}
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);
return;
}
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);
return;
}
if (dest[0] == '0') {
strcpy(dest, myrpt->name);
}
/* if not for me, redistribute to all links */
if (strcmp(dest, myrpt->name)) {
l = myrpt->links.next;
/* see if this is one in list */
while (l != &myrpt->links) {
if (l->name[0] == '0') {
/* dont send back from where it came */
if ((l == mylink) || (!strcmp(l->name, mylink->name))) {
l = l->next;
continue;
}
/* if it is, send it and we're done */
if (!strcmp(l->name, dest)) {
/* send, but not to src */
if (strcmp(l->name, src)) {
wf.data = ast_strdup(str);
if (l->chan)
}
return;
}
l = l->next;
}
l = myrpt->links.next;
/* otherwise, send it to all of em */
while (l != &myrpt->links) {
if (l->name[0] == '0') {
/* dont send back from where it came */
if ((l == mylink) || (!strcmp(l->name, mylink->name))) {
l = l->next;
continue;
}
/* send, but not to src */
wf.data = ast_strdup(str);
if (l->chan)
ast_write(l->chan, &wf);
}
l = l->next;
}
return;
}
rpt_mutex_lock(&myrpt->lock);
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)) {
myrpt->callmode = 2;
if (!myrpt->patchquiet) {
Jim Dixon
committed
rpt_mutex_unlock(&myrpt->lock);
rpt_telemetry(myrpt, PROC, NULL);
Jim Dixon
committed
rpt_mutex_lock(&myrpt->lock);
}
}
/* if can continue, do so */
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->mydtmf = c;
}
if (c == myrpt->p.funcchar) {
myrpt->rem_dtmfidx = 0;
myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
time(&myrpt->rem_dtmf_time);
rpt_mutex_unlock(&myrpt->lock);
return;
} else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0)) {
time(&myrpt->rem_dtmf_time);
if (myrpt->rem_dtmfidx < MAXDTMF) {
myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
rpt_mutex_unlock(&myrpt->lock);
ast_copy_string(cmd, myrpt->rem_dtmfbuf, sizeof(cmd));
res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
rpt_mutex_lock(&myrpt->lock);
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
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;
}
rpt_mutex_unlock(&myrpt->lock);
return;
}
static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink, char c)
{
char cmd[300];
int res;
rpt_mutex_lock(&myrpt->lock);
if (c == myrpt->p.endchar) {
if (mylink->lastrx) {
mylink->lastrx = 0;
rpt_mutex_unlock(&myrpt->lock);
return;
}
myrpt->stopgen = 1;
if (myrpt->cmdnode[0]) {
myrpt->cmdnode[0] = 0;
myrpt->dtmfidx = -1;
myrpt->dtmfbuf[0] = 0;
rpt_mutex_unlock(&myrpt->lock);
rpt_telemetry(myrpt, COMPLETE, NULL);
return;
}
}
if (myrpt->cmdnode[0]) {
rpt_mutex_unlock(&myrpt->lock);
send_link_dtmf(myrpt, c);
return;
}
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)) {
myrpt->callmode = 2;
if (!myrpt->patchquiet) {
Jim Dixon
committed
rpt_mutex_unlock(&myrpt->lock);
rpt_telemetry(myrpt, PROC, NULL);
Jim Dixon
committed
rpt_mutex_lock(&myrpt->lock);
}
}
/* if can continue, do so */
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->mydtmf = c;
}
if (c == myrpt->p.funcchar) {
myrpt->rem_dtmfidx = 0;
myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
time(&myrpt->rem_dtmf_time);
rpt_mutex_unlock(&myrpt->lock);
return;
} else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0)) {
time(&myrpt->rem_dtmf_time);
if (myrpt->rem_dtmfidx < MAXDTMF) {
myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
rpt_mutex_unlock(&myrpt->lock);
ast_copy_string(cmd, myrpt->rem_dtmfbuf, sizeof(cmd));
switch(mylink->phonemode) {
case 1:
res = collect_function_digits(myrpt, cmd,
SOURCE_PHONE, mylink);
break;
case 2:
res = collect_function_digits(myrpt, cmd,
break;
default:
res = collect_function_digits(myrpt, cmd,
SOURCE_LNK, mylink);
break;
}
rpt_mutex_lock(&myrpt->lock);
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
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;
}
}
}
rpt_mutex_unlock(&myrpt->lock);
return;
}
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
/* 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)
{
int i;
i = atoi(str) / 10; /* get the 10's of mhz */
switch (i) {
case 2:
return 10;
case 5:
return 11;
case 14:
return 2;
case 22:
return 3;
case 44:
return 4;
case 124:
return 0;
case 125:
return 1;
case 126:
return 8;
case 127:
return 5;
case 128:
return 6;
case 129:
return 7;
default:
break;
}
return -1;
}
/* take a PL frequency and turn it into a code */
static int rbi_pltocode(char *str)
{
int i;
char *s;
s = strchr(str, '.');
i = 0;
if (s)
i = atoi(s + 1);
i += atoi(str) * 10;
switch(i) {
case 670:
return 0;
case 719:
return 1;
case 744:
return 2;
case 770:
return 3;
case 797:
return 4;
case 825:
return 5;
case 854:
return 6;
case 885:
return 7;
case 915:
return 8;
case 948:
return 9;
case 974:
return 10;
case 1000:
return 11;
case 1035:
return 12;
case 1072:
return 13;
case 1109:
return 14;
case 1148:
return 15;
case 1188:
return 16;
case 1230:
return 17;
case 1273:
return 18;
case 1318:
return 19;
case 1365:
return 20;
case 1413:
return 21;
case 1462:
return 22;
case 1514:
return 23;
case 1567:
return 24;
case 1622:
return 25;
case 1679:
return 26;
case 1738:
return 27;
case 1799:
return 28;
case 1862:
return 29;
case 1928:
return 30;
case 2035:
return 31;
case 2107:
return 32;
case 2181:
return 33;
case 2257:
return 34;
case 2336:
return 35;
case 2418:
return 36;
case 2503:
return 37;
}
return -1;
}
/*
* Shift out a formatted serial bit stream
*/
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);
}
}
/* >= 50 us */
usleep(50);
}
static void rbi_out(struct rpt *myrpt, unsigned char *data)
struct zt_radio_param r = { 0, };
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) {
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);
return;
}
}
static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, char *rxbuf, int rxmaxbytes, int asciiflag)
{
int i;
struct zt_radio_param prm;
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;
}
return(prm.index);
}
static int setrbi(struct rpt *myrpt)
{
char tmp[MAXREMSTR] = "", *s;
unsigned char rbicmd[5];
int band, txoffset = 0, txpower = 0, txpl;
/* must be a remote system */
if (!myrpt->remote)
return(0);
/* must have rbi hardware */
if (strncmp(myrpt->remote, remote_rig_rbi, 3))
return(0);
ast_copy_string(tmp, myrpt->freq, sizeof(tmp));
s = strchr(tmp, '.');
/* if no decimal, is invalid */