From: Jim Dixon Date: Tue, 31 Jul 2007 21:09:39 +0000 (+0000) Subject: Much newer version, 0.70 with much additions X-Git-Tag: 1.4.10~48 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=93c169da6fbfb54668e20db18d201ebbf915f854;p=thirdparty%2Fasterisk.git Much newer version, 0.70 with much additions git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@77846 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/apps/app_rpt.c b/apps/app_rpt.c index 34732a25a1..056af1456b 100644 --- a/apps/app_rpt.c +++ b/apps/app_rpt.c @@ -1,7 +1,9 @@ +/* #define OLD_ASTERISK */ +#define OLDKEY /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 2002-2005, Jim Dixon, WB6NIL + * Copyright (C) 2002-2007, Jim Dixon, WB6NIL * * Jim Dixon, WB6NIL * Serious contributions by Steve RoDgers, WA6ZFT @@ -20,7 +22,7 @@ /*! \file * * \brief Radio Repeater / Remote Base program - * version 0.48 06/13/06 + * version 0.70 07/22/07 * * \author Jim Dixon, WB6NIL * @@ -60,9 +62,23 @@ * 1 - System warm boot * 2 - System enable * 3 - System disable - * 4 - Test Tone On + * 4 - Test Tone On/Off * 5 - Dump System Variables on Console (debug) * 6 - PTT (phone mode only) + * 7 - Time out timer enable + * 8 - Time out timer disable + * 9 - Autopatch enable + * 10 - Autopatch disable + * 11 - Link enable + * 12 - Link disable + * 13 - Query System State + * 14 - Change System State + * 15 - Scheduler Enable + * 16 - Scheduler Disable + * 17 - User functions (time, id, etc) enable + * 18 - User functions (time, id, etc) disable + * 19 - Select alternate hang timer + * 20 - Select standard hang timer * * ilink cmds: * @@ -72,6 +88,12 @@ * 4 - Enter command mode on specified link * 5 - System status * 6 - Disconnect all links + * 11 - Disconnect a previously permanently connected link + * 12 - Permanently connect specified link -- monitor only + * 13 - Permanently connect specified link -- tranceive + * 15 - Full system status (all nodes) + * 16 - Reconnect links disconnected with "disconnect all links" + * 200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc) * * remote cmds: * @@ -102,7 +124,7 @@ * 118 - Scan Up Fast * 119 - Transmit allowing auto-tune * 140 - Link Status (brief) - * + * 200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc) * * * 'duplex' modes: (defaults to duplex=2) @@ -133,9 +155,17 @@ #define MAXDTMF 32 #define MAXMACRO 2048 +#define MAXLINKLIST 512 +#define LINKLISTTIME 10000 +#define LINKLISTSHORTTIME 200 #define MACROTIME 100 #define MACROPTIME 500 #define DTMF_TIMEOUT 3 +#define KENWOOD_RETRIES 5 + +#define AUTHTELLTIME 7000 +#define AUTHTXTIME 1000 +#define AUTHLOGOUTTIME 25000 #ifdef __RPT_NOTCH #define MAXFILTERS 10 @@ -143,18 +173,30 @@ #define DISC_TIME 10000 /* report disc after 10 seconds of no connect */ #define MAX_RETRIES 5 +#define MAX_RETRIES_PERM 1000000000 #define REDUNDANT_TX_TIME 2000 #define RETRY_TIMER_MS 5000 +#define START_DELAY 10 + #define MAXPEERSTR 31 #define MAXREMSTR 15 #define DELIMCHR ',' #define QUOTECHR 34 +#define MONITOR_DISK_BLOCKS_PER_MINUTE 38 + +#define DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000 +#define DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60) +#define DEFAULT_REMOTE_TIMEOUT (60 * 60) +#define DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60) +#define DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30 + #define NODES "nodes" +#define EXTNODES "extnodes" #define MEMORY "memory" #define MACRO "macro" #define FUNCTIONS "functions" @@ -162,9 +204,12 @@ #define MORSE "morse" #define FUNCCHAR '*' #define ENDCHAR '#' +#define EXTNODEFILE "/var/lib/asterisk/rpt_extnodes" #define DEFAULT_IOBASE 0x378 +#define DEFAULT_CIV_ADDR 0x58 + #define MAXCONNECTTIME 5000 #define MAXNODESTR 300 @@ -177,23 +222,31 @@ #define REM_SCANTIME 100 +#define DTMF_LOCAL_TIME 250 +#define DTMF_LOCAL_STARTTIME 500 + +#define IC706_PL_MEMORY_OFFSET 50 enum {REM_OFF,REM_MONITOR,REM_TX}; enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO, CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME, STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH, - TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY}; + TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS, + MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS, + REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE, + TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX}; + enum {REM_SIMPLEX,REM_MINUS,REM_PLUS}; enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR}; -enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_DOKEY}; +enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY}; enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE}; -enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM}; +enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY}; enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM}; @@ -220,9 +273,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include #include #include +#include #include +#ifdef OLD_ASTERISK +#include +#include +#else #include #include +#endif #include #include @@ -241,6 +300,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/config.h" #include "asterisk/say.h" #include "asterisk/localtime.h" +#include "asterisk/cdr.h" +#include + +/* Start a tone-list going */ +int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible); +/*! Stop the tones from playing */ +void ast_playtones_stop(struct ast_channel *chan); + +static char *tdesc = "Radio Repeater / Remote Base version 0.70 07/22/2007"; static char *app = "Rpt"; @@ -281,21 +349,37 @@ static char *descrip = " available to the phone user.\n" "\n"; -static unsigned int vmajor = 0; -static unsigned int vminor = 47; - -static int debug = 0; /* FIXME Set this >0 for extra debug output */ +static int debug = 0; /* Set this >0 for extra debug output */ static int nrpts = 0; +static char remdtmfstr[] = "0123456789*#ABCD"; + +enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD}; + +int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000}; + +#define NRPTSTAT 7 + +struct rpt_chan_stat +{ + struct timeval last; + long long total; + unsigned long count; + unsigned long largest; + struct timeval largest_time; +}; + char *discstr = "!!DISCONNECT!!"; static char *remote_rig_ft897="ft897"; static char *remote_rig_rbi="rbi"; +static char *remote_rig_kenwood="kenwood"; +static char *remote_rig_ic706="ic706"; #ifdef OLD_ASTERISK STANDARD_LOCAL_USER; +LOCAL_USER_DECL; #endif - #define MSWAIT 200 #define HANGTIME 5000 #define TOTIME 180000 @@ -305,6 +389,23 @@ STANDARD_LOCAL_USER; #define POLITEID 30000 #define FUNCTDELAY 1500 +#define MAXXLAT 20 +#define MAXXLATTIME 3 + +#define MAX_SYSSTATES 10 + +struct rpt_xlat +{ +char funccharseq[MAXXLAT]; +char endcharseq[MAXXLAT]; +char passchars[MAXXLAT]; +int funcindex; +int endindex; +time_t lastone; +} ; + +static time_t starttime = 0; + static pthread_t rpt_master_thread; struct rpt; @@ -319,8 +420,11 @@ struct rpt_link char name[MAXNODESTR]; /* identifier (routing) string */ char lasttx; char lastrx; + char lastrx1; char connected; char hasconnected; + char perma; + char thisconnected; char outbound; char disced; char killme; @@ -328,11 +432,20 @@ struct rpt_link long disctime; long retrytimer; long retxtimer; + long rerxtimer; int retries; + int max_retries; int reconnects; long long connecttime; struct ast_channel *chan; struct ast_channel *pchan; + char linklist[MAXLINKLIST]; + time_t linklistreceived; + long linklisttimer; + int dtmfed; + int linkunkeytocttimer; + struct ast_frame *lastf1,*lastf2; + struct rpt_chan_stat chan_stat[NRPTSTAT]; } ; struct rpt_lstat @@ -344,7 +457,9 @@ struct rpt_lstat char mode; char outbound; char reconnects; + char thisconnected; long long connecttime; + struct rpt_chan_stat chan_stat[NRPTSTAT]; } ; struct rpt_tele @@ -356,6 +471,7 @@ struct rpt_tele int mode; struct rpt_link mylink; char param[TELEPARAMSIZE]; + int submode; pthread_t threadid; } ; @@ -381,9 +497,21 @@ struct telem_defaults } ; +struct sysstate +{ + char txdisable; + char totdisable; + char linkfundisable; + char autopatchdisable; + char schedulerdisable; + char userfundisable; + char alternatetail; +}; + static struct rpt { ast_mutex_t lock; + ast_mutex_t remlock; struct ast_config *cfg; char reload; @@ -391,21 +519,25 @@ static struct rpt char *rxchanname; char *txchanname; char *remote; + struct rpt_chan_stat chan_stat[NRPTSTAT]; + unsigned int scram; struct { - - const char *ourcontext; - const char *ourcallerid; - const char *acctcode; - const char *ident; + char *ourcontext; + char *ourcallerid; + char *acctcode; + char *ident; char *tonezone; char simple; - const char *functions; - const char *link_functions; - const char *phone_functions; - const char *dphone_functions; - const char *nodes; + char *functions; + char *link_functions; + char *phone_functions; + char *dphone_functions; + char *nodes; + char *extnodes; + char *extnodefile; int hangtime; + int althangtime; int totime; int idtime; int tailmessagetime; @@ -414,13 +546,33 @@ static struct rpt int politeid; char *tailmessages[500]; int tailmessagemax; - const char *memory; - const char *macro; - const char *startupmacro; + char *memory; + char *macro; + char *startupmacro; int iobase; + char *ioport; char funcchar; char endchar; - char nobusyout; + char nobusyout; + char notelemtx; + char propagate_dtmf; + char propagate_phonedtmf; + char linktolink; + unsigned char civaddr; + struct rpt_xlat inxlat; + struct rpt_xlat outxlat; + char *archivedir; + int authlevel; + char *csstanzaname; + char *skedstanzaname; + char *txlimitsstanzaname; + long monminblocks; + int remoteinacttimeout; + int remotetimeout; + int remotetimeoutwarning; + int remotetimeoutwarningfreq; + int sysstate_cur; + struct sysstate s[MAX_SYSSTATES]; } p; struct rpt_link links; int unkeytocttimer; @@ -430,16 +582,17 @@ static struct rpt char remoterx; char remotetx; char remoteon; + char remtxfreqok; char tounkeyed; char tonotify; - char enable; char dtmfbuf[MAXDTMF]; char macrobuf[MAXMACRO]; char rem_dtmfbuf[MAXDTMF]; char lastdtmfcommand[MAXDTMF]; char cmdnode[50]; - struct ast_channel *rxchannel,*txchannel; - struct ast_channel *pchannel,*txpchannel, *remchannel; + struct ast_channel *rxchannel,*txchannel, *monchannel; + struct ast_channel *pchannel,*txpchannel; + struct ast_frame *lastf1,*lastf2; struct rpt_tele tele; struct timeval lasttv,curtv; pthread_t rpt_call_thread,rpt_thread; @@ -452,6 +605,7 @@ static struct rpt int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts; int totalexecdcommands, dailyexecdcommands; long retxtimer; + long rerxtimer; long long totaltxtime; char mydtmf; char exten[AST_MAX_EXTENSION]; @@ -464,8 +618,10 @@ static struct rpt char tunerequest; char hfscanmode; int hfscanstatus; + char hfscanstop; char lastlinknode[MAXNODESTR]; - char stopgen; + char savednodes[MAXNODESTR]; + int stopgen; char patchfarenddisconnect; char patchnoct; char patchquiet; @@ -483,6 +639,15 @@ static struct rpt time_t lastthreadrestarttime; long macrotimer; char lastnodewhichkeyedusup[MAXNODESTR]; + int dtmf_local_timer; + char dtmf_local_str[100]; + struct ast_filestream *monstream; + char loginuser[50]; + char loginlevel[10]; + long authtelltimer; + long authtimer; + int iofd; + time_t start_time,last_activity_time; #ifdef __RPT_NOTCH struct rptfilter { @@ -505,6 +670,23 @@ static struct rpt #endif } rpt_vars[MAXRPTS]; +struct nodelog { +struct nodelog *next; +struct nodelog *prev; +time_t timestamp; +char archivedir[MAXNODESTR]; +char str[MAXNODESTR * 2]; +} nodelog; + +static int service_scan(struct rpt *myrpt); +static int set_mode_ft897(struct rpt *myrpt, char newmode); +static int set_mode_ic706(struct rpt *myrpt, char newmode); +static int simple_command_ft897(struct rpt *myrpt, char command); +static int setrem(struct rpt *myrpt); + +AST_MUTEX_DEFINE_STATIC(nodeloglock); + +AST_MUTEX_DEFINE_STATIC(nodelookuplock); #ifdef APP_RPT_LOCK_DEBUG @@ -532,7 +714,6 @@ struct by_lightning struct lockthread lockthread; } lock_ring[32]; - int lock_ring_index = 0; AST_MUTEX_DEFINE_STATIC(locklock); @@ -690,6 +871,19 @@ pthread_t id; #endif /* APP_RPT_LOCK_DEBUG */ +/* +* Return 1 if rig is multimode capable +*/ + +static int multimode_capable(struct rpt *myrpt) +{ + if(!strcmp(myrpt->remote, remote_rig_ft897)) + return 1; + if(!strcmp(myrpt->remote, remote_rig_ic706)) + return 1; + return 0; +} + /* * CLI extensions */ @@ -699,8 +893,10 @@ static int rpt_do_debug(int fd, int argc, char *argv[]); static int rpt_do_dump(int fd, int argc, char *argv[]); static int rpt_do_stats(int fd, int argc, char *argv[]); static int rpt_do_lstats(int fd, int argc, char *argv[]); +static int rpt_do_nodes(int fd, int argc, char *argv[]); static int rpt_do_reload(int fd, int argc, char *argv[]); static int rpt_do_restart(int fd, int argc, char *argv[]); +static int rpt_do_fun(int fd, int argc, char *argv[]); static char debug_usage[] = "Usage: rpt debug level {0-7}\n" @@ -718,6 +914,10 @@ static char dump_lstats[] = "Usage: rpt lstats \n" " Dumps link statistics to console\n"; +static char dump_nodes[] = +"Usage: rpt nodes \n" +" Dumps a list of directly and indirectly connected nodes to the console\n"; + static char reload_usage[] = "Usage: rpt reload\n" " Reloads app_rpt running config parameters\n"; @@ -726,30 +926,42 @@ static char restart_usage[] = "Usage: rpt restart\n" " Restarts app_rpt\n"; -static struct ast_cli_entry cli_rpt[] = { - { { "rpt", "debug", "level" }, - rpt_do_debug, "Enable app_rpt debugging", - debug_usage }, - - { { "rpt", "dump" }, - rpt_do_dump, "Dump app_rpt structs for debugging", - dump_usage }, - - { { "rpt", "stats" }, - rpt_do_stats, "Dump node statistics", - dump_stats }, - { { "rpt", "lstats" }, - rpt_do_lstats, "Dump link statistics", - dump_lstats }, - - { { "rpt", "reload" }, - rpt_do_reload, "Reload app_rpt config", - reload_usage }, - - { { "rpt", "restart" }, - rpt_do_restart, "Restart app_rpt", - restart_usage }, -}; +static char fun_usage[] = +"Usage: rpt fun \n" +" Send a DTMF function to a node\n"; + + +static struct ast_cli_entry cli_debug = + { { "rpt", "debug", "level" }, rpt_do_debug, + "Enable app_rpt debugging", debug_usage }; + +static struct ast_cli_entry cli_dump = + { { "rpt", "dump" }, rpt_do_dump, + "Dump app_rpt structs for debugging", dump_usage }; + +static struct ast_cli_entry cli_stats = + { { "rpt", "stats" }, rpt_do_stats, + "Dump node statistics", dump_stats }; + +static struct ast_cli_entry cli_nodes = + { { "rpt", "nodes" }, rpt_do_nodes, + "Dump node list", dump_nodes }; + +static struct ast_cli_entry cli_lstats = + { { "rpt", "lstats" }, rpt_do_lstats, + "Dump link statistics", dump_lstats }; + +static struct ast_cli_entry cli_reload = + { { "rpt", "reload" }, rpt_do_reload, + "Reload app_rpt config", reload_usage }; + +static struct ast_cli_entry cli_restart = + { { "rpt", "restart" }, rpt_do_restart, + "Restart app_rpt", restart_usage }; + +static struct ast_cli_entry cli_fun = + { { "rpt", "fun" }, rpt_do_fun, + "Execute a DTMF function", fun_usage }; /* * Telemetry defaults @@ -776,6 +988,10 @@ static struct telem_defaults tele_defs[] = { */ static int setrbi(struct rpt *myrpt); +static int set_ft897(struct rpt *myrpt); +static int set_ic706(struct rpt *myrpt); +static int setkenwood(struct rpt *myrpt); +static int setrbi_check(struct rpt *myrpt); @@ -804,6 +1020,228 @@ static struct function_table_tag function_table[] = { {"macro", function_macro} } ; +static long diskavail(struct rpt *myrpt) +{ +struct statfs statfsbuf; + + if (!myrpt->p.archivedir) return(0); + if (statfs(myrpt->p.archivedir,&statfsbuf) == -1) + { + ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n", + myrpt->p.archivedir,myrpt->name); + return(-1); + } + return(statfsbuf.f_bavail); +} + +static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c) +{ +struct rpt_link *l; + + l = myrpt->links.next; + /* go thru all the links */ + while(l != &myrpt->links) + { + if (!l->phonemode) + { + l = l->next; + continue; + } + /* dont send to self */ + if (mylink && (l == mylink)) + { + l = l->next; + continue; + } + if (l->chan) ast_senddigit(l->chan,c); + l = l->next; + } + return; +} + +/* node logging function */ +static void donodelog(struct rpt *myrpt,char *str) +{ +struct nodelog *nodep; +char datestr[100]; + + if (!myrpt->p.archivedir) return; + nodep = (struct nodelog *)malloc(sizeof(struct nodelog)); + if (nodep == NULL) + { + ast_log(LOG_ERROR,"Cannot get memory for node log"); + return; + } + time(&nodep->timestamp); + strncpy(nodep->archivedir,myrpt->p.archivedir, + sizeof(nodep->archivedir) - 1); + strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S", + localtime(&nodep->timestamp)); + snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n", + myrpt->name,datestr,str); + ast_mutex_lock(&nodeloglock); + insque((struct qelem *) nodep, (struct qelem *) nodelog.prev); + ast_mutex_unlock(&nodeloglock); +} + +/* must be called locked */ +static void do_dtmf_local(struct rpt *myrpt, char c) +{ +int i; +char digit; +static const char* dtmf_tones[] = { + "!941+1336/200,!0/200", /* 0 */ + "!697+1209/200,!0/200", /* 1 */ + "!697+1336/200,!0/200", /* 2 */ + "!697+1477/200,!0/200", /* 3 */ + "!770+1209/200,!0/200", /* 4 */ + "!770+1336/200,!0/200", /* 5 */ + "!770+1477/200,!0/200", /* 6 */ + "!852+1209/200,!0/200", /* 7 */ + "!852+1336/200,!0/200", /* 8 */ + "!852+1477/200,!0/200", /* 9 */ + "!697+1633/200,!0/200", /* A */ + "!770+1633/200,!0/200", /* B */ + "!852+1633/200,!0/200", /* C */ + "!941+1633/200,!0/200", /* D */ + "!941+1209/200,!0/200", /* * */ + "!941+1477/200,!0/200" }; /* # */ + + + if (c) + { + snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c); + if (!myrpt->dtmf_local_timer) + myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME; + } + /* if at timeout */ + if (myrpt->dtmf_local_timer == 1) + { + /* if anything in the string */ + if (myrpt->dtmf_local_str[0]) + { + digit = myrpt->dtmf_local_str[0]; + myrpt->dtmf_local_str[0] = 0; + for(i = 1; myrpt->dtmf_local_str[i]; i++) + { + myrpt->dtmf_local_str[i - 1] = + myrpt->dtmf_local_str[i]; + } + myrpt->dtmf_local_str[i - 1] = 0; + myrpt->dtmf_local_timer = DTMF_LOCAL_TIME; + rpt_mutex_unlock(&myrpt->lock); + if (digit >= '0' && digit <='9') + ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0); + else if (digit >= 'A' && digit <= 'D') + ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0); + else if (digit == '*') + ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0); + else if (digit == '#') + ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0); + else { + /* not handled */ + ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name); + } + rpt_mutex_lock(&myrpt->lock); + } + else + { + myrpt->dtmf_local_timer = 0; + } + } +} + +static int openserial(char *fname) +{ + struct termios mode; + int fd; + + fd = open(fname,O_RDWR); + if (fd == -1) + { + ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname); + return -1; + } + memset(&mode, 0, sizeof(mode)); + if (tcgetattr(fd, &mode)) { + ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno)); + return -1; + } +#ifndef SOLARIS + cfmakeraw(&mode); +#else + mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP + |INLCR|IGNCR|ICRNL|IXON); + mode.c_oflag &= ~OPOST; + mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS); + mode.c_cflag |= CS8; + mode.c_cc[TIME] = 3; + mode.c_cc[MAX] = 1; +#endif + + cfsetispeed(&mode, B9600); + cfsetospeed(&mode, B9600); + if (tcsetattr(fd, TCSANOW, &mode)) + ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno)); + return(fd); +} + +static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat) +{ +time_t now; +int gotone; + + time(&now); + gotone = 0; + /* if too much time, reset the skate machine */ + if ((now - xlat->lastone) > MAXXLATTIME) + { + xlat->funcindex = xlat->endindex = 0; + } + if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++])) + { + time(&xlat->lastone); + gotone = 1; + if (!xlat->funccharseq[xlat->funcindex]) + { + xlat->funcindex = xlat->endindex = 0; + return(myrpt->p.funcchar); + } + } else xlat->funcindex = 0; + if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++])) + { + time(&xlat->lastone); + gotone = 1; + if (!xlat->endcharseq[xlat->endindex]) + { + xlat->funcindex = xlat->endindex = 0; + return(myrpt->p.endchar); + } + } else xlat->endindex = 0; + /* if in middle of decode seq, send nothing back */ + if (gotone) return(0); + /* if no pass chars specified, return em all */ + if (!xlat->passchars[0]) return(c); + /* if a "pass char", pass it */ + if (strchr(xlat->passchars,c)) return(c); + return(0); +} + +/* + * Return a pointer to the first non-whitespace character + */ + +static char *eatwhite(char *s) +{ + while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */ + if(!*s) + break; + s++; + } + return s; +} + /* * Break up a delimited string into a table of substrings * @@ -853,9 +1291,135 @@ int i,l,inquo; } +/* must be called locked */ +static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf) +{ +struct rpt_link *l; +char mode; +int i,spos; + + buf[0] = 0; /* clear output buffer */ + /* go thru all links */ + for(l = myrpt->links.next; l != &myrpt->links; l = l->next) + { + /* if is not a real link, ignore it */ + if (l->name[0] == '0') continue; + /* dont count our stuff */ + if (l == mylink) continue; + if (mylink && (!strcmp(l->name,mylink->name))) continue; + /* figure out mode to report */ + mode = 'T'; /* use Tranceive by default */ + if (!l->mode) mode = 'R'; /* indicate RX for our mode */ + if (!l->thisconnected) mode = 'C'; /* indicate connecting */ + spos = strlen(buf); /* current buf size (b4 we add our stuff) */ + if (spos) + { + strcat(buf,","); + spos++; + } + /* add nodes into buffer */ + if (l->linklist[0]) + { + snprintf(buf + spos,MAXLINKLIST - spos, + "%c%s,%s",mode,l->name,l->linklist); + } + else /* if no nodes, add this node into buffer */ + { + snprintf(buf + spos,MAXLINKLIST - spos, + "%c%s",mode,l->name); + } + /* if we are in tranceive mode, let all modes stand */ + if (mode == 'T') continue; + /* downgrade everyone on this node if appropriate */ + for(i = spos; buf[i]; i++) + { + if (buf[i] == 'T') buf[i] = mode; + if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode; + } + } + return; +} + +/* must be called locked */ +static void __kickshort(struct rpt *myrpt) +{ +struct rpt_link *l; + + for(l = myrpt->links.next; l != &myrpt->links; l = l->next) + { + /* if is not a real link, ignore it */ + if (l->name[0] == '0') continue; + l->linklisttimer = LINKLISTSHORTTIME; + } + return; +} + +static char *node_lookup(struct rpt *myrpt,char *digitbuf) +{ + +char *val; +int longestnode,j; +struct stat mystat; +static time_t last = 0; +static struct ast_config *ourcfg = NULL; +struct ast_variable *vp; + + /* try to look it up locally first */ + val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf); + if (val) return(val); + ast_mutex_lock(&nodelookuplock); + /* if file does not exist */ + if (stat(myrpt->p.extnodefile,&mystat) == -1) + { + if (ourcfg) ast_config_destroy(ourcfg); + ourcfg = NULL; + ast_mutex_unlock(&nodelookuplock); + return(NULL); + } + /* if we need to reload */ + if (mystat.st_mtime > last) + { + if (ourcfg) ast_config_destroy(ourcfg); + ourcfg = ast_config_load(myrpt->p.extnodefile); + /* if file not there, just bail */ + if (!ourcfg) + { + ast_mutex_unlock(&nodelookuplock); + return(NULL); + } + /* reset "last" time */ + last = mystat.st_mtime; + + /* determine longest node length again */ + longestnode = 0; + vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes); + while(vp){ + j = strlen(vp->name); + if (j > longestnode) + longestnode = j; + vp = vp->next; + } + + vp = ast_variable_browse(ourcfg, myrpt->p.extnodes); + while(vp){ + j = strlen(vp->name); + if (j > longestnode) + longestnode = j; + vp = vp->next; + } + + myrpt->longestnode = longestnode; + } + val = NULL; + if (ourcfg) + val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf); + ast_mutex_unlock(&nodelookuplock); + return(val); +} + /* -* Match a keyword in a list, and return index of string plus 1 if there was a match, -* else return 0. If param is passed in non-null, then it will be set to the first character past the match +* Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0. +* If param is passed in non-null, then it will be set to the first character past the match */ static int matchkeyword(char *string, char **param, char *keywords[]) @@ -900,7 +1464,7 @@ int i; -static int myatoi(const char *str) +static int myatoi(char *str) { int ret; @@ -910,6 +1474,16 @@ int ret; return ret; } +static int mycompar(const void *a, const void *b) +{ +char **x = (char **) a; +char **y = (char **) b; +int xoff,yoff; + + if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0; + if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0; + return(strcmp((*x) + xoff,(*y) + yoff)); +} #ifdef __RPT_NOTCH @@ -937,16 +1511,50 @@ struct rptfilter *f; #endif + +/* + Get the time for the machine's time zone + Note: Asterisk requires a copy of localtime + in the /etc directory for this to work properly. + If /etc/localtime is not present, you will get + GMT time! This is especially important on systems + running embedded linux distributions as they don't usually + have support for locales. + + If OLD_ASTERISK is defined, then the older localtime_r + function will be used. The /etc/localtime file is not + required in this case. This provides backward compatibility + with Asterisk 1.2 systems. + +*/ + +static void rpt_localtime( time_t * t, struct tm *lt) +{ +#ifdef OLD_ASTERISK + localtime_r(t, lt); +#else + ast_localtime(t, lt, NULL); +#endif +} + /* Retrieve an int from a config file */ static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl) { - const char *var; + char *var; int ret; - - var = ast_variable_retrieve(myrpt->cfg, category, name); + char include_zero = 0; + + if(min < 0){ /* If min is negative, this means include 0 as a valid entry */ + min = -min; + include_zero = 1; + } + + var = (char *) ast_variable_retrieve(myrpt->cfg, category, name); if(var){ ret = myatoi(var); + if(include_zero && !ret) + return 0; if(ret < min) ret = min; if(ret > max) @@ -960,15 +1568,14 @@ static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int static void load_rpt_vars(int n,int init) { -char *this; - const char *val; -int j,longestnode; +char *this,*val; +int i,j,longestnode; struct ast_variable *vp; struct ast_config *cfg; -#ifdef __RPT_NOTCH -int i; char *strs[100]; -#endif +char s1[256]; +static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis", + "ufena","ufdis","atena","atdis",NULL}; if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n", @@ -1001,76 +1608,118 @@ char *strs[100]; /* zot out filters stuff */ memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters)); #endif - val = ast_variable_retrieve(cfg,this,"context"); + val = (char *) ast_variable_retrieve(cfg,this,"context"); if (val) rpt_vars[n].p.ourcontext = val; else rpt_vars[n].p.ourcontext = this; - val = ast_variable_retrieve(cfg,this,"callerid"); + val = (char *) ast_variable_retrieve(cfg,this,"callerid"); if (val) rpt_vars[n].p.ourcallerid = val; - val = ast_variable_retrieve(cfg,this,"accountcode"); + val = (char *) ast_variable_retrieve(cfg,this,"accountcode"); if (val) rpt_vars[n].p.acctcode = val; - val = ast_variable_retrieve(cfg,this,"idrecording"); + val = (char *) ast_variable_retrieve(cfg,this,"idrecording"); if (val) rpt_vars[n].p.ident = val; - val = ast_variable_retrieve(cfg,this,"hangtime"); + val = (char *) ast_variable_retrieve(cfg,this,"hangtime"); if (val) rpt_vars[n].p.hangtime = atoi(val); else rpt_vars[n].p.hangtime = HANGTIME; - val = ast_variable_retrieve(cfg,this,"totime"); + val = (char *) ast_variable_retrieve(cfg,this,"althangtime"); + if (val) rpt_vars[n].p.althangtime = atoi(val); + else rpt_vars[n].p.althangtime = HANGTIME; + val = (char *) ast_variable_retrieve(cfg,this,"totime"); if (val) rpt_vars[n].p.totime = atoi(val); else rpt_vars[n].p.totime = TOTIME; rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0); rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0); rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2); - rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", 60000, 2400000, IDTIME); /* Enforce a min max */ + rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME); /* Enforce a min max including zero */ rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */ - val = ast_variable_retrieve(cfg,this,"tonezone"); - if (val) rpt_vars[n].p.tonezone = ast_strdupa(val); + val = (char *) ast_variable_retrieve(cfg,this,"tonezone"); + if (val) rpt_vars[n].p.tonezone = val; rpt_vars[n].p.tailmessages[0] = 0; rpt_vars[n].p.tailmessagemax = 0; - val = ast_variable_retrieve(cfg,this,"tailmessagelist"); - if (val) rpt_vars[n].p.tailmessagemax = finddelim(ast_strdupa(val), rpt_vars[n].p.tailmessages, 500); - val = ast_variable_retrieve(cfg,this,"memory"); + val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist"); + if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500); + val = (char *) ast_variable_retrieve(cfg,this,"memory"); if (!val) val = MEMORY; rpt_vars[n].p.memory = val; - val = ast_variable_retrieve(cfg,this,"macro"); + val = (char *) ast_variable_retrieve(cfg,this,"macro"); if (!val) val = MACRO; rpt_vars[n].p.macro = val; - val = ast_variable_retrieve(cfg,this,"startup_macro"); + val = (char *) ast_variable_retrieve(cfg,this,"startup_macro"); if (val) rpt_vars[n].p.startupmacro = val; - val = ast_variable_retrieve(cfg,this,"iobase"); + val = (char *) ast_variable_retrieve(cfg,this,"iobase"); /* do not use atoi() here, we need to be able to have the input specified in hex or decimal so we use sscanf with a %i */ if ((!val) || (sscanf(val,"%i",&rpt_vars[n].p.iobase) != 1)) rpt_vars[n].p.iobase = DEFAULT_IOBASE; - val = ast_variable_retrieve(cfg,this,"functions"); + val = (char *) ast_variable_retrieve(cfg,this,"ioport"); + rpt_vars[n].p.ioport = val; + val = (char *) ast_variable_retrieve(cfg,this,"functions"); if (!val) { val = FUNCTIONS; rpt_vars[n].p.simple = 1; } rpt_vars[n].p.functions = val; - val = ast_variable_retrieve(cfg,this,"link_functions"); + val = (char *) ast_variable_retrieve(cfg,this,"link_functions"); if (val) rpt_vars[n].p.link_functions = val; else rpt_vars[n].p.link_functions = rpt_vars[n].p.functions; - val = ast_variable_retrieve(cfg,this,"phone_functions"); + val = (char *) ast_variable_retrieve(cfg,this,"phone_functions"); if (val) rpt_vars[n].p.phone_functions = val; - val = ast_variable_retrieve(cfg,this,"dphone_functions"); + val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions"); if (val) rpt_vars[n].p.dphone_functions = val; - val = ast_variable_retrieve(cfg,this,"funcchar"); + val = (char *) ast_variable_retrieve(cfg,this,"funcchar"); if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else rpt_vars[n].p.funcchar = *val; - val = ast_variable_retrieve(cfg,this,"endchar"); + val = (char *) ast_variable_retrieve(cfg,this,"endchar"); if (!val) rpt_vars[n].p.endchar = ENDCHAR; else rpt_vars[n].p.endchar = *val; - val = ast_variable_retrieve(cfg,this,"nobusyout"); + val = (char *) ast_variable_retrieve(cfg,this,"nobusyout"); if (val) rpt_vars[n].p.nobusyout = ast_true(val); - val = ast_variable_retrieve(cfg,this,"nodes"); + val = (char *) ast_variable_retrieve(cfg,this,"notelemtx"); + if (val) rpt_vars[n].p.notelemtx = ast_true(val); + val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf"); + if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val); + val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf"); + if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val); + val = (char *) ast_variable_retrieve(cfg,this,"linktolink"); + if (val) rpt_vars[n].p.linktolink = ast_true(val); + val = (char *) ast_variable_retrieve(cfg,this,"nodes"); if (!val) val = NODES; rpt_vars[n].p.nodes = val; + val = (char *) ast_variable_retrieve(cfg,this,"extnodes"); + if (!val) val = EXTNODES; + rpt_vars[n].p.extnodes = val; + val = (char *) ast_variable_retrieve(cfg,this,"extnodefile"); + if (!val) val = EXTNODEFILE; + rpt_vars[n].p.extnodefile = val; + val = (char *) ast_variable_retrieve(cfg,this,"archivedir"); + if (val) rpt_vars[n].p.archivedir = val; + val = (char *) ast_variable_retrieve(cfg,this,"authlevel"); + if (val) rpt_vars[n].p.authlevel = atoi(val); + else rpt_vars[n].p.authlevel = 0; + val = (char *) ast_variable_retrieve(cfg,this,"monminblocks"); + if (val) rpt_vars[n].p.monminblocks = atol(val); + else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS; + val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout"); + if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); + else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT; + val = (char *) ast_variable_retrieve(cfg,this,"civaddr"); + if (val) rpt_vars[n].p.civaddr = atoi(val); + else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR; + val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout"); + if (val) rpt_vars[n].p.remotetimeout = atoi(val); + else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT; + val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning"); + if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); + else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING; + val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq"); + if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); + else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ; #ifdef __RPT_NOTCH - val = ast_variable_retrieve(cfg,this,"rxnotch"); + val = (char *) ast_variable_retrieve(cfg,this,"rxnotch"); if (val) { - i = finddelim(ast_strdupa(val),strs,MAXFILTERS * 2); + i = finddelim(val,strs,MAXFILTERS * 2); i &= ~1; /* force an even number, rounded down */ if (i >= 2) for(j = 0; j < i; j += 2) { @@ -1085,6 +1734,34 @@ char *strs[100]; } #endif + val = (char *) ast_variable_retrieve(cfg,this,"inxlat"); + if (val) { + memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat)); + i = finddelim(val,strs,3); + if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1); + if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1); + if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1); + } + val = (char *) ast_variable_retrieve(cfg,this,"outxlat"); + if (val) { + memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat)); + i = finddelim(val,strs,3); + if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1); + if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1); + if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1); + } + /* retreive the stanza name for the control states if there is one */ + val = (char *) ast_variable_retrieve(cfg,this,"controlstates"); + rpt_vars[n].p.csstanzaname = val; + + /* retreive the stanza name for the scheduler if there is one */ + val = (char *) ast_variable_retrieve(cfg,this,"scheduler"); + rpt_vars[n].p.skedstanzaname = val; + + /* retreive the stanza name for the txlimits */ + val = (char *) ast_variable_retrieve(cfg,this,"txlimits"); + rpt_vars[n].p.txlimitsstanzaname = val; + longestnode = 0; vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes); @@ -1150,6 +1827,88 @@ char *strs[100]; rpt_vars[n].macro_longest = j; vp = vp->next; } + + /* Browse for control states */ + if(rpt_vars[n].p.csstanzaname) + vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname); + else + vp = NULL; + for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */ + int k,nukw,statenum; + statenum=atoi(vp->name); + strncpy(s1, vp->value, 255); + s1[255] = 0; + nukw = finddelim(s1,strs,32); + + for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */ + for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */ + if(!strcmp(strs[k],cs_keywords[j])){ + switch(j){ + case 0: /* rptena */ + rpt_vars[n].p.s[statenum].txdisable = 0; + break; + case 1: /* rptdis */ + rpt_vars[n].p.s[statenum].txdisable = 1; + break; + + case 2: /* apena */ + rpt_vars[n].p.s[statenum].autopatchdisable = 0; + break; + + case 3: /* apdis */ + rpt_vars[n].p.s[statenum].autopatchdisable = 1; + break; + + case 4: /* lnkena */ + rpt_vars[n].p.s[statenum].linkfundisable = 0; + break; + + case 5: /* lnkdis */ + rpt_vars[n].p.s[statenum].linkfundisable = 1; + break; + + case 6: /* totena */ + rpt_vars[n].p.s[statenum].totdisable = 0; + break; + + case 7: /* totdis */ + rpt_vars[n].p.s[statenum].totdisable = 1; + break; + + case 8: /* skena */ + rpt_vars[n].p.s[statenum].schedulerdisable = 0; + break; + + case 9: /* skdis */ + rpt_vars[n].p.s[statenum].schedulerdisable = 1; + break; + + case 10: /* ufena */ + rpt_vars[n].p.s[statenum].userfundisable = 0; + break; + + case 11: /* ufdis */ + rpt_vars[n].p.s[statenum].userfundisable = 1; + break; + + case 12: /* atena */ + rpt_vars[n].p.s[statenum].alternatetail = 1; + break; + + case 13: /* atdis */ + rpt_vars[n].p.s[statenum].alternatetail = 0; + break; + + default: + ast_log(LOG_WARNING, + "Unhandled control state keyword %s", cs_keywords[i]); + break; + } + } + } + } + vp = vp->next; + } ast_mutex_unlock(&rpt_vars[n].lock); } @@ -1213,7 +1972,8 @@ static int rpt_do_stats(int fd, int argc, char *argv[]) char *listoflinks[MAX_STAT_LINKS]; char *lastnodewhichkeyedusup, *lastdtmfcommand; char *tot_state, *ider_state, *patch_state; - char *reverse_patch_state, *enable_state, *input_signal, *called_number; + char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena; + char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type; struct rpt *myrpt; static char *not_applicable = "N/A"; @@ -1221,7 +1981,7 @@ static int rpt_do_stats(int fd, int argc, char *argv[]) if(argc != 3) return RESULT_SHOWUSAGE; - for(i = 0 ; i <= MAX_STAT_LINKS; i++) + for(i = 0 ; i < MAX_STAT_LINKS; i++) listoflinks[i] = NULL; tot_state = ider_state = @@ -1250,7 +2010,7 @@ static int rpt_do_stats(int fd, int argc, char *argv[]) reverse_patch_state = "DOWN"; j = 0; l = myrpt->links.next; - while(l != &myrpt->links){ + while(l && (l != &myrpt->links)){ if (l->name[0] == '0'){ /* Skip '0' nodes */ reverse_patch_state = "UP"; l = l->next; @@ -1271,10 +2031,40 @@ static int rpt_do_stats(int fd, int argc, char *argv[]) else input_signal = "NO"; - if(myrpt->enable) - enable_state = "YES"; + if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable) + sys_ena = "DISABLED"; + else + sys_ena = "ENABLED"; + + if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable) + tot_ena = "DISABLED"; else - enable_state = "NO"; + tot_ena = "ENABLED"; + + if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable) + link_ena = "DISABLED"; + else + link_ena = "ENABLED"; + + if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable) + patch_ena = "DISABLED"; + else + patch_ena = "ENABLED"; + + if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable) + sch_ena = "DISABLED"; + else + sch_ena = "ENABLED"; + + if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable) + user_funs = "DISABLED"; + else + user_funs = "ENABLED"; + + if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail) + tail_type = "ALTERNATE"; + else + tail_type = "STANDARD"; if(!myrpt->totimer) tot_state = "TIMED OUT!"; @@ -1324,8 +2114,12 @@ static int rpt_do_stats(int fd, int argc, char *argv[]) rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */ ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name); + ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur); ast_cli(fd, "Signal on input..................................: %s\n", input_signal); - ast_cli(fd, "Transmitter enabled..............................: %s\n", enable_state); + ast_cli(fd, "System...........................................: %s\n", sys_ena); + ast_cli(fd, "Scheduler........................................: %s\n", sch_ena); + ast_cli(fd, "Tail Time........................................: %s\n", tail_type); + ast_cli(fd, "Time out timer...................................: %s\n", tot_ena); ast_cli(fd, "Time out timer state.............................: %s\n", tot_state); ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts); ast_cli(fd, "Identifier state.................................: %s\n", ider_state); @@ -1336,7 +2130,6 @@ static int rpt_do_stats(int fd, int argc, char *argv[]) ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands); ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands); ast_cli(fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand); - hours = dailytxtime/3600000; dailytxtime %= 3600000; minutes = dailytxtime/60000; @@ -1377,10 +2170,12 @@ static int rpt_do_stats(int fd, int argc, char *argv[]) ast_cli(fd,"\n"); ast_cli(fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup); + ast_cli(fd, "Autopatch........................................: %s\n", patch_ena); ast_cli(fd, "Autopatch state..................................: %s\n", patch_state); ast_cli(fd, "Autopatch called number..........................: %s\n", called_number); - ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n\n", reverse_patch_state); - + ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state); + ast_cli(fd, "User linking commands............................: %s\n", link_ena); + ast_cli(fd, "User functions...................................: %s\n\n", user_funs); return RESULT_SUCCESS; } } @@ -1394,6 +2189,7 @@ static int rpt_do_stats(int fd, int argc, char *argv[]) static int rpt_do_lstats(int fd, int argc, char *argv[]) { int i,j; + char *connstate; struct rpt *myrpt; struct rpt_link *l; struct rpt_lstat *s,*t; @@ -1414,7 +2210,7 @@ static int rpt_do_lstats(int fd, int argc, char *argv[]) /* Traverse the list of connected nodes */ j = 0; l = myrpt->links.next; - while(l != &myrpt->links){ + while(l && (l != &myrpt->links)){ if (l->name[0] == '0'){ /* Skip '0' nodes */ l = l->next; continue; @@ -1425,34 +2221,42 @@ static int rpt_do_lstats(int fd, int argc, char *argv[]) return RESULT_FAILURE; } memset(s, 0, sizeof(struct rpt_lstat)); - ast_copy_string(s->name, l->name, MAXREMSTR); - pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1); + strncpy(s->name, l->name, MAXREMSTR - 1); + if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1); + else strcpy(s->peer,"(none)"); s->mode = l->mode; s->outbound = l->outbound; s->reconnects = l->reconnects; s->connecttime = l->connecttime; + s->thisconnected = l->thisconnected; + memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat)); insque((struct qelem *) s, (struct qelem *) s_head.next); + memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat)); l = l->next; } rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */ - ast_cli(fd, "NODE PEER RECONNECTS DIRECTION CONNECT TIME\n"); - ast_cli(fd, "---- ---- ---------- --------- ------------\n"); + ast_cli(fd, "NODE PEER RECONNECTS DIRECTION CONNECT TIME CONNECT STATE\n"); + ast_cli(fd, "---- ---- ---------- --------- ------------ -------------\n"); for(s = s_head.next; s != &s_head; s = s->next){ int hours, minutes, seconds; long long connecttime = s->connecttime; - char conntime[31]; + char conntime[21]; hours = (int) connecttime/3600000; connecttime %= 3600000; minutes = (int) connecttime/60000; connecttime %= 60000; seconds = (int) connecttime/1000; connecttime %= 1000; - snprintf(conntime, 30, "%02d:%02d:%02d.%d", + snprintf(conntime, 20, "%02d:%02d:%02d.%d", hours, minutes, seconds, (int) connecttime); - conntime[30] = 0; - ast_cli(fd, "%-10s%-20s%-12d%-11s%-30s\n", - s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime); + conntime[20] = 0; + if(s->thisconnected) + connstate = "ESTABLISHED"; + else + connstate = "CONNECTING"; + ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n", + s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate); } /* destroy our local link queue */ s = s_head.next; @@ -1469,9 +2273,59 @@ static int rpt_do_lstats(int fd, int argc, char *argv[]) } /* -* reload vars +* List all nodes connected, directly or indirectly */ - + +static int rpt_do_nodes(int fd, int argc, char *argv[]) +{ + int i,j; + char ns; + char lbuf[MAXLINKLIST],*strs[MAXLINKLIST]; + struct rpt *myrpt; + if(argc != 3) + return RESULT_SHOWUSAGE; + + for(i = 0; i < nrpts; i++) + { + if (!strcmp(argv[2],rpt_vars[i].name)){ + /* Make a copy of all stat variables while locked */ + myrpt = &rpt_vars[i]; + rpt_mutex_lock(&myrpt->lock); /* LOCK */ + __mklinklist(myrpt,NULL,lbuf); + rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */ + /* parse em */ + ns = finddelim(lbuf,strs,MAXLINKLIST); + /* sort em */ + if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar); + ast_cli(fd,"\n"); + ast_cli(fd, "************************* CONNECTED NODES *************************\n\n"); + for(j = 0 ;; j++){ + if(!strs[j]){ + if(!j){ + ast_cli(fd,""); + } + break; + } + ast_cli(fd, "%s", strs[j]); + if(j % 8 == 7){ + ast_cli(fd, "\n"); + } + else{ + if(strs[j + 1]) + ast_cli(fd, ", "); + } + } + ast_cli(fd,"\n\n"); + return RESULT_SUCCESS; + } + } + return RESULT_FAILURE; +} + +/* +* reload vars +*/ + static int rpt_do_reload(int fd, int argc, char *argv[]) { int n; @@ -1499,6 +2353,40 @@ int i; return RESULT_FAILURE; } + +/* +* send an app_rpt DTMF function from the CLI +*/ + +static int rpt_do_fun(int fd, int argc, char *argv[]) +{ + int i,busy=0; + + if (argc != 4) return RESULT_SHOWUSAGE; + + for(i = 0; i < nrpts; i++){ + if(!strcmp(argv[2], rpt_vars[i].name)){ + struct rpt *myrpt = &rpt_vars[i]; + rpt_mutex_lock(&myrpt->lock); + if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){ + rpt_mutex_unlock(&myrpt->lock); + busy=1; + } + if(!busy){ + myrpt->macrotimer = MACROTIME; + strncat(myrpt->macrobuf,argv[3],MAXMACRO - 1); + } + rpt_mutex_unlock(&myrpt->lock); + } + } + if(busy){ + ast_cli(fd, "Function decoder busy"); + } + return RESULT_FAILURE; +} + + + static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude) { int res; @@ -1524,7 +2412,7 @@ static int play_silence(struct ast_channel *chan, int duration) } -static int send_morse(struct ast_channel *chan, const char *string, int speed, int freq, int amplitude) +static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude) { static struct morse_bits mbits[] = { @@ -1686,7 +2574,7 @@ static struct morse_bits mbits[] = { return res; } -static int send_tone_telemetry(struct ast_channel *chan, const char *tonestring) +static int send_tone_telemetry(struct ast_channel *chan, char *tonestring) { char *stringp; char *tonesubset; @@ -1736,9 +2624,8 @@ static int send_tone_telemetry(struct ast_channel *chan, const char *tonestring) return res; } - -static int sayfile(struct ast_channel *mychannel, const char *fname) +static int sayfile(struct ast_channel *mychannel,char *fname) { int res; @@ -1777,7 +2664,7 @@ static int saynum(struct ast_channel *mychannel, int num) } -static int telem_any(struct rpt *myrpt,struct ast_channel *chan, const char *entry) +static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry) { int res; char c; @@ -1838,8 +2725,8 @@ static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, int res; int i; - const char *entry; - const char *telemetry; + char *entry; + char *telemetry; char *telemetry_save; res = 0; @@ -1847,14 +2734,14 @@ static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, entry = NULL; /* Retrieve the section name for telemetry from the node section */ - telemetry = ast_variable_retrieve(myrpt->cfg, node, TELEMETRY); + telemetry = (char *) ast_variable_retrieve(myrpt->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(myrpt->cfg, telemetry_save, name); + entry = (char *) ast_variable_retrieve(myrpt->cfg, telemetry_save, name); } /* Try to look up the telemetry name */ @@ -1882,54 +2769,69 @@ static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, static int get_wait_interval(struct rpt *myrpt, int type) { - int interval; - const char *wait_times; - char *wait_times_save = NULL; - - wait_times = ast_variable_retrieve(myrpt->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(myrpt, wait_times_save, "telemwait", 500, 5000, 1000); - else - interval = 1000; - break; - - case DLY_ID: - if (wait_times) - interval = retrieve_astcfgint(myrpt, wait_times_save, "idwait", 250, 5000, 500); - else - interval = 500; - break; - - case DLY_UNKEY: - if (wait_times) - interval = retrieve_astcfgint(myrpt, wait_times_save, "unkeywait", 500, 5000, 1000); - else - interval = 1000; - break; - - case DLY_CALLTERM: - if (wait_times) - interval = retrieve_astcfgint(myrpt, wait_times_save, "calltermwait", 500, 5000, 1500); - else - interval = 1500; - break; - - default: - return 0; - } + int interval; + char *wait_times; + char *wait_times_save; + + wait_times_save = NULL; + wait_times = (char *) ast_variable_retrieve(myrpt->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(myrpt,wait_times_save, "telemwait", 500, 5000, 1000); + else + interval = 1000; + break; + + case DLY_ID: + if(wait_times) + interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500); + else + interval = 500; + break; + + case DLY_UNKEY: + if(wait_times) + interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",500,5000,1000); + else + interval = 1000; + break; + + case DLY_LINKUNKEY: + if(wait_times) + interval = retrieve_astcfgint(myrpt,wait_times_save, "linkunkeywait",500,5000,1000); + else + interval = 1000; + break; + + case DLY_CALLTERM: + if(wait_times) + interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500); + else + interval = 1500; + break; + + case DLY_COMP: + if(wait_times) + interval = retrieve_astcfgint(myrpt,wait_times_save, "compwait",500,5000,200); + else + interval = 200; + break; + + default: + return 0; + } return interval; -} +} /* @@ -1950,6 +2852,7 @@ static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan) return; } +static int split_freq(char *mhz, char *decimals, char *freq); static void *rpt_tele_thread(void *this) { @@ -1958,12 +2861,18 @@ int res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x; struct rpt_tele *mytele = (struct rpt_tele *)this; struct rpt_tele *tlist; struct rpt *myrpt; -struct rpt_link *l,*m,linkbase; +struct rpt_link *l,*l1,linkbase; struct ast_channel *mychannel; - const char *p, *ct; - char *ct_copy, *ident, *nodename; +int vmajor, vminor, m; +char *p,*ct,*ct_copy,*ident, *nodename,*cp; time_t t; struct tm localtm; +char lbuf[MAXLINKLIST],*strs[MAXLINKLIST]; +int i,ns,rbimode; +char mhz[MAXREMSTR]; +char decimals[MAXREMSTR]; +struct zt_params par; + /* get a pointer to myrpt */ myrpt = mytele->rpt; @@ -1971,7 +2880,8 @@ struct tm localtm; /* Snag copies of a few key myrpt variables */ rpt_mutex_lock(&myrpt->lock); nodename = ast_strdupa(myrpt->name); - ident = ast_strdupa(myrpt->p.ident); + if (myrpt->p.ident) ident = ast_strdupa(myrpt->p.ident); + else ident = ""; rpt_mutex_unlock(&myrpt->lock); /* allocate a pseudo-channel thru asterisk */ @@ -1987,16 +2897,15 @@ struct tm localtm; pthread_exit(NULL); } rpt_mutex_lock(&myrpt->lock); - mytele->chan = mychannel; /* Save a copy of the channel so we can access it externally if need be */ + mytele->chan = mychannel; rpt_mutex_unlock(&myrpt->lock); - /* 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)) ? + (mytele->mode == TAILMSG) || (mytele->mode == LINKUNKEY)) || (mytele->mode == TIMEOUT) ? myrpt->txconf : myrpt->conf); ci.confmode = ZT_CONF_CONFANN; /* first put the channel on the conference in announce mode */ @@ -2014,7 +2923,6 @@ struct tm localtm; ast_stopstream(mychannel); switch(mytele->mode) { - case ID: case ID1: /* wait a bit */ @@ -2028,7 +2936,7 @@ struct tm localtm; break; case IDTALKOVER: - p = ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover"); + p = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover"); if(p) res = telem_any(myrpt,mychannel, p); imdone=1; @@ -2173,7 +3081,7 @@ struct tm localtm; ast_stopstream(mychannel); } } - else if((ct = ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */ + else if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */ ct_copy = ast_strdupa(ct); res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy); if(res) @@ -2197,7 +3105,7 @@ struct tm localtm; ast_hangup(mychannel); pthread_exit(NULL); } - if((ct = ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */ + if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */ ast_safe_sleep(mychannel,200); ct_copy = ast_strdupa(ct); res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy); @@ -2235,9 +3143,95 @@ struct tm localtm; #endif imdone = 1; break; + case LINKUNKEY: + if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */ + imdone = 1; + break; + } + + /* + * Reset the Unkey to CT timer + */ + + x = get_wait_interval(myrpt, DLY_LINKUNKEY); + mytele->mylink.linkunkeytocttimer = 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) + { + rpt_mutex_lock(&myrpt->lock); + while(tlist != &myrpt->tele){ + if (tlist->mode == LINKUNKEY) unkeys_queued++; + tlist = tlist->next; + } + rpt_mutex_unlock(&myrpt->lock); + } + if( unkeys_queued > 1){ + imdone = 1; + break; + } + + /* Wait for the telemetry timer to expire */ + /* Periodically check the timer since it can be re-initialized above */ + while(mytele->mylink.linkunkeytocttimer) + { + int ctint; + if(mytele->mylink.linkunkeytocttimer > 100) + ctint = 100; + else + ctint = mytele->mylink.linkunkeytocttimer; + ast_safe_sleep(mychannel, ctint); + rpt_mutex_lock(&myrpt->lock); + if(mytele->mylink.linkunkeytocttimer < ctint) + mytele->mylink.linkunkeytocttimer = 0; + else + mytele->mylink.linkunkeytocttimer -= ctint; + rpt_mutex_unlock(&myrpt->lock); + } + + if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "linkunkeyct"))){ /* Unlinked Courtesy Tone */ + ct_copy = ast_strdupa(ct); + res = telem_lookup(myrpt,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); + l = myrpt->links.next; + haslink = 0; + /* dont report if a link for this one still on system */ + if (l != &myrpt->links) + { + rpt_mutex_lock(&myrpt->lock); + while(l != &myrpt->links) + { + if (l->name[0] == '0') + { + l = l->next; + continue; + } + if (!strcmp(l->name,mytele->mylink.name)) + { + haslink = 1; + break; + } + l = l->next; + } + rpt_mutex_unlock(&myrpt->lock); + } + if (haslink) + { + imdone = 1; + break; + } res = ast_streamfile(mychannel, "rpt/node", mychannel->language); if (!res) res = ast_waitstream(mychannel, ""); @@ -2245,7 +3239,7 @@ struct tm localtm; 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) ? + res = ast_streamfile(mychannel, ((mytele->mylink.hasconnected) ? "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language); break; case REMALREADY: @@ -2274,50 +3268,17 @@ struct tm localtm; 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; - rpt_mutex_lock(&myrpt->lock); - /* make our own list of links */ - l = myrpt->links.next; - while(l != &myrpt->links) - { - if (l->name[0] == '0') - { - l = l->next; - continue; - } - m = malloc(sizeof(struct rpt_link)); - if (!m) - { - ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name); - 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); - } - memcpy(m,l,sizeof(struct rpt_link)); - m->next = m->prev = NULL; - insque((struct qelem *)m,(struct qelem *)linkbase.next); - l = l->next; - } - rpt_mutex_unlock(&myrpt->lock); + res = ast_streamfile(mychannel, "digits/2", 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, "rpt/node", mychannel->language); if (!res) res = ast_waitstream(mychannel, ""); @@ -2325,2074 +3286,3460 @@ struct tm localtm; 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); + imdone = 1; + 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); - if (myrpt->callmode) + ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language); + res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language); + break; + case MEMNOTFOUND: + /* wait a little bit */ + wait_interval(myrpt, DLY_TELEM, mychannel); + res = ast_streamfile(mychannel, "rpt/memory_notfound", mychannel->language); + break; + case SETREMOTE: + ast_mutex_lock(&myrpt->remlock); + res = 0; + if(!strcmp(myrpt->remote, remote_rig_ft897)) { - 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); + res = set_ft897(myrpt); } - l = linkbase.next; - while(l != &linkbase) + if(!strcmp(myrpt->remote, remote_rig_ic706)) { - 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); + res = set_ic706(myrpt); } - /* destroy our local link queue */ - l = linkbase.next; - while(l != &linkbase) + else if(!strcmp(myrpt->remote, remote_rig_rbi)) { - m = l; - l = l->next; - remque((struct qelem *)m); - free(m); - } - imdone = 1; - break; - - case LASTNODEKEY: /* Identify last node which keyed us up */ - rpt_mutex_lock(&myrpt->lock); - if(myrpt->lastnodewhichkeyedusup) - p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */ - else - p = NULL; - rpt_mutex_unlock(&myrpt->lock); - if(!p){ - imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */ + if (ioperm(myrpt->p.iobase,1,1) == -1) + { + rpt_mutex_unlock(&myrpt->lock); + ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase); + res = -1; + } + else res = setrbi(myrpt); + } + else if(!strcmp(myrpt->remote, remote_rig_kenwood)) + { + res = setkenwood(myrpt); + if (ast_safe_sleep(mychannel,200) == -1) + { + ast_mutex_unlock(&myrpt->remlock); + res = -1; + break; + } + i = ZT_FLUSH_EVENT; + if (ioctl(myrpt->txchannel->fds[0],ZT_FLUSH,&i) == -1) + { + ast_mutex_unlock(&myrpt->remlock); + ast_log(LOG_ERROR,"Cant flush events"); + res = -1; + break; + } + if (ioctl(myrpt->rxchannel->fds[0],ZT_GET_PARAMS,&par) == -1) + { + ast_mutex_unlock(&myrpt->remlock); + ast_log(LOG_ERROR,"Cant get params"); + res = -1; + break; + } + myrpt->remoterx = + (par.rxisoffhook || (myrpt->tele.next != &myrpt->tele)); + } + ast_mutex_unlock(&myrpt->remlock); + if (!res) + { + imdone = 1; break; } + /* fall thru to invalid freq */ + case INVFREQ: + /* 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, 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; - - 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); + res = ast_streamfile(mychannel, "rpt/invalid-freq", mychannel->language); break; - - case STATS_TIME: - wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */ - t = time(NULL); - localtime_r(&t, &localtm); - /* 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) + case REMMODE: + cp = 0; + wait_interval(myrpt, DLY_TELEM, mychannel); + switch(myrpt->remmode) { - imdone = 1; + case REM_MODE_FM: + saycharstr(mychannel,"FM"); + break; + case REM_MODE_USB: + saycharstr(mychannel,"USB"); + break; + case REM_MODE_LSB: + saycharstr(mychannel,"LSB"); + break; + case REM_MODE_AM: + saycharstr(mychannel,"AM"); break; } - /* Say the time is ... */ - if (sayfile(mychannel,"rpt/thetimeis") == -1) + wait_interval(myrpt, DLY_COMP, mychannel); + if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete"); + break; + case LOGINREQ: + wait_interval(myrpt, DLY_TELEM, mychannel); + sayfile(mychannel,"rpt/login"); + saycharstr(mychannel,myrpt->name); + break; + case REMLOGIN: + wait_interval(myrpt, DLY_TELEM, mychannel); + saycharstr(mychannel,myrpt->loginuser); + sayfile(mychannel,"rpt/node"); + saycharstr(mychannel,myrpt->name); + wait_interval(myrpt, DLY_COMP, mychannel); + if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete"); + break; + case REMXXX: + wait_interval(myrpt, DLY_TELEM, mychannel); + res = 0; + switch(mytele->submode) { - imdone = 1; + case 100: /* RX PL Off */ + sayfile(mychannel, "rpt/rxpl"); + sayfile(mychannel, "rpt/off"); + break; + case 101: /* RX PL On */ + sayfile(mychannel, "rpt/rxpl"); + sayfile(mychannel, "rpt/on"); + break; + case 102: /* TX PL Off */ + sayfile(mychannel, "rpt/txpl"); + sayfile(mychannel, "rpt/off"); + break; + case 103: /* TX PL On */ + sayfile(mychannel, "rpt/txpl"); + sayfile(mychannel, "rpt/on"); + break; + case 104: /* Low Power */ + sayfile(mychannel, "rpt/lopwr"); + break; + case 105: /* Medium Power */ + sayfile(mychannel, "rpt/medpwr"); + break; + case 106: /* Hi Power */ + sayfile(mychannel, "rpt/hipwr"); + break; + case 113: /* Scan down slow */ + sayfile(mychannel,"rpt/down"); + sayfile(mychannel, "rpt/slow"); + break; + case 114: /* Scan down quick */ + sayfile(mychannel,"rpt/down"); + sayfile(mychannel, "rpt/quick"); + break; + case 115: /* Scan down fast */ + sayfile(mychannel,"rpt/down"); + sayfile(mychannel, "rpt/fast"); + break; + case 116: /* Scan up slow */ + sayfile(mychannel,"rpt/up"); + sayfile(mychannel, "rpt/slow"); break; + case 117: /* Scan up quick */ + sayfile(mychannel,"rpt/up"); + sayfile(mychannel, "rpt/quick"); + break; + case 118: /* Scan up fast */ + sayfile(mychannel,"rpt/up"); + sayfile(mychannel, "rpt/fast"); + break; + default: + res = -1; } - /* 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: - wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */ - /* Say "version" */ - if (sayfile(mychannel,"rpt/version") == -1) + wait_interval(myrpt, DLY_COMP, mychannel); + if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete"); + break; + case SCAN: + ast_mutex_lock(&myrpt->remlock); + if (myrpt->hfscanstop) { + myrpt->hfscanstatus = 0; + myrpt->hfscanmode = 0; + myrpt->hfscanstop = 0; + mytele->mode = SCANSTAT; + ast_mutex_unlock(&myrpt->remlock); + if (ast_safe_sleep(mychannel,1000) == -1) break; + sayfile(mychannel, "rpt/stop"); 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) + if (myrpt->hfscanstatus > -2) service_scan(myrpt); + i = myrpt->hfscanstatus; + myrpt->hfscanstatus = 0; + if (i) mytele->mode = SCANSTAT; + ast_mutex_unlock(&myrpt->remlock); + if (i < 0) sayfile(mychannel, "rpt/stop"); + else if (i > 0) saynum(mychannel,i); + imdone = 1; + break; + case TUNE: + ast_mutex_lock(&myrpt->remlock); + if (!strcmp(myrpt->remote,remote_rig_ic706)) { + set_mode_ic706(myrpt, REM_MODE_AM); + if(play_tone(mychannel, 800, 6000, 8192) == -1) break; + ast_safe_sleep(mychannel,500); + set_mode_ic706(myrpt, myrpt->remmode); + myrpt->tunerequest = 0; + ast_mutex_unlock(&myrpt->remlock); 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); + set_mode_ft897(myrpt, REM_MODE_AM); + simple_command_ft897(myrpt, 8); + if(play_tone(mychannel, 800, 6000, 8192) == -1) break; + simple_command_ft897(myrpt, 0x88); + ast_safe_sleep(mychannel,500); + set_mode_ft897(myrpt, myrpt->remmode); + myrpt->tunerequest = 0; + ast_mutex_unlock(&myrpt->remlock); imdone = 1; - break; - 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; - int looptemp=0,i=0, dres = 0; + case REMSHORTSTATUS: + case REMLONGSTATUS: + wait_interval(myrpt, DLY_TELEM, mychannel); + res = sayfile(mychannel,"rpt/node"); + if(!res) + res = saycharstr(mychannel, myrpt->name); + if(!res) + res = sayfile(mychannel,"rpt/frequency"); + if(!res) + res = split_freq(mhz, decimals, myrpt->freq); + if (!multimode_capable(myrpt)) decimals[3] = 0; + if(!res){ + m = atoi(mhz); + if(m < 100) + res = saynum(mychannel, m); + else + res = saycharstr(mychannel, mhz); + } + if(!res) + res = sayfile(mychannel, "letters/dot"); + if(!res) + res = saycharstr(mychannel, decimals); + if(res) break; + if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */ + switch(myrpt->offset){ + + case REM_MINUS: + res = sayfile(mychannel,"rpt/minus"); + break; + + case REM_SIMPLEX: + res = sayfile(mychannel,"rpt/simplex"); + break; + + case REM_PLUS: + res = sayfile(mychannel,"rpt/plus"); + break; + + default: + break; + } + } + else{ /* Must be USB, LSB, or AM */ + switch(myrpt->remmode){ - tpl_working = strdupa(mytele->param); - myparm = strsep(&tpl_working,","); - tpl_current=strsep(&tpl_working, ":"); + case REM_MODE_USB: + res = saycharstr(mychannel, "USB"); + break; - while(tpl_current && looptemp < sizeof(tmp)) { - tmp[looptemp]=tpl_current; - looptemp++; - tpl_current=strsep(&tpl_working,":"); - } + case REM_MODE_LSB: + res = saycharstr(mychannel, "LSB"); + break; - for(i=0; ilanguage); - } 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; - } - } + case REM_MODE_AM: + res = saycharstr(mychannel, "AM"); + break; + + + default: + break; } } - imdone = 1; - break; - case TEST_TONE: - imdone = 1; - myrpt->stopgen = 0; - if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) + + if (res == -1) break; + + if(mytele->mode == REMSHORTSTATUS){ /* Short status? */ + wait_interval(myrpt, DLY_COMP, mychannel); + if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete"); break; - while(mychannel->generatordata && (!myrpt->stopgen)) { - if (ast_safe_sleep(mychannel,1)) break; - imdone = 1; - } - break; - default: - break; - } - myrpt->stopgen = 0; - if (!imdone) - { - if (!res) - res = ast_waitstream(mychannel, ""); - else { - ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name); - res = 0; - } - } - ast_stopstream(mychannel); - rpt_mutex_lock(&myrpt->lock); - if (mytele->mode == TAILMSG) - { - if (!res) - { - myrpt->tailmessagen++; - if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0; } - else + + if (strcmp(myrpt->remote,remote_rig_ic706)) { - myrpt->tmsgtimer = myrpt->p.tailsquashedtime; + switch(myrpt->powerlevel){ + + case REM_LOWPWR: + res = sayfile(mychannel,"rpt/lopwr") ; + break; + case REM_MEDPWR: + res = sayfile(mychannel,"rpt/medpwr"); + break; + case REM_HIPWR: + res = sayfile(mychannel,"rpt/hipwr"); + break; + } } - } - remque((struct qelem *)mytele); - rpt_mutex_unlock(&myrpt->lock); - free(mytele); - ast_hangup(mychannel); -#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 - pthread_exit(NULL); -} - -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; -pthread_attr_t attr; - - tele = malloc(sizeof(struct rpt_tele)); - if (!tele) - { - ast_log(LOG_WARNING, "Unable to allocate memory\n"); - pthread_exit(NULL); - return; - } - /* zero it out */ - memset((char *)tele,0,sizeof(struct rpt_tele)); - tele->rpt = myrpt; - tele->mode = mode; - rpt_mutex_lock(&myrpt->lock); - if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED)){ - memset(&tele->mylink,0,sizeof(struct rpt_link)); - if (mylink){ - memcpy(&tele->mylink,mylink,sizeof(struct rpt_link)); + rbimode = ((!strncmp(myrpt->remote,remote_rig_rbi,3)) + || (!strncmp(myrpt->remote,remote_rig_ic706,3))); + if (res || (sayfile(mychannel,"rpt/rxpl") == -1)) break; + if (rbimode && (sayfile(mychannel,"rpt/txpl") == -1)) break; + if ((sayfile(mychannel,"rpt/frequency") == -1) || + (saycharstr(mychannel,myrpt->rxpl) == -1)) break; + if ((!rbimode) && ((sayfile(mychannel,"rpt/txpl") == -1) || + (sayfile(mychannel,"rpt/frequency") == -1) || + (saycharstr(mychannel,myrpt->txpl) == -1))) break; + if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */ + if ((sayfile(mychannel,"rpt/rxpl") == -1) || + (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1) || + (sayfile(mychannel,"rpt/txpl") == -1) || + (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1)) + { + break; + } } - } - else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) { - ast_copy_string(tele->param, (char *) data, TELEPARAMSIZE); - } - insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next); - rpt_mutex_unlock(&myrpt->lock); - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele); - pthread_attr_destroy(&attr); - if(res < 0){ + wait_interval(myrpt, DLY_COMP, mychannel); + if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete"); + break; + case STATUS: + /* wait a little bit */ + wait_interval(myrpt, DLY_TELEM, mychannel); + hastx = 0; + linkbase.next = &linkbase; + linkbase.prev = &linkbase; 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)); - } - return; -} - -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; - - - myrpt->mydtmf = 0; - /* allocate a pseudo-channel thru asterisk */ - mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL); - if (!mychannel) - { - fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n"); - pthread_exit(NULL); - } - ci.chan = 0; - ci.confno = myrpt->conf; /* use the pseudo conference */ - 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) - { - fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n"); - ast_hangup(mychannel); - pthread_exit(NULL); - } - ci.chan = 0; - ci.confno = myrpt->conf; - 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->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)) - { - ast_log(LOG_WARNING, "Cannot start dialtone\n"); - ast_hangup(mychannel); - ast_hangup(genchannel); - myrpt->callmode = 0; - pthread_exit(NULL); - } - stopped = 0; - congstarted = 0; - dialtimer = 0; - lastcidx = 0; - aborted = 0; - - - while ((myrpt->callmode == 1) || (myrpt->callmode == 4)) - { - - if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){ - dialtimer = 0; - lastcidx = myrpt->cidx; - } - - 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)) + /* make our own list of links */ + l = myrpt->links.next; + while(l != &myrpt->links) { - stopped = 1; - /* stop dial tone */ - tone_zone_play_tone(mychannel->fds[0],-1); + if (l->name[0] == '0') + { + l = l->next; + continue; + } + l1 = malloc(sizeof(struct rpt_link)); + if (!l1) + { + ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name); + 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); + } + memcpy(l1,l,sizeof(struct rpt_link)); + l1->next = l1->prev = NULL; + insque((struct qelem *)l1,(struct qelem *)linkbase.next); + l = l->next; } - if (myrpt->callmode == 4) + rpt_mutex_unlock(&myrpt->lock); + res = ast_streamfile(mychannel, "rpt/node", mychannel->language); + if (!res) + res = ast_waitstream(mychannel, ""); + else + ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name); + ast_stopstream(mychannel); + ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language); + if (!res) + res = ast_waitstream(mychannel, ""); + else + ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name); + ast_stopstream(mychannel); + if (myrpt->callmode) { - if(!congstarted){ - congstarted = 1; - /* start congestion tone */ - tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION); - } + 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); } - res = ast_safe_sleep(mychannel, MSWAIT); - if (res < 0) + l = linkbase.next; + while(l != &linkbase) { - ast_hangup(mychannel); - ast_hangup(genchannel); - rpt_mutex_lock(&myrpt->lock); - myrpt->callmode = 0; - rpt_mutex_unlock(&myrpt->lock); - pthread_exit(NULL); + char *s; + + 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); + s = "rpt/tranceive"; + if (!l->mode) s = "rpt/monitor"; + if (!l->thisconnected) s = "rpt/connecting"; + res = ast_streamfile(mychannel, s, 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); } - dialtimer += MSWAIT; - } - /* stop any tone generation */ - tone_zone_play_tone(mychannel->fds[0],-1); - /* end if done */ - if (!myrpt->callmode) - { - ast_hangup(mychannel); - ast_hangup(genchannel); + /* destroy our local link queue */ + l = linkbase.next; + while(l != &linkbase) + { + l1 = l; + l = l->next; + remque((struct qelem *)l1); + free(l1); + } + imdone = 1; + break; + case FULLSTATUS: rpt_mutex_lock(&myrpt->lock); - myrpt->callmode = 0; + /* get all the nodes */ + __mklinklist(myrpt,NULL,lbuf); rpt_mutex_unlock(&myrpt->lock); - if((!myrpt->patchquiet) && aborted) - rpt_telemetry(myrpt, TERM, NULL); - pthread_exit(NULL); - } - - if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){ - char *name, *loc, *instr; - instr = strdup(myrpt->p.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); - } - } - - ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten)); - ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context)); - - if (myrpt->p.acctcode) - ast_string_field_set(mychannel, accountcode, myrpt->p.acctcode); - 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); - rpt_mutex_lock(&myrpt->lock); - myrpt->callmode = 0; - rpt_mutex_unlock(&myrpt->lock); - pthread_exit(NULL); - } - usleep(10000); - rpt_mutex_lock(&myrpt->lock); - 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)) + /* parse em */ + ns = finddelim(lbuf,strs,MAXLINKLIST); + /* sort em */ + if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar); + /* wait a little bit */ + wait_interval(myrpt, DLY_TELEM, mychannel); + hastx = 0; + 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) { - if(myrpt->patchfarenddisconnect){ /* If patch is setup for far end disconnect */ - myrpt->callmode = 0; - if(!myrpt->patchquiet){ - 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); - rpt_mutex_lock(&myrpt->lock); - } + 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); } - if (myrpt->mydtmf) + /* go thru all the nodes in list */ + for(i = 0; i < ns; i++) { - wf.frametype = AST_FRAME_DTMF; - wf.subclass = myrpt->mydtmf; - wf.offset = 0; - wf.mallocd = 0; - wf.data = NULL; - wf.datalen = 0; - wf.samples = 0; - rpt_mutex_unlock(&myrpt->lock); - ast_write(genchannel,&wf); - rpt_mutex_lock(&myrpt->lock); - myrpt->mydtmf = 0; - } - rpt_mutex_unlock(&myrpt->lock); - usleep(MSWAIT * 1000); - rpt_mutex_lock(&myrpt->lock); - } - rpt_mutex_unlock(&myrpt->lock); - tone_zone_play_tone(genchannel->fds[0],-1); - if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV); - ast_hangup(genchannel); - rpt_mutex_lock(&myrpt->lock); - myrpt->callmode = 0; - rpt_mutex_unlock(&myrpt->lock); - /* 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"); - } - pthread_exit(NULL); -} + char *s,mode = 'T'; -static void send_link_dtmf(struct rpt *myrpt,char c) -{ -char str[300]; -struct ast_frame wf; -struct rpt_link *l; + /* if a mode spec at first, handle it */ + if ((*strs[i] < '0') || (*strs[i] > '9')) + { + mode = *strs[i]; + strs[i]++; + } - 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 */ - if (!strcmp(l->name,myrpt->cmdnode)) + 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,strs[i],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); + s = "rpt/tranceive"; + if (mode == 'R') s = "rpt/monitor"; + if (mode == 'C') s = "rpt/connecting"; + res = ast_streamfile(mychannel, s, 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 (!hastx) { - wf.data = strdup(str); - if (l->chan) ast_write(l->chan,&wf); - return; + 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); } - l = l->next; - } - l = myrpt->links.next; - /* if not, give it to everyone */ - while(l != &myrpt->links) - { - wf.data = strdup(str); - if (l->chan) ast_write(l->chan,&wf); - l = l->next; - } - return; -} - -/* -* Internet linking function -*/ - -static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink) -{ + imdone = 1; + break; - const char *val; - char *s, *s1, *s2, *tele; - char tmp[300], deststr[300] = "",modechange = 0; - char digitbuf[MAXNODESTR]; - struct rpt_link *l; - int reconnects = 0; - ZT_CONFINFO ci; /* conference info */ + case LASTNODEKEY: /* Identify last node which keyed us up */ + rpt_mutex_lock(&myrpt->lock); + if(myrpt->lastnodewhichkeyedusup) + p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */ + else + p = NULL; + rpt_mutex_unlock(&myrpt->lock); + if(!p){ + 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; - if(!param) - return DC_ERROR; + case UNAUTHTX: /* Say unauthorized transmit frequency */ + wait_interval(myrpt, DLY_TELEM, mychannel); + res = ast_streamfile(mychannel, "rpt/unauthtx", 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; - - if (!myrpt->enable) - return DC_ERROR; - ast_copy_string(digitbuf,digits,MAXNODESTR); - - if(debug) - printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf); + 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; - 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; + case TIMEOUT_WARNING: + time(&t); + 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-warning", 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(!res) /* Say number of seconds */ + ast_say_number(mychannel, myrpt->p.remotetimeout - + (t - myrpt->last_activity_time), + "", mychannel->language, (char *) NULL); + if (!res) + res = ast_waitstream(mychannel, ""); + ast_stopstream(mychannel); + res = ast_streamfile(mychannel, "queue-seconds", mychannel->language); + break; + + case ACT_TIMEOUT_WARNING: + time(&t); + 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/act-timeout-warning", 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(!res) /* Say number of seconds */ + ast_say_number(mychannel, myrpt->p.remoteinacttimeout - + (t - myrpt->last_activity_time), + "", mychannel->language, (char *) NULL); + if (!res) + res = ast_waitstream(mychannel, ""); + ast_stopstream(mychannel); + res = ast_streamfile(mychannel, "queue-seconds", mychannel->language); + break; + + case STATS_TIME: + wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */ + t = time(NULL); + rpt_localtime(&t, &localtm); + /* 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; + 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; + 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,":"); } - ast_copy_string(tmp,val,sizeof(tmp)); - s = tmp; - s1 = strsep(&s,","); - s2 = strsep(&s,","); - 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; + + for(i=0; ilanguage); + } 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; + } } - /* if found matching string */ - if (!strcmp(l->name, digitbuf)) - break; + } + } + imdone = 1; + break; + case TEST_TONE: + imdone = 1; + if (myrpt->stopgen) break; + myrpt->stopgen = -1; + if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) + { + myrpt->stopgen = 0; + break; + } + while(mychannel->generatordata && (myrpt->stopgen <= 0)) { + if (ast_safe_sleep(mychannel,1)) break; + imdone = 1; + } + myrpt->stopgen = 0; + break; + default: + break; + } + if (!imdone) + { + if (!res) + res = ast_waitstream(mychannel, ""); + else { + ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name); + res = 0; + } + } + ast_stopstream(mychannel); + rpt_mutex_lock(&myrpt->lock); + if (mytele->mode == TAILMSG) + { + if (!res) + { + myrpt->tailmessagen++; + if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0; + } + else + { + myrpt->tmsgtimer = myrpt->p.tailsquashedtime; + } + } + remque((struct qelem *)mytele); + rpt_mutex_unlock(&myrpt->lock); + free(mytele); + ast_hangup(mychannel); +#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 + pthread_exit(NULL); +} + +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; +pthread_attr_t attr; + + tele = malloc(sizeof(struct rpt_tele)); + if (!tele) + { + ast_log(LOG_WARNING, "Unable to allocate memory\n"); + pthread_exit(NULL); + return; + } + /* zero it out */ + memset((char *)tele,0,sizeof(struct rpt_tele)); + tele->rpt = myrpt; + tele->mode = mode; + rpt_mutex_lock(&myrpt->lock); + if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED) || + (mode == LINKUNKEY)){ + 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); + tele->param[TELEPARAMSIZE - 1] = 0; + } + if (mode == REMXXX) tele->submode = (int) data; + insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next); + rpt_mutex_unlock(&myrpt->lock); + 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){ + 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",strerror(res)); + } + return; +} + +static void *rpt_call(void *this) +{ +ZT_CONFINFO ci; /* conference info */ +struct rpt *myrpt = (struct rpt *)this; +int res; +int stopped,congstarted,dialtimer,lastcidx,aborted; +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) + { + fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n"); + pthread_exit(NULL); + } + ci.chan = 0; + ci.confno = myrpt->conf; /* use the pseudo conference */ + 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) + { + fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n"); + ast_hangup(mychannel); + pthread_exit(NULL); + } + ci.chan = 0; + ci.confno = myrpt->conf; + 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->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)) + { + ast_log(LOG_WARNING, "Cannot start dialtone\n"); + ast_hangup(mychannel); + ast_hangup(genchannel); + myrpt->callmode = 0; + pthread_exit(NULL); + } + stopped = 0; + congstarted = 0; + dialtimer = 0; + lastcidx = 0; + aborted = 0; + + + while ((myrpt->callmode == 1) || (myrpt->callmode == 4)) + { + + if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){ + dialtimer = 0; + lastcidx = myrpt->cidx; + } + + 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)) + { + stopped = 1; + /* stop dial tone */ + tone_zone_play_tone(mychannel->fds[0],-1); + } + if (myrpt->callmode == 4) + { + if(!congstarted){ + congstarted = 1; + /* start congestion tone */ + tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION); + } + } + res = ast_safe_sleep(mychannel, MSWAIT); + if (res < 0) + { + ast_hangup(mychannel); + ast_hangup(genchannel); + rpt_mutex_lock(&myrpt->lock); + myrpt->callmode = 0; + rpt_mutex_unlock(&myrpt->lock); + pthread_exit(NULL); + } + dialtimer += MSWAIT; + } + /* stop any tone generation */ + tone_zone_play_tone(mychannel->fds[0],-1); + /* end if done */ + if (!myrpt->callmode) + { + ast_hangup(mychannel); + ast_hangup(genchannel); + rpt_mutex_lock(&myrpt->lock); + myrpt->callmode = 0; + rpt_mutex_unlock(&myrpt->lock); + if((!myrpt->patchquiet) && aborted) + rpt_telemetry(myrpt, TERM, NULL); + pthread_exit(NULL); + } + + if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){ + char *name, *loc, *instr; + instr = strdup(myrpt->p.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); + } + } + + ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1); + ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1); + + if (myrpt->p.acctcode) + ast_cdr_setaccount(mychannel,myrpt->p.acctcode); + 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); + rpt_mutex_lock(&myrpt->lock); + myrpt->callmode = 0; + rpt_mutex_unlock(&myrpt->lock); + pthread_exit(NULL); + } + usleep(10000); + rpt_mutex_lock(&myrpt->lock); + 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 */ + myrpt->callmode = 0; + if(!myrpt->patchquiet){ + 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); + rpt_mutex_lock(&myrpt->lock); + } + } + if (myrpt->mydtmf) + { + struct ast_frame wf = {AST_FRAME_DTMF, } ; + wf.subclass = myrpt->mydtmf; + rpt_mutex_unlock(&myrpt->lock); + ast_queue_frame(mychannel,&wf); + ast_senddigit(genchannel,myrpt->mydtmf); + rpt_mutex_lock(&myrpt->lock); + myrpt->mydtmf = 0; + } + rpt_mutex_unlock(&myrpt->lock); + usleep(MSWAIT * 1000); + rpt_mutex_lock(&myrpt->lock); + } + rpt_mutex_unlock(&myrpt->lock); + tone_zone_play_tone(genchannel->fds[0],-1); + if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV); + ast_hangup(genchannel); + rpt_mutex_lock(&myrpt->lock); + myrpt->callmode = 0; + rpt_mutex_unlock(&myrpt->lock); + /* 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"); + } + pthread_exit(NULL); +} + +static void send_link_dtmf(struct rpt *myrpt,char c) +{ +char str[300]; +struct ast_frame wf; +struct rpt_link *l; + + snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c); + wf.frametype = AST_FRAME_TEXT; + wf.subclass = 0; + wf.offset = 0; + wf.mallocd = 0; + 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 */ + if (!strcmp(l->name,myrpt->cmdnode)) + { + wf.data = str; + if (l->chan) ast_write(l->chan,&wf); + return; + } + l = l->next; + } + l = myrpt->links.next; + /* if not, give it to everyone */ + while(l != &myrpt->links) + { + wf.data = str; + if (l->chan) ast_write(l->chan,&wf); + l = l->next; + } + return; +} + +/* + * Connect a link + * + * Return values: + * -1: Error + * 0: Success + * 1: No match yet + * 2: Already connected to this node + */ + +static int connect_link(struct rpt *myrpt, char* node, int mode, int perma) +{ + char *val, *s, *s1, *s2, *tele; + char lstr[MAXLINKLIST],*strs[MAXLINKLIST]; + char tmp[300], deststr[300] = "",modechange = 0; + struct rpt_link *l; + int reconnects = 0; + int i,n; + ZT_CONFINFO ci; /* conference info */ + + val = node_lookup(myrpt,node); + if (!val){ + if(strlen(node) >= myrpt->longestnode) + return -1; /* No such node */ + return 1; /* No match yet */ + } + if(debug > 3){ + ast_log(LOG_NOTICE,"Connect attempt to node %s\n", node); + ast_log(LOG_NOTICE,"Mode: %s\n",(mode)?"Transceive":"Monitor"); + ast_log(LOG_NOTICE,"Connection type: %s\n",(perma)?"Permalink":"Normal"); + } + + strncpy(tmp,val,sizeof(tmp) - 1); + s = tmp; + s1 = strsep(&s,","); + s2 = strsep(&s,","); + 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; + } + /* if found matching string */ + if (!strcmp(l->name, node)) + 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); + return 2; /* Already linked */ + } + reconnects = l->reconnects; + rpt_mutex_unlock(&myrpt->lock); + if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV); + l->retries = l->max_retries + 1; + l->disced = 2; + modechange = 1; + } else + { + __mklinklist(myrpt,NULL,lstr); + rpt_mutex_unlock(&myrpt->lock); + n = finddelim(lstr,strs,MAXLINKLIST); + for(i = 0; i < n; i++) + { + if ((*strs[i] < '0') || + (*strs[i] > '9')) strs[i]++; + if (!strcmp(strs[i],node)) + { + return 2; /* Already linked */ + } + } + } + strncpy(myrpt->lastlinknode,node,MAXNODESTR - 1); + /* establish call */ + l = malloc(sizeof(struct rpt_link)); + if (!l) + { + ast_log(LOG_WARNING, "Unable to malloc\n"); + return -1; + } + /* zero the silly thing */ + memset((char *)l,0,sizeof(struct rpt_link)); + l->mode = mode; + l->outbound = 1; + l->thisconnected = 0; + strncpy(l->name, node, MAXNODESTR - 1); + l->isremote = (s && ast_true(s)); + if (modechange) l->connected = 1; + l->hasconnected = l->perma = perma; + snprintf(deststr, sizeof(deststr), "IAX2/%s", s1); + tele = strchr(deststr, '/'); + if (!tele){ + ast_log(LOG_WARNING,"link3:Dial number (%s) must be in format tech/number\n",deststr); + free(l); + return -1; + } + *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)"; + if (debug > 3) + ast_log(LOG_NOTICE, "rpt (remote) initiating call to %s/%s on %s\n", + deststr, tele, l->chan->name); + if(l->chan->cid.cid_num) + free(l->chan->cid.cid_num); + l->chan->cid.cid_num = strdup(myrpt->name); + ast_call(l->chan,tele,999); + } + else { + if(debug > 3) + ast_log(LOG_NOTICE, "Unable to place call to %s/%s on %s\n", + deststr,tele,l->chan->name); + if (myrpt->p.archivedir) + { + char str[100]; + sprintf(str,"LINKFAIL,%s",l->name); + donodelog(myrpt,str); + } + free(l); + return -1; + } + /* allocate a pseudo-channel thru asterisk */ + l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL); + if (!l->pchan){ + ast_log(LOG_WARNING,"rpt connect: Sorry unable to obtain pseudo channel\n"); + ast_hangup(l->chan); + free(l); + return -1; + } + 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); + free(l); + return -1; + } + rpt_mutex_lock(&myrpt->lock); + l->reconnects = reconnects; + /* insert at end of queue */ + l->max_retries = MAX_RETRIES; + if (perma) + l->max_retries = MAX_RETRIES_PERM; + if (l->isremote) l->retries = l->max_retries + 1; + insque((struct qelem *)l,(struct qelem *)myrpt->links.next); + __kickshort(myrpt); + rpt_mutex_unlock(&myrpt->lock); + return 0; +} + + + +/* +* Internet linking function +*/ + +static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink) +{ + + char *val, *s, *s1, *s2; + char tmp[300]; + char digitbuf[MAXNODESTR],*strs[MAXLINKLIST]; + char mode,perma; + struct rpt_link *l; + int i,r; + + if(!param) + return DC_ERROR; + + + if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable ) + return DC_ERROR; + + strncpy(digitbuf,digits,MAXNODESTR - 1); + + if(debug > 6) + printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf); + + switch(myatoi(param)){ + case 11: /* Perm Link off */ + case 1: /* Link off */ + if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0])) + strcpy(digitbuf,myrpt->lastlinknode); + val = node_lookup(myrpt,digitbuf); + if (!val){ + if(strlen(digitbuf) >= myrpt->longestnode) + return DC_ERROR; + break; + } + strncpy(tmp,val,sizeof(tmp) - 1); + s = tmp; + s1 = strsep(&s,","); + s2 = strsep(&s,","); + 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; + } + /* if found matching string */ + if (!strcmp(l->name, digitbuf)) + break; + l = l->next; + } + if (l != &myrpt->links){ /* if found */ + struct ast_frame wf; + + /* must use perm command on perm link */ + if ((myatoi(param) < 10) && + (l->max_retries > MAX_RETRIES)) + { + rpt_mutex_unlock(&myrpt->lock); + return DC_COMPLETE; + } + strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1); + l->retries = l->max_retries + 1; + l->disced = 1; + rpt_mutex_unlock(&myrpt->lock); + wf.frametype = AST_FRAME_TEXT; + wf.subclass = 0; + wf.offset = 0; + wf.mallocd = 0; + wf.datalen = strlen(discstr) + 1; + wf.samples = 0; + wf.data = discstr; + if (l->chan) + { + ast_write(l->chan,&wf); + if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR; + ast_softhangup(l->chan,AST_SOFTHANGUP_DEV); + } + rpt_telemetry(myrpt, COMPLETE, NULL); + return DC_COMPLETE; + } + rpt_mutex_unlock(&myrpt->lock); + return DC_COMPLETE; + case 2: /* Link Monitor */ + case 3: /* Link transceive */ + case 12: /* Link Monitor permanent */ + case 13: /* Link transceive permanent */ + if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0])) + strcpy(digitbuf,myrpt->lastlinknode); + /* Attempt connection */ + perma = (atoi(param) > 10) ? 1 : 0; + mode = (atoi(param) & 1) ? 1 : 0; + r = connect_link(myrpt, digitbuf, mode, perma); + switch(r){ + case 0: + rpt_telemetry(myrpt, COMPLETE, NULL); + return DC_COMPLETE; + + case 1: + break; + + case 2: + rpt_telemetry(myrpt, REMALREADY, NULL); + return DC_COMPLETE; + + default: + rpt_telemetry(myrpt, CONNFAIL, NULL); + return DC_COMPLETE; + } + break; + + 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])) + strcpy(digitbuf,myrpt->lastlinknode); + /* node must at least exist in list */ + val = node_lookup(myrpt,digitbuf); + if (!val){ + if(strlen(digitbuf) >= myrpt->longestnode) + return DC_ERROR; + break; + + } + rpt_mutex_lock(&myrpt->lock); + strcpy(myrpt->lastlinknode,digitbuf); + strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1); + 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 15: /* Full Status */ + rpt_telemetry(myrpt, FULLSTATUS, NULL); + return DC_COMPLETE; + + + case 6: /* All Links Off, including permalinks */ + rpt_mutex_lock(&myrpt->lock); + myrpt->savednodes[0] = 0; + l = myrpt->links.next; + /* loop through all links */ + while(l != &myrpt->links){ + struct ast_frame wf; + if (l->name[0] == '0') /* Skip any IAXRPT monitoring */ + { + l = l->next; + continue; + } + /* Make a string of disconnected nodes for possible restoration */ + sprintf(tmp,"%c%c%s",(l->mode) ? 'X' : 'M',(l->perma) ? 'P':'T',l->name); + if(strlen(tmp) + strlen(myrpt->savednodes) + 1 < MAXNODESTR){ + if(myrpt->savednodes[0]) + strcat(myrpt->savednodes, ","); + strcat(myrpt->savednodes, tmp); + } + l->retries = l->max_retries + 1; + l->disced = 2; /* Silently disconnect */ + rpt_mutex_unlock(&myrpt->lock); + /* ast_log(LOG_NOTICE,"dumping link %s\n",l->name); */ + + wf.frametype = AST_FRAME_TEXT; + wf.subclass = 0; + wf.offset = 0; + wf.mallocd = 0; + wf.datalen = strlen(discstr) + 1; + wf.samples = 0; + wf.data = discstr; + if (l->chan) + { + ast_write(l->chan,&wf); + ast_safe_sleep(l->chan,250); /* It's dead already, why check the return value? */ + ast_softhangup(l->chan,AST_SOFTHANGUP_DEV); + } + rpt_mutex_lock(&myrpt->lock); + l = l->next; + } + rpt_mutex_unlock(&myrpt->lock); + if(debug > 3) + ast_log(LOG_NOTICE,"Nodes disconnected: %s\n",myrpt->savednodes); + rpt_telemetry(myrpt, COMPLETE, NULL); + return DC_COMPLETE; + + case 7: /* Identify last node which keyed us up */ + rpt_telemetry(myrpt, LASTNODEKEY, NULL); + break; + + + case 16: /* Restore links disconnected with "disconnect all links" command */ + strcpy(tmp, myrpt->savednodes); /* Make a copy */ + finddelim(tmp, strs, MAXLINKLIST); /* convert into substrings */ + for(i = 0; tmp[0] && strs[i] != NULL && i < MAXLINKLIST; i++){ + s1 = strs[i]; + mode = (s1[0] == 'X') ? 1 : 0; + perma = (s1[1] == 'P') ? 1 : 0; + connect_link(myrpt, s1 + 2, mode, perma); /* Try to reconnect */ + } + rpt_telemetry(myrpt, COMPLETE, NULL); + break; + + case 200: + case 201: + case 202: + case 203: + case 204: + case 205: + case 206: + case 207: + case 208: + case 209: + case 210: + case 211: + case 212: + case 213: + case 214: + case 215: + if (((myrpt->p.propagate_dtmf) && + (command_source == SOURCE_LNK)) || + ((myrpt->p.propagate_phonedtmf) && + ((command_source == SOURCE_PHONE) || + (command_source == SOURCE_DPHONE)))) + do_dtmf_local(myrpt, + remdtmfstr[myatoi(param) - 200]); + 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) +{ + pthread_attr_t attr; + int i, index, paramlength; + char *lparam; + char *value = NULL; + char *paramlist[20]; + + static char *keywords[] = { + "context", + "dialtime", + "farenddisconnect", + "noct", + "quiet", + NULL + }; + + if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable) + return DC_ERROR; + + if(debug) + printf("@@@@ Autopatch up\n"); + + if(!myrpt->callmode){ + /* Set defaults */ + myrpt->patchnoct = 0; + myrpt->patchdialtime = 0; + myrpt->patchfarenddisconnect = 0; + myrpt->patchquiet = 0; + strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT); + + if(param){ + /* Process parameter list */ + lparam = ast_strdupa(param); + if(!lparam){ + ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__); + return DC_ERROR; + } + paramlength = finddelim(lparam, paramlist, 20); + for(i = 0; i < paramlength; i++){ + index = matchkeyword(paramlist[i], &value, keywords); + if(value) + value = skipchars(value, "= "); + switch(index){ + + case 1: /* context */ + strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ; + 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; + } + } + } + } + + rpt_mutex_lock(&myrpt->lock); + + /* if on call, force * into current audio stream */ + + if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){ + myrpt->mydtmf = myrpt->p.endchar; + } + 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); + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt); + return DC_COMPLETE; +} + +/* +* Autopatch down +*/ + +static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink) +{ + if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable) + return DC_ERROR; + + if(debug) + printf("@@@@ 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->p.s[myrpt->p.sysstate_cur].txdisable) || (myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)) + return DC_ERROR; + + if(debug) + printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf); + + switch(myatoi(param)){ + case 1: /* System ID */ + rpt_telemetry(myrpt, ID1, NULL); + return DC_COMPLETE; + case 2: /* System Time */ + rpt_telemetry(myrpt, STATS_TIME, NULL); + return DC_COMPLETE; + case 3: /* app_rpt.c version */ + rpt_telemetry(myrpt, STATS_VERSION, NULL); + default: + return DC_ERROR; + } + return DC_INDETERMINATE; +} + +/* +* Macro-oni (without Salami) +*/ + +static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink) +{ + +char *val; +int i; + if (myrpt->remote) + return DC_ERROR; + + if(debug) + printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf); + + if(strlen(digitbuf) < 1) /* 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 = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf); + /* param was 1 for local buf */ + if (!val){ + if (strlen(digitbuf) < myrpt->macro_longest) + return DC_INDETERMINATE; + rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL); + return DC_COMPLETE; + } + rpt_mutex_lock(&myrpt->lock); + if ((MAXMACRO - 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,MAXMACRO - 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) +{ + char string[16]; + + if(!param) + return DC_ERROR; + + switch(myatoi(param)){ + case 1: /* System reset */ + system("killall -9 asterisk"); + return DC_COMPLETE; + + case 2: + myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 0; + rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA"); + return DC_COMPLETE; + + case 3: + myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 1; + return DC_COMPLETE; + + case 4: /* test tone on */ + if (myrpt->stopgen < 0) + { + myrpt->stopgen = 1; + } + else + { + myrpt->stopgen = 0; + 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; + + + case 7: /* Time out timer enable */ + myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 0; + rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTENA"); + return DC_COMPLETE; + + case 8: /* Time out timer disable */ + myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 1; + rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTDIS"); + return DC_COMPLETE; + + case 9: /* Autopatch enable */ + myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 0; + rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APENA"); + return DC_COMPLETE; + + case 10: /* Autopatch disable */ + myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 1; + rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APDIS"); + return DC_COMPLETE; + + case 11: /* Link Enable */ + myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 0; + rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKENA"); + return DC_COMPLETE; + + case 12: /* Link Disable */ + myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 1; + rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKDIS"); + return DC_COMPLETE; + + case 13: /* Query System State */ + string[0] = string[1] = 'S'; + string[2] = myrpt->p.sysstate_cur + '0'; + string[3] = '\0'; + rpt_telemetry(myrpt, ARB_ALPHA, (void *) string); + return DC_COMPLETE; + + case 14: /* Change System State */ + if(strlen(digitbuf) == 0) + break; + if((digitbuf[0] < '0') || (digitbuf[0] > '9')) + return DC_ERROR; + myrpt->p.sysstate_cur = digitbuf[0] - '0'; + string[0] = string[1] = 'S'; + string[2] = myrpt->p.sysstate_cur + '0'; + string[3] = '\0'; + rpt_telemetry(myrpt, ARB_ALPHA, (void *) string); + return DC_COMPLETE; + + case 15: /* Scheduler Enable */ + myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 0; + rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKENA"); + return DC_COMPLETE; + + case 16: /* Scheduler Disable */ + myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 1; + rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKDIS"); + return DC_COMPLETE; + + case 17: /* User functions Enable */ + myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 0; + rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFENA"); + return DC_COMPLETE; + + case 18: /* User Functions Disable */ + myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 1; + rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFDIS"); + return DC_COMPLETE; + + case 19: /* Alternate Tail Enable */ + myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 1; + rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATENA"); + return DC_COMPLETE; + + case 20: /* Alternate Tail Disable */ + myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 0; + rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATDIS"); + return DC_COMPLETE; + } + 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,*action,*param,*functiondigits; + char function_table_name[30] = ""; + char workstring[200]; + + struct ast_variable *vp; + + if(debug) + printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source); + + if (command_source == SOURCE_DPHONE) { + if (!myrpt->p.dphone_functions) return DC_INDETERMINATE; + strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1); + } + else if (command_source == SOURCE_PHONE) { + if (!myrpt->p.phone_functions) return DC_INDETERMINATE; + strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1); + } + else if (command_source == SOURCE_LNK) + strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1); + else + strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1); + vp = ast_variable_browse(myrpt->cfg, function_table_name); + while(vp) { + if(!strncasecmp(vp->name, digits, strlen(vp->name))) + break; + vp = vp->next; + } + 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 */ + strncpy(workstring, vp->value, sizeof(workstring) - 1 ); + stringp = workstring; + action = strsep(&stringp, ","); + param = stringp; + if(debug) + printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)"); + /* Look up the action */ + for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){ + if(!strncasecmp(action, function_table[i].action, strlen(action))) + break; + } + if(debug) + printf("@@@@ 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 */ + if(debug) + printf("@@@@ NULL for action: %s\n",action); + return DC_ERROR; + } + functiondigits = digits + strlen(vp->name); + return (*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink); +} + + +static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink, + char *str) +{ +char tmp[512],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 = 0; + wf.datalen = strlen(str) + 1; + wf.samples = 0; + /* put string in our buffer */ + strncpy(tmp,str,sizeof(tmp) - 1); + + if (!strcmp(tmp,discstr)) + { + mylink->disced = 1; + mylink->retries = mylink->max_retries + 1; + ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV); + return; + } + if (tmp[0] == 'L') + { + rpt_mutex_lock(&myrpt->lock); + strcpy(mylink->linklist,tmp + 2); + time(&mylink->linklistreceived); + rpt_mutex_unlock(&myrpt->lock); + if (debug > 6) ast_log(LOG_NOTICE,"@@@@ node %s recieved node list %s from node %s\n", + myrpt->name,tmp,mylink->name); + return; + } + if (sscanf(tmp,"%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') + { l = l->next; + continue; } - 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; - rpt_mutex_unlock(&myrpt->lock); - wf.frametype = AST_FRAME_TEXT; - wf.subclass = 0; - wf.offset = 0; - wf.mallocd = 1; - wf.datalen = strlen(discstr) + 1; - wf.samples = 0; - wf.data = strdup(discstr); - if (l->chan) - { - ast_write(l->chan,&wf); - if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR; - ast_softhangup(l->chan,AST_SOFTHANGUP_DEV); - } - rpt_telemetry(myrpt, COMPLETE, NULL); - return DC_COMPLETE; - } - 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; - } - ast_copy_string(tmp, val, sizeof(tmp)); - s = tmp; - s1 = strsep(&s,","); - s2 = strsep(&s,","); - 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; - } - /* if found matching string */ - if (!strcmp(l->name, digitbuf)) - break; + /* dont send back from where it came */ + if ((l == mylink) || (!strcmp(l->name,mylink->name))) + { l = l->next; + continue; } - /* if found */ - if (l != &myrpt->links) + /* if it is, send it and we're done */ + if (!strcmp(l->name,dest)) { - /* 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; - + /* send, but not to src */ + if (strcmp(l->name,src)) { + wf.data = str; + if (l->chan) ast_write(l->chan,&wf); } - 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 */ - l = malloc(sizeof(struct rpt_link)); - if (!l){ - ast_log(LOG_WARNING, "Unable to malloc\n"); - return DC_ERROR; - } - /* zero the silly thing */ - memset((char *)l,0,sizeof(struct rpt_link)); - snprintf(deststr, sizeof(deststr), "IAX2/%s", s1); - tele = strchr(deststr,'/'); - if (!tele){ - fprintf(stderr,"link2:Dial number (%s) must be in format tech/number\n",deststr); - return DC_ERROR; + return; } - *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)"; - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n", - deststr,tele,l->chan->name); - if(l->chan->cid.cid_num) - free(l->chan->cid.cid_num); - l->chan->cid.cid_num = strdup(myrpt->name); - ast_call(l->chan,tele,0); + 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; } - else + /* dont send back from where it came */ + if ((l == mylink) || (!strcmp(l->name,mylink->name))) { - rpt_telemetry(myrpt,CONNFAIL,l); - free(l); - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n", - deststr,tele,l->chan->name); - return DC_ERROR; + l = l->next; + continue; } - /* allocate a pseudo-channel thru asterisk */ - l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL); - if (!l->pchan){ - fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n"); - ast_hangup(l->chan); - free(l); - return DC_ERROR; + /* send, but not to src */ + if (strcmp(l->name,src)) { + wf.data = str; + if (l->chan) ast_write(l->chan,&wf); } - 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); - free(l); - return DC_ERROR; + l = l->next; + } + return; + } + if (myrpt->p.archivedir) + { + char str[100]; + + sprintf(str,"DTMF,%s,%c",mylink->name,c); + donodelog(myrpt,str); + } + c = func_xlat(myrpt,c,&myrpt->p.outxlat); + if (!c) 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){ + rpt_mutex_unlock(&myrpt->lock); + rpt_telemetry(myrpt,PROC,NULL); + rpt_mutex_lock(&myrpt->lock); } - rpt_mutex_lock(&myrpt->lock); - l->reconnects = reconnects; - /* insert at end of queue */ - insque((struct qelem *)l,(struct qelem *)myrpt->links.next); + } + /* 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 (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 (myrpt->rem_dtmfidx < 0) + { + if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) + { + myrpt->mydtmf = c; + } + if (myrpt->p.propagate_dtmf) do_dtmf_local(myrpt,c); + if (myrpt->p.propagate_phonedtmf) do_dtmf_phone(myrpt,mylink,c); + 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); - rpt_telemetry(myrpt,COMPLETE,NULL); - return DC_COMPLETE; - case 3: /* Link transceive */ - 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; - } - ast_copy_string(tmp,val,sizeof(tmp)); - s = tmp; - s1 = strsep(&s,","); - s2 = strsep(&s,","); + strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1); + res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink); 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; - } - /* if found matching string */ - if (!strcmp(l->name, digitbuf)) + + switch(res){ + + case DC_INDETERMINATE: + break; + + case DC_REQ_FLUSH: + myrpt->rem_dtmfidx = 0; + myrpt->rem_dtmfbuf[0] = 0; + break; + + + case DC_COMPLETE: + case DC_COMPLETEQUIET: + myrpt->totalexecdcommands++; + myrpt->dailyexecdcommands++; + strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1); + 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; - 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 */ - l = malloc(sizeof(struct rpt_link)); - if (!l){ - ast_log(LOG_WARNING, "Unable to malloc\n"); - return(DC_ERROR); - } - /* zero the silly thing */ - memset((char *)l,0,sizeof(struct rpt_link)); - 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", s1); - tele = strchr(deststr, '/'); - if (!tele){ - fprintf(stderr,"link3:Dial number (%s) must be in format tech/number\n",deststr); - 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)"; - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "rpt (remote) initiating call to %s/%s on %s\n", - deststr, tele, l->chan->name); - if(l->chan->cid.cid_num) - free(l->chan->cid.cid_num); - l->chan->cid.cid_num = strdup(myrpt->name); - ast_call(l->chan,tele,999); - } - else{ - rpt_telemetry(myrpt,CONNFAIL,l); - free(l); - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n", - deststr,tele,l->chan->name); - return DC_ERROR; - } - /* allocate a pseudo-channel thru asterisk */ - l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL); - if (!l->pchan){ - fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n"); - ast_hangup(l->chan); - free(l); - return DC_ERROR; - } - ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR); - ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR); - /* make a conference for the tx */ - ci.chan = 0; - ci.confno = myrpt->conf; - ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER; - /* first put the channel on the conference in proper mode */ - if (ioctl(l->pchan->fds[0], ZT_SETCONF, &ci) == -1) - { - ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); - ast_hangup(l->chan); - ast_hangup(l->pchan); - 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); + return; +} + +static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink, + char c) +{ + +char cmd[300]; +int res; + + if (myrpt->p.archivedir) + { + char str[100]; + + sprintf(str,"DTMF(P),%s,%c",mylink->name,c); + donodelog(myrpt,str); + } + 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 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; + 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){ + rpt_mutex_unlock(&myrpt->lock); + rpt_telemetry(myrpt,PROC,NULL); + rpt_mutex_lock(&myrpt->lock); } - if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0])) - 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; - break; + } + /* 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); + strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1); + switch(mylink->phonemode) + { + case 1: + res = collect_function_digits(myrpt, cmd, + SOURCE_PHONE, mylink); + break; + case 2: + res = collect_function_digits(myrpt, cmd, + SOURCE_DPHONE,mylink); + break; + default: + res = collect_function_digits(myrpt, cmd, + SOURCE_LNK, mylink); + break; } + 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; + 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: + case DC_COMPLETEQUIET: + myrpt->totalexecdcommands++; + myrpt->dailyexecdcommands++; + strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1); + 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_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; -} + rpt_mutex_unlock(&myrpt->lock); + return; +} + +/* 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; +} /* -* Autopatch up +* Shift out a formatted serial bit stream */ -static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink) +static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data) + { + int i,j; + unsigned char od,d; + static volatile long long delayvar; + + for(i = 0 ; i < 5 ; i++){ + od = *data++; + for(j = 0 ; j < 8 ; j++){ + d = od & 1; + outb(d,myrpt->p.iobase); + /* >= 15 us */ + for(delayvar = 1; delayvar < 15000; delayvar++); + od >>= 1; + outb(d | 2,myrpt->p.iobase); + /* >= 30 us */ + for(delayvar = 1; delayvar < 30000; delayvar++); + outb(d,myrpt->p.iobase); + /* >= 10 us */ + for(delayvar = 1; delayvar < 10000; delayvar++); + } + } + /* >= 50 us */ + for(delayvar = 1; delayvar < 50000; delayvar++); + } + +static void rbi_out(struct rpt *myrpt,unsigned char *data) { - pthread_attr_t attr; - int i, index, paramlength; - char *lparam; - char *value = NULL; - char *paramlist[20]; +struct zt_radio_param r; - static char *keywords[] = { - "context", - "dialtime", - "farenddisconnect", - "noct", - "quiet", - NULL - }; - - if (!myrpt->enable) - return DC_ERROR; - - if(debug) - printf("@@@@ Autopatch up\n"); + memset(&r,0,sizeof(struct zt_radio_param)); + 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) + { + 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); + return; + } +} - if(!myrpt->callmode){ - /* Set defaults */ - myrpt->patchnoct = 0; - myrpt->patchdialtime = 0; - myrpt->patchfarenddisconnect = 0; - myrpt->patchquiet = 0; - ast_copy_string(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT); +static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, + unsigned char *rxbuf, int rxmaxbytes, int asciiflag) +{ + int i,j,index,oldmode,olddata; + struct zt_radio_param prm; + char c; - if(param){ - /* Process parameter list */ - lparam = ast_strdupa(param); - if(!lparam){ - ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__); - return DC_ERROR; + if(debug){ + printf("String output was: "); + for(i = 0; i < txbytes; i++) + printf("%02X ", (unsigned char ) txbuf[i]); + printf("\n"); + } + if (myrpt->iofd > 0) /* if to do out a serial port */ + { + if (rxmaxbytes && rxbuf) tcflush(myrpt->iofd,TCIFLUSH); + if (write(myrpt->iofd,txbuf,txbytes) != txbytes) return -1; + if ((!rxmaxbytes) || (rxbuf == NULL)) return(0); + memset(rxbuf,0,rxmaxbytes); + for(i = 0; i < rxmaxbytes; i++) + { + j = read(myrpt->iofd,&c,1); + if (j < 1) return(i); + rxbuf[i] = c; + if (asciiflag & 1) + { + rxbuf[i + 1] = 0; + if (c == '\r') break; } - paramlength = finddelim(lparam, paramlist, 20); - for(i = 0; i < paramlength; i++){ - index = matchkeyword(paramlist[i], &value, keywords); - if(value) - value = skipchars(value, "= "); - switch(index){ + } + if(debug){ + printf("String returned was: "); + for(j = 0; j < i; j++) + printf("%02X ", (unsigned char ) rxbuf[j]); + printf("\n"); + } + return(i); + } + + prm.radpar = ZT_RADPAR_UIOMODE; + if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_GETPARAM,&prm) == -1) return -1; + oldmode = prm.data; + prm.radpar = ZT_RADPAR_UIODATA; + if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_GETPARAM,&prm) == -1) return -1; + olddata = prm.data; + prm.radpar = ZT_RADPAR_REMMODE; + if (asciiflag & 1) 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; + if (asciiflag & 2) + { + i = ZT_ONHOOK; + if (ioctl(myrpt->rxchannel->fds[0],ZT_HOOK,&i) == -1) return -1; + usleep(100000); + } + 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; + memcpy(rxbuf,prm.buf,prm.index); + } + index = prm.index; + prm.radpar = ZT_RADPAR_REMMODE; + prm.data = ZT_RADPAR_REM_NONE; + if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1; + if (asciiflag & 2) + { + i = ZT_OFFHOOK; + if (ioctl(myrpt->rxchannel->fds[0],ZT_HOOK,&i) == -1) return -1; + } + prm.radpar = ZT_RADPAR_UIOMODE; + prm.data = oldmode; + if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1; + prm.radpar = ZT_RADPAR_UIODATA; + prm.data = olddata; + if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1; + return(index); +} - case 1: /* context */ - ast_copy_string(myrpt->patchcontext, value, MAXPATCHCONTEXT) ; - break; - - case 2: /* dialtime */ - myrpt->patchdialtime = atoi(value); - break; +static int civ_cmd(struct rpt *myrpt,unsigned char *cmd, int cmdlen) +{ +unsigned char rxbuf[100]; +int i,rv ; + + rv = serial_remote_io(myrpt,cmd,cmdlen,rxbuf,cmdlen + 6,0); + if (rv == -1) return(-1); + if (rv != (cmdlen + 6)) return(1); + for(i = 0; i < 6; i++) + if (rxbuf[i] != cmd[i]) return(1); + if (rxbuf[cmdlen] != 0xfe) return(1); + if (rxbuf[cmdlen + 1] != 0xfe) return(1); + if (rxbuf[cmdlen + 4] != 0xfb) return(1); + if (rxbuf[cmdlen + 5] != 0xfd) return(1); + return(0); +} - case 3: /* farenddisconnect */ - myrpt->patchfarenddisconnect = atoi(value); - break; +static int sendkenwood(struct rpt *myrpt,char *txstr, char *rxstr) +{ +int i; + + if (debug) printf("Send to kenwood: %s\n",txstr); + i = serial_remote_io(myrpt, (unsigned char *)txstr, strlen(txstr), + (unsigned char *)rxstr,RAD_SERIAL_BUFLEN - 1,3); + if (i < 0) return -1; + if ((i > 0) && (rxstr[i - 1] == '\r')) + rxstr[i-- - 1] = 0; + if (debug) printf("Got from kenwood: %s\n",rxstr); + return(i); +} + +/* take a PL frequency and turn it into a code */ +static int kenwood_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 1; + case 719: + return 3; + case 744: + return 4; + case 770: + return 5; + case 797: + return 6; + case 825: + return 7; + case 854: + return 8; + case 885: + return 9; + case 915: + return 10; + case 948: + return 11; + case 974: + return 12; + case 1000: + return 13; + case 1035: + return 14; + case 1072: + return 15; + case 1109: + return 16; + case 1148: + return 17; + case 1188: + return 18; + case 1230: + return 19; + case 1273: + return 20; + case 1318: + return 21; + case 1365: + return 22; + case 1413: + return 23; + case 1462: + return 24; + case 1514: + return 25; + case 1567: + return 26; + case 1622: + return 27; + case 1679: + return 28; + case 1738: + return 29; + case 1799: + return 30; + case 1862: + return 31; + case 1928: + return 32; + case 2035: + return 33; + case 2107: + return 34; + case 2181: + return 35; + case 2257: + return 36; + case 2336: + return 37; + case 2418: + return 38; + case 2503: + return 39; + } + return -1; +} - case 4: /* noct */ - myrpt->patchnoct = atoi(value); - break; +static int sendrxkenwood(struct rpt *myrpt, char *txstr, char *rxstr, + char *cmpstr) +{ +int i,j; - case 5: /* quiet */ - myrpt->patchquiet = atoi(value); - break; - - default: - break; - } - } - } + for(i = 0;i < KENWOOD_RETRIES;i++) + { + j = sendkenwood(myrpt,txstr,rxstr); + if (j < 0) return(j); + if (j == 0) continue; + if (!strncmp(rxstr,cmpstr,strlen(cmpstr))) return(0); } - - rpt_mutex_lock(&myrpt->lock); + return(-1); +} - /* if on call, force * into current audio stream */ +static int setkenwood(struct rpt *myrpt) +{ +char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20]; +char mhz[MAXREMSTR],offset[20],band,decimals[MAXREMSTR],band1,band2; - if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){ - myrpt->mydtmf = myrpt->p.funcchar; - } - if (myrpt->callmode){ - rpt_mutex_unlock(&myrpt->lock); - return DC_COMPLETE; +int offsets[] = {0,2,1}; +int powers[] = {2,1,0}; + + if (sendrxkenwood(myrpt,"VMC 0,0\r",rxstr,"VMC") < 0) return -1; + split_freq(mhz, decimals, myrpt->freq); + if (atoi(mhz) > 400) + { + band = '6'; + band1 = '1'; + band2 = '5'; + strcpy(offset,"005000000"); } - myrpt->callmode = 1; - myrpt->cidx = 0; - myrpt->exten[myrpt->cidx] = 0; - rpt_mutex_unlock(&myrpt->lock); - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt); - pthread_attr_destroy(&attr); - return DC_COMPLETE; + else + { + band = '2'; + band1 = '0'; + band2 = '2'; + strcpy(offset,"000600000"); + } + strcpy(freq,"000000"); + strncpy(freq,decimals,strlen(decimals)); + sprintf(txstr,"VW %c,%05d%s,0,%d,0,%d,%d,,%02d,,%02d,%s\r", + band,atoi(mhz),freq,offsets[(int)myrpt->offset], + (myrpt->txplon != 0),(myrpt->rxplon != 0), + kenwood_pltocode(myrpt->txpl),kenwood_pltocode(myrpt->rxpl), + offset); + if (sendrxkenwood(myrpt,txstr,rxstr,"VW") < 0) return -1; + sprintf(txstr,"RBN %c\r",band2); + if (sendrxkenwood(myrpt,txstr,rxstr,"RBN") < 0) return -1; + sprintf(txstr,"PC %c,%d\r",band1,powers[(int)myrpt->powerlevel]); + if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1; + return 0; } -/* -* Autopatch down -*/ - -static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink) +static int setrbi(struct rpt *myrpt) { - if (!myrpt->enable) - return DC_ERROR; - - if(debug) - printf("@@@@ Autopatch down\n"); - - rpt_mutex_lock(&myrpt->lock); +char tmp[MAXREMSTR] = "",*s; +unsigned char rbicmd[5]; +int band,txoffset = 0,txpower = 0,rxpl; + + /* must be a remote system */ + if (!myrpt->remote) return(0); + /* must have rbi hardware */ + if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0); + if (setrbi_check(myrpt) == -1) return(-1); + strncpy(tmp, myrpt->freq, sizeof(tmp) - 1); + s = strchr(tmp,'.'); + /* if no decimal, is invalid */ - if (!myrpt->callmode){ - rpt_mutex_unlock(&myrpt->lock); - return DC_COMPLETE; + if (s == NULL){ + if(debug) + printf("@@@@ Frequency needs a decimal\n"); + return -1; } - 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; + *s++ = 0; + if (strlen(tmp) < 2){ + if(debug) + printf("@@@@ Bad MHz digits: %s\n", tmp); + return -1; + } + + if (strlen(s) < 3){ + if(debug) + printf("@@@@ Bad KHz digits: %s\n", s); + return -1; + } - if (!myrpt->enable) - return DC_ERROR; + if ((s[2] != '0') && (s[2] != '5')){ + if(debug) + printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]); + return -1; + } + + band = rbi_mhztoband(tmp); + if (band == -1){ + if(debug) + printf("@@@@ Bad Band: %s\n", tmp); + return -1; + } + + rxpl = rbi_pltocode(myrpt->rxpl); + + if (rxpl == -1){ + if(debug) + printf("@@@@ Bad TX PL: %s\n", myrpt->rxpl); + return -1; + } - if(debug) - printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf); - switch(myatoi(param)){ - case 1: /* System ID */ - rpt_telemetry(myrpt, ID1, NULL); - return DC_COMPLETE; - case 2: /* System Time */ - rpt_telemetry(myrpt, STATS_TIME, NULL); - return DC_COMPLETE; - case 3: /* app_rpt.c version */ - rpt_telemetry(myrpt, STATS_VERSION, NULL); - default: - return DC_ERROR; + switch(myrpt->offset) + { + case REM_MINUS: + txoffset = 0; + break; + case REM_PLUS: + txoffset = 0x10; + break; + case REM_SIMPLEX: + txoffset = 0x20; + break; } - return DC_INDETERMINATE; + switch(myrpt->powerlevel) + { + case REM_LOWPWR: + txpower = 0; + break; + case REM_MEDPWR: + txpower = 0x20; + break; + case REM_HIPWR: + txpower = 0x10; + break; + } + rbicmd[0] = 0; + rbicmd[1] = band | txpower | 0xc0; + rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80; + if (s[2] == '5') rbicmd[2] |= 0x40; + rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0'); + rbicmd[4] = rxpl; + if (myrpt->txplon) rbicmd[4] |= 0x40; + if (myrpt->rxplon) rbicmd[4] |= 0x80; + rbi_out(myrpt,rbicmd); + return 0; } -/* -* Macro-oni (without Salami) -*/ - -static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink) +static int setrbi_check(struct rpt *myrpt) { +char tmp[MAXREMSTR] = "",*s; +int band,txpl; - const char *val; -int i; -struct ast_channel *mychannel; - - if ((!myrpt->remote) && (!myrpt->enable)) - return DC_ERROR; - - if(debug) - printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf); + /* must be a remote system */ + if (!myrpt->remote) return(0); + /* must have rbi hardware */ + if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0); + strncpy(tmp, myrpt->freq, sizeof(tmp) - 1); + s = strchr(tmp,'.'); + /* if no decimal, is invalid */ - mychannel = myrpt->remchannel; + if (s == NULL){ + if(debug) + printf("@@@@ Frequency needs a decimal\n"); + return -1; + } + + *s++ = 0; + if (strlen(tmp) < 2){ + if(debug) + printf("@@@@ Bad MHz digits: %s\n", tmp); + return -1; + } + + if (strlen(s) < 3){ + if(debug) + printf("@@@@ Bad KHz digits: %s\n", s); + return -1; + } - if(strlen(digitbuf) < 1) /* needs 1 digit */ - return DC_INDETERMINATE; - - for(i = 0 ; i < digitbuf[i] ; i++) { - if((digitbuf[i] < '0') || (digitbuf[i] > '9')) - return DC_ERROR; + if ((s[2] != '0') && (s[2] != '5')){ + if(debug) + printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]); + return -1; } - - 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 ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)) - { - rpt_mutex_unlock(&myrpt->lock); - rpt_telemetry(myrpt, MACRO_BUSY, NULL); - return DC_ERROR; + + band = rbi_mhztoband(tmp); + if (band == -1){ + if(debug) + printf("@@@@ Bad Band: %s\n", tmp); + return -1; } - myrpt->macrotimer = MACROTIME; - strncat(myrpt->macrobuf,val,MAXMACRO - 1); - rpt_mutex_unlock(&myrpt->lock); - return DC_COMPLETE; + + txpl = rbi_pltocode(myrpt->txpl); + + if (txpl == -1){ + if(debug) + printf("@@@@ Bad TX PL: %s\n", myrpt->txpl); + return -1; + } + return 0; } -/* -* COP - Control operator -*/ - -static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink) +static int check_freq_kenwood(int m, int d, int *defmode) { - if(!param) - return DC_ERROR; - - switch(myatoi(param)){ - case 1: /* System reset */ - system("killall -9 asterisk"); /* FIXME to drastic? */ - 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; + int dflmd = REM_MODE_FM; - case 5: /* Disgorge variables to log for debug purposes */ - myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */ - return DC_COMPLETE; + if (m == 144){ /* 2 meters */ + if(d < 10100) + return -1; + } + else if((m >= 145) && (m < 148)){ + ; + } + else if((m >= 430) && (m < 450)){ /* 70 centimeters */ + ; + } + else + return -1; + + if(defmode) + *defmode = dflmd; - case 6: /* Simulate COR being activated (phone only) */ - if (command_source != SOURCE_PHONE) return DC_INDETERMINATE; - return DC_DOKEY; - } - return DC_INDETERMINATE; + return 0; } -/* -* 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) +/* Check for valid rbi frequency */ +/* Hard coded limits now, configurable later, maybe? */ + +static int check_freq_rbi(int m, int d, int *defmode) { - int i; - char *stringp,*action,*param,*functiondigits; - char function_table_name[30] = ""; - char workstring[200]; - - struct ast_variable *vp; - - if(debug) - printf("@@@@ 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)); - vp = ast_variable_browse(myrpt->cfg, function_table_name); - while(vp) { - if(!strncasecmp(vp->name, digits, strlen(vp->name))) - break; - vp = vp->next; - } - if(!vp) { - int n; + int dflmd = REM_MODE_FM; - 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 */ - ast_copy_string(workstring, vp->value, sizeof(workstring)); - stringp = workstring; - action = strsep(&stringp, ","); - param = stringp; - if(debug) - printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)"); - /* Look up the action */ - for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){ - if(!strncasecmp(action, function_table[i].action, strlen(action))) - break; + if(m == 50){ /* 6 meters */ + if(d < 10100) + return -1; } - if(debug) - printf("@@@@ table index i = %d\n",i); - if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){ - /* Error, action not in table */ - return DC_ERROR; + else if((m >= 51) && ( m < 54)){ + ; } - if(function_table[i].function == NULL){ - /* Error, function undefined */ - if(debug) - printf("@@@@ NULL for action: %s\n",action); - return DC_ERROR; + else if(m == 144){ /* 2 meters */ + if(d < 10100) + return -1; } - functiondigits = digits + strlen(vp->name); - return (*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink); -} - - -static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink, - char *str) -{ -char tmp[300],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; - /* put string in our buffer */ - ast_copy_string(tmp, str, sizeof(tmp)); - - if (!strcmp(tmp,discstr)) - { - mylink->disced = 1; - mylink->retries = MAX_RETRIES + 1; - ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV); - return; - } - if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5) - { - ast_log(LOG_WARNING, "Unable to parse link string %s\n",str); - return; + else if((m >= 145) && (m < 148)){ + ; } - if (strcmp(cmd,"D")) - { - ast_log(LOG_WARNING, "Unable to parse link string %s\n",str); - return; + else if((m >= 222) && (m < 225)){ /* 1.25 meters */ + ; } - - 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') - { - l = l->next; - continue; - } - /* 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 = strdup(str); - if (l->chan) ast_write(l->chan,&wf); - } - return; - } - 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))) - { - l = l->next; - continue; - } - /* send, but not to src */ - if (strcmp(l->name,src)) { - wf.data = strdup(str); - if (l->chan) ast_write(l->chan,&wf); - } - l = l->next; - } - return; + else if((m >= 430) && (m < 450)){ /* 70 centimeters */ + ; } - 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){ - rpt_mutex_unlock(&myrpt->lock); - rpt_telemetry(myrpt,PROC,NULL); - 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; - } + else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */ + ; } - if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) - { - myrpt->mydtmf = c; + else + return -1; + + if(defmode) + *defmode = dflmd; + + + return 0; +} + +/* + * Convert decimals of frequency to int + */ + +static int decimals2int(char *fraction) +{ + int i; + char len = strlen(fraction); + int multiplier = 100000; + int res = 0; + + if(!len) + return 0; + for( i = 0 ; i < len ; i++, multiplier /= 10) + res += (fraction[i] - '0') * multiplier; + return res; +} + + +/* +* Split frequency into mhz and decimals +*/ + +static int split_freq(char *mhz, char *decimals, char *freq) +{ + char freq_copy[MAXREMSTR]; + char *decp; + + decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.'); + if(decp){ + *decp++ = 0; + strncpy(mhz, freq_copy, MAXREMSTR); + strcpy(decimals, "00000"); + strncpy(decimals, decp, strlen(decp)); + decimals[5] = 0; + return 0; } - 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); - - switch(res){ + else + return -1; - 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; - } - } +} + +/* +* Split ctcss frequency into hertz and decimal +*/ + +static int split_ctcss_freq(char *hertz, char *decimal, char *freq) +{ + char freq_copy[MAXREMSTR]; + char *decp; + decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.'); + if(decp){ + *decp++ = 0; + strncpy(hertz, freq_copy, MAXREMSTR); + strncpy(decimal, decp, strlen(decp)); + decimal[strlen(decp)] = '\0'; + return 0; } - rpt_mutex_unlock(&myrpt->lock); - return; + else + return -1; } -static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink, - char c) + + +/* +* FT-897 I/O handlers +*/ + +/* Check to see that the frequency is valid */ +/* Hard coded limits now, configurable later, maybe? */ + + +static int check_freq_ft897(int m, int d, int *defmode) { + int dflmd = REM_MODE_FM; -char cmd[300]; -int res; + if(m == 1){ /* 160 meters */ + dflmd = REM_MODE_LSB; + if(d < 80000) + return -1; + } + else if(m == 3){ /* 80 meters */ + dflmd = REM_MODE_LSB; + if(d < 50000) + return -1; + } + else if(m == 7){ /* 40 meters */ + dflmd = REM_MODE_LSB; + if(d > 30000) + return -1; + } + else if(m == 14){ /* 20 meters */ + dflmd = REM_MODE_USB; + if(d > 35000) + return -1; + } + else if(m == 18){ /* 17 meters */ + dflmd = REM_MODE_USB; + if((d < 6800) || (d > 16800)) + return -1; + } + else if(m == 21){ /* 15 meters */ + dflmd = REM_MODE_USB; + if((d < 20000) || (d > 45000)) + return -1; + } + else if(m == 24){ /* 12 meters */ + dflmd = REM_MODE_USB; + if((d < 89000) || (d > 99000)) + return -1; + } + else if(m == 28){ /* 10 meters */ + dflmd = REM_MODE_USB; + } + else if(m == 29){ + if(d >= 51000) + dflmd = REM_MODE_FM; + else + dflmd = REM_MODE_USB; + if(d > 70000) + return -1; + } + else if(m == 50){ /* 6 meters */ + if(d >= 30000) + dflmd = REM_MODE_FM; + else + dflmd = REM_MODE_USB; - 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; + else if((m >= 51) && ( m < 54)){ + dflmd = REM_MODE_FM; } - 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){ - rpt_mutex_unlock(&myrpt->lock); - rpt_telemetry(myrpt,PROC,NULL); - 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; - } + else if(m == 144){ /* 2 meters */ + if(d >= 30000) + dflmd = REM_MODE_FM; + else + dflmd = REM_MODE_USB; } - if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) - { - myrpt->mydtmf = c; + else if((m >= 145) && (m < 148)){ + dflmd = REM_MODE_FM; } - 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, - SOURCE_DPHONE,mylink); - break; - default: - res = collect_function_digits(myrpt, cmd, - SOURCE_LNK, mylink); - break; - } + else if((m >= 430) && (m < 450)){ /* 70 centimeters */ + if(m < 438) + dflmd = REM_MODE_USB; + else + dflmd = REM_MODE_FM; + ; + } + else + return -1; + + if(defmode) + *defmode = dflmd; + + return 0; +} + +/* +* Set a new frequency for the FT897 +*/ + +static int set_freq_ft897(struct rpt *myrpt, char *newfreq) +{ + unsigned char cmdstr[5]; + int fd,m,d; + char mhz[MAXREMSTR]; + char decimals[MAXREMSTR]; - rpt_mutex_lock(&myrpt->lock); - - switch(res){ + fd = 0; + if(debug) + printf("New frequency: %s\n",newfreq); - 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->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; - } - } + if(split_freq(mhz, decimals, newfreq)) + return -1; - } - rpt_mutex_unlock(&myrpt->lock); - return; -} + m = atoi(mhz); + d = atoi(decimals); -/* 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 - */ + /* The FT-897 likes packed BCD frequencies */ -/* take the frequency from the 10 mhz digits (and up) and convert it - to a band number */ + cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10); /* 100MHz 10Mhz */ + cmdstr[1] = ((m % 10) << 4) + (d / 10000); /* 1MHz 100KHz */ + cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100); /* 10KHz 1KHz */ + cmdstr[3] = (((d % 100)/10) << 4) + (d % 10); /* 100Hz 10Hz */ + cmdstr[4] = 0x01; /* command */ -static int rbi_mhztoband(char *str) -{ -int i; + return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0); - 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) +/* ft-897 simple commands */ + +static int simple_command_ft897(struct rpt *myrpt, char command) { -int i; -char *s; + unsigned char cmdstr[5]; + + memset(cmdstr, 0, 5); - 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; -} + cmdstr[4] = command; -/* -* Shift out a formatted serial bit stream -*/ + return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0); -static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data) - { - int i,j; - unsigned char od,d; - static volatile long long delayvar; +} - for(i = 0 ; i < 5 ; i++){ - od = *data++; - for(j = 0 ; j < 8 ; j++){ - d = od & 1; - outb(d,myrpt->p.iobase); - /* >= 15 us */ - for(delayvar = 1; delayvar < 15000; delayvar++); - od >>= 1; - outb(d | 2,myrpt->p.iobase); - /* >= 30 us */ - for(delayvar = 1; delayvar < 30000; delayvar++); - outb(d,myrpt->p.iobase); - /* >= 10 us */ - for(delayvar = 1; delayvar < 10000; delayvar++); - } - } - /* >= 50 us */ - for(delayvar = 1; delayvar < 50000; delayvar++); - } +/* ft-897 offset */ -static void rbi_out(struct rpt *myrpt,unsigned char *data) +static int set_offset_ft897(struct rpt *myrpt, char offset) { -struct zt_radio_param r; + unsigned char cmdstr[5]; + + memset(cmdstr, 0, 5); + + switch(offset){ + case REM_SIMPLEX: + cmdstr[0] = 0x89; + break; + + case REM_MINUS: + cmdstr[0] = 0x09; + break; + + case REM_PLUS: + cmdstr[0] = 0x49; + break; - memset(&r,0,sizeof(struct zt_radio_param)); - 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) - { - 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); - return; + default: + return -1; } + + cmdstr[4] = 0x09; + + return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0); } -static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, char *rxbuf, - int rxmaxbytes, int asciiflag) +/* ft-897 mode */ + +static int set_mode_ft897(struct rpt *myrpt, char newmode) { - int i; - struct zt_radio_param prm; + unsigned char cmdstr[5]; + + memset(cmdstr, 0, 5); + + switch(newmode){ + case REM_MODE_FM: + cmdstr[0] = 0x08; + break; - if(debug){ - printf("String output was: "); - for(i = 0; i < txbytes; i++) - printf("%02X ", (unsigned char ) txbuf[i]); - printf("\n"); + case REM_MODE_USB: + cmdstr[0] = 0x01; + break; + + case REM_MODE_LSB: + cmdstr[0] = 0x00; + break; + + case REM_MODE_AM: + cmdstr[0] = 0x04; + break; + + default: + return -1; } + cmdstr[4] = 0x07; - 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; - memcpy(rxbuf,prm.buf,prm.index); - } - return(prm.index); + return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0); } -static int setrbi(struct rpt *myrpt) -{ -char tmp[MAXREMSTR] = "",*s; -unsigned char rbicmd[5]; -int band,txoffset = 0,txpower = 0,txpl; +/* Set tone encode and decode modes */ - /* 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 */ +static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon) +{ + unsigned char cmdstr[5]; - if (s == NULL){ - if(debug) - printf("@@@@ Frequency needs a decimal\n"); - return -1; - } + memset(cmdstr, 0, 5); - *s++ = 0; - if (strlen(tmp) < 2){ - if(debug) - printf("@@@@ Bad MHz digits: %s\n", tmp); - return -1; - } - - if (strlen(s) < 3){ - if(debug) - printf("@@@@ Bad KHz digits: %s\n", s); - return -1; - } + if(rxplon && txplon) + cmdstr[0] = 0x2A; /* Encode and Decode */ + else if (!rxplon && txplon) + cmdstr[0] = 0x4A; /* Encode only */ + else if (rxplon && !txplon) + cmdstr[0] = 0x3A; /* Encode only */ + else + cmdstr[0] = 0x8A; /* OFF */ - if ((s[2] != '0') && (s[2] != '5')){ - if(debug) - printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]); - return -1; - } - - band = rbi_mhztoband(tmp); - if (band == -1){ - if(debug) - printf("@@@@ Bad Band: %s\n", tmp); - return -1; - } + cmdstr[4] = 0x0A; + + return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0); +} + + +/* Set transmit and receive ctcss tone frequencies */ + +static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone) +{ + unsigned char cmdstr[5]; + char hertz[MAXREMSTR],decimal[MAXREMSTR]; + int h,d; + + memset(cmdstr, 0, 5); + + if(split_ctcss_freq(hertz, decimal, txtone)) + return -1; + + h = atoi(hertz); + d = atoi(decimal); - txpl = rbi_pltocode(myrpt->txpl); + cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10; + cmdstr[1] = ((h % 10) << 4) + (d % 10); - if (txpl == -1){ - if(debug) - printf("@@@@ Bad TX PL: %s\n", myrpt->txpl); - return -1; - } + if(rxtone){ + + if(split_ctcss_freq(hertz, decimal, rxtone)) + return -1; + h = atoi(hertz); + d = atoi(decimal); - switch(myrpt->offset) - { - case REM_MINUS: - txoffset = 0; - break; - case REM_PLUS: - txoffset = 0x10; - break; - case REM_SIMPLEX: - txoffset = 0x20; - break; - } - switch(myrpt->powerlevel) - { - case REM_LOWPWR: - txpower = 0; - break; - case REM_MEDPWR: - txpower = 0x20; - break; - case REM_HIPWR: - txpower = 0x10; - break; + cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10; + cmdstr[3] = ((h % 10) << 4) + (d % 10); } - rbicmd[0] = 0; - rbicmd[1] = band | txpower | 0xc0; - rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80; - if (s[2] == '5') rbicmd[2] |= 0x40; - rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0'); - rbicmd[4] = txpl; - if (myrpt->txplon) rbicmd[4] |= 0x40; - if (myrpt->rxplon) rbicmd[4] |= 0x80; - rbi_out(myrpt,rbicmd); - return 0; -} + cmdstr[4] = 0x0B; + return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0); +} -/* Check for valid rbi frequency */ -/* Hard coded limits now, configurable later, maybe? */ -static int check_freq_rbi(int m, int d, int *defmode) + +static int set_ft897(struct rpt *myrpt) { - int dflmd = REM_MODE_FM; + int res; + + if(debug) + printf("@@@@ lock on\n"); - if(m == 50){ /* 6 meters */ - if(d < 10100) - return -1; - } - else if((m >= 51) && ( m < 54)){ - ; - } - else if(m == 144){ /* 2 meters */ - if(d < 10100) - return -1; - } - else if((m >= 145) && (m < 148)){ - ; - } - else if((m >= 222) && (m < 225)){ /* 1.25 meters */ - ; - } - else if((m >= 430) && (m < 450)){ /* 70 centimeters */ - ; + res = simple_command_ft897(myrpt, 0x00); /* LOCK on */ + + if(debug) + printf("@@@@ ptt off\n"); + + if(!res) + res = simple_command_ft897(myrpt, 0x88); /* PTT off */ + + if(debug) + printf("Modulation mode\n"); + + if(!res) + res = set_mode_ft897(myrpt, myrpt->remmode); /* Modulation mode */ + + if(debug) + printf("Split off\n"); + + if(!res) + simple_command_ft897(myrpt, 0x82); /* Split off */ + + if(debug) + printf("Frequency\n"); + + if(!res) + res = set_freq_ft897(myrpt, myrpt->freq); /* Frequency */ + if((myrpt->remmode == REM_MODE_FM)){ + if(debug) + printf("Offset\n"); + if(!res) + res = set_offset_ft897(myrpt, myrpt->offset); /* Offset if FM */ + if((!res)&&(myrpt->rxplon || myrpt->txplon)){ + if(debug) + printf("CTCSS tone freqs.\n"); + res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */ + } + if(!res){ + if(debug) + printf("CTCSS mode\n"); + res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */ + } } - else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */ - ; + if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){ + if(debug) + printf("Clarifier off\n"); + simple_command_ft897(myrpt, 0x85); /* Clarifier off if LSB or USB */ } - else - return -1; - - if(defmode) - *defmode = dflmd; - + return res; +} +static int closerem_ft897(struct rpt *myrpt) +{ + simple_command_ft897(myrpt, 0x88); /* PTT off */ return 0; -} +} /* -* Split frequency into mhz and decimals +* Bump frequency up or down by a small amount +* Return 0 if the new frequnecy is valid, or -1 if invalid +* Interval is in Hz, resolution is 10Hz */ - -static int split_freq(char *mhz, char *decimals, char *freq) + +static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval) { - char *decp; + int m,d; + char mhz[MAXREMSTR], decimals[MAXREMSTR]; - freq = ast_strdupa(freq); - if ((decp = strchr(freq, '.'))) { - *decp++ = 0; - ast_copy_string(mhz, freq, MAXREMSTR); - strcpy(decimals, "00000"); - ast_copy_string(decimals, decp, 6); - return 0; - } - else - return -1; + if(debug) + printf("Before bump: %s\n", myrpt->freq); -} + if(split_freq(mhz, decimals, myrpt->freq)) + return -1; -/* -* Split ctcss frequency into hertz and decimal -*/ - -static int split_ctcss_freq(char *hertz, char *decimal, char *freq) -{ - char *decp; + m = atoi(mhz); + d = atoi(decimals); - freq = ast_strdupa(freq); - if ((decp = strchr(freq, '.'))) { - *decp++ = 0; - ast_copy_string(hertz, freq, MAXREMSTR); - ast_copy_string(decimal, decp, sizeof(decimal)); - return 0; + d += (interval / 10); /* 10Hz resolution */ + if(d < 0){ + m--; + d += 100000; } - else + else if(d >= 100000){ + m++; + d -= 100000; + } + + if(check_freq_ft897(m, d, NULL)){ + if(debug) + printf("Bump freq invalid\n"); return -1; + } + + snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d); + + if(debug) + printf("After bump: %s\n", myrpt->freq); + + return set_freq_ft897(myrpt, myrpt->freq); } /* -* FT-897 I/O handlers +* IC-706 I/O handlers */ /* Check to see that the frequency is valid */ /* Hard coded limits now, configurable later, maybe? */ -static int check_freq_ft897(int m, int d, int *defmode) +static int check_freq_ic706(int m, int d, int *defmode) { int dflmd = REM_MODE_FM; if(m == 1){ /* 160 meters */ dflmd = REM_MODE_LSB; - if(d < 80001) + if(d < 80000) return -1; } else if(m == 3){ /* 80 meters */ dflmd = REM_MODE_LSB; - if(d < 75001) + if(d < 50000) return -1; } else if(m == 7){ /* 40 meters */ dflmd = REM_MODE_LSB; - if((d < 15001) || (d > 29999)) + if(d > 30000) return -1; } else if(m == 14){ /* 20 meters */ dflmd = REM_MODE_USB; - if((d < 15001) || (d > 34999)) + if(d > 35000) return -1; } else if(m == 18){ /* 17 meters */ dflmd = REM_MODE_USB; - if((d < 11001) || (d > 16797)) + if((d < 6800) || (d > 16800)) return -1; } else if(m == 21){ /* 15 meters */ dflmd = REM_MODE_USB; - if((d < 20001) || (d > 44999)) + if((d < 20000) || (d > 45000)) return -1; } else if(m == 24){ /* 12 meters */ dflmd = REM_MODE_USB; - if((d < 93001) || (d > 98999)) + if((d < 89000) || (d > 99000)) return -1; } else if(m == 28){ /* 10 meters */ dflmd = REM_MODE_USB; - if(d < 30001) - return -1; } else if(m == 29){ if(d >= 51000) dflmd = REM_MODE_FM; else dflmd = REM_MODE_USB; - if(d > 69999) + if(d > 70000) return -1; } else if(m == 50){ /* 6 meters */ - if(d < 10100) - return -1; if(d >= 30000) dflmd = REM_MODE_FM; else @@ -4403,8 +6750,6 @@ static int check_freq_ft897(int m, int d, int *defmode) dflmd = REM_MODE_FM; } else if(m == 144){ /* 2 meters */ - if(d < 10100) - return -1; if(d >= 30000) dflmd = REM_MODE_FM; else @@ -4429,15 +6774,146 @@ static int check_freq_ft897(int m, int d, int *defmode) return 0; } +/* take a PL frequency and turn it into a code */ +static int ic706_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 693: + return 1; + case 719: + return 2; + case 744: + return 3; + case 770: + return 4; + case 797: + return 5; + case 825: + return 6; + case 854: + return 7; + case 885: + return 8; + case 915: + return 9; + case 948: + return 10; + case 974: + return 11; + case 1000: + return 12; + case 1035: + return 13; + case 1072: + return 14; + case 1109: + return 15; + case 1148: + return 16; + case 1188: + return 17; + case 1230: + return 18; + case 1273: + return 19; + case 1318: + return 20; + case 1365: + return 21; + case 1413: + return 22; + case 1462: + return 23; + case 1514: + return 24; + case 1567: + return 25; + case 1598: + return 26; + case 1622: + return 27; + case 1655: + return 28; + case 1679: + return 29; + case 1713: + return 30; + case 1738: + return 31; + case 1773: + return 32; + case 1799: + return 33; + case 1835: + return 34; + case 1862: + return 35; + case 1899: + return 36; + case 1928: + return 37; + case 1966: + return 38; + case 1995: + return 39; + case 2035: + return 40; + case 2065: + return 41; + case 2107: + return 42; + case 2181: + return 43; + case 2257: + return 44; + case 2291: + return 45; + case 2336: + return 46; + case 2418: + return 47; + case 2503: + return 48; + case 2541: + return 49; + } + return -1; +} + +/* ic-706 simple commands */ + +static int simple_command_ic706(struct rpt *myrpt, char command, char subcommand) +{ + unsigned char cmdstr[10]; + + cmdstr[0] = cmdstr[1] = 0xfe; + cmdstr[2] = myrpt->p.civaddr; + cmdstr[3] = 0xe0; + cmdstr[4] = command; + cmdstr[5] = subcommand; + cmdstr[6] = 0xfd; + + return(civ_cmd(myrpt,cmdstr,7)); +} + /* -* Set a new frequency for the FT897 +* Set a new frequency for the ic706 */ -static int set_freq_ft897(struct rpt *myrpt, char *newfreq) +static int set_freq_ic706(struct rpt *myrpt, char *newfreq) { - char mhz[MAXREMSTR]; - char decimals[MAXREMSTR]; - unsigned char cmdstr[5]; + unsigned char cmdstr[20]; + char mhz[MAXREMSTR], decimals[MAXREMSTR]; int fd,m,d; fd = 0; @@ -4450,125 +6926,115 @@ static int set_freq_ft897(struct rpt *myrpt, char *newfreq) m = atoi(mhz); d = atoi(decimals); - /* The FT-897 likes packed BCD frequencies */ - - cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10); /* 100MHz 10Mhz */ - cmdstr[1] = ((m % 10) << 4) + (d / 10000); /* 1MHz 100KHz */ - cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100); /* 10KHz 1KHz */ - cmdstr[3] = (((d % 100)/10) << 4) + (d % 10); /* 100Hz 10Hz */ - cmdstr[4] = 0x01; /* command */ - - return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0); - -} - -/* ft-897 simple commands */ - -static int simple_command_ft897(struct rpt *myrpt, char command) -{ - unsigned char cmdstr[5]; - - memset(cmdstr, 0, 5); - - cmdstr[4] = command; + /* The ic-706 likes packed BCD frequencies */ - return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0); + cmdstr[0] = cmdstr[1] = 0xfe; + cmdstr[2] = myrpt->p.civaddr; + cmdstr[3] = 0xe0; + cmdstr[4] = 5; + cmdstr[5] = ((d % 10) << 4); + cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10); + cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000); + cmdstr[8] = (((m % 100)/10) << 4) + (m % 10); + cmdstr[9] = (m / 100); + cmdstr[10] = 0xfd; + return(civ_cmd(myrpt,cmdstr,11)); } -/* ft-897 offset */ +/* ic-706 offset */ -static int set_offset_ft897(struct rpt *myrpt, char offset) +static int set_offset_ic706(struct rpt *myrpt, char offset) { - unsigned char cmdstr[5]; - - memset(cmdstr, 0, 5); + unsigned char c; switch(offset){ case REM_SIMPLEX: - cmdstr[0] = 0x89; + c = 0x10; break; case REM_MINUS: - cmdstr[0] = 0x09; + c = 0x11; break; case REM_PLUS: - cmdstr[0] = 0x49; + c = 0x12; break; default: return -1; } - cmdstr[4] = 0x09; + return simple_command_ic706(myrpt,0x0f,c); - return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0); } -/* ft-897 mode */ +/* ic-706 mode */ -static int set_mode_ft897(struct rpt *myrpt, char newmode) +static int set_mode_ic706(struct rpt *myrpt, char newmode) { - unsigned char cmdstr[5]; - - memset(cmdstr, 0, 5); + unsigned char c; switch(newmode){ case REM_MODE_FM: - cmdstr[0] = 0x08; + c = 5; break; case REM_MODE_USB: - cmdstr[0] = 0x01; + c = 1; break; case REM_MODE_LSB: - cmdstr[0] = 0x00; + c = 0; break; case REM_MODE_AM: - cmdstr[0] = 0x04; + c = 2; break; default: return -1; } - cmdstr[4] = 0x07; - - return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0); + return simple_command_ic706(myrpt,6,c); } /* Set tone encode and decode modes */ -static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon) +static int set_ctcss_mode_ic706(struct rpt *myrpt, char txplon, char rxplon) { - unsigned char cmdstr[5]; - - memset(cmdstr, 0, 5); - - if(rxplon && txplon) - cmdstr[0] = 0x2A; /* Encode and Decode */ - else if (!rxplon && txplon) - cmdstr[0] = 0x4A; /* Encode only */ - else if (rxplon && !txplon) - cmdstr[0] = 0x3A; /* Encode only */ - else - cmdstr[0] = 0x8A; /* OFF */ - - cmdstr[4] = 0x0A; - - return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0); + unsigned char cmdstr[10]; + int rv; + + cmdstr[0] = cmdstr[1] = 0xfe; + cmdstr[2] = myrpt->p.civaddr; + cmdstr[3] = 0xe0; + cmdstr[4] = 0x16; + cmdstr[5] = 0x42; + cmdstr[6] = (txplon != 0); + cmdstr[7] = 0xfd; + + rv = civ_cmd(myrpt,cmdstr,8); + if (rv) return(-1); + + cmdstr[0] = cmdstr[1] = 0xfe; + cmdstr[2] = myrpt->p.civaddr; + cmdstr[3] = 0xe0; + cmdstr[4] = 0x16; + cmdstr[5] = 0x43; + cmdstr[6] = (rxplon != 0); + cmdstr[7] = 0xfd; + + return(civ_cmd(myrpt,cmdstr,8)); } - +#if 0 /* Set transmit and receive ctcss tone frequencies */ -static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone) +static int set_ctcss_freq_ic706(struct rpt *myrpt, char *txtone, char *rxtone) { - unsigned char cmdstr[5]; + unsigned char cmdstr[10]; char hertz[MAXREMSTR],decimal[MAXREMSTR]; - int h,d; + int h,d,rv; memset(cmdstr, 0, 5); @@ -4578,99 +7044,152 @@ static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone) h = atoi(hertz); d = atoi(decimal); - cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10; - cmdstr[1] = ((h % 10) << 4) + (d % 10); - - if(rxtone){ - - if(split_ctcss_freq(hertz, decimal, rxtone)) - return -1; + cmdstr[0] = cmdstr[1] = 0xfe; + cmdstr[2] = myrpt->p.civaddr; + cmdstr[3] = 0xe0; + cmdstr[4] = 0x1b; + cmdstr[5] = 0; + cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10; + cmdstr[7] = ((h % 10) << 4) + (d % 10); + cmdstr[8] = 0xfd; - h = atoi(hertz); - d = atoi(decimal); - - cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10; - cmdstr[3] = ((h % 10) << 4) + (d % 10); - } - cmdstr[4] = 0x0B; + rv = civ_cmd(myrpt,cmdstr,9); + if (rv) return(-1); - return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0); + if (!rxtone) return(0); + + if(split_ctcss_freq(hertz, decimal, rxtone)) + return -1; + + h = atoi(hertz); + d = atoi(decimal); + + cmdstr[0] = cmdstr[1] = 0xfe; + cmdstr[2] = myrpt->p.civaddr; + cmdstr[3] = 0xe0; + cmdstr[4] = 0x1b; + cmdstr[5] = 1; + cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10; + cmdstr[7] = ((h % 10) << 4) + (d % 10); + cmdstr[8] = 0xfd; + return(civ_cmd(myrpt,cmdstr,9)); } +#endif + +static int vfo_ic706(struct rpt *myrpt) +{ + unsigned char cmdstr[10]; + + cmdstr[0] = cmdstr[1] = 0xfe; + cmdstr[2] = myrpt->p.civaddr; + cmdstr[3] = 0xe0; + cmdstr[4] = 7; + cmdstr[5] = 0xfd; + + return(civ_cmd(myrpt,cmdstr,6)); +} +static int mem2vfo_ic706(struct rpt *myrpt) +{ + unsigned char cmdstr[10]; + + cmdstr[0] = cmdstr[1] = 0xfe; + cmdstr[2] = myrpt->p.civaddr; + cmdstr[3] = 0xe0; + cmdstr[4] = 0x0a; + cmdstr[5] = 0xfd; + return(civ_cmd(myrpt,cmdstr,6)); +} -static int set_ft897(struct rpt *myrpt) +static int select_mem_ic706(struct rpt *myrpt, int slot) { - int res; + unsigned char cmdstr[10]; + + cmdstr[0] = cmdstr[1] = 0xfe; + cmdstr[2] = myrpt->p.civaddr; + cmdstr[3] = 0xe0; + cmdstr[4] = 8; + cmdstr[5] = 0; + cmdstr[6] = ((slot / 10) << 4) + (slot % 10); + cmdstr[7] = 0xfd; + + return(civ_cmd(myrpt,cmdstr,8)); +} + +static int set_ic706(struct rpt *myrpt) +{ + int res = 0,i; if(debug) - printf("@@@@ lock on\n"); + printf("Set to VFO A\n"); + + if (!res) + res = simple_command_ic706(myrpt,7,0); - res = simple_command_ft897(myrpt, 0x00); /* LOCK on */ + if((myrpt->remmode == REM_MODE_FM)) + { + i = ic706_pltocode(myrpt->rxpl); + if (i == -1) return -1; + if(debug) + printf("Select memory number\n"); + if (!res) + res = select_mem_ic706(myrpt,i + IC706_PL_MEMORY_OFFSET); + if(debug) + printf("Transfer memory to VFO\n"); + if (!res) + res = mem2vfo_ic706(myrpt); + } + if(debug) - printf("@@@@ ptt off\n"); + printf("Set to VFO\n"); - if(!res) - res = simple_command_ft897(myrpt, 0x88); /* PTT off */ + if (!res) + res = vfo_ic706(myrpt); if(debug) printf("Modulation mode\n"); - if(!res) - res = set_mode_ft897(myrpt, myrpt->remmode); /* Modulation mode */ + if (!res) + res = set_mode_ic706(myrpt, myrpt->remmode); /* Modulation mode */ if(debug) printf("Split off\n"); if(!res) - simple_command_ft897(myrpt, 0x82); /* Split off */ + simple_command_ic706(myrpt, 0x82,0); /* Split off */ if(debug) printf("Frequency\n"); if(!res) - res = set_freq_ft897(myrpt, myrpt->freq); /* Frequency */ + res = set_freq_ic706(myrpt, myrpt->freq); /* Frequency */ if((myrpt->remmode == REM_MODE_FM)){ if(debug) printf("Offset\n"); if(!res) - res = set_offset_ft897(myrpt, myrpt->offset); /* Offset if FM */ - if((!res)&&(myrpt->rxplon || myrpt->txplon)){ - if(debug) - printf("CTCSS tone freqs.\n"); - res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */ - } + res = set_offset_ic706(myrpt, myrpt->offset); /* Offset if FM */ if(!res){ if(debug) printf("CTCSS mode\n"); - res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */ + res = set_ctcss_mode_ic706(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */ } } - if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){ - if(debug) - printf("Clarifier off\n"); - simple_command_ft897(myrpt, 0x85); /* Clarifier off if LSB or USB */ - } return res; } -static int closerem_ft897(struct rpt *myrpt) -{ - simple_command_ft897(myrpt, 0x88); /* PTT off */ - return 0; -} - /* * Bump frequency up or down by a small amount * Return 0 if the new frequnecy is valid, or -1 if invalid * Interval is in Hz, resolution is 10Hz */ -static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval) +static int multimode_bump_freq_ic706(struct rpt *myrpt, int interval) { int m,d; char mhz[MAXREMSTR], decimals[MAXREMSTR]; + unsigned char cmdstr[20]; if(debug) printf("Before bump: %s\n", myrpt->freq); @@ -4691,7 +7210,7 @@ static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval) d -= 100000; } - if(check_freq_ft897(m, d, NULL)){ + if(check_freq_ic706(m, d, NULL)){ if(debug) printf("Bump freq invalid\n"); return -1; @@ -4702,7 +7221,20 @@ static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval) if(debug) printf("After bump: %s\n", myrpt->freq); - return set_freq_ft897(myrpt, myrpt->freq); + /* The ic-706 likes packed BCD frequencies */ + + cmdstr[0] = cmdstr[1] = 0xfe; + cmdstr[2] = myrpt->p.civaddr; + cmdstr[3] = 0xe0; + cmdstr[4] = 0; + cmdstr[5] = ((d % 10) << 4); + cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10); + cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000); + cmdstr[8] = (((m % 100)/10) << 4) + (m % 10); + cmdstr[9] = (m / 100); + cmdstr[10] = 0xfd; + + return(serial_remote_io(myrpt,cmdstr,11,NULL,0,0)); } @@ -4713,18 +7245,54 @@ static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval) static int setrem(struct rpt *myrpt) { - return 0; /* XXX BROKEN!! */ +char str[300]; +char *offsets[] = {"MINUS","SIMPLEX","PLUS"}; +char *powerlevels[] = {"LOW","MEDIUM","HIGH"}; +char *modes[] = {"FM","USB","LSB","AM"}; +int res = -1; + + if (myrpt->p.archivedir) + { + sprintf(str,"FREQ,%s,%s,%s,%s,%s,%s,%d,%d",myrpt->freq, + modes[(int)myrpt->remmode], + myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset], + powerlevels[(int)myrpt->powerlevel],myrpt->txplon, + myrpt->rxplon); + donodelog(myrpt,str); + } if(!strcmp(myrpt->remote, remote_rig_ft897)) - return set_ft897(myrpt); + { + rpt_telemetry(myrpt,SETREMOTE,NULL); + res = 0; + } + if(!strcmp(myrpt->remote, remote_rig_ic706)) + { + rpt_telemetry(myrpt,SETREMOTE,NULL); + res = 0; + } else if(!strcmp(myrpt->remote, remote_rig_rbi)) - return setrbi(myrpt); + { + res = setrbi_check(myrpt); + if (!res) + { + rpt_telemetry(myrpt,SETREMOTE,NULL); + res = 0; + } + } + else if(!strcmp(myrpt->remote, remote_rig_kenwood)) { + rpt_telemetry(myrpt,SETREMOTE,NULL); + res = 0; + } else - return -1; + res = 0; + + if (res < 0) ast_log(LOG_ERROR,"Unable to send remote command on node %s\n",myrpt->name); + + return res; } static int closerem(struct rpt *myrpt) { - return 0; /* XXX BROKEN!! */ if(!strcmp(myrpt->remote, remote_rig_ft897)) return closerem_ft897(myrpt); else @@ -4732,29 +7300,153 @@ static int closerem(struct rpt *myrpt) } /* -* Dispatch to correct frequency checker +* Dispatch to correct RX frequency checker */ static int check_freq(struct rpt *myrpt, int m, int d, int *defmode) { if(!strcmp(myrpt->remote, remote_rig_ft897)) return check_freq_ft897(m, d, defmode); + else if(!strcmp(myrpt->remote, remote_rig_ic706)) + return check_freq_ic706(m, d, defmode); else if(!strcmp(myrpt->remote, remote_rig_rbi)) return check_freq_rbi(m, d, defmode); + else if(!strcmp(myrpt->remote, remote_rig_kenwood)) + return check_freq_kenwood(m, d, defmode); else return -1; } /* -* Return 1 if rig is multimode capable -*/ + * Check TX frequency before transmitting + */ -static int multimode_capable(struct rpt *myrpt) +static char check_tx_freq(struct rpt *myrpt) { - if(!strcmp(myrpt->remote, remote_rig_ft897)) - return 1; + int i; + int radio_mhz, radio_decimals, ulimit_mhz, ulimit_decimals, llimit_mhz, llimit_decimals; + char radio_mhz_char[MAXREMSTR]; + char radio_decimals_char[MAXREMSTR]; + char limit_mhz_char[MAXREMSTR]; + char limit_decimals_char[MAXREMSTR]; + char limits[256]; + char *limit_ranges[40]; + struct ast_variable *limitlist; + + + /* Must have user logged in and tx_limits defined */ + + if(!myrpt->p.txlimitsstanzaname || !myrpt->loginuser[0] || !myrpt->loginlevel[0]){ + if(debug > 3){ + ast_log(LOG_NOTICE, "No tx band table defined, or no user logged in\n"); + } + return 1; /* Assume it's ok otherwise */ + } + + /* Retrieve the band table for the loginlevel */ + limitlist = ast_variable_browse(myrpt->cfg, myrpt->p.txlimitsstanzaname); + + if(!limitlist){ + ast_log(LOG_WARNING, "No entries in %s band table stanza\n", myrpt->p.txlimitsstanzaname); + return 0; + } + + split_freq(radio_mhz_char, radio_decimals_char, myrpt->freq); + radio_mhz = atoi(radio_mhz_char); + radio_decimals = decimals2int(radio_decimals_char); + + + if(debug > 3){ + ast_log(LOG_NOTICE, "Login User = %s, login level = %s\n", myrpt->loginuser, myrpt->loginlevel); + } + + /* Find our entry */ + + for(;limitlist; limitlist=limitlist->next){ + if(!strcmp(limitlist->name, myrpt->loginlevel)) + break; + } + + if(!limitlist){ + ast_log(LOG_WARNING, "Can't find %s entry in band table stanza %s\n", myrpt->loginlevel, myrpt->p.txlimitsstanzaname); + return 0; + } + + if(debug > 3){ + ast_log(LOG_NOTICE, "Auth %s = %s\n", limitlist->name, limitlist->value); + } + + /* Parse the limits */ + + strncpy(limits, limitlist->value, 256); + limits[255] = 0; + finddelim(limits, limit_ranges, 40); + for(i = 0; i < 40 && limit_ranges[i] ; i++){ + char range[40]; + char *r,*s; + strncpy(range, limit_ranges[i], 40); + range[39] = 0; + if(debug > 3){ + ast_log(LOG_NOTICE, "Checking to see if %s is within limits of %s\n", myrpt->freq, range); + } + + r = strchr(range, '-'); + if(!r){ + ast_log(LOG_WARNING, "Malformed range in %s tx band table entry\n", limitlist->name); + return 0; + } + *r++ = 0; + s = eatwhite(range); + r = eatwhite(r); + split_freq(limit_mhz_char, limit_decimals_char, s); + llimit_mhz = atoi(limit_mhz_char); + llimit_decimals = decimals2int(limit_decimals_char); + split_freq(limit_mhz_char, limit_decimals_char, r); + ulimit_mhz = atoi(limit_mhz_char); + ulimit_decimals = decimals2int(limit_decimals_char); + + if((radio_mhz >= llimit_mhz) && (radio_mhz <= ulimit_mhz)){ + if(radio_mhz == llimit_mhz){ /* CASE 1: TX freq is in llimit mhz portion of band */ + if(radio_decimals >= llimit_decimals){ /* Cannot be below llimit decimals */ + if(llimit_mhz == ulimit_mhz){ /* If bandwidth < 1Mhz, check ulimit decimals */ + if(radio_decimals <= ulimit_decimals){ + return 1; + } + else{ + if(debug > 3) + ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 1\n"); + return 0; + } + } + else{ + return 1; + } + } + else{ /* Is below llimit decimals */ + if(debug > 3) + ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 2\n"); + return 0; + } + } + else if(radio_mhz == ulimit_mhz){ /* CASE 2: TX freq not in llimit mhz portion of band */ + if(radio_decimals <= ulimit_decimals){ + return 1; + } + else{ /* Is above ulimit decimals */ + if(debug > 3) + ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 3\n"); + return 0; + } + } + else /* CASE 3: TX freq within a multi-Mhz band and ok */ + return 1; + } + } + if(debug > 3) /* No match found in TX band table */ + ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 4\n"); return 0; -} +} + /* * Dispatch to correct frequency bumping function @@ -4764,6 +7456,8 @@ static int multimode_bump_freq(struct rpt *myrpt, int interval) { if(!strcmp(myrpt->remote, remote_rig_ft897)) return multimode_bump_freq_ft897(myrpt, interval); + else if(!strcmp(myrpt->remote, remote_rig_ic706)) + return multimode_bump_freq_ic706(myrpt, interval); else return -1; } @@ -4773,10 +7467,10 @@ static int multimode_bump_freq(struct rpt *myrpt, int interval) * Queue announcment that scan has been stopped */ -static void stop_scan(struct rpt *myrpt, int flag) +static void stop_scan(struct rpt *myrpt) { - myrpt->hfscanmode = 0; - myrpt->hfscanstatus = ((flag) ? -2 : -1); + myrpt->hfscanstop = 1; + rpt_telemetry(myrpt,SCAN,0); } /* @@ -4833,7 +7527,8 @@ static int service_scan(struct rpt *myrpt) if(res){ - stop_scan(myrpt,1); + myrpt->hfscanmode = 0; + myrpt->hfscanstatus = -2; return -1; } @@ -4842,76 +7537,112 @@ static int service_scan(struct rpt *myrpt) int myhund = (interval < 0) ? k100 : decimals[0]; int myten = (interval < 0) ? k10 : decimals[1]; myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10; - } + } else myrpt->hfscanstatus = 0; return res; } +/* + * Retrieve a memory channel + * Return 0 if sucessful, + * -1 if channel not found, + * 1 if parse error + */ -static int rmt_telem_start(struct rpt *myrpt, struct ast_channel *chan, int delay) -{ - myrpt->remotetx = 0; - ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY); - if (!myrpt->remoterx) - ast_indicate(chan,AST_CONTROL_RADIO_KEY); - if (ast_safe_sleep(chan, delay) == -1) - return -1; - return 0; -} - - -static int rmt_telem_finish(struct rpt *myrpt, struct ast_channel *chan) +static int retreive_memory(struct rpt *myrpt, char *memory) { + char tmp[30], *s, *s1, *val; -struct zt_params par; - - if (ioctl(myrpt->txchannel->fds[0],ZT_GET_PARAMS,&par) == -1) - { + val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, memory); + if (!val){ return -1; + } + strncpy(tmp,val,sizeof(tmp) - 1); + tmp[sizeof(tmp)-1] = 0; - } - if (!par.rxisoffhook) - { - ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_UNKEY); - myrpt->remoterx = 0; - } - else - { - myrpt->remoterx = 1; + s = strchr(tmp,','); + if (!s) + return 1; + *s++ = 0; + s1 = strchr(s,','); + if (!s1) + return 1; + *s1++ = 0; + strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1); + strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1); + strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1); + myrpt->remmode = REM_MODE_FM; + myrpt->offset = REM_SIMPLEX; + myrpt->powerlevel = REM_MEDPWR; + myrpt->txplon = myrpt->rxplon = 0; + while(*s1){ + switch(*s1++){ + case 'A': + case 'a': + strcpy(myrpt->rxpl, "100.0"); + strcpy(myrpt->txpl, "100.0"); + myrpt->remmode = REM_MODE_AM; + break; + case 'B': + case 'b': + strcpy(myrpt->rxpl, "100.0"); + strcpy(myrpt->txpl, "100.0"); + myrpt->remmode = REM_MODE_LSB; + break; + case 'F': + myrpt->remmode = REM_MODE_FM; + break; + case 'L': + case 'l': + myrpt->powerlevel = REM_LOWPWR; + break; + case 'H': + case 'h': + myrpt->powerlevel = REM_HIPWR; + break; + + case 'M': + case 'm': + myrpt->powerlevel = REM_MEDPWR; + break; + + case '-': + myrpt->offset = REM_MINUS; + break; + + case '+': + myrpt->offset = REM_PLUS; + break; + + case 'S': + case 's': + myrpt->offset = REM_SIMPLEX; + break; + + case 'T': + case 't': + myrpt->txplon = 1; + break; + + case 'R': + case 'r': + myrpt->rxplon = 1; + break; + + case 'U': + case 'u': + strcpy(myrpt->rxpl, "100.0"); + strcpy(myrpt->txpl, "100.0"); + myrpt->remmode = REM_MODE_USB; + break; + default: + return 1; + } } return 0; } -static int rmt_sayfile(struct rpt *myrpt, struct ast_channel *chan, int delay, char *filename) -{ - int res; - - res = rmt_telem_start(myrpt, chan, delay); - - if(!res) - res = sayfile(chan, filename); - - if(!res) - res = rmt_telem_finish(myrpt, chan); - return res; -} - -static int rmt_saycharstr(struct rpt *myrpt, struct ast_channel *chan, int delay, char *charstr) -{ - int res; - - res = rmt_telem_start(myrpt, chan, delay); - - if(!res) - res = saycharstr(chan, charstr); - - if(!res) - res = rmt_telem_finish(myrpt, chan); - return res; -} - - /* * Remote base function @@ -4920,23 +7651,22 @@ static int rmt_saycharstr(struct rpt *myrpt, struct ast_channel *chan, int delay static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink) { char *s,*s1,*s2; - const char *val; - int i,j,ht,k,l,ls2,m,d,res,offset,offsave, modesave, defmode; + int i,j,p,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode; char multimode = 0; - char oc; + char oc,*cp,*cp1,*cp2; char tmp[20], freq[20] = "", savestr[20] = ""; char mhz[MAXREMSTR], decimals[MAXREMSTR]; - struct ast_channel *mychannel; if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK)) return DC_ERROR; + p = myatoi(param); + + if ((p != 99) && (p != 5) && (p != 140) && myrpt->p.authlevel && + (!myrpt->loginlevel[0])) return DC_ERROR; multimode = multimode_capable(myrpt); - mychannel = myrpt->remchannel; - - - switch(myatoi(param)){ + switch(p){ case 1: /* retrieve memory */ if(strlen(digitbuf) < 2) /* needs 2 digits */ @@ -4947,101 +7677,15 @@ static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int c return DC_ERROR; } - val = ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, digitbuf); - if (!val){ - if (ast_safe_sleep(mychannel,1000) == -1) - return DC_ERROR; - sayfile(mychannel,"rpt/memory_notfound"); + r = retreive_memory(myrpt, digitbuf); + if (r < 0){ + rpt_telemetry(myrpt,MEMNOTFOUND,NULL); return DC_COMPLETE; - } - ast_copy_string(tmp, val, sizeof(tmp)); - s = strchr(tmp,','); - if (!s) - return DC_ERROR; - *s++ = 0; - s1 = strchr(s,','); - if (!s1) - return DC_ERROR; - *s1++ = 0; - ast_copy_string(myrpt->freq, tmp, sizeof(myrpt->freq)); - ast_copy_string(myrpt->rxpl, s, sizeof(myrpt->rxpl)); - ast_copy_string(myrpt->txpl, s, sizeof(myrpt->rxpl)); - myrpt->remmode = REM_MODE_FM; - myrpt->offset = REM_SIMPLEX; - myrpt->powerlevel = REM_MEDPWR; - myrpt->txplon = myrpt->rxplon = 0; - while(*s1) - { - switch(*s1++){ - case 'A': - case 'a': - strcpy(myrpt->rxpl, "100.0"); - strcpy(myrpt->txpl, "100.0"); - myrpt->remmode = REM_MODE_AM; - break; - - case 'B': - case 'b': - strcpy(myrpt->rxpl, "100.0"); - strcpy(myrpt->txpl, "100.0"); - myrpt->remmode = REM_MODE_LSB; - break; - - case 'F': - myrpt->remmode = REM_MODE_FM; - break; - - case 'L': - case 'l': - myrpt->powerlevel = REM_LOWPWR; - break; - case 'H': - case 'h': - myrpt->powerlevel = REM_HIPWR; - break; - - case 'M': - case 'm': - myrpt->powerlevel = REM_MEDPWR; - break; - - case '-': - myrpt->offset = REM_MINUS; - break; - - case '+': - myrpt->offset = REM_PLUS; - break; - - case 'S': - case 's': - myrpt->offset = REM_SIMPLEX; - break; - - case 'T': - case 't': - myrpt->txplon = 1; - break; - - case 'R': - case 'r': - myrpt->rxplon = 1; - break; - - case 'U': - case 'u': - strcpy(myrpt->rxpl, "100.0"); - strcpy(myrpt->txpl, "100.0"); - myrpt->remmode = REM_MODE_USB; - break; - } } - - - if (setrem(myrpt) == -1) + if (r > 0){ return DC_ERROR; - - + } + if (setrem(myrpt) == -1) return DC_ERROR; return DC_COMPLETE; case 2: /* set freq and offset */ @@ -5079,7 +7723,7 @@ static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int c /* We have a frequency */ - ast_copy_string(tmp, digitbuf ,sizeof(tmp)); + strncpy(tmp, digitbuf ,sizeof(tmp) - 1); s = tmp; s1 = strsep(&s, "*"); /* Pick off MHz */ @@ -5164,29 +7808,25 @@ static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int c } offsave = myrpt->offset; modesave = myrpt->remmode; - ast_copy_string(savestr, myrpt->freq, sizeof(savestr)); - ast_copy_string(myrpt->freq, freq, sizeof(myrpt->freq)); + strncpy(savestr, myrpt->freq, sizeof(savestr) - 1); + strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1); myrpt->offset = offset; myrpt->remmode = defmode; if (setrem(myrpt) == -1){ myrpt->offset = offsave; myrpt->remmode = modesave; - ast_copy_string(myrpt->freq, savestr, sizeof(myrpt->freq)); + strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1); goto invalid_freq; } return DC_COMPLETE; - - invalid_freq: - - rmt_sayfile(myrpt, mychannel, 1000, "rpt/invalid-freq"); - +invalid_freq: + rpt_telemetry(myrpt,INVFREQ,NULL); return DC_ERROR; case 3: /* set rx PL tone */ - for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */ if(digitbuf[i] == '*'){ j++; @@ -5209,16 +7849,19 @@ static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int c if(debug) printf("PL digits entered %s\n", digitbuf); - ast_copy_string(tmp, digitbuf, sizeof(tmp)); + strncpy(tmp, digitbuf, sizeof(tmp) - 1); /* see if we have at least 1 */ s = strchr(tmp,'*'); if(s) *s = '.'; - ast_copy_string(savestr, myrpt->rxpl, sizeof(savestr)); - ast_copy_string(myrpt->rxpl, tmp, sizeof(myrpt->rxpl)); - + strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1); + strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1); + if(!strcmp(myrpt->remote, remote_rig_rbi)) + { + strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1); + } if (setrem(myrpt) == -1){ - ast_copy_string(myrpt->rxpl, savestr, sizeof(myrpt->rxpl)); + strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1); return DC_ERROR; } @@ -5226,7 +7869,11 @@ static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int c return DC_COMPLETE; case 4: /* set tx PL tone */ - + /* cant set tx tone on RBI (rx tone does both) */ + if(!strcmp(myrpt->remote, remote_rig_rbi)) + return DC_ERROR; + if(!strcmp(myrpt->remote, remote_rig_ic706)) + return DC_ERROR; for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */ if(digitbuf[i] == '*'){ j++; @@ -5249,16 +7896,16 @@ static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int c if(debug) printf("PL digits entered %s\n", digitbuf); - ast_copy_string(tmp, digitbuf, sizeof(tmp)); + strncpy(tmp, digitbuf, sizeof(tmp) - 1); /* see if we have at least 1 */ s = strchr(tmp,'*'); if(s) *s = '.'; - ast_copy_string(savestr, myrpt->txpl, sizeof(savestr)); - ast_copy_string(myrpt->txpl, tmp, sizeof(myrpt->txpl)); + strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1); + strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1); if (setrem(myrpt) == -1){ - ast_copy_string(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1); + strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1); return DC_ERROR; } @@ -5280,345 +7927,208 @@ static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int c if(m < 29) /* No FM allowed below 29MHz! */ return DC_ERROR; myrpt->remmode = REM_MODE_FM; - res = rmt_saycharstr(myrpt, mychannel, 1000,"FM"); + + rpt_telemetry(myrpt,REMMODE,NULL); break; case '2': myrpt->remmode = REM_MODE_USB; - res = rmt_saycharstr(myrpt, mychannel, 1000,"USB"); + rpt_telemetry(myrpt,REMMODE,NULL); break; case '3': myrpt->remmode = REM_MODE_LSB; - res = rmt_saycharstr(myrpt, mychannel, 1000,"LSB"); + rpt_telemetry(myrpt,REMMODE,NULL); break; case '4': myrpt->remmode = REM_MODE_AM; - res = rmt_saycharstr(myrpt, mychannel, 1000,"AM"); + rpt_telemetry(myrpt,REMMODE,NULL); break; default: return DC_ERROR; } - if(res) - return DC_ERROR; if(setrem(myrpt)) return DC_ERROR; - return DC_COMPLETE; - - case 100: /* other stuff */ - case 101: - case 102: - case 103: - case 104: - case 105: - case 106: - res = rmt_telem_start(myrpt, mychannel, 1000); - switch(myatoi(param)){ /* Quick commands requiring a setrem call */ - case 100: /* RX PL Off */ - myrpt->rxplon = 0; - if(!res) - res = sayfile(mychannel, "rpt/rxpl"); - if(!res) - sayfile(mychannel, "rpt/off"); - break; - - case 101: /* RX PL On */ - myrpt->rxplon = 1; - if(!res) - res = sayfile(mychannel, "rpt/rxpl"); - if(!res) - sayfile(mychannel, "rpt/on"); - break; - - - case 102: /* TX PL Off */ - myrpt->txplon = 0; - if(!res) - res = sayfile(mychannel, "rpt/txpl"); - if(!res) - sayfile(mychannel, "rpt/off"); - break; - - case 103: /* TX PL On */ - myrpt->txplon = 1; - if(!res) - res = sayfile(mychannel, "rpt/txpl"); - if(!res) - sayfile(mychannel, "rpt/on"); - break; - - case 104: /* Low Power */ - myrpt->powerlevel = REM_LOWPWR; - if(!res) - res = sayfile(mychannel, "rpt/lopwr"); - break; - - case 105: /* Medium Power */ - myrpt->powerlevel = REM_MEDPWR; - if(!res) - res = sayfile(mychannel, "rpt/medpwr"); - break; - - case 106: /* Hi Power */ - myrpt->powerlevel = REM_HIPWR; - if(!res) - res = sayfile(mychannel, "rpt/hipwr"); - break; - - default: - if(!res) - rmt_telem_finish(myrpt, mychannel); - return DC_ERROR; - } - if(!res) - res = rmt_telem_finish(myrpt, mychannel); - if(res) + return DC_COMPLETEQUIET; + case 99: + /* cant log in when logged in */ + if (myrpt->loginlevel[0]) return DC_ERROR; + *myrpt->loginuser = 0; + myrpt->loginlevel[0] = 0; + cp = strdup(param); + cp1 = strchr(cp,','); + ast_mutex_lock(&myrpt->lock); + if (cp1) + { + *cp1 = 0; + cp2 = strchr(cp1 + 1,','); + if (cp2) + { + *cp2 = 0; + strncpy(myrpt->loginlevel,cp2 + 1, + sizeof(myrpt->loginlevel) - 1); + } + strncpy(myrpt->loginuser,cp1 + 1,sizeof(myrpt->loginuser)); + ast_mutex_unlock(&myrpt->lock); + if (myrpt->p.archivedir) + { + char str[100]; - if (setrem(myrpt) == -1) + sprintf(str,"LOGIN,%s,%s", + myrpt->loginuser,myrpt->loginlevel); + donodelog(myrpt,str); + } + if (debug) + printf("loginuser %s level %s\n",myrpt->loginuser,myrpt->loginlevel); + rpt_telemetry(myrpt,REMLOGIN,NULL); + } + free(cp); + return DC_COMPLETEQUIET; + case 100: /* RX PL Off */ + myrpt->rxplon = 0; + setrem(myrpt); + rpt_telemetry(myrpt,REMXXX,(void *)p); + return DC_COMPLETEQUIET; + case 101: /* RX PL On */ + myrpt->rxplon = 1; + setrem(myrpt); + rpt_telemetry(myrpt,REMXXX,(void *)p); + return DC_COMPLETEQUIET; + case 102: /* TX PL Off */ + myrpt->txplon = 0; + setrem(myrpt); + rpt_telemetry(myrpt,REMXXX,(void *)p); + return DC_COMPLETEQUIET; + case 103: /* TX PL On */ + myrpt->txplon = 1; + setrem(myrpt); + rpt_telemetry(myrpt,REMXXX,(void *)p); + return DC_COMPLETEQUIET; + case 104: /* Low Power */ + if(!strcmp(myrpt->remote, remote_rig_ic706)) return DC_ERROR; - return DC_COMPLETE; - + myrpt->powerlevel = REM_LOWPWR; + setrem(myrpt); + rpt_telemetry(myrpt,REMXXX,(void *)p); + return DC_COMPLETEQUIET; + case 105: /* Medium Power */ + if(!strcmp(myrpt->remote, remote_rig_ic706)) + return DC_ERROR; + myrpt->powerlevel = REM_MEDPWR; + setrem(myrpt); + rpt_telemetry(myrpt,REMXXX,(void *)p); + return DC_COMPLETEQUIET; + case 106: /* Hi Power */ + if(!strcmp(myrpt->remote, remote_rig_ic706)) + return DC_ERROR; + myrpt->powerlevel = REM_HIPWR; + setrem(myrpt); + rpt_telemetry(myrpt,REMXXX,(void *)p); + return DC_COMPLETEQUIET; case 107: /* Bump down 20Hz */ multimode_bump_freq(myrpt, -20); return DC_COMPLETE; - case 108: /* Bump down 100Hz */ multimode_bump_freq(myrpt, -100); return DC_COMPLETE; - case 109: /* Bump down 500Hz */ multimode_bump_freq(myrpt, -500); return DC_COMPLETE; - case 110: /* Bump up 20Hz */ multimode_bump_freq(myrpt, 20); return DC_COMPLETE; - case 111: /* Bump up 100Hz */ multimode_bump_freq(myrpt, 100); return DC_COMPLETE; - case 112: /* Bump up 500Hz */ multimode_bump_freq(myrpt, 500); return DC_COMPLETE; - - - case 113: - case 114: - case 115: - case 116: - case 117: - case 118: - myrpt->remotetx = 0; - ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY); - if (!myrpt->remoterx) - ast_indicate(mychannel,AST_CONTROL_RADIO_KEY); - if (ast_safe_sleep(mychannel,1000) == -1) - return DC_ERROR; - - switch(myatoi(param)){ - - case 113: /* Scan down slow */ - res = sayfile(mychannel,"rpt/down"); - if(!res) - res = sayfile(mychannel, "rpt/slow"); - if(!res){ - myrpt->scantimer = REM_SCANTIME; - myrpt->hfscanmode = HF_SCAN_DOWN_SLOW; - } - break; - - case 114: /* Scan down quick */ - res = sayfile(mychannel,"rpt/down"); - if(!res) - res = sayfile(mychannel, "rpt/quick"); - if(!res){ - myrpt->scantimer = REM_SCANTIME; - myrpt->hfscanmode = HF_SCAN_DOWN_QUICK; - } - break; - - case 115: /* Scan down fast */ - res = sayfile(mychannel,"rpt/down"); - if(!res) - res = sayfile(mychannel, "rpt/fast"); - if(!res){ - myrpt->scantimer = REM_SCANTIME; - myrpt->hfscanmode = HF_SCAN_DOWN_FAST; - } - break; - - case 116: /* Scan up slow */ - res = sayfile(mychannel,"rpt/up"); - if(!res) - res = sayfile(mychannel, "rpt/slow"); - if(!res){ - myrpt->scantimer = REM_SCANTIME; - myrpt->hfscanmode = HF_SCAN_UP_SLOW; - } - break; - - case 117: /* Scan up quick */ - res = sayfile(mychannel,"rpt/up"); - if(!res) - res = sayfile(mychannel, "rpt/quick"); - if(!res){ - myrpt->scantimer = REM_SCANTIME; - myrpt->hfscanmode = HF_SCAN_UP_QUICK; - } - break; - - case 118: /* Scan up fast */ - res = sayfile(mychannel,"rpt/up"); - if(!res) - res = sayfile(mychannel, "rpt/fast"); - if(!res){ - myrpt->scantimer = REM_SCANTIME; - myrpt->hfscanmode = HF_SCAN_UP_FAST; - } - break; - } - rmt_telem_finish(myrpt,mychannel); - return DC_COMPLETE; - - + case 113: /* Scan down slow */ + myrpt->scantimer = REM_SCANTIME; + myrpt->hfscanmode = HF_SCAN_DOWN_SLOW; + rpt_telemetry(myrpt,REMXXX,(void *)p); + return DC_COMPLETEQUIET; + case 114: /* Scan down quick */ + myrpt->scantimer = REM_SCANTIME; + myrpt->hfscanmode = HF_SCAN_DOWN_QUICK; + rpt_telemetry(myrpt,REMXXX,(void *)p); + return DC_COMPLETEQUIET; + case 115: /* Scan down fast */ + myrpt->scantimer = REM_SCANTIME; + myrpt->hfscanmode = HF_SCAN_DOWN_FAST; + rpt_telemetry(myrpt,REMXXX,(void *)p); + return DC_COMPLETEQUIET; + case 116: /* Scan up slow */ + myrpt->scantimer = REM_SCANTIME; + myrpt->hfscanmode = HF_SCAN_UP_SLOW; + rpt_telemetry(myrpt,REMXXX,(void *)p); + return DC_COMPLETEQUIET; + case 117: /* Scan up quick */ + myrpt->scantimer = REM_SCANTIME; + myrpt->hfscanmode = HF_SCAN_UP_QUICK; + rpt_telemetry(myrpt,REMXXX,(void *)p); + return DC_COMPLETEQUIET; + case 118: /* Scan up fast */ + myrpt->scantimer = REM_SCANTIME; + myrpt->hfscanmode = HF_SCAN_UP_FAST; + rpt_telemetry(myrpt,REMXXX,(void *)p); + return DC_COMPLETEQUIET; case 119: /* Tune Request */ - myrpt->tunerequest = 1; - return DC_COMPLETE; - + /* if not currently going, and valid to do */ + if((!myrpt->tunerequest) && + ((!strcmp(myrpt->remote, remote_rig_ft897) || + !strcmp(myrpt->remote, remote_rig_ic706)) )) { + myrpt->remotetx = 0; + ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY); + myrpt->tunerequest = 1; + rpt_telemetry(myrpt,TUNE,NULL); + return DC_COMPLETEQUIET; + } + return DC_ERROR; case 5: /* Long Status */ + rpt_telemetry(myrpt,REMLONGSTATUS,NULL); + return DC_COMPLETEQUIET; case 140: /* Short Status */ - res = rmt_telem_start(myrpt, mychannel, 1000); - - res = sayfile(mychannel,"rpt/node"); - if(!res) - res = saycharstr(mychannel, myrpt->name); - if(!res) - res = sayfile(mychannel,"rpt/frequency"); - if(!res) - res = split_freq(mhz, decimals, myrpt->freq); - if(!res){ - m = atoi(mhz); - if(m < 100) - res = saynum(mychannel, m); - else - res = saycharstr(mychannel, mhz); - } - if(!res) - res = sayfile(mychannel, "letters/dot"); - if(!res) - res = saycharstr(mychannel, decimals); - - if(res){ - rmt_telem_finish(myrpt,mychannel); - return DC_ERROR; - } - if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */ - switch(myrpt->offset){ - - case REM_MINUS: - res = sayfile(mychannel,"rpt/minus"); - break; - - case REM_SIMPLEX: - res = sayfile(mychannel,"rpt/simplex"); - break; - - case REM_PLUS: - res = sayfile(mychannel,"rpt/plus"); - break; - - default: - return DC_ERROR; - - } - } - else{ /* Must be USB, LSB, or AM */ - switch(myrpt->remmode){ - - case REM_MODE_USB: - res = saycharstr(mychannel, "USB"); - break; - - case REM_MODE_LSB: - res = saycharstr(mychannel, "LSB"); - break; - - case REM_MODE_AM: - res = saycharstr(mychannel, "AM"); - break; - - - default: - return DC_ERROR; - } - } - - if (res == -1){ - rmt_telem_finish(myrpt,mychannel); - return DC_ERROR; - } - - if(myatoi(param) == 140){ /* Short status? */ - if(!res) - res = rmt_telem_finish(myrpt, mychannel); - if(res) - return DC_ERROR; - return DC_COMPLETE; - } - - switch(myrpt->powerlevel){ - - case REM_LOWPWR: - res = sayfile(mychannel,"rpt/lopwr") ; - break; - - case REM_MEDPWR: - res = sayfile(mychannel,"rpt/medpwr"); - break; - case REM_HIPWR: - res = sayfile(mychannel,"rpt/hipwr"); - break; - } - if (res || (sayfile(mychannel,"rpt/rxpl") == -1) || - (sayfile(mychannel,"rpt/frequency") == -1) || - (saycharstr(mychannel,myrpt->rxpl) == -1) || - (sayfile(mychannel,"rpt/txpl") == -1) || - (sayfile(mychannel,"rpt/frequency") == -1) || - (saycharstr(mychannel,myrpt->txpl) == -1) || - (sayfile(mychannel,"rpt/txpl") == -1) || - (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1) || - (sayfile(mychannel,"rpt/rxpl") == -1) || - (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1)) - { - rmt_telem_finish(myrpt,mychannel); - return DC_ERROR; - } - if(!res) - res = rmt_telem_finish(myrpt,mychannel); - if(res) - return DC_ERROR; - - return DC_COMPLETE; - default: - return DC_ERROR; + rpt_telemetry(myrpt,REMSHORTSTATUS,NULL); + return DC_COMPLETEQUIET; + case 200: + case 201: + case 202: + case 203: + case 204: + case 205: + case 206: + case 207: + case 208: + case 209: + case 210: + case 211: + case 212: + case 213: + case 214: + case 215: + do_dtmf_local(myrpt,remdtmfstr[p - 200]); + return DC_COMPLETEQUIET; + default: + break; } - return DC_INDETERMINATE; } + static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode) { time_t now; int ret,res = 0,src; + time(&myrpt->last_activity_time); /* Stop scan mode if in scan mode */ if(myrpt->hfscanmode){ - stop_scan(myrpt,0); + stop_scan(myrpt); return 0; } @@ -5634,7 +8144,16 @@ int ret,res = 0,src; if (myrpt->dtmfidx == -1) { /* if not lead-in digit, dont worry */ - if (c != myrpt->p.funcchar) return 0; + if (c != myrpt->p.funcchar) + { + if (!myrpt->p.propagate_dtmf) + { + rpt_mutex_lock(&myrpt->lock); + do_dtmf_local(myrpt,c); + rpt_mutex_unlock(&myrpt->lock); + } + return 0; + } myrpt->dtmfidx = 0; myrpt->dtmfbuf[0] = 0; myrpt->dtmf_time_rem = now; @@ -5688,13 +8207,15 @@ int ret,res = 0,src; case DC_COMPLETE: + res = 1; + case DC_COMPLETEQUIET: myrpt->totalexecdcommands++; myrpt->dailyexecdcommands++; - ast_copy_string(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF); + strncpy(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF-1); + myrpt->lastdtmfcommand[MAXDTMF-1] = '\0'; myrpt->dtmfbuf[0] = 0; myrpt->dtmfidx = -1; myrpt->dtmf_time_rem = 0; - res = 1; break; case DC_ERROR: @@ -5715,7 +8236,7 @@ char tmp[300],cmd[300],dest[300],src[300],c; int seq,res; /* put string in our buffer */ - ast_copy_string(tmp,str,sizeof(tmp)); + strncpy(tmp,str,sizeof(tmp) - 1); if (!strcmp(tmp,discstr)) return 0; if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5) { @@ -5729,19 +8250,20 @@ int seq,res; } /* if not for me, ignore */ if (strcmp(dest,myrpt->name)) return 0; + if (myrpt->p.archivedir) + { + char str[100]; + + sprintf(str,"DTMF,%c",c); + donodelog(myrpt,str); + } + c = func_xlat(myrpt,c,&myrpt->p.outxlat); + if (!c) return(0); res = handle_remote_dtmf_digit(myrpt,c, NULL, 0); if (res != 1) return res; - myrpt->remotetx = 0; - ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY); - if (!myrpt->remoterx) - { - ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_KEY); - } - if (ast_safe_sleep(myrpt->remchannel,1000) == -1) return -1; - res = telem_lookup(myrpt,myrpt->remchannel, myrpt->name, "functcomplete"); - rmt_telem_finish(myrpt,myrpt->remchannel); - return res; + rpt_telemetry(myrpt,COMPLETE,NULL); + return 0; } static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode) @@ -5755,28 +8277,26 @@ int res; return DC_INDETERMINATE; } + if (myrpt->p.archivedir) + { + char str[100]; + + sprintf(str,"DTMF(P),%c",c); + donodelog(myrpt,str); + } res = handle_remote_dtmf_digit(myrpt,c,keyed, phonemode); if (res != 1) return res; - myrpt->remotetx = 0; - ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY); - if (!myrpt->remoterx) - { - ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_KEY); - } - if (ast_safe_sleep(myrpt->remchannel,1000) == -1) return -1; - res = telem_lookup(myrpt,myrpt->remchannel, myrpt->name, "functcomplete"); - rmt_telem_finish(myrpt,myrpt->remchannel); - return res; + rpt_telemetry(myrpt,COMPLETE,NULL); + return 0; } static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l) { - const char *val; - char *s, *s1, *s2, *tele; + char *val, *s, *s1, *s2, *tele; char tmp[300], deststr[300] = ""; - val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, l->name); + val = node_lookup(myrpt,l->name); if (!val) { fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name); @@ -5787,7 +8307,7 @@ static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l) /* remove from queue */ remque((struct qelem *) l); rpt_mutex_unlock(&myrpt->lock); - ast_copy_string(tmp,val,sizeof(tmp)); + strncpy(tmp,val,sizeof(tmp) - 1); s = tmp; s1 = strsep(&s,","); s2 = strsep(&s,","); @@ -5800,6 +8320,7 @@ static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l) *tele++ = 0; l->elaptime = 0; l->connecttime = 0; + l->thisconnected = 0; l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL); if (l->chan){ ast_set_read_format(l->chan, AST_FORMAT_SLINEAR); @@ -5838,6 +8359,13 @@ int res; pthread_attr_t attr; char cmd[MAXDTMF+1] = ""; + if (myrpt->p.archivedir) + { + char str[100]; + + sprintf(str,"DTMF,MAIN,%c",c); + donodelog(myrpt,str); + } if (c == myrpt->p.endchar) { /* if in simple mode, kill autopatch */ @@ -5858,7 +8386,13 @@ char cmd[MAXDTMF+1] = ""; myrpt->dtmfbuf[0] = 0; rpt_mutex_unlock(&myrpt->lock); rpt_telemetry(myrpt,COMPLETE,NULL); - } else rpt_mutex_unlock(&myrpt->lock); + } + else + { + rpt_mutex_unlock(&myrpt->lock); + if (myrpt->p.propagate_phonedtmf) + do_dtmf_phone(myrpt,NULL,c); + } return; } rpt_mutex_lock(&myrpt->lock); @@ -5887,7 +8421,7 @@ char cmd[MAXDTMF+1] = ""; myrpt->dtmfbuf[myrpt->dtmfidx++] = c; myrpt->dtmfbuf[myrpt->dtmfidx] = 0; - ast_copy_string(cmd, myrpt->dtmfbuf, sizeof(cmd)); + strncpy(cmd, myrpt->dtmfbuf, sizeof(cmd) - 1); rpt_mutex_unlock(&myrpt->lock); res = collect_function_digits(myrpt, cmd, SOURCE_RPT, NULL); @@ -5900,9 +8434,11 @@ char cmd[MAXDTMF+1] = ""; myrpt->dtmfbuf[0] = 0; break; case DC_COMPLETE: + case DC_COMPLETEQUIET: myrpt->totalexecdcommands++; myrpt->dailyexecdcommands++; - ast_copy_string(myrpt->lastdtmfcommand, cmd, MAXDTMF); + strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1); + myrpt->lastdtmfcommand[MAXDTMF-1] = '\0'; myrpt->dtmfbuf[0] = 0; myrpt->dtmfidx = -1; myrpt->dtmf_time = 0; @@ -5931,14 +8467,13 @@ char cmd[MAXDTMF+1] = ""; myrpt->patchquiet = 0; myrpt->patchfarenddisconnect = 0; myrpt->patchdialtime = 0; - ast_copy_string(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT); + strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT); myrpt->cidx = 0; myrpt->exten[myrpt->cidx] = 0; rpt_mutex_unlock(&myrpt->lock); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt); - pthread_attr_destroy(&attr); return; } } @@ -5969,6 +8504,8 @@ char cmd[MAXDTMF+1] = ""; myrpt->mydtmf = c; } rpt_mutex_unlock(&myrpt->lock); + if ((myrpt->dtmfidx < 0) && myrpt->p.propagate_phonedtmf) + do_dtmf_phone(myrpt,NULL,c); return; } @@ -5977,19 +8514,24 @@ char cmd[MAXDTMF+1] = ""; static void queue_id(struct rpt *myrpt) { - myrpt->mustid = myrpt->tailid = 0; - myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */ - rpt_mutex_unlock(&myrpt->lock); - rpt_telemetry(myrpt,ID,NULL); - rpt_mutex_lock(&myrpt->lock); + if(myrpt->p.idtime){ /* ID time must be non-zero */ + myrpt->mustid = myrpt->tailid = 0; + myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */ + rpt_mutex_unlock(&myrpt->lock); + rpt_telemetry(myrpt,ID,NULL); + rpt_mutex_lock(&myrpt->lock); + } } /* Scheduler */ +/* must be called locked */ static void do_scheduler(struct rpt *myrpt) { - int res; + int i,res; struct tm tmnow; + struct ast_variable *skedlist; + char *strs[5],*vp,*val,value[100]; memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval)); @@ -6001,7 +8543,7 @@ static void do_scheduler(struct rpt *myrpt) if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec) return; - ast_localtime(&myrpt->curtv.tv_sec, &tmnow, NULL); + rpt_localtime(&myrpt->curtv.tv_sec, &tmnow); /* If midnight, then reset all daily statistics */ @@ -6011,6 +8553,96 @@ static void do_scheduler(struct rpt *myrpt) myrpt->dailykerchunks = 0; myrpt->dailyexecdcommands = 0; } + + if(tmnow.tm_sec != 0) + return; + + /* Code below only executes once per minute */ + + + /* Don't schedule if remote */ + + if (myrpt->remote) + return; + + /* Don't schedule if disabled */ + + if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable){ + if(debug > 6) + ast_log(LOG_NOTICE, "Scheduler disabled\n"); + return; + } + + if(!myrpt->p.skedstanzaname){ /* No stanza means we do nothing */ + if(debug > 6) + ast_log(LOG_NOTICE,"No stanza for scheduler in rpt.conf\n"); + return; + } + + /* get pointer to linked list of scheduler entries */ + skedlist = ast_variable_browse(myrpt->cfg, myrpt->p.skedstanzaname); + + if(debug > 6){ + ast_log(LOG_NOTICE, "Time now: %02d:%02d %02d %02d %02d\n", + tmnow.tm_hour,tmnow.tm_min,tmnow.tm_mday,tmnow.tm_mon + 1, tmnow.tm_wday); + } + /* walk the list */ + for(; skedlist; skedlist = skedlist->next){ + if(debug > 6) + ast_log(LOG_NOTICE, "Scheduler entry %s = %s being considered\n",skedlist->name, skedlist->value); + strncpy(value,skedlist->value,99); + value[99] = 0; + /* point to the substrings for minute, hour, dom, month, and dow */ + for( i = 0, vp = value ; i < 5; i++){ + if(!*vp) + break; + while((*vp == ' ') || (*vp == 0x09)) /* get rid of any leading white space */ + vp++; + strs[i] = vp; /* save pointer to beginning of substring */ + while((*vp != ' ') && (*vp != 0x09) && (*vp != 0)) /* skip over substring */ + vp++; + if(*vp) + *vp++ = 0; /* mark end of substring */ + } + if(debug > 6) + ast_log(LOG_NOTICE, "i = %d, min = %s, hour = %s, mday=%s, mon=%s, wday=%s\n",i, + strs[0], strs[1], strs[2], strs[3], strs[4]); + if(i == 5){ + if((*strs[0] != '*')&&(atoi(strs[0]) != tmnow.tm_min)) + continue; + if((*strs[1] != '*')&&(atoi(strs[1]) != tmnow.tm_hour)) + continue; + if((*strs[2] != '*')&&(atoi(strs[2]) != tmnow.tm_mday)) + continue; + if((*strs[3] != '*')&&(atoi(strs[3]) != tmnow.tm_mon + 1)) + continue; + if(atoi(strs[4]) == 7) + strs[4] = "0"; + if((*strs[4] != '*')&&(atoi(strs[4]) != tmnow.tm_wday)) + continue; + if(debug) + ast_log(LOG_NOTICE, "Executing scheduler entry %s = %s\n", skedlist->name, skedlist->value); + if(atoi(skedlist->name) == 0) + return; /* Zero is reserved for the startup macro */ + val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, skedlist->name); + if (!val){ + ast_log(LOG_WARNING,"Scheduler could not find macro %s\n",skedlist->name); + return; /* Macro not found */ + } + if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)){ + ast_log(LOG_WARNING, "Scheduler could not execute macro %s: Macro buffer full\n", + skedlist->name); + return; /* Macro buffer full */ + } + myrpt->macrotimer = MACROTIME; + strncat(myrpt->macrobuf,val,MAXMACRO - 1); + } + else{ + ast_log(LOG_WARNING,"Malformed scheduler entry in rpt.conf: %s = %s\n", + skedlist->name, skedlist->value); + } + } + } @@ -6018,16 +8650,20 @@ static void do_scheduler(struct rpt *myrpt) static void *rpt(void *this) { struct rpt *myrpt = (struct rpt *)this; - char *tele, c; - const char *idtalkover; -int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued,tailmessagequeued,ctqueued; +char *tele,*idtalkover,c; +int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued; +int tailmessagequeued,ctqueued,dtmfed; struct ast_channel *who; ZT_CONFINFO ci; /* conference info */ time_t t; struct rpt_link *l,*m; struct rpt_tele *telem; -char tmpstr[300]; +char tmpstr[300],lstr[MAXLINKLIST]; + + if (myrpt->p.archivedir) mkdir(myrpt->p.archivedir,0600); + sprintf(tmpstr,"%s/%s",myrpt->p.archivedir,myrpt->name); + mkdir(tmpstr,0600); rpt_mutex_lock(&myrpt->lock); telem = myrpt->tele.next; @@ -6047,7 +8683,7 @@ char tmpstr[300]; } } rpt_mutex_lock(&myrpt->lock); - ast_copy_string(tmpstr,myrpt->rxchanname,sizeof(tmpstr)); + strncpy(tmpstr,myrpt->rxchanname,sizeof(tmpstr) - 1); tele = strchr(tmpstr,'/'); if (!tele) { @@ -6094,7 +8730,7 @@ char tmpstr[300]; } if (myrpt->txchanname) { - ast_copy_string(tmpstr,myrpt->txchanname,sizeof(tmpstr)); + strncpy(tmpstr,myrpt->txchanname,sizeof(tmpstr) - 1); tele = strchr(tmpstr,'/'); if (!tele) { @@ -6162,6 +8798,20 @@ char tmpstr[300]; myrpt->rpt_thread = AST_PTHREADT_STOP; pthread_exit(NULL); } + /* allocate a pseudo-channel thru asterisk */ + myrpt->monchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL); + if (!myrpt->monchannel) + { + fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n"); + rpt_mutex_unlock(&myrpt->lock); + if (myrpt->txchannel != myrpt->rxchannel) + ast_hangup(myrpt->txchannel); + ast_hangup(myrpt->rxchannel); + myrpt->rpt_thread = AST_PTHREADT_STOP; + pthread_exit(NULL); + } + ast_set_read_format(myrpt->monchannel,AST_FORMAT_SLINEAR); + ast_set_write_format(myrpt->monchannel,AST_FORMAT_SLINEAR); /* make a conference for the tx */ ci.chan = 0; ci.confno = -1; /* make a new conf */ @@ -6172,6 +8822,7 @@ char tmpstr[300]; ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); rpt_mutex_unlock(&myrpt->lock); ast_hangup(myrpt->pchannel); + ast_hangup(myrpt->monchannel); if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel); ast_hangup(myrpt->rxchannel); @@ -6182,23 +8833,61 @@ char tmpstr[300]; myrpt->txconf = ci.confno; /* make a conference for the pseudo */ ci.chan = 0; - ci.confno = -1; /* make a new conf */ - ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON : - (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER); + ci.confno = -1; /* make a new 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"); + rpt_mutex_unlock(&myrpt->lock); + ast_hangup(myrpt->pchannel); + ast_hangup(myrpt->monchannel); + if (myrpt->txchannel != myrpt->rxchannel) + ast_hangup(myrpt->txchannel); + ast_hangup(myrpt->rxchannel); + myrpt->rpt_thread = AST_PTHREADT_STOP; + pthread_exit(NULL); + } + /* save pseudo channel conference number */ + myrpt->conf = ci.confno; + /* make a conference for the pseudo */ + ci.chan = 0; + if (strstr(myrpt->txchannel->name,"pseudo") == NULL) + { + /* get tx channel's port number */ + if (ioctl(myrpt->txchannel->fds[0],ZT_CHANNO,&ci.confno) == -1) + { + ast_log(LOG_WARNING, "Unable to set tx channel's chan number\n"); + rpt_mutex_unlock(&myrpt->lock); + ast_hangup(myrpt->pchannel); + ast_hangup(myrpt->monchannel); + if (myrpt->txchannel != myrpt->rxchannel) + ast_hangup(myrpt->txchannel); + ast_hangup(myrpt->rxchannel); + myrpt->rpt_thread = AST_PTHREADT_STOP; + pthread_exit(NULL); + } + ci.confmode = ZT_CONF_MONITORTX; + } + else + { + ci.confno = myrpt->txconf; + ci.confmode = ZT_CONF_CONFANNMON; + } /* first put the channel on the conference in announce mode */ - if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1) + if (ioctl(myrpt->monchannel->fds[0],ZT_SETCONF,&ci) == -1) { - ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); + ast_log(LOG_WARNING, "Unable to set conference mode for monitor\n"); rpt_mutex_unlock(&myrpt->lock); ast_hangup(myrpt->pchannel); + ast_hangup(myrpt->monchannel); if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel); ast_hangup(myrpt->rxchannel); myrpt->rpt_thread = AST_PTHREADT_STOP; pthread_exit(NULL); } - /* save pseudo channel conference number */ - myrpt->conf = ci.confno; /* allocate a pseudo-channel thru asterisk */ myrpt->txpchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL); if (!myrpt->txpchannel) @@ -6206,6 +8895,7 @@ char tmpstr[300]; fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n"); rpt_mutex_unlock(&myrpt->lock); ast_hangup(myrpt->pchannel); + ast_hangup(myrpt->monchannel); if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel); ast_hangup(myrpt->rxchannel); @@ -6222,7 +8912,7 @@ char tmpstr[300]; ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); rpt_mutex_unlock(&myrpt->lock); ast_hangup(myrpt->txpchannel); - ast_hangup(myrpt->pchannel); + ast_hangup(myrpt->monchannel); if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel); ast_hangup(myrpt->rxchannel); @@ -6243,18 +8933,18 @@ char tmpstr[300]; myrpt->tounkeyed = 0; myrpt->tonotify = 0; myrpt->retxtimer = 0; + myrpt->rerxtimer = 0; myrpt->skedtimer = 0; myrpt->tailevent = 0; lasttx = 0; myrpt->keyed = 0; - idtalkover = ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover"); + idtalkover = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover"); myrpt->dtmfidx = -1; myrpt->dtmfbuf[0] = 0; myrpt->rem_dtmfidx = -1; myrpt->rem_dtmfbuf[0] = 0; myrpt->dtmf_time = 0; myrpt->rem_dtmf_time = 0; - myrpt->enable = 1; myrpt->disgorgetime = 0; myrpt->lastnodewhichkeyedusup[0] = '\0'; myrpt->dailytxtime = 0; @@ -6273,15 +8963,17 @@ char tmpstr[300]; snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro); } rpt_mutex_unlock(&myrpt->lock); - val = 0; - ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0); val = 1; ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0); + val = 1; + ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0); + if (myrpt->p.archivedir) donodelog(myrpt,"STARTUP"); + dtmfed = 0; while (ms >= 0) { - struct ast_frame *f; - struct ast_channel *cs[300]; - int totx=0,elap=0,n,toexit=0; + struct ast_frame *f,*f1,*f2; + struct ast_channel *cs[300],*cs1[300]; + int totx=0,elap=0,n,x,toexit=0; /* DEBUG Dump */ if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){ @@ -6299,7 +8991,6 @@ char tmpstr[300]; ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed); ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx); ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode); - ast_log(LOG_NOTICE,"myrpt->enable = %d\n",myrpt->enable); ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid); ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed); ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify); @@ -6366,10 +9057,11 @@ char tmpstr[300]; if (ast_check_hangup(myrpt->rxchannel)) break; if (ast_check_hangup(myrpt->txchannel)) break; if (ast_check_hangup(myrpt->pchannel)) break; + if (ast_check_hangup(myrpt->monchannel)) break; if (ast_check_hangup(myrpt->txpchannel)) break; - /* Update local tx with keyed if not parsing a command */ - myrpt->localtx = myrpt->keyed && (myrpt->dtmfidx == -1) && (!myrpt->cmdnode[0]); + /* Set local tx with keyed */ + myrpt->localtx = myrpt->keyed; /* If someone's connected, and they're transmitting from their end to us, set remrx true */ l = myrpt->links.next; remrx = 0; @@ -6383,11 +9075,15 @@ char tmpstr[300]; l = l->next; } /* Create a "must_id" flag for the cleanup ID */ - myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ; + if(myrpt->p.idtime) /* ID time must be non-zero */ + myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ; /* Build a fresh totx from myrpt->keyed and autopatch activated */ totx = myrpt->callmode; /* If full duplex, add local tx to totx */ - if (myrpt->p.duplex > 1) totx = totx || myrpt->localtx; + if (myrpt->p.duplex > 1) + { + totx = totx || myrpt->localtx; + } /* Traverse the telemetry list to see what's queued */ identqueued = 0; othertelemqueued = 0; @@ -6405,7 +9101,7 @@ char tmpstr[300]; } else { - if (telem->mode != UNKEY) + if ((telem->mode != UNKEY) && (telem->mode != LINKUNKEY)) othertelemqueued = 1; /* Other telemetry */ else ctqueued = 1; /* Courtesy tone telemetry */ @@ -6413,10 +9109,11 @@ char tmpstr[300]; telem = telem->next; } - /* Add in any "other" telemetry, if 3/4 or full duplex */ - if (myrpt->p.duplex > 0) totx = totx || othertelemqueued; + /* Add in any "other" telemetry, unless specified otherwise */ + if (!myrpt->p.notelemtx) totx = totx || othertelemqueued; /* Update external (to links) transmitter PTT state with everything but ID, CT, and tailmessage telemetry */ myrpt->exttx = totx; + totx = totx || myrpt->dtmf_local_timer; /* If half or 3/4 duplex, add localtx to external link tx */ if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx; /* Add in ID telemetry to local transmitter */ @@ -6424,6 +9121,12 @@ char tmpstr[300]; /* If 3/4 or full duplex, add in ident and CT telemetry */ if (myrpt->p.duplex > 0) totx = totx || identqueued || ctqueued; + /* If full duplex, add local dtmf stuff active */ + if (myrpt->p.duplex > 1) + { + totx = totx || (myrpt->dtmfidx > -1) || + myrpt->cmdnode[0]; + } /* Reset time out timer variables if there is no activity */ if (!totx) { @@ -6431,8 +9134,11 @@ char tmpstr[300]; myrpt->tounkeyed = 0; myrpt->tonotify = 0; } - else - myrpt->tailtimer = myrpt->p.hangtime; /* Initialize tail timer */ + else{ + myrpt->tailtimer = myrpt->p.s[myrpt->p.sysstate_cur].alternatetail ? + myrpt->p.althangtime : /* Initialize tail timer */ + myrpt->p.hangtime; + } /* Disable the local transmitter if we are timed out */ totx = totx && myrpt->totimer; /* if timed-out and not said already, say it */ @@ -6496,8 +9202,8 @@ char tmpstr[300]; if(myrpt->mustid && (!myrpt->idtimer)) queue_id(myrpt); - if ((totx && (!myrpt->exttx) && - (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) + if ((myrpt->p.idtime && totx && (!myrpt->exttx) && + (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) /* ID time must be non-zero */ { myrpt->tailid = 1; } @@ -6526,6 +9232,28 @@ char tmpstr[300]; if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele); if (totx && (!lasttx)) { + char mydate[100],myfname[100]; + time_t myt; + + if (myrpt->monstream) ast_closestream(myrpt->monstream); + if (myrpt->p.archivedir) + { + long blocksleft; + + time(&myt); + strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S", + localtime(&myt)); + sprintf(myfname,"%s/%s/%s",myrpt->p.archivedir, + myrpt->name,mydate); + myrpt->monstream = ast_writefile(myfname,"wav49", + "app_rpt Air Archive",O_CREAT | O_APPEND,0,0600); + if (myrpt->p.monminblocks) + { + blocksleft = diskavail(myrpt); + if (blocksleft >= myrpt->p.monminblocks) + donodelog(myrpt,"TXKEY,MAIN"); + } else donodelog(myrpt,"TXKEY,MAIN"); + } lasttx = 1; myrpt->dailykeyups++; myrpt->totalkeyups++; @@ -6533,13 +9261,17 @@ char tmpstr[300]; ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY); rpt_mutex_lock(&myrpt->lock); } - totx = totx && myrpt->enable; + totx = totx && !myrpt->p.s[myrpt->p.sysstate_cur].txdisable; if ((!totx) && lasttx) { + if (myrpt->monstream) ast_closestream(myrpt->monstream); + myrpt->monstream = NULL; + lasttx = 0; rpt_mutex_unlock(&myrpt->lock); ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY); rpt_mutex_lock(&myrpt->lock); + donodelog(myrpt,"TXUNKEY,MAIN"); } time(&t); /* if DTMF timeout */ @@ -6581,6 +9313,7 @@ char tmpstr[300]; n = 0; cs[n++] = myrpt->rxchannel; cs[n++] = myrpt->pchannel; + cs[n++] = myrpt->monchannel; cs[n++] = myrpt->txpchannel; if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel; l = myrpt->links.next; @@ -6595,21 +9328,76 @@ char tmpstr[300]; } rpt_mutex_unlock(&myrpt->lock); ms = MSWAIT; - who = ast_waitfor_n(cs,n,&ms); + for(x = 0; x < n; x++) + { + int s = -(-x - myrpt->scram - 1) % n; + cs1[x] = cs[s]; + } + myrpt->scram++; + who = ast_waitfor_n(cs1,n,&ms); if (who == NULL) ms = 0; elap = MSWAIT - ms; rpt_mutex_lock(&myrpt->lock); l = myrpt->links.next; while(l != &myrpt->links) { - if (!l->lasttx) + if (l->linklisttimer) + { + l->linklisttimer -= elap; + if (l->linklisttimer < 0) l->linklisttimer = 0; + } + if ((!l->linklisttimer) && (l->name[0] != '0') && (!l->isremote)) + { + struct ast_frame lf; + + memset(&lf,0,sizeof(lf)); + lf.frametype = AST_FRAME_TEXT; + lf.subclass = 0; + lf.offset = 0; + lf.mallocd = 0; + lf.samples = 0; + l->linklisttimer = LINKLISTTIME; + strcpy(lstr,"L "); + __mklinklist(myrpt,l,lstr + 2); + if (l->chan) + { + lf.datalen = strlen(lstr) + 1; + lf.data = lstr; + ast_write(l->chan,&lf); + if (debug > 6) ast_log(LOG_NOTICE, + "@@@@ node %s sent node string %s to node %s\n", + myrpt->name,lstr,l->name); + } + } +#ifndef OLDKEY + if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME) + { + l->retxtimer = 0; + if (l->chan && l->phonemode == 0) + { + if (l->lasttx) + ast_indicate(l->chan,AST_CONTROL_RADIO_KEY); + else + ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY); + } + } + if ((l->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 5)) { - if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME) + if (debug == 7) printf("@@@@ rx un-key\n"); + l->lastrx = 0; + l->rerxtimer = 0; + if(myrpt->p.duplex) + rpt_telemetry(myrpt,LINKUNKEY,l); + if (myrpt->p.archivedir) { - l->retxtimer = 0; - if (l->chan) ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY); + char str[100]; + + l->lastrx1 = 0; + sprintf(str,"RXUNKEY(T),%s",l->name); + donodelog(myrpt,str); } - } else l->retxtimer = 0; + } +#endif if (l->disctime) /* Disconnect timer active on a channel ? */ { l->disctime -= elap; @@ -6644,26 +9432,28 @@ char tmpstr[300]; break; } if ((!l->chan) && (!l->retrytimer) && l->outbound && - (l->retries++ < MAX_RETRIES) && (l->hasconnected)) + (l->retries++ < l->max_retries) && (l->hasconnected)) { if (l->chan) ast_hangup(l->chan); + l->chan = 0; rpt_mutex_unlock(&myrpt->lock); if ((l->name[0] != '0') && (!l->isremote)) - { - l->retrytimer = MAX_RETRIES + 1; - } - else { if (attempt_reconnect(myrpt,l) == -1) { l->retrytimer = RETRY_TIMER_MS; - } + } + } + else + { + l->retrytimer = l->max_retries + 1; } + rpt_mutex_lock(&myrpt->lock); break; } if ((!l->chan) && (!l->retrytimer) && l->outbound && - (l->retries >= MAX_RETRIES)) + (l->retries >= l->max_retries)) { /* remove from queue */ remque((struct qelem *) l); @@ -6676,6 +9466,16 @@ char tmpstr[300]; rpt_telemetry(myrpt,CONNFAIL,l); else rpt_telemetry(myrpt,REMDISC,l); } + if (myrpt->p.archivedir) + { + char str[100]; + + if (!l->hasconnected) + sprintf(str,"LINKFAIL,%s",l->name); + else + sprintf(str,"LINKDISC,%s",l->name); + donodelog(myrpt,str); + } /* hang-up on call to device */ ast_hangup(l->pchan); free(l); @@ -6693,6 +9493,13 @@ char tmpstr[300]; { rpt_telemetry(myrpt,REMDISC,l); } + if (myrpt->p.archivedir) + { + char str[100]; + + sprintf(str,"LINKDISC,%s",l->name); + donodelog(myrpt,str); + } /* hang-up on call to device */ ast_hangup(l->pchan); free(l); @@ -6710,7 +9517,7 @@ char tmpstr[300]; if (myrpt->tailtimer < 0) myrpt->tailtimer = 0; if((i) && (myrpt->tailtimer == 0)) myrpt->tailevent = 1; - if (myrpt->totimer) myrpt->totimer -= elap; + if ((!myrpt->p.s[myrpt->p.sysstate_cur].totdisable) && myrpt->totimer) myrpt->totimer -= elap; if (myrpt->totimer < 0) myrpt->totimer = 0; if (myrpt->idtimer) myrpt->idtimer -= elap; if (myrpt->idtimer < 0) myrpt->idtimer = 0; @@ -6719,6 +9526,13 @@ char tmpstr[300]; /* do macro timers */ if (myrpt->macrotimer) myrpt->macrotimer -= elap; if (myrpt->macrotimer < 0) myrpt->macrotimer = 0; + /* do local dtmf timer */ + if (myrpt->dtmf_local_timer) + { + if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap; + if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1; + } + do_dtmf_local(myrpt,0); /* Execute scheduler appx. every 2 tenths of a second */ if (myrpt->skedtimer <= 0){ myrpt->skedtimer = 200; @@ -6732,17 +9546,28 @@ char tmpstr[300]; continue; } c = myrpt->macrobuf[0]; - if (c && (!myrpt->macrotimer)) + time(&t); + if (c && (!myrpt->macrotimer) && + starttime && (t > (starttime + START_DELAY))) { myrpt->macrotimer = MACROTIME; memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1); if ((c == 'p') || (c == 'P')) myrpt->macrotimer = MACROPTIME; rpt_mutex_unlock(&myrpt->lock); + if (myrpt->p.archivedir) + { + char str[100]; + + sprintf(str,"DTMF(M),MAIN,%c",c); + donodelog(myrpt,str); + } local_dtmf_helper(myrpt,c); } else rpt_mutex_unlock(&myrpt->lock); if (who == myrpt->rxchannel) /* if it was a read from rx */ { + int ismuted; + f = ast_read(myrpt->rxchannel); if (!f) { @@ -6757,7 +9582,7 @@ char tmpstr[300]; int n; #endif - if (!myrpt->localtx) { + if ((!myrpt->localtx) && (!myrpt->p.linktolink)) { memset(f->data,0,f->datalen); } @@ -6804,14 +9629,60 @@ char tmpstr[300]; /* apply inbound filters, if any */ rpt_filter(myrpt,f->data,f->datalen / 2); #endif - ast_write(myrpt->pchannel,f); + if (ioctl(myrpt->rxchannel->fds[0], ZT_GETCONFMUTE, &ismuted) == -1) + { + ismuted = 0; + } + if (dtmfed) ismuted = 1; + dtmfed = 0; + if (ismuted) + { + memset(f->data,0,f->datalen); + if (myrpt->lastf1) + memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen); + if (myrpt->lastf2) + memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen); + } + if (f) f2 = ast_frdup(f); + else f2 = NULL; + f1 = myrpt->lastf2; + myrpt->lastf2 = myrpt->lastf1; + myrpt->lastf1 = f2; + if (ismuted) + { + if (myrpt->lastf1) + memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen); + if (myrpt->lastf2) + memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen); + } + if (f1) + { + ast_write(myrpt->pchannel,f1); + ast_frfree(f1); + } } +#ifndef OLD_ASTERISK + else if (f->frametype == AST_FRAME_DTMF_BEGIN) + { + if (myrpt->lastf1) + memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen); + if (myrpt->lastf2) + memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen); + dtmfed = 1; + } +#endif else if (f->frametype == AST_FRAME_DTMF) { c = (char) f->subclass; /* get DTMF char */ ast_frfree(f); + if (myrpt->lastf1) + memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen); + if (myrpt->lastf2) + memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen); + dtmfed = 1; if (!myrpt->keyed) continue; - local_dtmf_helper(myrpt,c); + c = func_xlat(myrpt,c,&myrpt->p.inxlat); + if (c) local_dtmf_helper(myrpt,c); continue; } else if (f->frametype == AST_FRAME_CONTROL) @@ -6825,22 +9696,30 @@ char tmpstr[300]; /* if RX key */ if (f->subclass == AST_CONTROL_RADIO_KEY) { - if ((!lasttx) || (myrpt->p.duplex > 1)) + if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink)) { if (debug == 7) printf("@@@@ rx key\n"); myrpt->keyed = 1; } + if (myrpt->p.archivedir) + { + donodelog(myrpt,"RXKEY,MAIN"); + } } /* if RX un-key */ if (f->subclass == AST_CONTROL_RADIO_UNKEY) { - if ((!lasttx) || (myrpt->p.duplex > 1)) + if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink)) { if (debug == 7) printf("@@@@ rx un-key\n"); - if(myrpt->keyed) { + if(myrpt->p.duplex && myrpt->keyed) { rpt_telemetry(myrpt,UNKEY,NULL); } - myrpt->keyed = 0; + } + myrpt->keyed = 0; + if (myrpt->p.archivedir) + { + donodelog(myrpt,"RXUNKEY,MAIN"); } } } @@ -6903,6 +9782,8 @@ char tmpstr[300]; } if (who == l->chan) /* if it was a read from rx */ { + int remnomute; + remrx = 0; /* see if any other links are receiving */ m = myrpt->links.next; @@ -6913,9 +9794,12 @@ char tmpstr[300]; m = m->next; } rpt_mutex_unlock(&myrpt->lock); - totx = (((l->isremote) ? myrpt->localtx : + remnomute = myrpt->localtx && + (!(myrpt->cmdnode[0] || + (myrpt->dtmfidx > -1))); + totx = (((l->isremote) ? (remnomute) : myrpt->exttx) || remrx) && l->mode; - if (l->chan && (l->lasttx != totx)) + if (l->phonemode == 0 && l->chan && (l->lasttx != totx)) { if (totx) { @@ -6925,11 +9809,24 @@ char tmpstr[300]; { ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY); } + if (myrpt->p.archivedir) + { + char str[100]; + + if (totx) + sprintf(str,"TXKEY,%s",l->name); + else + sprintf(str,"TXUNKEY,%s",l->name); + donodelog(myrpt,str); + } } l->lasttx = totx; f = ast_read(l->chan); if (!f) { + rpt_mutex_lock(&myrpt->lock); + __kickshort(myrpt); + rpt_mutex_unlock(&myrpt->lock); if ((!l->disced) && (!l->outbound)) { if ((l->name[0] == '0') || l->isremote) @@ -6944,20 +9841,21 @@ char tmpstr[300]; if (l->retrytimer) { + ast_hangup(l->chan); + l->chan = 0; rpt_mutex_lock(&myrpt->lock); break; } - if (l->outbound && (l->retries++ < MAX_RETRIES) && (l->hasconnected)) + if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected)) { rpt_mutex_lock(&myrpt->lock); - ast_hangup(l->chan); + if (l->chan) ast_hangup(l->chan); l->chan = 0; - rpt_mutex_unlock(&myrpt->lock); - if (attempt_reconnect(myrpt,l) == -1) - { - l->retrytimer = RETRY_TIMER_MS; - } - rpt_mutex_lock(&myrpt->lock); + l->hasconnected = 1; + l->retrytimer = RETRY_TIMER_MS; + l->elaptime = 0; + l->connecttime = 0; + l->thisconnected = 0; break; } rpt_mutex_lock(&myrpt->lock); @@ -6965,10 +9863,25 @@ char tmpstr[300]; remque((struct qelem *) l); if (!strcmp(myrpt->cmdnode,l->name)) myrpt->cmdnode[0] = 0; + __kickshort(myrpt); rpt_mutex_unlock(&myrpt->lock); if (!l->hasconnected) rpt_telemetry(myrpt,CONNFAIL,l); else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l); + if (myrpt->p.archivedir) + { + char str[100]; + + if (!l->hasconnected) + sprintf(str,"LINKFAIL,%s",l->name); + else + sprintf(str,"LINKDISC,%s",l->name); + donodelog(myrpt,str); + } + if (l->lastf1) ast_frfree(l->lastf1); + l->lastf1 = NULL; + if (l->lastf2) ast_frfree(l->lastf2); + l->lastf2 = NULL; /* hang-up on call to device */ ast_hangup(l->chan); ast_hangup(l->pchan); @@ -6978,18 +9891,73 @@ char tmpstr[300]; } if (f->frametype == AST_FRAME_VOICE) { - if (!l->lastrx) + int ismuted; + + if (l->phonemode) + { + if (ioctl(l->chan->fds[0], ZT_GETCONFMUTE, &ismuted) == -1) + { + ismuted = 0; + } + /* if not receiving, zero-out audio */ + ismuted |= (!l->lastrx); + if (l->dtmfed && l->phonemode) ismuted = 1; + l->dtmfed = 0; + if (ismuted) + { + memset(f->data,0,f->datalen); + if (l->lastf1) + memset(l->lastf1->data,0,l->lastf1->datalen); + if (l->lastf2) + memset(l->lastf2->data,0,l->lastf2->datalen); + } + if (f) f2 = ast_frdup(f); + else f2 = NULL; + f1 = l->lastf2; + l->lastf2 = l->lastf1; + l->lastf1 = f2; + if (ismuted) + { + if (l->lastf1) + memset(l->lastf1->data,0,l->lastf1->datalen); + if (l->lastf2) + memset(l->lastf2->data,0,l->lastf2->datalen); + } + if (f1) + { + ast_write(l->pchan,f1); + ast_frfree(f1); + } + } + else { - memset(f->data,0,f->datalen); + if (!l->lastrx) + memset(f->data,0,f->datalen); + ast_write(l->pchan,f); } - ast_write(l->pchan,f); } +#ifndef OLD_ASTERISK + else if (f->frametype == AST_FRAME_DTMF_BEGIN) + { + if (l->lastf1) + memset(l->lastf1->data,0,l->lastf1->datalen); + if (l->lastf2) + memset(l->lastf2->data,0,l->lastf2->datalen); + l->dtmfed = 1; + } +#endif + if (f->frametype == AST_FRAME_TEXT) { handle_link_data(myrpt,l,f->data); } if (f->frametype == AST_FRAME_DTMF) { + if (l->lastf1) + memset(l->lastf1->data,0,l->lastf1->datalen); + if (l->lastf2) + memset(l->lastf2->data,0,l->lastf2->datalen); + l->dtmfed = 1; handle_link_phone_dtmf(myrpt,l,f->subclass); } if (f->frametype == AST_FRAME_CONTROL) @@ -6997,12 +9965,27 @@ char tmpstr[300]; if (f->subclass == AST_CONTROL_ANSWER) { char lconnected = l->connected; + + __kickshort(myrpt); l->connected = 1; l->hasconnected = 1; + l->thisconnected = 1; l->elaptime = -1; - l->retries = 0; + if (!l->isremote) l->retries = 0; if (!lconnected) + { rpt_telemetry(myrpt,CONNECTED,l); + if (myrpt->p.archivedir) + { + char str[100]; + + if (l->mode) + sprintf(str,"LINKTRX,%s",l->name); + else + sprintf(str,"LINKMONITOR,%s",l->name); + donodelog(myrpt,str); + } + } else l->reconnects++; } @@ -7011,16 +9994,39 @@ char tmpstr[300]; { if (debug == 7 ) printf("@@@@ rx key\n"); l->lastrx = 1; + l->rerxtimer = 0; + if (myrpt->p.archivedir && (!l->lastrx1)) + { + char str[100]; + + l->lastrx1 = 1; + sprintf(str,"RXKEY,%s",l->name); + donodelog(myrpt,str); + } } /* if RX un-key */ if (f->subclass == AST_CONTROL_RADIO_UNKEY) { if (debug == 7) printf("@@@@ rx un-key\n"); l->lastrx = 0; + l->rerxtimer = 0; + if(myrpt->p.duplex) + rpt_telemetry(myrpt,LINKUNKEY,l); + if (myrpt->p.archivedir && (l->lastrx1)) + { + char str[100]; + + l->lastrx1 = 0; + sprintf(str,"RXUNKEY,%s",l->name); + donodelog(myrpt,str); + } } if (f->subclass == AST_CONTROL_HANGUP) { ast_frfree(f); + rpt_mutex_lock(&myrpt->lock); + __kickshort(myrpt); + rpt_mutex_unlock(&myrpt->lock); if ((!l->outbound) && (!l->disced)) { if ((l->name[0] == '0') || l->isremote) @@ -7034,20 +10040,21 @@ char tmpstr[300]; } if (l->retrytimer) { + if (l->chan) ast_hangup(l->chan); + l->chan = 0; rpt_mutex_lock(&myrpt->lock); break; } - if (l->outbound && (l->retries++ < MAX_RETRIES) && (l->hasconnected)) + if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected)) { rpt_mutex_lock(&myrpt->lock); - ast_hangup(l->chan); + if (l->chan) ast_hangup(l->chan); l->chan = 0; - rpt_mutex_unlock(&myrpt->lock); - if (attempt_reconnect(myrpt,l) == -1) - { - l->retrytimer = RETRY_TIMER_MS; - } - rpt_mutex_lock(&myrpt->lock); + l->hasconnected = 1; + l->elaptime = 0; + l->retrytimer = RETRY_TIMER_MS; + l->connecttime = 0; + l->thisconnected = 0; break; } rpt_mutex_lock(&myrpt->lock); @@ -7055,10 +10062,25 @@ char tmpstr[300]; remque((struct qelem *) l); if (!strcmp(myrpt->cmdnode,l->name)) myrpt->cmdnode[0] = 0; + __kickshort(myrpt); rpt_mutex_unlock(&myrpt->lock); if (!l->hasconnected) rpt_telemetry(myrpt,CONNFAIL,l); else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l); + if (myrpt->p.archivedir) + { + char str[100]; + + if (!l->hasconnected) + sprintf(str,"LINKFAIL,%s",l->name); + else + sprintf(str,"LINKDISC,%s",l->name); + donodelog(myrpt,str); + } + if (l->lastf1) ast_frfree(l->lastf1); + l->lastf1 = NULL; + if (l->lastf2) ast_frfree(l->lastf2); + l->lastf2 = NULL; /* hang-up on call to device */ ast_hangup(l->chan); ast_hangup(l->pchan); @@ -7105,6 +10127,31 @@ char tmpstr[300]; } rpt_mutex_unlock(&myrpt->lock); if (toexit) break; + if (who == myrpt->monchannel) + { + f = ast_read(myrpt->monchannel); + if (!f) + { + if (debug) printf("@@@@ rpt:Hung Up\n"); + break; + } + if (f->frametype == AST_FRAME_VOICE) + { + if (myrpt->monstream) + ast_writestream(myrpt->monstream,f); + } + if (f->frametype == AST_FRAME_CONTROL) + { + if (f->subclass == AST_CONTROL_HANGUP) + { + if (debug) printf("@@@@ rpt:Hung Up\n"); + ast_frfree(f); + break; + } + } + ast_frfree(f); + continue; + } if (who == myrpt->txpchannel) /* if it was a read from remote tx */ { f = ast_read(myrpt->txpchannel); @@ -7128,8 +10175,13 @@ char tmpstr[300]; } usleep(100000); ast_hangup(myrpt->pchannel); + ast_hangup(myrpt->monchannel); ast_hangup(myrpt->txpchannel); if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel); + if (myrpt->lastf1) ast_frfree(myrpt->lastf1); + myrpt->lastf1 = NULL; + if (myrpt->lastf2) ast_frfree(myrpt->lastf2); + myrpt->lastf2 = NULL; ast_hangup(myrpt->rxchannel); rpt_mutex_lock(&myrpt->lock); l = myrpt->links.next; @@ -7152,18 +10204,19 @@ char tmpstr[300]; } -static void *rpt_master(void *config) +static void *rpt_master(void *ignore) { int i,n; pthread_attr_t attr; struct ast_config *cfg; - char *this; - const char *val; +char *this,*val; + /* init nodelog queue */ + nodelog.next = nodelog.prev = &nodelog; /* go thru all the specified repeaters */ this = NULL; n = 0; - rpt_vars[n].cfg = config; + rpt_vars[n].cfg = ast_config_load("rpt.conf"); cfg = rpt_vars[n].cfg; if (!cfg) { ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n"); @@ -7178,13 +10231,14 @@ struct ast_config *cfg; if(i != strlen(this)) continue; /* Not a node defn */ memset(&rpt_vars[n],0,sizeof(rpt_vars[n])); rpt_vars[n].name = strdup(this); - val = ast_variable_retrieve(cfg,this,"rxchannel"); + val = (char *) ast_variable_retrieve(cfg,this,"rxchannel"); if (val) rpt_vars[n].rxchanname = strdup(val); - val = ast_variable_retrieve(cfg,this,"txchannel"); + val = (char *) ast_variable_retrieve(cfg,this,"txchannel"); if (val) rpt_vars[n].txchanname = strdup(val); - val = ast_variable_retrieve(cfg,this,"remote"); + val = (char *) ast_variable_retrieve(cfg,this,"remote"); if (val) rpt_vars[n].remote = strdup(val); ast_mutex_init(&rpt_vars[n].lock); + ast_mutex_init(&rpt_vars[n].remlock); rpt_vars[n].tele.next = &rpt_vars[n].tele; rpt_vars[n].tele.prev = &rpt_vars[n].tele; rpt_vars[n].rpt_thread = AST_PTHREADT_NULL; @@ -7205,12 +10259,15 @@ struct ast_config *cfg; /* if is a remote, dont start one for it */ if (rpt_vars[i].remote) { - strcpy(rpt_vars[i].freq, "146.580"); - strcpy(rpt_vars[i].rxpl, "100.0"); - strcpy(rpt_vars[i].txpl, "100.0"); - rpt_vars[i].remmode = REM_MODE_FM; - rpt_vars[i].offset = REM_SIMPLEX; - rpt_vars[i].powerlevel = REM_MEDPWR; + if(retreive_memory(&rpt_vars[i],"init")){ /* Try to retreive initial memory channel */ + strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1); + strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1); + + strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1); + rpt_vars[i].remmode = REM_MODE_FM; + rpt_vars[i].offset = REM_SIMPLEX; + rpt_vars[i].powerlevel = REM_MEDPWR; + } continue; } if (!rpt_vars[i].p.ident) @@ -7222,9 +10279,9 @@ struct ast_config *cfg; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]); - pthread_attr_destroy(&attr); } usleep(500000); + time(&starttime); for(;;) { /* Now monitor each thread, and restart it if necessary */ @@ -7258,11 +10315,53 @@ struct ast_config *cfg; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]); - pthread_attr_destroy(&attr); ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name); } } + for(;;) + { + struct nodelog *nodep; + char *space,datestr[100],fname[300]; + int fd; + + ast_mutex_lock(&nodeloglock); + nodep = nodelog.next; + if(nodep == &nodelog) /* if nothing in queue */ + { + ast_mutex_unlock(&nodeloglock); + break; + } + remque((struct qelem *)nodep); + ast_mutex_unlock(&nodeloglock); + space = strchr(nodep->str,' '); + if (!space) + { + free(nodep); + continue; + } + *space = 0; + strftime(datestr,sizeof(datestr) - 1,"%Y%m%d", + localtime(&nodep->timestamp)); + sprintf(fname,"%s/%s/%s.txt",nodep->archivedir, + nodep->str,datestr); + fd = open(fname,O_WRONLY | O_CREAT | O_APPEND,0600); + if (fd == -1) + { + ast_log(LOG_ERROR,"Cannot open node log file %s for write",space + 1); + free(nodep); + continue; + } + if (write(fd,space + 1,strlen(space + 1)) != + strlen(space + 1)) + { + ast_log(LOG_ERROR,"Cannot write node log file %s for write",space + 1); + free(nodep); + continue; + } + close(fd); + free(nodep); + } usleep(2000000); } ast_config_destroy(cfg); @@ -7271,24 +10370,41 @@ struct ast_config *cfg; static int rpt_exec(struct ast_channel *chan, void *data) { - int res=-1,i,rem_totx,n,phone_mode = 0; - struct ast_module_user *u; - char tmp[256], keyed = 0; + int res=-1,i,rem_totx,rem_rx,remkeyed,n,phone_mode = 0; + int iskenwood_pci4,authtold,authreq,setting,notremming,reming; + int ismuted,dtmfed; +#ifdef OLD_ASTERISK + struct localuser *u; +#endif + char tmp[256], keyed = 0,keyed1 = 0; char *options,*stringp,*tele,c; struct rpt *myrpt; - struct ast_frame *f; + struct ast_frame *f,*f1,*f2; struct ast_channel *who; struct ast_channel *cs[20]; struct rpt_link *l; ZT_CONFINFO ci; /* conference info */ ZT_PARAMS par; - int ms,elap; + int ms,elap,nullfd; + time_t t,last_timeout_warning; + struct zt_radio_param z; + struct rpt_tele *telem; + nullfd = open("/dev/null",O_RDWR); if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n"); return -1; } - ast_copy_string(tmp, (char *)data, sizeof(tmp)); + strncpy(tmp, (char *)data, sizeof(tmp)-1); + time(&t); + /* if time has externally shifted negative, screw it */ + if (t < starttime) t = starttime + START_DELAY; + if ((!starttime) || (t < (starttime + START_DELAY))) + { + ast_log(LOG_NOTICE,"Node %s rejecting call: too soon!\n",tmp); + ast_safe_sleep(chan,3000); + return -1; + } stringp=tmp; strsep(&stringp, "|"); options = stringp; @@ -7308,13 +10424,22 @@ static int rpt_exec(struct ast_channel *chan, void *data) ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp); return -1; } + + if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable){ /* Do not allow incoming connections if disabled */ + ast_log(LOG_NOTICE, "Connect attempt to node %s with tx disabled", myrpt->name); + return -1; + } /* if not phone access, must be an IAX connection */ if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R'))) { + int val; + phone_mode = 1; if (*options == 'D') phone_mode = 2; ast_set_callerid(chan,"0","app_rpt user","0"); + val = 1; + ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0); } else { @@ -7361,7 +10486,7 @@ static int rpt_exec(struct ast_channel *chan, void *data) return -1; } s=orig_s; - ast_copy_string(s,options,l); + strncpy(s,options,l); template=strsep(&s,"|"); if(!template) { @@ -7409,9 +10534,9 @@ static int rpt_exec(struct ast_channel *chan, void *data) #else if(exten) #endif - ast_copy_string(chan->exten, exten, sizeof(chan->exten)); + strncpy(chan->exten, exten, sizeof(chan->exten)-1); if(context) - ast_copy_string(chan->context, context, sizeof(chan->context)); + strncpy(chan->context, context, sizeof(chan->context)-1); } else { /* increment the priority by default*/ chan->priority++; } @@ -7445,9 +10570,7 @@ static int rpt_exec(struct ast_channel *chan, void *data) struct ast_hostent ahp; struct hostent *hp; struct in_addr ia; - char hisip[100],nodeip[100]; - const char *val; - char *s, *s1, *s2, *b,*b1; + char hisip[100],nodeip[100],*val, *s, *s1, *s2, *b,*b1; /* look at callerid to see what node this comes from */ if (!chan->cid.cid_num) /* if doesn't have caller id */ @@ -7481,13 +10604,13 @@ static int rpt_exec(struct ast_channel *chan, void *data) /* look for his reported node string */ - val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, b1); + val = node_lookup(myrpt,b1); if (!val) { ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1); return -1; } - ast_copy_string(tmp,val,sizeof(tmp)); + strncpy(tmp,val,sizeof(tmp) - 1); s = tmp; s1 = strsep(&s,","); s2 = strsep(&s,","); @@ -7504,7 +10627,11 @@ static int rpt_exec(struct ast_channel *chan, void *data) return -1; } memcpy(&ia,hp->h_addr,sizeof(in_addr_t)); - ast_copy_string(nodeip, ast_inet_ntoa(ia), sizeof(nodeip)); +#ifdef OLD_ASTERISK + ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia); +#else + strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1); +#endif if (strcmp(hisip,nodeip)) { char *s3 = strchr(s1,'@'); @@ -7518,7 +10645,11 @@ static int rpt_exec(struct ast_channel *chan, void *data) return -1; } memcpy(&ia,hp->h_addr,sizeof(in_addr_t)); - ast_copy_string(nodeip, ast_inet_ntoa(ia), sizeof(nodeip)); +#ifdef OLD_ASTERISK + ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia); +#else + strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1); +#endif if (strcmp(hisip,nodeip)) { ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip); @@ -7567,7 +10698,7 @@ static int rpt_exec(struct ast_channel *chan, void *data) if (l != &myrpt->links) { l->killme = 1; - l->retries = MAX_RETRIES + 1; + l->retries = l->max_retries + 1; l->disced = 2; reconnects = l->reconnects; reconnects++; @@ -7585,13 +10716,17 @@ static int rpt_exec(struct ast_channel *chan, void *data) /* zero the silly thing */ memset((char *)l,0,sizeof(struct rpt_link)); l->mode = 1; - ast_copy_string(l->name,b1,MAXNODESTR); + strncpy(l->name,b1,MAXNODESTR - 1); l->isremote = 0; l->chan = chan; l->connected = 1; + l->thisconnected = 1; l->hasconnected = 1; l->reconnects = reconnects; l->phonemode = phone_mode; + l->lastf1 = NULL; + l->lastf2 = NULL; + l->dtmfed = 0; ast_set_read_format(l->chan,AST_FORMAT_SLINEAR); ast_set_write_format(l->chan,AST_FORMAT_SLINEAR); /* allocate a pseudo-channel thru asterisk */ @@ -7615,14 +10750,27 @@ static int rpt_exec(struct ast_channel *chan, void *data) } rpt_mutex_lock(&myrpt->lock); if (phone_mode > 1) l->lastrx = 1; + l->max_retries = MAX_RETRIES; /* insert at end of queue */ insque((struct qelem *)l,(struct qelem *)myrpt->links.next); + __kickshort(myrpt); rpt_mutex_unlock(&myrpt->lock); if (chan->_state != AST_STATE_UP) { ast_answer(chan); } + if (myrpt->p.archivedir) + { + char str[100]; + + if (l->phonemode) + sprintf(str,"LINK(P),%s",l->name); + else + sprintf(str,"LINK,%s",l->name); + donodelog(myrpt,str); + } return AST_PBX_KEEPALIVE; } + /* well, then it is a remote */ rpt_mutex_lock(&myrpt->lock); /* if remote, error if anyone else already linked */ if (myrpt->remoteon) @@ -7636,14 +10784,17 @@ static int rpt_exec(struct ast_channel *chan, void *data) } rpt_mutex_lock(&myrpt->lock); } - myrpt->remoteon = 1; - if (ioperm(myrpt->p.iobase,1,1) == -1) + if ((!strcmp(myrpt->remote, remote_rig_rbi)) && + (ioperm(myrpt->p.iobase,1,1) == -1)) { rpt_mutex_unlock(&myrpt->lock); ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase); return -1; } - u = ast_module_user_add(chan); + myrpt->remoteon = 1; +#ifdef OLD_ASTERISK + LOCAL_USER_ADD(u); +#endif rpt_mutex_unlock(&myrpt->lock); /* find our index, and load the vars initially */ for(i = 0; i < nrpts; i++) @@ -7713,20 +10864,117 @@ static int rpt_exec(struct ast_channel *chan, void *data) } else { - fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n"); - rpt_mutex_unlock(&myrpt->lock); - ast_hangup(myrpt->rxchannel); - pthread_exit(NULL); + fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n"); + rpt_mutex_unlock(&myrpt->lock); + ast_hangup(myrpt->rxchannel); + pthread_exit(NULL); + } + *--tele = '/'; + } + else + { + myrpt->txchannel = myrpt->rxchannel; + } + /* allocate a pseudo-channel thru asterisk */ + myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL); + if (!myrpt->pchannel) + { + fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n"); + rpt_mutex_unlock(&myrpt->lock); + if (myrpt->txchannel != myrpt->rxchannel) + ast_hangup(myrpt->txchannel); + ast_hangup(myrpt->rxchannel); + pthread_exit(NULL); + } + ast_set_read_format(myrpt->pchannel,AST_FORMAT_SLINEAR); + ast_set_write_format(myrpt->pchannel,AST_FORMAT_SLINEAR); + /* make a conference for the pseudo */ + ci.chan = 0; + ci.confno = -1; /* make a new conf */ + ci.confmode = ZT_CONF_CONFANNMON ; + /* first put the channel on the conference in announce/monitor mode */ + if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1) + { + ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n"); + rpt_mutex_unlock(&myrpt->lock); + ast_hangup(myrpt->pchannel); + if (myrpt->txchannel != myrpt->rxchannel) + ast_hangup(myrpt->txchannel); + ast_hangup(myrpt->rxchannel); + pthread_exit(NULL); + } + /* if serial io port, open it */ + myrpt->iofd = -1; + if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt->p.ioport)) == -1)) + { + rpt_mutex_unlock(&myrpt->lock); + ast_hangup(myrpt->pchannel); + if (myrpt->txchannel != myrpt->rxchannel) + ast_hangup(myrpt->txchannel); + ast_hangup(myrpt->rxchannel); + pthread_exit(NULL); + } + iskenwood_pci4 = 0; + memset(&z,0,sizeof(z)); + if (myrpt->iofd < 1) + { + z.radpar = ZT_RADPAR_REMMODE; + z.data = ZT_RADPAR_REM_NONE; + res = ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z); + /* if PCIRADIO and kenwood selected */ + if ((!res) && (!strcmp(myrpt->remote,remote_rig_kenwood))) + { + z.radpar = ZT_RADPAR_UIOMODE; + z.data = 1; + if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1) + { + ast_log(LOG_ERROR,"Cannot set UIOMODE\n"); + return -1; + } + z.radpar = ZT_RADPAR_UIODATA; + z.data = 3; + if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1) + { + ast_log(LOG_ERROR,"Cannot set UIODATA\n"); + return -1; + } + i = ZT_OFFHOOK; + if (ioctl(myrpt->txchannel->fds[0],ZT_HOOK,&i) == -1) + { + ast_log(LOG_ERROR,"Cannot set hook\n"); + return -1; + } + iskenwood_pci4 = 1; } - *--tele = '/'; } - else + i = ZT_ONHOOK; + ioctl(myrpt->txchannel->fds[0],ZT_HOOK,&i); + /* if PCIRADIO and Yaesu ft897/ICOM IC-706 selected */ + if ((myrpt->iofd < 1) && (!res) && + (!strcmp(myrpt->remote,remote_rig_ft897) || + (!strcmp(myrpt->remote,remote_rig_ic706)))) { - myrpt->txchannel = myrpt->rxchannel; + z.radpar = ZT_RADPAR_UIOMODE; + z.data = 1; + if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1) + { + ast_log(LOG_ERROR,"Cannot set UIOMODE\n"); + return -1; + } + z.radpar = ZT_RADPAR_UIODATA; + z.data = 3; + if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1) + { + ast_log(LOG_ERROR,"Cannot set UIODATA\n"); + return -1; + } } + /* save pseudo channel conference number */ + myrpt->conf = myrpt->txconf = ci.confno; myrpt->remoterx = 0; myrpt->remotetx = 0; myrpt->retxtimer = 0; + myrpt->rerxtimer = 0; myrpt->remoteon = 1; myrpt->dtmfidx = -1; myrpt->dtmfbuf[0] = 0; @@ -7735,14 +10983,19 @@ static int rpt_exec(struct ast_channel *chan, void *data) myrpt->hfscanstatus = 0; if (myrpt->p.startupmacro) { - myrpt->remchannel = chan; /* Save copy of channel */ snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro); } + time(&myrpt->start_time); + myrpt->last_activity_time = myrpt->start_time; + last_timeout_warning = 0; myrpt->reload = 0; + myrpt->tele.next = &myrpt->tele; + myrpt->tele.prev = &myrpt->tele; rpt_mutex_unlock(&myrpt->lock); - setrem(myrpt); ast_set_write_format(chan, AST_FORMAT_SLINEAR); ast_set_read_format(chan, AST_FORMAT_SLINEAR); + rem_rx = 0; + remkeyed = 0; /* if we are on 2w loop and are a remote, turn EC on */ if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel)) { @@ -7753,27 +11006,88 @@ static int rpt_exec(struct ast_channel *chan, void *data) ast_answer(chan); } - if (ioctl(myrpt->txchannel->fds[0],ZT_GET_PARAMS,&par) != -1) + if (ioctl(myrpt->rxchannel->fds[0],ZT_GET_PARAMS,&par) != -1) { if (par.rxisoffhook) { ast_indicate(chan,AST_CONTROL_RADIO_KEY); myrpt->remoterx = 1; + remkeyed = 1; } } + if (myrpt->p.archivedir) + { + char mycmd[100],mydate[100],*b,*b1; + time_t myt; + long blocksleft; + + + mkdir(myrpt->p.archivedir,0600); + sprintf(mycmd,"%s/%s",myrpt->p.archivedir,myrpt->name); + mkdir(mycmd,0600); + time(&myt); + strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S", + localtime(&myt)); + sprintf(mycmd,"mixmonitor start %s %s/%s/%s.wav49 a",chan->name, + myrpt->p.archivedir,myrpt->name,mydate); + if (myrpt->p.monminblocks) + { + blocksleft = diskavail(myrpt); + if (myrpt->p.remotetimeout) + { + blocksleft -= (myrpt->p.remotetimeout * + MONITOR_DISK_BLOCKS_PER_MINUTE) / 60; + } + if (blocksleft >= myrpt->p.monminblocks) + ast_cli_command(nullfd,mycmd); + } else ast_cli_command(nullfd,mycmd); + /* look at callerid to see what node this comes from */ + if (!chan->cid.cid_num) /* if doesn't have caller id */ + { + b1 = "0"; + } else { + ast_callerid_parse(chan->cid.cid_num,&b,&b1); + ast_shrink_phone_number(b1); + } + sprintf(mycmd,"CONNECT,%s",b1); + donodelog(myrpt,mycmd); + } + myrpt->loginuser[0] = 0; + myrpt->loginlevel[0] = 0; + myrpt->authtelltimer = 0; + myrpt->authtimer = 0; + authtold = 0; + authreq = 0; + if (myrpt->p.authlevel > 1) authreq = 1; + setrem(myrpt); n = 0; + dtmfed = 0; cs[n++] = chan; cs[n++] = myrpt->rxchannel; + cs[n++] = myrpt->pchannel; if (myrpt->rxchannel != myrpt->txchannel) cs[n++] = myrpt->txchannel; + /* start un-locked */ for(;;) { if (ast_check_hangup(chan)) break; if (ast_check_hangup(myrpt->rxchannel)) break; + notremming = 0; + setting = 0; + reming = 0; + telem = myrpt->tele.next; + while(telem != &myrpt->tele) + { + if (telem->mode == SETREMOTE) setting = 1; + if ((telem->mode == SETREMOTE) || + (telem->mode == SCAN) || + (telem->mode == TUNE)) reming = 1; + else notremming = 1; + telem = telem->next; + } if (myrpt->reload) { myrpt->reload = 0; - rpt_mutex_unlock(&myrpt->lock); /* find our index, and load the vars */ for(i = 0; i < nrpts; i++) { @@ -7783,7 +11097,83 @@ static int rpt_exec(struct ast_channel *chan, void *data) break; } } - rpt_mutex_lock(&myrpt->lock); + } + time(&t); + if (myrpt->p.remotetimeout) + { + time_t r; + + r = (t - myrpt->start_time); + if (r >= myrpt->p.remotetimeout) + { + sayfile(chan,"rpt/node"); + ast_say_character_str(chan,myrpt->name,NULL,chan->language); + sayfile(chan,"rpt/timeout"); + ast_safe_sleep(chan,1000); + break; + } + if ((myrpt->p.remotetimeoutwarning) && + (r >= (myrpt->p.remotetimeout - + myrpt->p.remotetimeoutwarning)) && + (r <= (myrpt->p.remotetimeout - + myrpt->p.remotetimeoutwarningfreq))) + { + if (myrpt->p.remotetimeoutwarningfreq) + { + if ((t - last_timeout_warning) >= + myrpt->p.remotetimeoutwarningfreq) + { + time(&last_timeout_warning); + rpt_telemetry(myrpt,TIMEOUT_WARNING,0); + } + } + else + { + if (!last_timeout_warning) + { + time(&last_timeout_warning); + rpt_telemetry(myrpt,TIMEOUT_WARNING,0); + } + } + } + } + if (myrpt->p.remoteinacttimeout && myrpt->last_activity_time) + { + time_t r; + + r = (t - myrpt->last_activity_time); + if (r >= myrpt->p.remoteinacttimeout) + { + sayfile(chan,"rpt/node"); + ast_say_character_str(chan,myrpt->name,NULL,chan->language); + sayfile(chan,"rpt/timeout"); + ast_safe_sleep(chan,1000); + break; + } + if ((myrpt->p.remotetimeoutwarning) && + (r >= (myrpt->p.remoteinacttimeout - + myrpt->p.remotetimeoutwarning)) && + (r <= (myrpt->p.remoteinacttimeout - + myrpt->p.remotetimeoutwarningfreq))) + { + if (myrpt->p.remotetimeoutwarningfreq) + { + if ((t - last_timeout_warning) >= + myrpt->p.remotetimeoutwarningfreq) + { + time(&last_timeout_warning); + rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0); + } + } + else + { + if (!last_timeout_warning) + { + time(&last_timeout_warning); + rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0); + } + } + } } ms = MSWAIT; who = ast_waitfor_n(cs,n,&ms); @@ -7791,53 +11181,161 @@ static int rpt_exec(struct ast_channel *chan, void *data) elap = MSWAIT - ms; if (myrpt->macrotimer) myrpt->macrotimer -= elap; if (myrpt->macrotimer < 0) myrpt->macrotimer = 0; - rpt_mutex_unlock(&myrpt->lock); if (!ms) continue; - rem_totx = keyed; - - - if ((!myrpt->remoterx) && (!myrpt->remotetx)) + /* do local dtmf timer */ + if (myrpt->dtmf_local_timer) + { + if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap; + if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1; + } + rpt_mutex_lock(&myrpt->lock); + do_dtmf_local(myrpt,0); + rpt_mutex_unlock(&myrpt->lock); + rem_totx = myrpt->dtmf_local_timer && (!phone_mode); + rem_totx |= keyed && (!myrpt->tunerequest); + rem_rx = (remkeyed && (!setting)) || (myrpt->tele.next != &myrpt->tele); + if(!strcmp(myrpt->remote, remote_rig_ic706)) + rem_totx |= myrpt->tunerequest; + if (keyed && (!keyed1)) + { + keyed1 = 1; + } + + if (!keyed && (keyed1)) { - if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME) + time_t myt; + + keyed1 = 0; + time(&myt); + /* if login necessary, and not too soon */ + if ((myrpt->p.authlevel) && + (!myrpt->loginlevel[0]) && + (myt > (t + 3))) { - myrpt->retxtimer = 0; - ast_indicate(chan,AST_CONTROL_RADIO_UNKEY); + authreq = 1; + authtold = 0; + myrpt->authtelltimer = AUTHTELLTIME - AUTHTXTIME; } - } else myrpt->retxtimer = 0; - if (rem_totx && (!myrpt->remotetx)) /* Remote base radio TX key */ + } + + + if (rem_rx && (!myrpt->remoterx)) { - myrpt->remotetx = 1; - ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY); + myrpt->remoterx = 1; + ast_indicate(chan,AST_CONTROL_RADIO_KEY); } - if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */ + if ((!rem_rx) && (myrpt->remoterx)) { - myrpt->remotetx = 0; - ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY); + myrpt->remoterx = 0; + ast_indicate(chan,AST_CONTROL_RADIO_UNKEY); + } + /* if auth requested, and not authed yet */ + if (authreq && (!myrpt->loginlevel[0])) + { + if ((!authtold) && ((myrpt->authtelltimer += elap) + >= AUTHTELLTIME)) + { + authtold = 1; + rpt_telemetry(myrpt,LOGINREQ,NULL); + } + if ((myrpt->authtimer += elap) >= AUTHLOGOUTTIME) + { + break; /* if not logged in, hang up after a time */ + } + } +#ifndef OLDKEY + if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME) + { + myrpt->retxtimer = 0; + if ((myrpt->remoterx) && (!myrpt->remotetx)) + ast_indicate(chan,AST_CONTROL_RADIO_KEY); + else + ast_indicate(chan,AST_CONTROL_RADIO_UNKEY); } - if(myrpt->tunerequest && (!strcmp(myrpt->remote, remote_rig_ft897))){ /* ft-897 specific for now... */ - myrpt->tunerequest = 0; - set_mode_ft897(myrpt, REM_MODE_AM); - simple_command_ft897(myrpt, 8); + if ((myrpt->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 2)) + { + keyed = 0; + myrpt->rerxtimer = 0; + } +#endif + if (rem_totx && (!myrpt->remotetx)) + { + /* if not authed, and needed, dont transmit */ + if ((!myrpt->p.authlevel) || myrpt->loginlevel[0]) + { + myrpt->remotetx = 1; + if((myrpt->remtxfreqok = check_tx_freq(myrpt))) + { + time(&myrpt->last_activity_time); + if (iskenwood_pci4) + { + z.radpar = ZT_RADPAR_UIODATA; + z.data = 1; + if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1) + { + ast_log(LOG_ERROR,"Cannot set UIODATA\n"); + return -1; + } + } + else + { + ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY); + } + if (myrpt->p.archivedir) donodelog(myrpt,"TXKEY"); + } + } + } + if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */ + { myrpt->remotetx = 0; - ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY); - if (!myrpt->remoterx) - ast_indicate(chan, AST_CONTROL_RADIO_KEY); - if(play_tone(chan, 800, 6000, 8192) == -1) - break; - - rmt_telem_finish(myrpt,chan); - set_mode_ft897(myrpt, 0x88); - setrem(myrpt); + if(!myrpt->remtxfreqok){ + rpt_telemetry(myrpt,UNAUTHTX,NULL); + } + if (iskenwood_pci4) + { + z.radpar = ZT_RADPAR_UIODATA; + z.data = 3; + if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1) + { + ast_log(LOG_ERROR,"Cannot set UIODATA\n"); + return -1; + } + } + else + { + ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY); + } + if (myrpt->p.archivedir) donodelog(myrpt,"TXUNKEY"); } - if (myrpt->hfscanmode){ myrpt->scantimer -= elap; if(myrpt->scantimer <= 0){ - myrpt->scantimer = REM_SCANTIME; - service_scan(myrpt); + if (!reming) + { + myrpt->scantimer = REM_SCANTIME; + rpt_telemetry(myrpt,SCAN,0); + } else myrpt->scantimer = 1; } } + rpt_mutex_lock(&myrpt->lock); + c = myrpt->macrobuf[0]; + if (c && (!myrpt->macrotimer)) + { + myrpt->macrotimer = MACROTIME; + memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1); + if ((c == 'p') || (c == 'P')) + myrpt->macrotimer = MACROPTIME; + rpt_mutex_unlock(&myrpt->lock); + if (myrpt->p.archivedir) + { + char str[100]; + sprintf(str,"DTMF(M),%c",c); + donodelog(myrpt,str); + } + if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break; + continue; + } else rpt_mutex_unlock(&myrpt->lock); if (who == chan) /* if it was a read from incomming */ { f = ast_read(chan); @@ -7848,14 +11346,60 @@ static int rpt_exec(struct ast_channel *chan, void *data) } if (f->frametype == AST_FRAME_VOICE) { + if (ioctl(chan->fds[0], ZT_GETCONFMUTE, &ismuted) == -1) + { + ismuted = 0; + } /* if not transmitting, zero-out audio */ - if (!myrpt->remotetx) + ismuted |= (!myrpt->remotetx); + if (dtmfed && phone_mode) ismuted = 1; + dtmfed = 0; + if (ismuted) + { memset(f->data,0,f->datalen); - ast_write(myrpt->txchannel,f); + if (myrpt->lastf1) + memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen); + if (myrpt->lastf2) + memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen); + } + if (f) f2 = ast_frdup(f); + else f2 = NULL; + f1 = myrpt->lastf2; + myrpt->lastf2 = myrpt->lastf1; + myrpt->lastf1 = f2; + if (ismuted) + { + if (myrpt->lastf1) + memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen); + if (myrpt->lastf2) + memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen); + } + if (f1) + { + if (phone_mode) + ast_write(myrpt->txchannel,f1); + else + ast_write(myrpt->txchannel,f); + ast_frfree(f1); + } + } +#ifndef OLD_ASTERISK + else if (f->frametype == AST_FRAME_DTMF_BEGIN) + { + if (myrpt->lastf1) + memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen); + if (myrpt->lastf2) + memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen); + dtmfed = 1; } +#endif if (f->frametype == AST_FRAME_DTMF) { - myrpt->remchannel = chan; /* Save copy of channel */ + if (myrpt->lastf1) + memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen); + if (myrpt->lastf2) + memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen); + dtmfed = 1; if (handle_remote_phone_dtmf(myrpt,f->subclass,&keyed,phone_mode) == -1) { if (debug) printf("@@@@ rpt:Hung Up\n"); @@ -7865,7 +11409,6 @@ static int rpt_exec(struct ast_channel *chan, void *data) } if (f->frametype == AST_FRAME_TEXT) { - myrpt->remchannel = chan; /* Save copy of channel */ if (handle_remote_data(myrpt,f->data) == -1) { if (debug) printf("@@@@ rpt:Hung Up\n"); @@ -7886,49 +11429,17 @@ static int rpt_exec(struct ast_channel *chan, void *data) { if (debug == 7) printf("@@@@ rx key\n"); keyed = 1; + myrpt->rerxtimer = 0; } /* if RX un-key */ if (f->subclass == AST_CONTROL_RADIO_UNKEY) { + myrpt->rerxtimer = 0; if (debug == 7) printf("@@@@ rx un-key\n"); keyed = 0; } } - if (myrpt->hfscanstatus){ - myrpt->remchannel = chan; /* Save copy of channel */ - myrpt->remotetx = 0; - ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY); - if (!myrpt->remoterx) - { - ast_indicate(myrpt->remchannel,AST_CONTROL_RADIO_KEY); - } - if(myrpt->hfscanstatus < 0) { - if (myrpt->hfscanstatus == -1) { - if (ast_safe_sleep(myrpt->remchannel,1000) == -1) break; - } - sayfile(myrpt->remchannel, "rpt/stop"); - } - else - { - saynum(myrpt->remchannel, myrpt->hfscanstatus ); - } - rmt_telem_finish(myrpt,myrpt->remchannel); - myrpt->hfscanstatus = 0; - } ast_frfree(f); - rpt_mutex_lock(&myrpt->lock); - c = myrpt->macrobuf[0]; - if (c && (!myrpt->macrotimer)) - { - myrpt->macrotimer = MACROTIME; - memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1); - if ((c == 'p') || (c == 'P')) - myrpt->macrotimer = MACROPTIME; - rpt_mutex_unlock(&myrpt->lock); - if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break; - continue; - } - rpt_mutex_unlock(&myrpt->lock); continue; } if (who == myrpt->rxchannel) /* if it was a read from radio */ @@ -7941,9 +11452,17 @@ static int rpt_exec(struct ast_channel *chan, void *data) } if (f->frametype == AST_FRAME_VOICE) { - if ((myrpt->remote) && (myrpt->remotetx)) - memset(f->data,0,f->datalen); - ast_write(chan,f); + int myreming = 0; + + if(!strcmp(myrpt->remote, remote_rig_kenwood)) + myreming = reming; + + if (myreming || (!remkeyed) || + ((myrpt->remote) && (myrpt->remotetx)) || + ((myrpt->remmode != REM_MODE_FM) && + notremming)) + memset(f->data,0,f->datalen); + ast_write(myrpt->pchannel,f); } else if (f->frametype == AST_FRAME_CONTROL) { @@ -7959,8 +11478,7 @@ static int rpt_exec(struct ast_channel *chan, void *data) if (debug == 7) printf("@@@@ remote rx key\n"); if (!myrpt->remotetx) { - ast_indicate(chan,AST_CONTROL_RADIO_KEY); - myrpt->remoterx = 1; + remkeyed = 1; } } /* if RX un-key */ @@ -7969,14 +11487,37 @@ static int rpt_exec(struct ast_channel *chan, void *data) if (debug == 7) printf("@@@@ remote rx un-key\n"); if (!myrpt->remotetx) { - ast_indicate(chan,AST_CONTROL_RADIO_UNKEY); - myrpt->remoterx = 0; + remkeyed = 0; } } } ast_frfree(f); continue; } + if (who == myrpt->pchannel) /* if is remote mix output */ + { + f = ast_read(myrpt->pchannel); + if (!f) + { + if (debug) printf("@@@@ link:Hung Up\n"); + break; + } + if (f->frametype == AST_FRAME_VOICE) + { + ast_write(chan,f); + } + if (f->frametype == AST_FRAME_CONTROL) + { + if (f->subclass == AST_CONTROL_HANGUP) + { + if (debug) printf("@@@@ rpt:Hung Up\n"); + ast_frfree(f); + break; + } + } + ast_frfree(f); + continue; + } if ((myrpt->rxchannel != myrpt->txchannel) && (who == myrpt->txchannel)) /* do this cuz you have to */ { @@ -7998,62 +11539,160 @@ static int rpt_exec(struct ast_channel *chan, void *data) ast_frfree(f); continue; } - } + if (myrpt->p.archivedir) + { + char mycmd[100],*b,*b1; + + /* look at callerid to see what node this comes from */ + if (!chan->cid.cid_num) /* if doesn't have caller id */ + { + b1 = "0"; + } else { + ast_callerid_parse(chan->cid.cid_num,&b,&b1); + ast_shrink_phone_number(b1); + } + sprintf(mycmd,"DISCONNECT,%s",b1); + donodelog(myrpt,mycmd); + } + /* wait for telem to be done */ + while(myrpt->tele.next != &myrpt->tele) usleep(100000); + sprintf(tmp,"mixmonitor stop %s",chan->name); + ast_cli_command(nullfd,tmp); + close(nullfd); rpt_mutex_lock(&myrpt->lock); - if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel); - ast_hangup(myrpt->rxchannel); myrpt->hfscanmode = 0; myrpt->hfscanstatus = 0; myrpt->remoteon = 0; rpt_mutex_unlock(&myrpt->lock); + if (myrpt->lastf1) ast_frfree(myrpt->lastf1); + myrpt->lastf1 = NULL; + if (myrpt->lastf2) ast_frfree(myrpt->lastf2); + myrpt->lastf2 = NULL; + if (iskenwood_pci4) + { + z.radpar = ZT_RADPAR_UIOMODE; + z.data = 3; + if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1) + { + ast_log(LOG_ERROR,"Cannot set UIOMODE\n"); + return -1; + } + z.radpar = ZT_RADPAR_UIODATA; + z.data = 3; + if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1) + { + ast_log(LOG_ERROR,"Cannot set UIODATA\n"); + return -1; + } + i = ZT_OFFHOOK; + if (ioctl(myrpt->txchannel->fds[0],ZT_HOOK,&i) == -1) + { + ast_log(LOG_ERROR,"Cannot set hook\n"); + return -1; + } + } + if (myrpt->iofd) close(myrpt->iofd); + myrpt->iofd = -1; + ast_hangup(myrpt->pchannel); + if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel); + ast_hangup(myrpt->rxchannel); closerem(myrpt); - ast_module_user_remove(u); +#ifdef OLD_ASTERISK + LOCAL_USER_REMOVE(u); +#endif return res; } +#ifdef OLD_ASTERISK +int unload_module() +#else static int unload_module(void) +#endif { int i; - ast_module_user_hangup_all(); +#ifdef OLD_ASTERISK + STANDARD_HANGUP_LOCALUSERS; +#endif for(i = 0; i < nrpts; i++) { if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue; ast_mutex_destroy(&rpt_vars[i].lock); + ast_mutex_destroy(&rpt_vars[i].remlock); } i = ast_unregister_application(app); /* Unregister cli extensions */ - ast_cli_unregister_multiple(cli_rpt, sizeof(cli_rpt) / sizeof(struct ast_cli_entry)); + ast_cli_unregister(&cli_debug); + ast_cli_unregister(&cli_dump); + ast_cli_unregister(&cli_stats); + ast_cli_unregister(&cli_lstats); + ast_cli_unregister(&cli_nodes); + ast_cli_unregister(&cli_reload); + ast_cli_unregister(&cli_restart); + ast_cli_unregister(&cli_fun); return i; } +#ifdef OLD_ASTERISK +int load_module() +#else static int load_module(void) +#endif { - struct ast_config *cfg = ast_config_load("rpt.conf"); - if (!cfg) { - ast_log(LOG_WARNING, "No such configuration file rpt.conf\n"); - return AST_MODULE_LOAD_DECLINE; - } - ast_pthread_create(&rpt_master_thread,NULL,rpt_master,cfg); + ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL); /* Register cli extensions */ - ast_cli_register_multiple(cli_rpt, sizeof(cli_rpt) / sizeof(struct ast_cli_entry)); + ast_cli_register(&cli_debug); + ast_cli_register(&cli_dump); + ast_cli_register(&cli_stats); + ast_cli_register(&cli_lstats); + ast_cli_register(&cli_nodes); + ast_cli_register(&cli_reload); + ast_cli_register(&cli_restart); + ast_cli_register(&cli_fun); return ast_register_application(app, rpt_exec, synopsis, descrip); } +#ifdef OLD_ASTERISK +char *description() +{ + return tdesc; +} +int usecount(void) +{ + int res; + STANDARD_USECOUNT(res); + return res; +} + +char *key() +{ + return ASTERISK_GPL_KEY; +} +#endif + +#ifdef OLD_ASTERISK +int reload() +#else static int reload(void) +#endif { - int n; +int n; for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1; return(0); } -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater / Remote Base", +#ifndef OLD_ASTERISK +/* STD_MOD(MOD_1, reload, NULL, NULL); */ +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application", .load = load_module, .unload = unload_module, .reload = reload, ); + +#endif +