Thu Oct 11 06:41:59 2012

Asterisk developer's documentation


app_rpt.c

Go to the documentation of this file.
00001 /* #define OLD_ASTERISK */
00002 #define  OLDKEY
00003 /*
00004  * Asterisk -- An open source telephony toolkit.
00005  *
00006  * Copyright (C) 2002-2007, Jim Dixon, WB6NIL
00007  *
00008  * Jim Dixon, WB6NIL <jim@lambdatel.com>
00009  * Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
00010  *
00011  * See http://www.asterisk.org for more information about
00012  * the Asterisk project. Please do not directly contact
00013  * any of the maintainers of this project for assistance;
00014  * the project provides a web site, mailing lists and IRC
00015  * channels for your use.
00016  *
00017  * This program is free software, distributed under the terms of
00018  * the GNU General Public License Version 2. See the LICENSE file
00019  * at the top of the source tree.
00020  */
00021 /*! \file
00022  *
00023  * \brief Radio Repeater / Remote Base program 
00024  *  version 0.73 09/04/07
00025  * 
00026  * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
00027  *
00028  * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
00029  * 
00030  * See http://www.zapatatelephony.org/app_rpt.html
00031  *
00032  *
00033  * Repeater / Remote Functions:
00034  * "Simple" Mode:  * - autopatch access, # - autopatch hangup
00035  * Normal mode:
00036  * See the function list in rpt.conf (autopatchup, autopatchdn)
00037  * autopatchup can optionally take comma delimited setting=value pairs:
00038  *  
00039  *
00040  * context=string    :  Override default context with "string"
00041  * dialtime=ms       :  Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
00042  * farenddisconnect=1      :  Automatically disconnect when called party hangs up
00043  * noct=1         :  Don't send repeater courtesy tone during autopatch calls
00044  * quiet=1        :  Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
00045  *
00046  *
00047  * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
00048  *
00049  *  To send an asterisk (*) while dialing or talking on phone,
00050  *  use the autopatch acess code.
00051  *
00052  *
00053  * status cmds:
00054  *
00055  *  1 - Force ID
00056  *  2 - Give Time of Day
00057  *  3 - Give software Version
00058  *
00059  * cop (control operator) cmds:
00060  *
00061  *  1 - System warm boot
00062  *  2 - System enable
00063  *  3 - System disable
00064  *  4 - Test Tone On/Off
00065  *  5 - Dump System Variables on Console (debug)
00066  *  6 - PTT (phone mode only)
00067  *  7 - Time out timer enable
00068  *  8 - Time out timer disable
00069  *  9 - Autopatch enable
00070  *  10 - Autopatch disable
00071  *  11 - Link enable
00072  *  12 - Link disable
00073  *  13 - Query System State
00074  *  14 - Change System State
00075  *  15 - Scheduler Enable
00076  *  16 - Scheduler Disable
00077  *  17 - User functions (time, id, etc) enable
00078  *  18 - User functions (time, id, etc) disable
00079  *  19 - Select alternate hang timer
00080  *  20 - Select standard hang timer 
00081  *
00082  * ilink cmds:
00083  *
00084  *  1 - Disconnect specified link
00085  *  2 - Connect specified link -- monitor only
00086  *  3 - Connect specified link -- tranceive
00087  *  4 - Enter command mode on specified link
00088  *  5 - System status
00089  *  6 - Disconnect all links
00090  *  11 - Disconnect a previously permanently connected link
00091  *  12 - Permanently connect specified link -- monitor only
00092  *  13 - Permanently connect specified link -- tranceive
00093  *  15 - Full system status (all nodes)
00094  *  16 - Reconnect links disconnected with "disconnect all links"
00095  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
00096  *
00097  * remote cmds:
00098  *
00099  *  1 - Recall Memory MM  (*000-*099) (Gets memory from rpt.conf)
00100  *  2 - Set VFO MMMMM*KKK*O   (Mhz digits, Khz digits, Offset)
00101  *  3 - Set Rx PL Tone HHH*D*
00102  *  4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
00103  *  5 - Link Status (long)
00104  *  6 - Set operating mode M (FM, USB, LSB, AM, etc)
00105  *  100 - RX PL off (Default)
00106  *  101 - RX PL On
00107  *  102 - TX PL Off (Default)
00108  *  103 - TX PL On
00109  *  104 - Low Power
00110  *  105 - Med Power
00111  *  106 - Hi Power
00112  *  107 - Bump Down 20 Hz
00113  *  108 - Bump Down 100 Hz
00114  *  109 - Bump Down 500 Hz
00115  *  110 - Bump Up 20 Hz
00116  *  111 - Bump Up 100 Hz
00117  *  112 - Bump Up 500 Hz
00118  *  113 - Scan Down Slow
00119  *  114 - Scan Down Medium
00120  *  115 - Scan Down Fast
00121  *  116 - Scan Up Slow
00122  *  117 - Scan Up Medium
00123  *  118 - Scan Up Fast
00124  *  119 - Transmit allowing auto-tune
00125  *  140 - Link Status (brief)
00126  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
00127  *
00128  *
00129  * 'duplex' modes:  (defaults to duplex=2)
00130  *
00131  * 0 - Only remote links key Tx and no main repeat audio.
00132  * 1 - Everything other then main Rx keys Tx, no main repeat audio.
00133  * 2 - Normal mode
00134  * 3 - Normal except no main repeat audio.
00135  * 4 - Normal except no main repeat audio during autopatch only
00136  *
00137 */
00138 
00139 /*** MODULEINFO
00140    <depend>dahdi</depend>
00141    <depend>tonezone</depend>
00142    <defaultenabled>no</defaultenabled>
00143  ***/
00144 
00145 /* Un-comment the following to include support for MDC-1200 digital tone
00146    signalling protocol (using KA6SQG's GPL'ed implementation) */
00147 /* #include "mdc_decode.c" */
00148 
00149 /* Un-comment the following to include support for notch filters in the
00150    rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
00151 /* #include "rpt_notch.c" */
00152 
00153 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
00154 
00155 #define  MAXDTMF 32
00156 #define  MAXMACRO 2048
00157 #define  MAXLINKLIST 512
00158 #define  LINKLISTTIME 10000
00159 #define  LINKLISTSHORTTIME 200
00160 #define  MACROTIME 100
00161 #define  MACROPTIME 500
00162 #define  DTMF_TIMEOUT 3
00163 #define  KENWOOD_RETRIES 5
00164 
00165 #define  AUTHTELLTIME 7000
00166 #define  AUTHTXTIME 1000
00167 #define  AUTHLOGOUTTIME 25000
00168 
00169 #ifdef   __RPT_NOTCH
00170 #define  MAXFILTERS 10
00171 #endif
00172 
00173 #define  DISC_TIME 10000  /* report disc after 10 seconds of no connect */
00174 #define  MAX_RETRIES 5
00175 #define  MAX_RETRIES_PERM 1000000000
00176 
00177 #define  REDUNDANT_TX_TIME 2000
00178 
00179 #define  RETRY_TIMER_MS 5000
00180 
00181 #define  START_DELAY 2
00182 
00183 #define MAXPEERSTR 31
00184 #define  MAXREMSTR 15
00185 
00186 #define  DELIMCHR ','
00187 #define  QUOTECHR 34
00188 
00189 #define  MONITOR_DISK_BLOCKS_PER_MINUTE 38
00190 
00191 #define  DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000
00192 #define  DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60)
00193 #define  DEFAULT_REMOTE_TIMEOUT (60 * 60)
00194 #define  DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60)
00195 #define  DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30
00196 
00197 #define  NODES "nodes"
00198 #define  EXTNODES "extnodes"
00199 #define MEMORY "memory"
00200 #define MACRO "macro"
00201 #define  FUNCTIONS "functions"
00202 #define TELEMETRY "telemetry"
00203 #define MORSE "morse"
00204 #define  FUNCCHAR '*'
00205 #define  ENDCHAR '#'
00206 #define  EXTNODEFILE "/var/lib/asterisk/rpt_extnodes"
00207 
00208 #define  DEFAULT_IOBASE 0x378
00209 
00210 #define  DEFAULT_CIV_ADDR 0x58
00211 
00212 #define  MAXCONNECTTIME 5000
00213 
00214 #define MAXNODESTR 300
00215 
00216 #define MAXPATCHCONTEXT 100
00217 
00218 #define ACTIONSIZE 32
00219 
00220 #define TELEPARAMSIZE 256
00221 
00222 #define REM_SCANTIME 100
00223 
00224 #define  DTMF_LOCAL_TIME 250
00225 #define  DTMF_LOCAL_STARTTIME 500
00226 
00227 #define  IC706_PL_MEMORY_OFFSET 50
00228 
00229 #define  ALLOW_LOCAL_CHANNELS
00230 
00231 enum {REM_OFF,REM_MONITOR,REM_TX};
00232 
00233 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
00234    CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME,
00235    STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
00236    TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS,
00237    MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS,
00238    REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE,
00239    TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX};
00240 
00241 
00242 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
00243 
00244 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
00245 
00246 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY};
00247 
00248 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE};
00249 
00250 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY};
00251 
00252 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
00253 
00254 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
00255       HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
00256 
00257 #include "asterisk.h"
00258 
00259 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 299002 $")
00260 
00261 #include <signal.h>
00262 #include <stdio.h>
00263 #include <stdint.h>
00264 #include <unistd.h>
00265 #include <string.h>
00266 #include <stdlib.h>
00267 #include <search.h>
00268 #include <sys/types.h>
00269 #include <sys/stat.h>
00270 #include <errno.h>
00271 #include <dirent.h>
00272 #include <ctype.h>
00273 #include <sys/stat.h>
00274 #include <sys/time.h>
00275 #include <sys/file.h>
00276 #include <sys/ioctl.h>
00277 #ifdef HAVE_SYS_IO_H
00278 #include <sys/io.h>
00279 #endif
00280 #include <sys/vfs.h>
00281 #include <math.h>
00282 #include <netinet/in.h>
00283 #include <arpa/inet.h>
00284 #include <termios.h>
00285 
00286 #include "asterisk/utils.h"
00287 #include "asterisk/lock.h"
00288 #include "asterisk/file.h"
00289 #include "asterisk/logger.h"
00290 #include "asterisk/channel.h"
00291 #include "asterisk/callerid.h"
00292 #include "asterisk/pbx.h"
00293 #include "asterisk/module.h"
00294 #include "asterisk/translate.h"
00295 #include "asterisk/features.h"
00296 #include "asterisk/options.h"
00297 #include "asterisk/cli.h"
00298 #include "asterisk/config.h"
00299 #include "asterisk/say.h"
00300 #include "asterisk/localtime.h"
00301 #include "asterisk/cdr.h"
00302 #include "asterisk/options.h"
00303 
00304 #include "asterisk/dahdi_compat.h"
00305 #include "asterisk/tonezone_compat.h"
00306 
00307 /* Start a tone-list going */
00308 int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
00309 /*! Stop the tones from playing */
00310 void ast_playtones_stop(struct ast_channel *chan);
00311 
00312 static  char *tdesc = "Radio Repeater / Remote Base  version 0.73  09/04/2007";
00313 
00314 static char *app = "Rpt";
00315 
00316 static char *synopsis = "Radio Repeater/Remote Base Control System";
00317 
00318 static char *descrip = 
00319 "  Rpt(nodename[|options]):  Radio Remote Link or Remote Base Link Endpoint Process.\n"
00320 "\n"
00321 "    Not specifying an option puts it in normal endpoint mode (where source\n"
00322 "    IP and nodename are verified).\n"
00323 "\n"
00324 "    Options are as follows:\n"
00325 "\n"
00326 "        X - Normal endpoint mode WITHOUT security check. Only specify\n"
00327 "            this if you have checked security already (like with an IAX2\n"
00328 "            user/password or something).\n"
00329 "\n"
00330 "        Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
00331 "            Reverse Autopatch. Caller is put on hold, and announcement (as\n"
00332 "            specified by the 'announce-string') is played on radio system.\n"
00333 "            Users of radio system can access autopatch, dial specified\n"
00334 "            code, and pick up call. Announce-string is list of names of\n"
00335 "            recordings, or \"PARKED\" to substitute code for un-parking,\n"
00336 "            or \"NODE\" to substitute node number.\n"
00337 "\n"
00338 "        P - Phone Control mode. This allows a regular phone user to have\n"
00339 "            full control and audio access to the radio system. For the\n"
00340 "            user to have DTMF control, the 'phone_functions' parameter\n"
00341 "            must be specified for the node in 'rpt.conf'. An additional\n"
00342 "            function (cop,6) must be listed so that PTT control is available.\n"
00343 "\n"
00344 "        D - Dumb Phone Control mode. This allows a regular phone user to\n"
00345 "            have full control and audio access to the radio system. In this\n"
00346 "            mode, the PTT is activated for the entire length of the call.\n"
00347 "            For the user to have DTMF control (not generally recomended in\n"
00348 "            this mode), the 'dphone_functions' parameter must be specified\n"
00349 "            for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
00350 "            available to the phone user.\n"
00351 "\n";
00352 
00353 static int debug = 0;  /* Set this >0 for extra debug output */
00354 static int nrpts = 0;
00355 
00356 static char remdtmfstr[] = "0123456789*#ABCD";
00357 
00358 enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
00359 
00360 int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
00361 
00362 #define NRPTSTAT 7
00363 
00364 struct rpt_chan_stat
00365 {
00366    struct timeval last;
00367    long long total;
00368    unsigned long count;
00369    unsigned long largest;
00370    struct timeval largest_time;
00371 };
00372 
00373 char *discstr = "!!DISCONNECT!!";
00374 static char *remote_rig_ft897="ft897";
00375 static char *remote_rig_rbi="rbi";
00376 static char *remote_rig_kenwood="kenwood";
00377 static char *remote_rig_ic706="ic706";
00378 
00379 #ifdef   OLD_ASTERISK
00380 STANDARD_LOCAL_USER;
00381 LOCAL_USER_DECL;
00382 #endif
00383 
00384 #define  MSWAIT 200
00385 #define  HANGTIME 5000
00386 #define  TOTIME 180000
00387 #define  IDTIME 300000
00388 #define  MAXRPTS 20
00389 #define MAX_STAT_LINKS 32
00390 #define POLITEID 30000
00391 #define FUNCTDELAY 1500
00392 
00393 #define  MAXXLAT 20
00394 #define  MAXXLATTIME 3
00395 
00396 #define MAX_SYSSTATES 10
00397 
00398 struct rpt_xlat
00399 {
00400 char  funccharseq[MAXXLAT];
00401 char  endcharseq[MAXXLAT];
00402 char  passchars[MAXXLAT];
00403 int   funcindex;
00404 int   endindex;
00405 time_t   lastone;
00406 } ;
00407 
00408 static time_t  starttime = 0;
00409 
00410 static  pthread_t rpt_master_thread;
00411 
00412 struct rpt;
00413 
00414 struct rpt_link
00415 {
00416    struct rpt_link *next;
00417    struct rpt_link *prev;
00418    char  mode;       /* 1 if in tx mode */
00419    char  isremote;
00420    char  phonemode;
00421    char  name[MAXNODESTR]; /* identifier (routing) string */
00422    char  lasttx;
00423    char  lastrx;
00424    char  lastrx1;
00425    char  connected;
00426    char  hasconnected;
00427    char  perma;
00428    char  thisconnected;
00429    char  outbound;
00430    char  disced;
00431    char  killme;
00432    long  elaptime;
00433    long  disctime;
00434    long  retrytimer;
00435    long  retxtimer;
00436    long  rerxtimer;
00437    int   retries;
00438    int   max_retries;
00439    int   reconnects;
00440    long long connecttime;
00441    struct ast_channel *chan;  
00442    struct ast_channel *pchan; 
00443    char  linklist[MAXLINKLIST];
00444    time_t   linklistreceived;
00445    long  linklisttimer;
00446    int   dtmfed;
00447    int linkunkeytocttimer;
00448    struct   ast_frame *lastf1,*lastf2;
00449    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00450 } ;
00451 
00452 struct rpt_lstat
00453 {
00454    struct   rpt_lstat *next;
00455    struct   rpt_lstat *prev;
00456    char  peer[MAXPEERSTR];
00457    char  name[MAXNODESTR];
00458    char  mode;
00459    char  outbound;
00460    char  reconnects;
00461    char  thisconnected;
00462    long long   connecttime;
00463    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00464 } ;
00465 
00466 struct rpt_tele
00467 {
00468    struct rpt_tele *next;
00469    struct rpt_tele *prev;
00470    struct rpt *rpt;
00471    struct ast_channel *chan;
00472    int   mode;
00473    struct rpt_link mylink;
00474    char param[TELEPARAMSIZE];
00475    intptr_t submode;
00476    pthread_t threadid;
00477 } ;
00478 
00479 struct function_table_tag
00480 {
00481    char action[ACTIONSIZE];
00482    int (*function)(struct rpt *myrpt, char *param, char *digitbuf, 
00483       int command_source, struct rpt_link *mylink);
00484 } ;
00485 
00486 /* Used to store the morse code patterns */
00487 
00488 struct morse_bits
00489 {       
00490    int len;
00491    int ddcomb;
00492 } ;
00493 
00494 struct telem_defaults
00495 {
00496    char name[20];
00497    char value[80];
00498 } ;
00499 
00500 
00501 struct sysstate
00502 {
00503    char txdisable;
00504    char totdisable;
00505    char linkfundisable;
00506    char autopatchdisable;
00507    char schedulerdisable;
00508    char userfundisable;
00509    char alternatetail;
00510 };
00511 
00512 static struct rpt
00513 {
00514    ast_mutex_t lock;
00515    ast_mutex_t remlock;
00516    struct ast_config *cfg;
00517    char reload;
00518 
00519    char *name;
00520    char *rxchanname;
00521    char *txchanname;
00522    char *remote;
00523    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00524    unsigned int scram;
00525 
00526    struct {
00527       char *ourcontext;
00528       char *ourcallerid;
00529       char *acctcode;
00530       char *ident;
00531       char *tonezone;
00532       char simple;
00533       char *functions;
00534       char *link_functions;
00535       char *phone_functions;
00536       char *dphone_functions;
00537       char *nodes;
00538       char *extnodes;
00539       char *extnodefile;
00540       int hangtime;
00541       int althangtime;
00542       int totime;
00543       int idtime;
00544       int tailmessagetime;
00545       int tailsquashedtime;
00546       int duplex;
00547       int politeid;
00548       char *tailmessages[500];
00549       int tailmessagemax;
00550       char  *memory;
00551       char  *macro;
00552       char  *startupmacro;
00553       int iobase;
00554       char *ioport;
00555       char funcchar;
00556       char endchar;
00557       char nobusyout;
00558       char notelemtx;
00559       char propagate_dtmf;
00560       char propagate_phonedtmf;
00561       char linktolink;
00562       unsigned char civaddr;
00563       struct rpt_xlat inxlat;
00564       struct rpt_xlat outxlat;
00565       char *archivedir;
00566       int authlevel;
00567       char *csstanzaname;
00568       char *skedstanzaname;
00569       char *txlimitsstanzaname;
00570       long monminblocks;
00571       int remoteinacttimeout;
00572       int remotetimeout;
00573       int remotetimeoutwarning;
00574       int remotetimeoutwarningfreq;
00575       int sysstate_cur;
00576       struct sysstate s[MAX_SYSSTATES];
00577    } p;
00578    struct rpt_link links;
00579    int unkeytocttimer;
00580    char keyed;
00581    char exttx;
00582    char localtx;
00583    char remoterx;
00584    char remotetx;
00585    char remoteon;
00586    char remtxfreqok;
00587    char tounkeyed;
00588    char tonotify;
00589    char dtmfbuf[MAXDTMF];
00590    char macrobuf[MAXMACRO];
00591    char rem_dtmfbuf[MAXDTMF];
00592    char lastdtmfcommand[MAXDTMF];
00593    char cmdnode[50];
00594    struct ast_channel *rxchannel,*txchannel, *monchannel;
00595    struct ast_channel *pchannel,*txpchannel, *zaprxchannel, *zaptxchannel;
00596    struct ast_frame *lastf1,*lastf2;
00597    struct rpt_tele tele;
00598    struct timeval lasttv,curtv;
00599    pthread_t rpt_call_thread,rpt_thread;
00600    time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
00601    int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
00602    int mustid,tailid;
00603    int tailevent;
00604    int telemrefcount;
00605    int dtmfidx,rem_dtmfidx;
00606    int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
00607    int totalexecdcommands, dailyexecdcommands;
00608    long  retxtimer;
00609    long  rerxtimer;
00610    long long totaltxtime;
00611    char mydtmf;
00612    char exten[AST_MAX_EXTENSION];
00613    char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
00614    char offset;
00615    char powerlevel;
00616    char txplon;
00617    char rxplon;
00618    char remmode;
00619    char tunerequest;
00620    char hfscanmode;
00621    int hfscanstatus;
00622    char hfscanstop;
00623    char lastlinknode[MAXNODESTR];
00624    char savednodes[MAXNODESTR];
00625    int stopgen;
00626    char patchfarenddisconnect;
00627    char patchnoct;
00628    char patchquiet;
00629    char patchcontext[MAXPATCHCONTEXT];
00630    int patchdialtime;
00631    int macro_longest;
00632    int phone_longestfunc;
00633    int dphone_longestfunc;
00634    int link_longestfunc;
00635    int longestfunc;
00636    int longestnode;
00637    int threadrestarts;     
00638    int tailmessagen;
00639    time_t disgorgetime;
00640    time_t lastthreadrestarttime;
00641    long  macrotimer;
00642    char  lastnodewhichkeyedusup[MAXNODESTR];
00643    int   dtmf_local_timer;
00644    char  dtmf_local_str[100];
00645    struct ast_filestream *monstream;
00646    char  loginuser[50];
00647    char  loginlevel[10];
00648    long  authtelltimer;
00649    long  authtimer;
00650    int iofd;
00651    time_t start_time,last_activity_time;
00652 #ifdef   __RPT_NOTCH
00653    struct rptfilter
00654    {
00655       char  desc[100];
00656       float x0;
00657       float x1;
00658       float x2;
00659       float y0;
00660       float y1;
00661       float y2;
00662       float gain;
00663       float const0;
00664       float const1;
00665       float const2;
00666    } filters[MAXFILTERS];
00667 #endif
00668 #ifdef   _MDC_DECODE_H_
00669    mdc_decoder_t *mdc;
00670    unsigned short lastunit;
00671 #endif
00672 } rpt_vars[MAXRPTS]; 
00673 
00674 struct nodelog {
00675 struct nodelog *next;
00676 struct nodelog *prev;
00677 time_t   timestamp;
00678 char archivedir[MAXNODESTR];
00679 char str[MAXNODESTR * 2];
00680 } nodelog;
00681 
00682 static int service_scan(struct rpt *myrpt);
00683 static int set_mode_ft897(struct rpt *myrpt, char newmode);
00684 static int set_mode_ic706(struct rpt *myrpt, char newmode);
00685 static int simple_command_ft897(struct rpt *myrpt, char command);
00686 static int setrem(struct rpt *myrpt);
00687 
00688 AST_MUTEX_DEFINE_STATIC(nodeloglock);
00689 
00690 AST_MUTEX_DEFINE_STATIC(nodelookuplock);
00691 
00692 #ifdef   APP_RPT_LOCK_DEBUG
00693 
00694 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
00695 
00696 #define  MAXLOCKTHREAD 100
00697 
00698 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
00699 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
00700 
00701 struct lockthread
00702 {
00703    pthread_t id;
00704    int lockcount;
00705    int lastlock;
00706    int lastunlock;
00707 } lockthreads[MAXLOCKTHREAD];
00708 
00709 
00710 struct by_lightning
00711 {
00712    int line;
00713    struct timeval tv;
00714    struct rpt *rpt;
00715    struct lockthread lockthread;
00716 } lock_ring[32];
00717 
00718 int lock_ring_index = 0;
00719 
00720 AST_MUTEX_DEFINE_STATIC(locklock);
00721 
00722 static struct lockthread *get_lockthread(pthread_t id)
00723 {
00724 int   i;
00725 
00726    for(i = 0; i < MAXLOCKTHREAD; i++)
00727    {
00728       if (lockthreads[i].id == id) return(&lockthreads[i]);
00729    }
00730    return(NULL);
00731 }
00732 
00733 static struct lockthread *put_lockthread(pthread_t id)
00734 {
00735 int   i;
00736 
00737    for(i = 0; i < MAXLOCKTHREAD; i++)
00738    {
00739       if (lockthreads[i].id == id)
00740          return(&lockthreads[i]);
00741    }
00742    for(i = 0; i < MAXLOCKTHREAD; i++)
00743    {
00744       if (!lockthreads[i].id)
00745       {
00746          lockthreads[i].lockcount = 0;
00747          lockthreads[i].lastlock = 0;
00748          lockthreads[i].lastunlock = 0;
00749          lockthreads[i].id = id;
00750          return(&lockthreads[i]);
00751       }
00752    }
00753    return(NULL);
00754 }
00755 
00756 
00757 static void rpt_mutex_spew(void)
00758 {
00759    struct by_lightning lock_ring_copy[32];
00760    int lock_ring_index_copy;
00761    int i,j;
00762    long long diff;
00763    char a[100];
00764    struct timeval lasttv;
00765 
00766    ast_mutex_lock(&locklock);
00767    memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
00768    lock_ring_index_copy = lock_ring_index;
00769    ast_mutex_unlock(&locklock);
00770 
00771    lasttv.tv_sec = lasttv.tv_usec = 0;
00772    for(i = 0 ; i < 32 ; i++)
00773    {
00774       j = (i + lock_ring_index_copy) % 32;
00775       strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
00776          localtime(&lock_ring_copy[j].tv.tv_sec));
00777       diff = 0;
00778       if(lasttv.tv_sec)
00779       {
00780          diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
00781             * 1000000;
00782          diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
00783       }
00784       lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
00785       lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
00786       if (!lock_ring_copy[j].tv.tv_sec) continue;
00787       if (lock_ring_copy[j].line < 0)
00788       {
00789          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00790             i - 31,-lock_ring_copy[j].line,lock_ring_copy[j].rpt->name,(int) lock_ring_copy[j].lockthread.id,diff,a,(int)lock_ring_copy[j].tv.tv_usec);
00791       }
00792       else
00793       {
00794          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00795             i - 31,lock_ring_copy[j].line,lock_ring_copy[j].rpt->name,(int) lock_ring_copy[j].lockthread.id,diff,a,(int)lock_ring_copy[j].tv.tv_usec);
00796       }
00797    }
00798 }
00799 
00800 
00801 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
00802 {
00803 struct lockthread *t;
00804 pthread_t id;
00805 
00806    id = pthread_self();
00807    ast_mutex_lock(&locklock);
00808    t = put_lockthread(id);
00809    if (!t)
00810    {
00811       ast_mutex_unlock(&locklock);
00812       return;
00813    }
00814    if (t->lockcount)
00815    {
00816       int lastline = t->lastlock;
00817       ast_mutex_unlock(&locklock);
00818       ast_log(LOG_NOTICE,"rpt_mutex_lock: Double lock request line %d node %s pid %x, last lock was line %d\n",line,myrpt->name,(int) t->id,lastline);
00819       rpt_mutex_spew();
00820       return;
00821    }
00822    t->lastlock = line;
00823    t->lockcount = 1;
00824    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
00825    lock_ring[lock_ring_index].rpt = myrpt;
00826    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
00827    lock_ring[lock_ring_index++].line = line;
00828    if(lock_ring_index == 32)
00829       lock_ring_index = 0;
00830    ast_mutex_unlock(&locklock);
00831    ast_mutex_lock(lockp);
00832 }
00833 
00834 
00835 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
00836 {
00837 struct lockthread *t;
00838 pthread_t id;
00839 
00840    id = pthread_self();
00841    ast_mutex_lock(&locklock);
00842    t = put_lockthread(id);
00843    if (!t)
00844    {
00845       ast_mutex_unlock(&locklock);
00846       return;
00847    }
00848    if (!t->lockcount)
00849    {
00850       int lastline = t->lastunlock;
00851       ast_mutex_unlock(&locklock);
00852       ast_log(LOG_NOTICE,"rpt_mutex_lock: Double un-lock request line %d node %s pid %x, last un-lock was line %d\n",line,myrpt->name,(int) t->id,lastline);
00853       rpt_mutex_spew();
00854       return;
00855    }
00856    t->lastunlock = line;
00857    t->lockcount = 0;
00858    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
00859    lock_ring[lock_ring_index].rpt = myrpt;
00860    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
00861    lock_ring[lock_ring_index++].line = -line;
00862    if(lock_ring_index == 32)
00863       lock_ring_index = 0;
00864    ast_mutex_unlock(&locklock);
00865    ast_mutex_unlock(lockp);
00866 }
00867 
00868 #else  /* APP_RPT_LOCK_DEBUG */
00869 
00870 #define rpt_mutex_lock(x) ast_mutex_lock(x)
00871 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
00872 
00873 #endif  /* APP_RPT_LOCK_DEBUG */
00874 
00875 /*
00876 * Return 1 if rig is multimode capable
00877 */
00878 
00879 static int multimode_capable(struct rpt *myrpt)
00880 {
00881    if(!strcmp(myrpt->remote, remote_rig_ft897))
00882       return 1;
00883    if(!strcmp(myrpt->remote, remote_rig_ic706))
00884       return 1;
00885    return 0;
00886 }  
00887 
00888 /*
00889 * CLI extensions
00890 */
00891 
00892 /* Debug mode */
00893 static int rpt_do_debug(int fd, int argc, char *argv[]);
00894 static int rpt_do_dump(int fd, int argc, char *argv[]);
00895 static int rpt_do_stats(int fd, int argc, char *argv[]);
00896 static int rpt_do_lstats(int fd, int argc, char *argv[]);
00897 static int rpt_do_nodes(int fd, int argc, char *argv[]);
00898 static int rpt_do_reload(int fd, int argc, char *argv[]);
00899 static int rpt_do_restart(int fd, int argc, char *argv[]);
00900 static int rpt_do_fun(int fd, int argc, char *argv[]);
00901 
00902 static char debug_usage[] =
00903 "Usage: rpt debug level {0-7}\n"
00904 "       Enables debug messages in app_rpt\n";
00905 
00906 static char dump_usage[] =
00907 "Usage: rpt dump <nodename>\n"
00908 "       Dumps struct debug info to log\n";
00909 
00910 static char dump_stats[] =
00911 "Usage: rpt stats <nodename>\n"
00912 "       Dumps node statistics to console\n";
00913 
00914 static char dump_lstats[] =
00915 "Usage: rpt lstats <nodename>\n"
00916 "       Dumps link statistics to console\n";
00917 
00918 static char dump_nodes[] =
00919 "Usage: rpt nodes <nodename>\n"
00920 "       Dumps a list of directly and indirectly connected nodes to the console\n";
00921 
00922 static char reload_usage[] =
00923 "Usage: rpt reload\n"
00924 "       Reloads app_rpt running config parameters\n";
00925 
00926 static char restart_usage[] =
00927 "Usage: rpt restart\n"
00928 "       Restarts app_rpt\n";
00929 
00930 static char fun_usage[] =
00931 "Usage: rpt fun <nodename> <command>\n"
00932 "       Send a DTMF function to a node\n";
00933 
00934 
00935 static struct ast_cli_entry  cli_debug =
00936         { { "rpt", "debug", "level" }, rpt_do_debug, 
00937       "Enable app_rpt debugging", debug_usage };
00938 
00939 static struct ast_cli_entry  cli_dump =
00940         { { "rpt", "dump" }, rpt_do_dump,
00941       "Dump app_rpt structs for debugging", dump_usage };
00942 
00943 static struct ast_cli_entry  cli_stats =
00944         { { "rpt", "stats" }, rpt_do_stats,
00945       "Dump node statistics", dump_stats };
00946 
00947 static struct ast_cli_entry  cli_nodes =
00948         { { "rpt", "nodes" }, rpt_do_nodes,
00949       "Dump node list", dump_nodes };
00950 
00951 static struct ast_cli_entry  cli_lstats =
00952         { { "rpt", "lstats" }, rpt_do_lstats,
00953       "Dump link statistics", dump_lstats };
00954 
00955 static struct ast_cli_entry  cli_reload =
00956         { { "rpt", "reload" }, rpt_do_reload,
00957       "Reload app_rpt config", reload_usage };
00958 
00959 static struct ast_cli_entry  cli_restart =
00960         { { "rpt", "restart" }, rpt_do_restart,
00961       "Restart app_rpt", restart_usage };
00962 
00963 static struct ast_cli_entry  cli_fun =
00964         { { "rpt", "fun" }, rpt_do_fun,
00965       "Execute a DTMF function", fun_usage };
00966 
00967 /*
00968 * Telemetry defaults
00969 */
00970 
00971 
00972 static struct telem_defaults tele_defs[] = {
00973    {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
00974    {"ct2","|t(660,880,150,3072)"},
00975    {"ct3","|t(440,0,150,3072)"},
00976    {"ct4","|t(550,0,150,3072)"},
00977    {"ct5","|t(660,0,150,3072)"},
00978    {"ct6","|t(880,0,150,3072)"},
00979    {"ct7","|t(660,440,150,3072)"},
00980    {"ct8","|t(700,1100,150,3072)"},
00981    {"remotemon","|t(1600,0,75,2048)"},
00982    {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
00983    {"cmdmode","|t(900,904,200,2048)"},
00984    {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
00985 } ;
00986 
00987 /*
00988 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
00989 */
00990 
00991 static int setrbi(struct rpt *myrpt);
00992 static int set_ft897(struct rpt *myrpt);
00993 static int set_ic706(struct rpt *myrpt);
00994 static int setkenwood(struct rpt *myrpt);
00995 static int setrbi_check(struct rpt *myrpt);
00996 
00997 
00998 
00999 /*
01000 * Define function protos for function table here
01001 */
01002 
01003 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01004 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01005 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01006 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01007 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01008 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01009 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01010 /*
01011 * Function table
01012 */
01013 
01014 static struct function_table_tag function_table[] = {
01015    {"cop", function_cop},
01016    {"autopatchup", function_autopatchup},
01017    {"autopatchdn", function_autopatchdn},
01018    {"ilink", function_ilink},
01019    {"status", function_status},
01020    {"remote", function_remote},
01021    {"macro", function_macro}
01022 } ;
01023 
01024 static long diskavail(struct rpt *myrpt)
01025 {
01026 struct   statfs statfsbuf;
01027 
01028    if (!myrpt->p.archivedir) return(0);
01029    if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
01030    {
01031       ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
01032          myrpt->p.archivedir,myrpt->name);
01033       return(-1);
01034    }
01035    return(statfsbuf.f_bavail);
01036 }
01037 
01038 static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
01039 {
01040 struct        rpt_link *l;
01041 
01042        l = myrpt->links.next;
01043        /* go thru all the links */
01044        while(l != &myrpt->links)
01045        {
01046                if (!l->phonemode)
01047                {
01048                        l = l->next;
01049                        continue;
01050                }
01051                /* dont send to self */
01052                if (mylink && (l == mylink))
01053                {
01054                        l = l->next;
01055                        continue;
01056                }
01057                if (l->chan) ast_senddigit(l->chan,c);
01058                l = l->next;
01059        }
01060        return;
01061 }
01062 
01063 /* node logging function */
01064 static void donodelog(struct rpt *myrpt,char *str)
01065 {
01066 struct nodelog *nodep;
01067 char  datestr[100];
01068 
01069    if (!myrpt->p.archivedir) return;
01070    nodep = (struct nodelog *)malloc(sizeof(struct nodelog));
01071    if (nodep == NULL)
01072    {
01073       ast_log(LOG_ERROR,"Cannot get memory for node log");
01074       return;
01075    }
01076    time(&nodep->timestamp);
01077    strncpy(nodep->archivedir,myrpt->p.archivedir,
01078       sizeof(nodep->archivedir) - 1);
01079    strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
01080       localtime(&nodep->timestamp));
01081    snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
01082       myrpt->name,datestr,str);
01083    ast_mutex_lock(&nodeloglock);
01084    insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
01085    ast_mutex_unlock(&nodeloglock);
01086 }
01087 
01088 /* must be called locked */
01089 static void do_dtmf_local(struct rpt *myrpt, char c)
01090 {
01091 int   i;
01092 char  digit;
01093 static const char* dtmf_tones[] = {
01094    "!941+1336/200,!0/200", /* 0 */
01095    "!697+1209/200,!0/200", /* 1 */
01096    "!697+1336/200,!0/200", /* 2 */
01097    "!697+1477/200,!0/200", /* 3 */
01098    "!770+1209/200,!0/200", /* 4 */
01099    "!770+1336/200,!0/200", /* 5 */
01100    "!770+1477/200,!0/200", /* 6 */
01101    "!852+1209/200,!0/200", /* 7 */
01102    "!852+1336/200,!0/200", /* 8 */
01103    "!852+1477/200,!0/200", /* 9 */
01104    "!697+1633/200,!0/200", /* A */
01105    "!770+1633/200,!0/200", /* B */
01106    "!852+1633/200,!0/200", /* C */
01107    "!941+1633/200,!0/200", /* D */
01108    "!941+1209/200,!0/200", /* * */
01109    "!941+1477/200,!0/200" };  /* # */
01110 
01111 
01112    if (c)
01113    {
01114       snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
01115       if (!myrpt->dtmf_local_timer) 
01116           myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
01117    }
01118    /* if at timeout */
01119    if (myrpt->dtmf_local_timer == 1)
01120    {
01121       /* if anything in the string */
01122       if (myrpt->dtmf_local_str[0])
01123       {
01124          digit = myrpt->dtmf_local_str[0];
01125          myrpt->dtmf_local_str[0] = 0;
01126          for(i = 1; myrpt->dtmf_local_str[i]; i++)
01127          {
01128             myrpt->dtmf_local_str[i - 1] =
01129                myrpt->dtmf_local_str[i];
01130          }
01131          myrpt->dtmf_local_str[i - 1] = 0;
01132          myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
01133          rpt_mutex_unlock(&myrpt->lock);
01134          if (digit >= '0' && digit <='9')
01135             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
01136          else if (digit >= 'A' && digit <= 'D')
01137             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
01138          else if (digit == '*')
01139             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
01140          else if (digit == '#')
01141             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
01142          else {
01143             /* not handled */
01144             ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name);
01145          }
01146          rpt_mutex_lock(&myrpt->lock);
01147       }
01148       else
01149       {
01150          myrpt->dtmf_local_timer = 0;
01151       }
01152    }
01153 }
01154 
01155 static int openserial(char *fname)
01156 {
01157    struct termios mode;
01158    int fd;
01159 
01160    fd = open(fname,O_RDWR);
01161    if (fd == -1)
01162    {
01163       ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
01164       return -1;
01165    }
01166    memset(&mode, 0, sizeof(mode));
01167    if (tcgetattr(fd, &mode)) {
01168       ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
01169       return -1;
01170    }
01171 #ifndef SOLARIS
01172    cfmakeraw(&mode);
01173 #else
01174         mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
01175                         |INLCR|IGNCR|ICRNL|IXON);
01176         mode.c_oflag &= ~OPOST;
01177         mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
01178         mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
01179         mode.c_cflag |= CS8;
01180    mode.c_cc[TIME] = 3;
01181    mode.c_cc[MAX] = 1;
01182 #endif
01183 
01184    cfsetispeed(&mode, B9600);
01185    cfsetospeed(&mode, B9600);
01186    if (tcsetattr(fd, TCSANOW, &mode)) 
01187       ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
01188    return(fd); 
01189 }
01190 
01191 static void mdc1200_notify(struct rpt *myrpt,char *fromnode, unsigned int unit)
01192 {
01193    if (!fromnode)
01194    {
01195       ast_verbose("Got MDC-1200 ID %04X from local system (%s)\n",
01196          unit,myrpt->name);
01197    }
01198    else
01199    {
01200       ast_verbose("Got MDC-1200 ID %04X from node %s (%s)\n",
01201          unit,fromnode,myrpt->name);
01202    }
01203 }
01204 
01205 #ifdef   _MDC_DECODE_H_
01206 
01207 static void mdc1200_send(struct rpt *myrpt, unsigned int unit)
01208 {
01209 struct rpt_link *l;
01210 struct   ast_frame wf;
01211 char  str[200];
01212 
01213 
01214    sprintf(str,"I %s %04X",myrpt->name,unit);
01215 
01216    wf.frametype = AST_FRAME_TEXT;
01217    wf.subclass = 0;
01218    wf.offset = 0;
01219    wf.mallocd = 0;
01220    wf.datalen = strlen(str) + 1;
01221    wf.samples = 0;
01222 
01223 
01224    l = myrpt->links.next;
01225    /* otherwise, send it to all of em */
01226    while(l != &myrpt->links)
01227    {
01228       if (l->name[0] == '0') 
01229       {
01230          l = l->next;
01231          continue;
01232       }
01233       wf.data = str;
01234       if (l->chan) ast_write(l->chan,&wf); 
01235       l = l->next;
01236    }
01237    return;
01238 }
01239 
01240 #endif
01241 
01242 static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
01243 {
01244 time_t   now;
01245 int   gotone;
01246 
01247    time(&now);
01248    gotone = 0;
01249    /* if too much time, reset the skate machine */
01250    if ((now - xlat->lastone) > MAXXLATTIME)
01251    {
01252       xlat->funcindex = xlat->endindex = 0;
01253    }
01254    if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
01255    {
01256       time(&xlat->lastone);
01257       gotone = 1;
01258       if (!xlat->funccharseq[xlat->funcindex])
01259       {
01260          xlat->funcindex = xlat->endindex = 0;
01261          return(myrpt->p.funcchar);
01262       }
01263    } else xlat->funcindex = 0;
01264    if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
01265    {
01266       time(&xlat->lastone);
01267       gotone = 1;
01268       if (!xlat->endcharseq[xlat->endindex])
01269       {
01270          xlat->funcindex = xlat->endindex = 0;
01271          return(myrpt->p.endchar);
01272       }
01273    } else xlat->endindex = 0;
01274    /* if in middle of decode seq, send nothing back */
01275    if (gotone) return(0);
01276    /* if no pass chars specified, return em all */
01277    if (!xlat->passchars[0]) return(c);
01278    /* if a "pass char", pass it */
01279    if (strchr(xlat->passchars,c)) return(c);
01280    return(0);
01281 }
01282 
01283 /*
01284  * Return a pointer to the first non-whitespace character
01285  */
01286 
01287 static char *eatwhite(char *s)
01288 {
01289    while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
01290       if(!*s)
01291          break;
01292       s++;
01293    }
01294    return s;
01295 }
01296 
01297 /*
01298 * Break up a delimited string into a table of substrings
01299 *
01300 * str - delimited string ( will be modified )
01301 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
01302 * limit- maximum number of substrings to process
01303 */
01304    
01305 
01306 
01307 static int finddelim(char *str, char *strp[], int limit)
01308 {
01309 int     i,l,inquo;
01310 
01311         inquo = 0;
01312         i = 0;
01313         strp[i++] = str;
01314         if (!*str)
01315            {
01316                 strp[0] = 0;
01317                 return(0);
01318            }
01319         for(l = 0; *str && (l < limit) ; str++)
01320            {
01321                 if (*str == QUOTECHR)
01322                    {
01323                         if (inquo)
01324                            {
01325                                 *str = 0;
01326                                 inquo = 0;
01327                            }
01328                         else
01329                            {
01330                                 strp[i - 1] = str + 1;
01331                                 inquo = 1;
01332                            }
01333       }
01334                 if ((*str == DELIMCHR) && (!inquo))
01335                 {
01336                         *str = 0;
01337          l++;
01338                         strp[i++] = str + 1;
01339                 }
01340            }
01341         strp[i] = 0;
01342         return(i);
01343 
01344 }
01345 
01346 /* must be called locked */
01347 static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
01348 {
01349 struct rpt_link *l;
01350 char mode;
01351 int   i,spos;
01352 
01353    buf[0] = 0; /* clear output buffer */
01354    /* go thru all links */
01355    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01356    {
01357       /* if is not a real link, ignore it */
01358       if (l->name[0] == '0') continue;
01359       /* dont count our stuff */
01360       if (l == mylink) continue;
01361       if (mylink && (!strcmp(l->name,mylink->name))) continue;
01362       /* figure out mode to report */
01363       mode = 'T'; /* use Tranceive by default */
01364       if (!l->mode) mode = 'R'; /* indicate RX for our mode */
01365       if (!l->thisconnected)  mode = 'C'; /* indicate connecting */
01366       spos = strlen(buf); /* current buf size (b4 we add our stuff) */
01367       if (spos)
01368       {
01369          strcat(buf,",");
01370          spos++;
01371       }
01372       /* add nodes into buffer */
01373       if (l->linklist[0])
01374       {
01375          snprintf(buf + spos,MAXLINKLIST - spos,
01376             "%c%s,%s",mode,l->name,l->linklist);
01377       }
01378       else /* if no nodes, add this node into buffer */
01379       {
01380          snprintf(buf + spos,MAXLINKLIST - spos,
01381             "%c%s",mode,l->name);
01382       }
01383       /* if we are in tranceive mode, let all modes stand */
01384       if (mode == 'T') continue;
01385       /* downgrade everyone on this node if appropriate */
01386       for(i = spos; buf[i]; i++)
01387       {
01388          if (buf[i] == 'T') buf[i] = mode;
01389          if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
01390       }
01391    }
01392    return;
01393 }
01394 
01395 /* must be called locked */
01396 static void __kickshort(struct rpt *myrpt)
01397 {
01398 struct rpt_link *l;
01399 
01400    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01401    {
01402       /* if is not a real link, ignore it */
01403       if (l->name[0] == '0') continue;
01404       l->linklisttimer = LINKLISTSHORTTIME;
01405    }
01406    return;
01407 }
01408 
01409 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
01410 {
01411 
01412 char *val;
01413 int longestnode,j;
01414 struct stat mystat;
01415 static time_t last = 0;
01416 static struct ast_config *ourcfg = NULL;
01417 struct ast_variable *vp;
01418 
01419    /* try to look it up locally first */
01420    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
01421    if (val) return(val);
01422    ast_mutex_lock(&nodelookuplock);
01423    /* if file does not exist */
01424    if (stat(myrpt->p.extnodefile,&mystat) == -1)
01425    {
01426       if (ourcfg) ast_config_destroy(ourcfg);
01427       ourcfg = NULL;
01428       ast_mutex_unlock(&nodelookuplock);
01429       return(NULL);
01430    }
01431    /* if we need to reload */
01432    if (mystat.st_mtime > last)
01433    {
01434       if (ourcfg) ast_config_destroy(ourcfg);
01435       ourcfg = ast_config_load(myrpt->p.extnodefile);
01436       /* if file not there, just bail */
01437       if (!ourcfg)
01438       {
01439          ast_mutex_unlock(&nodelookuplock);
01440          return(NULL);
01441       }
01442       /* reset "last" time */
01443       last = mystat.st_mtime;
01444 
01445       /* determine longest node length again */    
01446       longestnode = 0;
01447       vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
01448       while(vp){
01449          j = strlen(vp->name);
01450          if (j > longestnode)
01451             longestnode = j;
01452          vp = vp->next;
01453       }
01454 
01455       vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
01456       while(vp){
01457          j = strlen(vp->name);
01458          if (j > longestnode)
01459             longestnode = j;
01460          vp = vp->next;
01461       }
01462 
01463       myrpt->longestnode = longestnode;
01464    }
01465    val = NULL;
01466    if (ourcfg)
01467       val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
01468    ast_mutex_unlock(&nodelookuplock);
01469    return(val);
01470 }
01471 
01472 /*
01473 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
01474 * If param is passed in non-null, then it will be set to the first character past the match
01475 */
01476 
01477 static int matchkeyword(char *string, char **param, char *keywords[])
01478 {
01479 int   i,ls;
01480    for( i = 0 ; keywords[i] ; i++){
01481       ls = strlen(keywords[i]);
01482       if(!ls){
01483          *param = NULL;
01484          return 0;
01485       }
01486       if(!strncmp(string, keywords[i], ls)){
01487          if(param)
01488             *param = string + ls;
01489          return i + 1; 
01490       }
01491    }
01492    param = NULL;
01493    return 0;
01494 }
01495 
01496 /*
01497 * Skip characters in string which are in charlist, and return a pointer to the
01498 * first non-matching character
01499 */
01500 
01501 static char *skipchars(char *string, char *charlist)
01502 {
01503 int i;   
01504    while(*string){
01505       for(i = 0; charlist[i] ; i++){
01506          if(*string == charlist[i]){
01507             string++;
01508             break;
01509          }
01510       }
01511       if(!charlist[i])
01512          return string;
01513    }
01514    return string;
01515 }  
01516                
01517 
01518 
01519 static int myatoi(char *str)
01520 {
01521 int   ret;
01522 
01523    if (str == NULL) return -1;
01524    /* leave this %i alone, non-base-10 input is useful here */
01525    if (sscanf(str,"%30i",&ret) != 1) return -1;
01526    return ret;
01527 }
01528 
01529 static int mycompar(const void *a, const void *b)
01530 {
01531 char  **x = (char **) a;
01532 char  **y = (char **) b;
01533 int   xoff,yoff;
01534 
01535    if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
01536    if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
01537    return(strcmp((*x) + xoff,(*y) + yoff));
01538 }
01539 
01540 #ifdef   __RPT_NOTCH
01541 
01542 /* rpt filter routine */
01543 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
01544 {
01545 int   i,j;
01546 struct   rptfilter *f;
01547 
01548    for(i = 0; i < len; i++)
01549    {
01550       for(j = 0; j < MAXFILTERS; j++)
01551       {
01552          f = &myrpt->filters[j];
01553          if (!*f->desc) continue;
01554          f->x0 = f->x1; f->x1 = f->x2;
01555               f->x2 = ((float)buf[i]) / f->gain;
01556               f->y0 = f->y1; f->y1 = f->y2;
01557               f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
01558                            + (f->const1 * f->y0) + (f->const2 * f->y1);
01559          buf[i] = (short)f->y2;
01560       }
01561    }
01562 }
01563 
01564 #endif
01565 
01566 
01567 /*
01568  Get the time for the machine's time zone
01569  Note: Asterisk requires a copy of localtime
01570  in the /etc directory for this to work properly.
01571  If /etc/localtime is not present, you will get
01572  GMT time! This is especially important on systems
01573  running embedded linux distributions as they don't usually
01574  have support for locales. 
01575 
01576  If OLD_ASTERISK is defined, then the older localtime_r
01577  function will be used. The /etc/localtime file is not
01578  required in this case. This provides backward compatibility
01579  with Asterisk 1.2 systems.
01580 
01581 */
01582 
01583 static void rpt_localtime( time_t * t, struct tm *lt)
01584 {
01585 #ifdef OLD_ASTERISK
01586    localtime_r(t, lt);
01587 #else
01588    ast_localtime(t, lt, NULL);
01589 #endif
01590 }
01591 
01592 /* Retrieve an int from a config file */
01593                                                                                 
01594 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
01595 {
01596         char *var;
01597         int ret;
01598    char include_zero = 0;
01599 
01600    if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
01601       min = -min;
01602       include_zero = 1;
01603    }           
01604                                                                      
01605         var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
01606         if(var){
01607                 ret = myatoi(var);
01608       if(include_zero && !ret)
01609          return 0;
01610                 if(ret < min)
01611                         ret = min;
01612                 if(ret > max)
01613                         ret = max;
01614         }
01615         else
01616                 ret = defl;
01617         return ret;
01618 }
01619 
01620 
01621 static void load_rpt_vars(int n,int init)
01622 {
01623 char *this,*val;
01624 int   i,j,longestnode;
01625 struct ast_variable *vp;
01626 struct ast_config *cfg;
01627 char *strs[100];
01628 char s1[256];
01629 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
01630             "ufena","ufdis","atena","atdis",NULL};
01631 
01632    if (option_verbose > 2)
01633       ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
01634          (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
01635    ast_mutex_lock(&rpt_vars[n].lock);
01636    if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
01637    cfg = ast_config_load("rpt.conf");
01638    if (!cfg) {
01639       ast_mutex_unlock(&rpt_vars[n].lock);
01640       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
01641       pthread_exit(NULL);
01642    }
01643    rpt_vars[n].cfg = cfg; 
01644    this = rpt_vars[n].name;
01645    memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
01646    if (init)
01647    {
01648       /* clear all the fields in the structure after 'p' */
01649       memset(&rpt_vars[n].p + sizeof(rpt_vars[0].p), 0, sizeof(rpt_vars[0]) - sizeof(rpt_vars[0].p) - offsetof(typeof(rpt_vars[0]), p));
01650       rpt_vars[n].tele.next = &rpt_vars[n].tele;
01651       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
01652       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
01653       rpt_vars[n].tailmessagen = 0;
01654    }
01655 #ifdef   __RPT_NOTCH
01656    /* zot out filters stuff */
01657    memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
01658 #endif
01659    val = (char *) ast_variable_retrieve(cfg,this,"context");
01660    if (val) rpt_vars[n].p.ourcontext = val;
01661    else rpt_vars[n].p.ourcontext = this;
01662    val = (char *) ast_variable_retrieve(cfg,this,"callerid");
01663    if (val) rpt_vars[n].p.ourcallerid = val;
01664    val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
01665    if (val) rpt_vars[n].p.acctcode = val;
01666    val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
01667    if (val) rpt_vars[n].p.ident = val;
01668    val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
01669    if (val) rpt_vars[n].p.hangtime = atoi(val);
01670       else rpt_vars[n].p.hangtime = HANGTIME;
01671    val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
01672    if (val) rpt_vars[n].p.althangtime = atoi(val);
01673       else rpt_vars[n].p.althangtime = HANGTIME;
01674    val = (char *) ast_variable_retrieve(cfg,this,"totime");
01675    if (val) rpt_vars[n].p.totime = atoi(val);
01676       else rpt_vars[n].p.totime = TOTIME;
01677    rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);    
01678    rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);     
01679    rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
01680    rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME);   /* Enforce a min max including zero */
01681    rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
01682    val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
01683    if (val) rpt_vars[n].p.tonezone = val;
01684    rpt_vars[n].p.tailmessages[0] = 0;
01685    rpt_vars[n].p.tailmessagemax = 0;
01686    val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
01687    if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
01688    val = (char *) ast_variable_retrieve(cfg,this,"memory");
01689    if (!val) val = MEMORY;
01690    rpt_vars[n].p.memory = val;
01691    val = (char *) ast_variable_retrieve(cfg,this,"macro");
01692    if (!val) val = MACRO;
01693    rpt_vars[n].p.macro = val;
01694    val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
01695    if (val) rpt_vars[n].p.startupmacro = val;
01696    val = (char *) ast_variable_retrieve(cfg,this,"iobase");
01697    /* do not use atoi() here, we need to be able to have
01698       the input specified in hex or decimal so we use
01699       sscanf with a %i */
01700    if ((!val) || (sscanf(val,"%30i",&rpt_vars[n].p.iobase) != 1))
01701    rpt_vars[n].p.iobase = DEFAULT_IOBASE;
01702    val = (char *) ast_variable_retrieve(cfg,this,"ioport");
01703    rpt_vars[n].p.ioport = val;
01704    val = (char *) ast_variable_retrieve(cfg,this,"functions");
01705    if (!val)
01706       {
01707          val = FUNCTIONS;
01708          rpt_vars[n].p.simple = 1;
01709       } 
01710    rpt_vars[n].p.functions = val;
01711    val =  (char *) ast_variable_retrieve(cfg,this,"link_functions");
01712    if (val) rpt_vars[n].p.link_functions = val;
01713    else 
01714       rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
01715    val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
01716    if (val) rpt_vars[n].p.phone_functions = val;
01717    val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
01718    if (val) rpt_vars[n].p.dphone_functions = val;
01719    val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
01720    if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
01721       rpt_vars[n].p.funcchar = *val;      
01722    val = (char *) ast_variable_retrieve(cfg,this,"endchar");
01723    if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
01724       rpt_vars[n].p.endchar = *val;    
01725    val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
01726    if (val) rpt_vars[n].p.nobusyout = ast_true(val);
01727    val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
01728    if (val) rpt_vars[n].p.notelemtx = ast_true(val);
01729    val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
01730    if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
01731    val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
01732    if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
01733    val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
01734    if (val) rpt_vars[n].p.linktolink = ast_true(val);
01735    val = (char *) ast_variable_retrieve(cfg,this,"nodes");
01736    if (!val) val = NODES;
01737    rpt_vars[n].p.nodes = val;
01738    val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
01739    if (!val) val = EXTNODES;
01740    rpt_vars[n].p.extnodes = val;
01741    val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
01742    if (!val) val = EXTNODEFILE;
01743    rpt_vars[n].p.extnodefile = val;
01744    val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
01745    if (val) rpt_vars[n].p.archivedir = val;
01746    val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
01747    if (val) rpt_vars[n].p.authlevel = atoi(val); 
01748    else rpt_vars[n].p.authlevel = 0;
01749    val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
01750    if (val) rpt_vars[n].p.monminblocks = atol(val); 
01751    else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
01752    val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
01753    if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); 
01754    else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
01755    val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
01756    if (val) rpt_vars[n].p.civaddr = atoi(val); 
01757    else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
01758    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
01759    if (val) rpt_vars[n].p.remotetimeout = atoi(val); 
01760    else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
01761    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
01762    if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); 
01763    else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
01764    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
01765    if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); 
01766    else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
01767 #ifdef   __RPT_NOTCH
01768    val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
01769    if (val) {
01770       i = finddelim(val,strs,MAXFILTERS * 2);
01771       i &= ~1; /* force an even number, rounded down */
01772       if (i >= 2) for(j = 0; j < i; j += 2)
01773       {
01774          rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
01775            &rpt_vars[n].filters[j >> 1].gain,
01776              &rpt_vars[n].filters[j >> 1].const0,
01777             &rpt_vars[n].filters[j >> 1].const1,
01778                 &rpt_vars[n].filters[j >> 1].const2);
01779          sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
01780             strs[j],strs[j + 1]);
01781       }
01782 
01783    }
01784 #endif
01785    val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
01786    if (val) {
01787       memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
01788       i = finddelim(val,strs,3);
01789       if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
01790       if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
01791       if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
01792    }
01793    val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
01794    if (val) {
01795       memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
01796       i = finddelim(val,strs,3);
01797       if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
01798       if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
01799       if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
01800    }
01801    /* retreive the stanza name for the control states if there is one */
01802    val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
01803    rpt_vars[n].p.csstanzaname = val;
01804       
01805    /* retreive the stanza name for the scheduler if there is one */
01806    val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
01807    rpt_vars[n].p.skedstanzaname = val;
01808 
01809    /* retreive the stanza name for the txlimits */
01810    val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
01811    rpt_vars[n].p.txlimitsstanzaname = val;
01812 
01813    longestnode = 0;
01814 
01815    vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
01816       
01817    while(vp){
01818       j = strlen(vp->name);
01819       if (j > longestnode)
01820          longestnode = j;
01821       vp = vp->next;
01822    }
01823 
01824    rpt_vars[n].longestnode = longestnode;
01825       
01826    /*
01827    * For this repeater, Determine the length of the longest function 
01828    */
01829    rpt_vars[n].longestfunc = 0;
01830    vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
01831    while(vp){
01832       j = strlen(vp->name);
01833       if (j > rpt_vars[n].longestfunc)
01834          rpt_vars[n].longestfunc = j;
01835       vp = vp->next;
01836    }
01837    /*
01838    * For this repeater, Determine the length of the longest function 
01839    */
01840    rpt_vars[n].link_longestfunc = 0;
01841    vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
01842    while(vp){
01843       j = strlen(vp->name);
01844       if (j > rpt_vars[n].link_longestfunc)
01845          rpt_vars[n].link_longestfunc = j;
01846       vp = vp->next;
01847    }
01848    rpt_vars[n].phone_longestfunc = 0;
01849    if (rpt_vars[n].p.phone_functions)
01850    {
01851       vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
01852       while(vp){
01853          j = strlen(vp->name);
01854          if (j > rpt_vars[n].phone_longestfunc)
01855             rpt_vars[n].phone_longestfunc = j;
01856          vp = vp->next;
01857       }
01858    }
01859    rpt_vars[n].dphone_longestfunc = 0;
01860    if (rpt_vars[n].p.dphone_functions)
01861    {
01862       vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
01863       while(vp){
01864          j = strlen(vp->name);
01865          if (j > rpt_vars[n].dphone_longestfunc)
01866             rpt_vars[n].dphone_longestfunc = j;
01867          vp = vp->next;
01868       }
01869    }
01870    rpt_vars[n].macro_longest = 1;
01871    vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
01872    while(vp){
01873       j = strlen(vp->name);
01874       if (j > rpt_vars[n].macro_longest)
01875          rpt_vars[n].macro_longest = j;
01876       vp = vp->next;
01877    }
01878    
01879    /* Browse for control states */
01880    if(rpt_vars[n].p.csstanzaname)
01881       vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
01882    else
01883       vp = NULL;
01884    for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
01885       int k,nukw,statenum;
01886       statenum=atoi(vp->name);
01887       strncpy(s1, vp->value, 255);
01888       s1[255] = 0;
01889       nukw  = finddelim(s1,strs,32);
01890       
01891       for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */  
01892          for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
01893             if(!strcmp(strs[k],cs_keywords[j])){
01894                switch(j){
01895                   case 0: /* rptena */
01896                      rpt_vars[n].p.s[statenum].txdisable = 0;
01897                      break;
01898                   case 1: /* rptdis */
01899                      rpt_vars[n].p.s[statenum].txdisable = 1;
01900                      break;
01901          
01902                   case 2: /* apena */
01903                      rpt_vars[n].p.s[statenum].autopatchdisable = 0;
01904                      break;
01905 
01906                   case 3: /* apdis */
01907                      rpt_vars[n].p.s[statenum].autopatchdisable = 1;
01908                      break;
01909 
01910                   case 4: /* lnkena */
01911                      rpt_vars[n].p.s[statenum].linkfundisable = 0;
01912                      break;
01913    
01914                   case 5: /* lnkdis */
01915                      rpt_vars[n].p.s[statenum].linkfundisable = 1;
01916                      break;
01917 
01918                   case 6: /* totena */
01919                      rpt_vars[n].p.s[statenum].totdisable = 0;
01920                      break;
01921                
01922                   case 7: /* totdis */
01923                      rpt_vars[n].p.s[statenum].totdisable = 1;
01924                      break;
01925 
01926                   case 8: /* skena */
01927                      rpt_vars[n].p.s[statenum].schedulerdisable = 0;
01928                      break;
01929 
01930                   case 9: /* skdis */
01931                      rpt_vars[n].p.s[statenum].schedulerdisable = 1;
01932                      break;
01933 
01934                   case 10: /* ufena */
01935                      rpt_vars[n].p.s[statenum].userfundisable = 0;
01936                      break;
01937 
01938                   case 11: /* ufdis */
01939                      rpt_vars[n].p.s[statenum].userfundisable = 1;
01940                      break;
01941 
01942                   case 12: /* atena */
01943                      rpt_vars[n].p.s[statenum].alternatetail = 1;
01944                      break;
01945 
01946                   case 13: /* atdis */
01947                      rpt_vars[n].p.s[statenum].alternatetail = 0;
01948                      break;
01949          
01950                   default:
01951                      ast_log(LOG_WARNING,
01952                         "Unhandled control state keyword %s", cs_keywords[i]);
01953                      break;
01954                }
01955             }
01956          }
01957       }
01958       vp = vp->next;
01959    }
01960    ast_mutex_unlock(&rpt_vars[n].lock);
01961 }
01962 
01963 /*
01964 * Enable or disable debug output at a given level at the console
01965 */
01966                                                                                                                                  
01967 static int rpt_do_debug(int fd, int argc, char *argv[])
01968 {
01969    int newlevel;
01970 
01971         if (argc != 4)
01972                 return RESULT_SHOWUSAGE;
01973         newlevel = myatoi(argv[3]);
01974         if((newlevel < 0) || (newlevel > 7))
01975                 return RESULT_SHOWUSAGE;
01976         if(newlevel)
01977                 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
01978         else
01979                 ast_cli(fd, "app_rpt Debugging disabled\n");
01980 
01981         debug = newlevel;                                                                                                                          
01982         return RESULT_SUCCESS;
01983 }
01984 
01985 /*
01986 * Dump rpt struct debugging onto console
01987 */
01988                                                                                                                                  
01989 static int rpt_do_dump(int fd, int argc, char *argv[])
01990 {
01991    int i;
01992 
01993         if (argc != 3)
01994                 return RESULT_SHOWUSAGE;
01995 
01996    for(i = 0; i < nrpts; i++)
01997    {
01998       if (!strcmp(argv[2],rpt_vars[i].name))
01999       {
02000          rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
02001               ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
02002               return RESULT_SUCCESS;
02003       }
02004    }
02005    return RESULT_FAILURE;
02006 }
02007 
02008 /*
02009 * Dump statistics onto console
02010 */
02011 
02012 static int rpt_do_stats(int fd, int argc, char *argv[])
02013 {
02014    int i,j;
02015    int dailytxtime, dailykerchunks;
02016    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
02017    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
02018    long long totaltxtime;
02019    struct   rpt_link *l;
02020    char *listoflinks[MAX_STAT_LINKS];  
02021    char *lastnodewhichkeyedusup, *lastdtmfcommand;
02022    char *tot_state, *ider_state, *patch_state;
02023    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
02024    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
02025    struct rpt *myrpt;
02026 
02027    static char *not_applicable = "N/A";
02028 
02029    if(argc != 3)
02030       return RESULT_SHOWUSAGE;
02031 
02032    for(i = 0 ; i < MAX_STAT_LINKS; i++)
02033       listoflinks[i] = NULL;
02034 
02035    tot_state = ider_state = 
02036    patch_state = reverse_patch_state = 
02037    input_signal = called_number = 
02038    lastdtmfcommand = not_applicable;
02039 
02040    for(i = 0; i < nrpts; i++)
02041    {
02042       if (!strcmp(argv[2],rpt_vars[i].name)){
02043          /* Make a copy of all stat variables while locked */
02044          myrpt = &rpt_vars[i];
02045          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02046 
02047          dailytxtime = myrpt->dailytxtime;
02048          totaltxtime = myrpt->totaltxtime;
02049          dailykeyups = myrpt->dailykeyups;
02050          totalkeyups = myrpt->totalkeyups;
02051          dailykerchunks = myrpt->dailykerchunks;
02052          totalkerchunks = myrpt->totalkerchunks;
02053          dailyexecdcommands = myrpt->dailyexecdcommands;
02054          totalexecdcommands = myrpt->totalexecdcommands;
02055          timeouts = myrpt->timeouts;
02056 
02057          /* Traverse the list of connected nodes */
02058          reverse_patch_state = "DOWN";
02059          j = 0;
02060          l = myrpt->links.next;
02061          while(l && (l != &myrpt->links)){
02062             if (l->name[0] == '0'){ /* Skip '0' nodes */
02063                reverse_patch_state = "UP";
02064                l = l->next;
02065                continue;
02066             }
02067             listoflinks[j] = ast_strdupa(l->name);
02068             if(listoflinks[j])
02069                j++;
02070             l = l->next;
02071          }
02072 
02073          lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);       
02074          if((!lastnodewhichkeyedusup) || (!strlen(lastnodewhichkeyedusup)))
02075             lastnodewhichkeyedusup = not_applicable;
02076 
02077          if(myrpt->keyed)
02078             input_signal = "YES";
02079          else
02080             input_signal = "NO";
02081 
02082          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
02083             sys_ena = "DISABLED";
02084          else
02085             sys_ena = "ENABLED";
02086 
02087          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
02088             tot_ena = "DISABLED";
02089          else
02090             tot_ena = "ENABLED";
02091 
02092          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
02093             link_ena = "DISABLED";
02094          else
02095             link_ena = "ENABLED";
02096 
02097          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
02098             patch_ena = "DISABLED";
02099          else
02100             patch_ena = "ENABLED";
02101 
02102          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
02103             sch_ena = "DISABLED";
02104          else
02105             sch_ena = "ENABLED";
02106 
02107          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
02108             user_funs = "DISABLED";
02109          else
02110             user_funs = "ENABLED";
02111 
02112          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
02113             tail_type = "ALTERNATE";
02114          else
02115             tail_type = "STANDARD";
02116 
02117          if(!myrpt->totimer)
02118             tot_state = "TIMED OUT!";
02119          else if(myrpt->totimer != myrpt->p.totime)
02120             tot_state = "ARMED";
02121          else
02122             tot_state = "RESET";
02123 
02124          if(myrpt->tailid)
02125             ider_state = "QUEUED IN TAIL";
02126          else if(myrpt->mustid)
02127             ider_state = "QUEUED FOR CLEANUP";
02128          else
02129             ider_state = "CLEAN";
02130 
02131          switch(myrpt->callmode){
02132             case 1:
02133                patch_state = "DIALING";
02134                break;
02135             case 2:
02136                patch_state = "CONNECTING";
02137                break;
02138             case 3:
02139                patch_state = "UP";
02140                break;
02141 
02142             case 4:
02143                patch_state = "CALL FAILED";
02144                break;
02145 
02146             default:
02147                patch_state = "DOWN";
02148          }
02149 
02150          if(strlen(myrpt->exten)){
02151             called_number = ast_strdupa(myrpt->exten);
02152             if(!called_number)
02153                called_number = not_applicable;
02154          }
02155 
02156          if(strlen(myrpt->lastdtmfcommand)){
02157             lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
02158             if(!lastdtmfcommand)
02159                lastdtmfcommand = not_applicable;
02160          }
02161 
02162          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02163 
02164          ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
02165          ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
02166          ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
02167          ast_cli(fd, "System...........................................: %s\n", sys_ena);
02168          ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
02169          ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
02170          ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
02171          ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
02172          ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
02173          ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
02174          ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
02175          ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
02176          ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
02177          ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
02178          ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
02179          ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
02180          ast_cli(fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
02181          hours = dailytxtime/3600000;
02182          dailytxtime %= 3600000;
02183          minutes = dailytxtime/60000;
02184          dailytxtime %= 60000;
02185          seconds = dailytxtime/1000;
02186          dailytxtime %= 1000;
02187 
02188          ast_cli(fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
02189             hours, minutes, seconds, dailytxtime);
02190 
02191          hours = (int) totaltxtime/3600000;
02192          totaltxtime %= 3600000;
02193          minutes = (int) totaltxtime/60000;
02194          totaltxtime %= 60000;
02195          seconds = (int)  totaltxtime/1000;
02196          totaltxtime %= 1000;
02197 
02198          ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
02199              hours, minutes, seconds, (int) totaltxtime);
02200          ast_cli(fd, "Nodes currently connected to us..................: ");
02201          for(j = 0 ;; j++){
02202             if(!listoflinks[j]){
02203                if(!j){
02204                   ast_cli(fd,"<NONE>");
02205                }
02206                break;
02207             }
02208             ast_cli(fd, "%s", listoflinks[j]);
02209             if(j % 4 == 3){
02210                ast_cli(fd, "\n");
02211                ast_cli(fd, "                                                 : ");
02212             }
02213             else{
02214                if(listoflinks[j + 1])
02215                   ast_cli(fd, ", ");
02216             }
02217          }
02218          ast_cli(fd,"\n");
02219 
02220          ast_cli(fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
02221          ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
02222          ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
02223          ast_cli(fd, "Autopatch called number..........................: %s\n", called_number);
02224          ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
02225          ast_cli(fd, "User linking commands............................: %s\n", link_ena);
02226          ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
02227               return RESULT_SUCCESS;
02228       }
02229    }
02230    return RESULT_FAILURE;
02231 }
02232 
02233 /*
02234 * Link stats function
02235 */
02236 
02237 static int rpt_do_lstats(int fd, int argc, char *argv[])
02238 {
02239    int i,j;
02240    char *connstate;
02241    struct rpt *myrpt;
02242    struct rpt_link *l;
02243    struct rpt_lstat *s,*t;
02244    struct rpt_lstat s_head;
02245    if(argc != 3)
02246       return RESULT_SHOWUSAGE;
02247 
02248    s = NULL;
02249    s_head.next = &s_head;
02250    s_head.prev = &s_head;
02251 
02252    for(i = 0; i < nrpts; i++)
02253    {
02254       if (!strcmp(argv[2],rpt_vars[i].name)){
02255          /* Make a copy of all stat variables while locked */
02256          myrpt = &rpt_vars[i];
02257          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02258          /* Traverse the list of connected nodes */
02259          j = 0;
02260          l = myrpt->links.next;
02261          while(l && (l != &myrpt->links)){
02262             if (l->name[0] == '0'){ /* Skip '0' nodes */
02263                l = l->next;
02264                continue;
02265             }
02266             if((s = (struct rpt_lstat *) malloc(sizeof(struct rpt_lstat))) == NULL){
02267                ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
02268                rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02269                return RESULT_FAILURE;
02270             }
02271             memset(s, 0, sizeof(struct rpt_lstat));
02272             strncpy(s->name, l->name, MAXREMSTR - 1);
02273             if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
02274             else strcpy(s->peer,"(none)");
02275             s->mode = l->mode;
02276             s->outbound = l->outbound;
02277             s->reconnects = l->reconnects;
02278             s->connecttime = l->connecttime;
02279             s->thisconnected = l->thisconnected;
02280             memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
02281             insque((struct qelem *) s, (struct qelem *) s_head.next);
02282             memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
02283             l = l->next;
02284          }
02285          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02286          ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME        CONNECT STATE\n");
02287          ast_cli(fd, "----      ----                ----------  ---------  ------------        -------------\n");
02288 
02289          for(s = s_head.next; s != &s_head; s = s->next){
02290             int hours, minutes, seconds;
02291             long long connecttime = s->connecttime;
02292             char conntime[21];
02293             hours = (int) connecttime/3600000;
02294             connecttime %= 3600000;
02295             minutes = (int) connecttime/60000;
02296             connecttime %= 60000;
02297             seconds = (int)  connecttime/1000;
02298             connecttime %= 1000;
02299             snprintf(conntime, 20, "%02d:%02d:%02d.%d",
02300                hours, minutes, seconds, (int) connecttime);
02301             conntime[20] = 0;
02302             if(s->thisconnected)
02303                connstate  = "ESTABLISHED";
02304             else
02305                connstate = "CONNECTING";
02306             ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
02307                s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
02308          }  
02309          /* destroy our local link queue */
02310          s = s_head.next;
02311          while(s != &s_head){
02312             t = s;
02313             s = s->next;
02314             remque((struct qelem *)t);
02315             free(t);
02316          }        
02317          return RESULT_SUCCESS;
02318       }
02319    }
02320    return RESULT_FAILURE;
02321 }
02322 
02323 /*
02324 * List all nodes connected, directly or indirectly
02325 */
02326 
02327 static int rpt_do_nodes(int fd, int argc, char *argv[])
02328 {
02329    int i,j;
02330    char ns;
02331    char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
02332    struct rpt *myrpt;
02333    if(argc != 3)
02334       return RESULT_SHOWUSAGE;
02335 
02336    for(i = 0; i < nrpts; i++)
02337    {
02338       if (!strcmp(argv[2],rpt_vars[i].name)){
02339          /* Make a copy of all stat variables while locked */
02340          myrpt = &rpt_vars[i];
02341          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02342          __mklinklist(myrpt,NULL,lbuf);
02343          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02344          /* parse em */
02345          ns = finddelim(lbuf,strs,MAXLINKLIST);
02346          /* sort em */
02347          if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
02348          ast_cli(fd,"\n");
02349          ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
02350          for(j = 0 ;; j++){
02351             if(!strs[j]){
02352                if(!j){
02353                   ast_cli(fd,"<NONE>");
02354                }
02355                break;
02356             }
02357             ast_cli(fd, "%s", strs[j]);
02358             if(j % 8 == 7){
02359                ast_cli(fd, "\n");
02360             }
02361             else{
02362                if(strs[j + 1])
02363                   ast_cli(fd, ", ");
02364             }
02365          }
02366          ast_cli(fd,"\n\n");
02367          return RESULT_SUCCESS;
02368       }
02369    }
02370    return RESULT_FAILURE;
02371 }
02372 
02373 /*
02374 * reload vars 
02375 */
02376 
02377 static int rpt_do_reload(int fd, int argc, char *argv[])
02378 {
02379 int   n;
02380 
02381         if (argc > 2) return RESULT_SHOWUSAGE;
02382 
02383    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
02384 
02385    return RESULT_FAILURE;
02386 }
02387 
02388 /*
02389 * restart app_rpt
02390 */
02391                                                                                                                                  
02392 static int rpt_do_restart(int fd, int argc, char *argv[])
02393 {
02394 int   i;
02395 
02396         if (argc > 2) return RESULT_SHOWUSAGE;
02397    for(i = 0; i < nrpts; i++)
02398    {
02399       if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
02400    }
02401    return RESULT_FAILURE;
02402 }
02403 
02404 
02405 /*
02406 * send an app_rpt DTMF function from the CLI
02407 */
02408                                                                                                                                  
02409 static int rpt_do_fun(int fd, int argc, char *argv[])
02410 {
02411    int   i,busy=0;
02412 
02413         if (argc != 4) return RESULT_SHOWUSAGE;
02414 
02415    for(i = 0; i < nrpts; i++){
02416       if(!strcmp(argv[2], rpt_vars[i].name)){
02417          struct rpt *myrpt = &rpt_vars[i];
02418          rpt_mutex_lock(&myrpt->lock);
02419          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
02420             rpt_mutex_unlock(&myrpt->lock);
02421             busy=1;
02422          }
02423          if(!busy){
02424             myrpt->macrotimer = MACROTIME;
02425             strncat(myrpt->macrobuf, argv[3], MAXMACRO - strlen(myrpt->macrobuf) - 1);
02426          }
02427          rpt_mutex_unlock(&myrpt->lock);
02428       }
02429    }
02430    if(busy){
02431       ast_cli(fd, "Function decoder busy");
02432    }
02433    return RESULT_FAILURE;
02434 }
02435 
02436 
02437 
02438 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
02439 {
02440    int res;
02441 
02442         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
02443                 return res;
02444                                                                                                                                             
02445         while(chan->generatordata) {
02446       if (ast_safe_sleep(chan,1)) return -1;
02447    }
02448 
02449         return 0;
02450 }
02451 
02452 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
02453 {
02454    return play_tone_pair(chan, freq, 0, duration, amplitude);
02455 }
02456 
02457 static int play_silence(struct ast_channel *chan, int duration)
02458 {
02459    return play_tone_pair(chan, 0, 0, duration, 0);
02460 }
02461 
02462 
02463 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
02464 {
02465 
02466 static struct morse_bits mbits[] = {
02467       {0, 0}, /* SPACE */
02468       {0, 0}, 
02469       {6, 18},/* " */
02470       {0, 0},
02471       {7, 72},/* $ */
02472       {0, 0},
02473       {0, 0},
02474       {6, 30},/* ' */
02475       {5, 13},/* ( */
02476       {6, 29},/* ) */
02477       {0, 0},
02478       {5, 10},/* + */
02479       {6, 51},/* , */
02480       {6, 33},/* - */
02481       {6, 42},/* . */
02482       {5, 9}, /* / */
02483       {5, 31},/* 0 */
02484       {5, 30},/* 1 */
02485       {5, 28},/* 2 */
02486       {5, 24},/* 3 */
02487       {5, 16},/* 4 */
02488       {5, 0}, /* 5 */
02489       {5, 1}, /* 6 */
02490       {5, 3}, /* 7 */
02491       {5, 7}, /* 8 */
02492       {5, 15},/* 9 */
02493       {6, 7}, /* : */
02494       {6, 21},/* ; */
02495       {0, 0},
02496       {5, 33},/* = */
02497       {0, 0},
02498       {6, 12},/* ? */
02499       {0, 0},
02500          {2, 2}, /* A */
02501       {4, 1}, /* B */
02502       {4, 5}, /* C */
02503       {3, 1}, /* D */
02504       {1, 0}, /* E */
02505       {4, 4}, /* F */
02506       {3, 3}, /* G */
02507       {4, 0}, /* H */
02508       {2, 0}, /* I */
02509       {4, 14},/* J */
02510       {3, 5}, /* K */
02511       {4, 2}, /* L */
02512       {2, 3}, /* M */
02513       {2, 1}, /* N */
02514       {3, 7}, /* O */
02515       {4, 6}, /* P */
02516       {4, 11},/* Q */
02517       {3, 2}, /* R */
02518       {3, 0}, /* S */
02519       {1, 1}, /* T */
02520       {3, 4}, /* U */
02521       {4, 8}, /* V */
02522       {3, 6}, /* W */
02523       {4, 9}, /* X */
02524       {4, 13},/* Y */
02525       {4, 3}  /* Z */
02526    };
02527 
02528 
02529    int dottime;
02530    int dashtime;
02531    int intralettertime;
02532    int interlettertime;
02533    int interwordtime;
02534    int len, ddcomb;
02535    int res;
02536    int c;
02537    int i;
02538    int flags;
02539          
02540    res = 0;
02541    
02542    /* Approximate the dot time from the speed arg. */
02543    
02544    dottime = 900/speed;
02545    
02546    /* Establish timing releationships */
02547    
02548    dashtime = 3 * dottime;
02549    intralettertime = dottime;
02550    interlettertime = dottime * 4 ;
02551    interwordtime = dottime * 7;
02552    
02553    for(;(*string) && (!res); string++){
02554    
02555       c = *string;
02556       
02557       /* Convert lower case to upper case */
02558       
02559       if((c >= 'a') && (c <= 'z'))
02560          c -= 0x20;
02561       
02562       /* Can't deal with any char code greater than Z, skip it */
02563       
02564       if(c  > 'Z')
02565          continue;
02566       
02567       /* If space char, wait the inter word time */
02568                
02569       if(c == ' '){
02570          if(!res)
02571             res = play_silence(chan, interwordtime);
02572          continue;
02573       }
02574       
02575       /* Subtract out control char offset to match our table */
02576       
02577       c -= 0x20;
02578       
02579       /* Get the character data */
02580       
02581       len = mbits[c].len;
02582       ddcomb = mbits[c].ddcomb;
02583       
02584       /* Send the character */
02585       
02586       for(; len ; len--){
02587          if(!res)
02588             res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
02589          if(!res)
02590             res = play_silence(chan, intralettertime);
02591          ddcomb >>= 1;
02592       }
02593       
02594       /* Wait the interletter time */
02595       
02596       if(!res)
02597          res = play_silence(chan, interlettertime - intralettertime);
02598    }
02599    
02600    /* Wait for all the frames to be sent */
02601    
02602    if (!res) 
02603       res = ast_waitstream(chan, "");
02604    ast_stopstream(chan);
02605    
02606    /*
02607    * Wait for the zaptel driver to physically write the tone blocks to the hardware
02608    */
02609 
02610    for(i = 0; i < 20 ; i++){
02611       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
02612       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
02613       if(flags & DAHDI_IOMUX_WRITEEMPTY)
02614          break;
02615       if( ast_safe_sleep(chan, 50)){
02616          res = -1;
02617          break;
02618       }
02619    }
02620 
02621    
02622    return res;
02623 }
02624 
02625 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
02626 {
02627    char *stringp;
02628    char *tonesubset;
02629    int f1,f2;
02630    int duration;
02631    int amplitude;
02632    int res;
02633    int i;
02634    int flags;
02635    
02636    res = 0;
02637    
02638    stringp = ast_strdupa(tonestring);
02639 
02640    for(;tonestring;){
02641       tonesubset = strsep(&stringp,")");
02642       if(!tonesubset)
02643          break;
02644       if(sscanf(tonesubset,"(%30d,%30d,%30d,%30d", &f1, &f2, &duration, &amplitude) != 4)
02645          break;
02646       res = play_tone_pair(chan, f1, f2, duration, amplitude);
02647       if(res)
02648          break;
02649    }
02650    if(!res)
02651       res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
02652    
02653    if (!res) 
02654       res = ast_waitstream(chan, "");
02655    ast_stopstream(chan);
02656 
02657    /*
02658    * Wait for the zaptel driver to physically write the tone blocks to the hardware
02659    */
02660 
02661    for(i = 0; i < 20 ; i++){
02662       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
02663       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
02664       if(flags & DAHDI_IOMUX_WRITEEMPTY)
02665          break;
02666       if( ast_safe_sleep(chan, 50)){
02667          res = -1;
02668          break;
02669       }
02670    }
02671       
02672    return res;
02673       
02674 }
02675 
02676 static int sayfile(struct ast_channel *mychannel,char *fname)
02677 {
02678 int   res;
02679 
02680    res = ast_streamfile(mychannel, fname, mychannel->language);
02681    if (!res) 
02682       res = ast_waitstream(mychannel, "");
02683    else
02684        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02685    ast_stopstream(mychannel);
02686    return res;
02687 }
02688 
02689 static int saycharstr(struct ast_channel *mychannel,char *str)
02690 {
02691 int   res;
02692 
02693    res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
02694    if (!res) 
02695       res = ast_waitstream(mychannel, "");
02696    else
02697        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02698    ast_stopstream(mychannel);
02699    return res;
02700 }
02701 
02702 static int saynum(struct ast_channel *mychannel, int num)
02703 {
02704    int res;
02705    res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
02706    if(!res)
02707       res = ast_waitstream(mychannel, "");
02708    else
02709       ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02710    ast_stopstream(mychannel);
02711    return res;
02712 }
02713 
02714 
02715 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
02716 {
02717    int res;
02718    char c;
02719    
02720    static int morsespeed;
02721    static int morsefreq;
02722    static int morseampl;
02723    static int morseidfreq = 0;
02724    static int morseidampl;
02725    static char mcat[] = MORSE;
02726    
02727    res = 0;
02728    
02729    if(!morseidfreq){ /* Get the morse parameters if not already loaded */
02730       morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
02731          morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
02732          morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
02733       morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
02734       morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330); 
02735    }
02736    
02737    /* Is it a file, or a tone sequence? */
02738          
02739    if(entry[0] == '|'){
02740       c = entry[1];
02741       if((c >= 'a')&&(c <= 'z'))
02742          c -= 0x20;
02743    
02744       switch(c){
02745          case 'I': /* Morse ID */
02746             res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
02747             break;
02748          
02749          case 'M': /* Morse Message */
02750             res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
02751             break;
02752          
02753          case 'T': /* Tone sequence */
02754             res = send_tone_telemetry(chan, entry + 2);
02755             break;
02756          default:
02757             res = -1;
02758       }
02759    }
02760    else
02761       res = sayfile(chan, entry); /* File */
02762    return res;
02763 }
02764 
02765 /*
02766 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
02767 *
02768 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
02769 */
02770 
02771 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
02772 {
02773    
02774    int res;
02775    int i;
02776    char *entry;
02777    char *telemetry;
02778    char *telemetry_save;
02779 
02780    res = 0;
02781    telemetry_save = NULL;
02782    entry = NULL;
02783    
02784    /* Retrieve the section name for telemetry from the node section */
02785    telemetry = (char *) ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
02786    if(telemetry ){
02787       telemetry_save = ast_strdupa(telemetry);
02788       if(!telemetry_save){
02789          ast_log(LOG_WARNING,"ast_strdupa() failed in telem_lookup()\n");
02790          return res;
02791       }
02792       entry = (char *) ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
02793    }
02794    
02795    /* Try to look up the telemetry name */   
02796 
02797    if(!entry){
02798       /* Telemetry name wasn't found in the config file, use the default */
02799       for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
02800          if(!strcasecmp(tele_defs[i].name, name))
02801             entry = tele_defs[i].value;
02802       }
02803    }
02804    if(entry){  
02805       if(strlen(entry))
02806          telem_any(myrpt,chan, entry);
02807    }
02808    else{
02809       res = -1;
02810    }
02811    return res;
02812 }
02813 
02814 /*
02815 * Retrieve a wait interval
02816 */
02817 
02818 static int get_wait_interval(struct rpt *myrpt, int type)
02819 {
02820         int interval;
02821         char *wait_times;
02822         char *wait_times_save;
02823                                                                                                                   
02824         wait_times_save = NULL;
02825         wait_times = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
02826                                                                                                                   
02827         if(wait_times){
02828                 wait_times_save = ast_strdupa(wait_times);
02829                 if(!wait_times_save){
02830                         ast_log(LOG_WARNING, "Out of memory in wait_interval()\n");
02831                         wait_times = NULL;
02832                 }
02833         }
02834                                                                                                                   
02835         switch(type){
02836                 case DLY_TELEM:
02837                         if(wait_times)
02838                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
02839                         else
02840                                 interval = 1000;
02841                         break;
02842                                                                                                                   
02843                 case DLY_ID:
02844                         if(wait_times)
02845                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
02846                         else
02847                                 interval = 500;
02848                         break;
02849                                                                                                                   
02850                 case DLY_UNKEY:
02851                         if(wait_times)
02852                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",500,5000,1000);
02853                         else
02854                                 interval = 1000;
02855                         break;
02856                                                                                                                   
02857                 case DLY_LINKUNKEY:
02858                         if(wait_times)
02859                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "linkunkeywait",500,5000,1000);
02860                         else
02861                                 interval = 1000;
02862                         break;
02863                                                                                                                   
02864                 case DLY_CALLTERM:
02865                         if(wait_times)
02866                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
02867                         else
02868                                 interval = 1500;
02869                         break;
02870                                                                                                                   
02871                 case DLY_COMP:
02872                         if(wait_times)
02873                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "compwait",500,5000,200);
02874                         else
02875                                 interval = 200;
02876                         break;
02877                                                                                                                   
02878                 default:
02879                         return 0;
02880         }
02881    return interval;
02882 }                                                                                                                  
02883 
02884 
02885 /*
02886 * Wait a configurable interval of time 
02887 */
02888 
02889 
02890 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
02891 {
02892    int interval;
02893    interval = get_wait_interval(myrpt, type);
02894    if(debug)
02895       ast_log(LOG_NOTICE," Delay interval = %d\n", interval);
02896    if(interval)
02897       ast_safe_sleep(chan,interval);
02898    if(debug)
02899       ast_log(LOG_NOTICE,"Delay complete\n");
02900    return;
02901 }
02902 
02903 static int split_freq(char *mhz, char *decimals, char *freq);
02904 
02905 static void *rpt_tele_thread(void *this)
02906 {
02907 struct dahdi_confinfo ci;  /* conference info */
02908 int   res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
02909 struct   rpt_tele *mytele = (struct rpt_tele *)this;
02910 struct  rpt_tele *tlist;
02911 struct   rpt *myrpt;
02912 struct   rpt_link *l,*l1,linkbase;
02913 struct   ast_channel *mychannel;
02914 int vmajor, vminor, m;
02915 char *p,*ct,*ct_copy,*ident, *nodename,*cp;
02916 time_t t;
02917 struct tm localtm;
02918 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
02919 int   i,ns,rbimode;
02920 char mhz[MAXREMSTR];
02921 char decimals[MAXREMSTR];
02922 struct dahdi_params par;
02923 
02924 
02925    /* get a pointer to myrpt */
02926    myrpt = mytele->rpt;
02927 
02928    /* Snag copies of a few key myrpt variables */
02929    rpt_mutex_lock(&myrpt->lock);
02930    nodename = ast_strdupa(myrpt->name);
02931    if (myrpt->p.ident) ident = ast_strdupa(myrpt->p.ident);
02932    else ident = "";
02933    rpt_mutex_unlock(&myrpt->lock);
02934    
02935    /* allocate a pseudo-channel thru asterisk */
02936    mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
02937    if (!mychannel)
02938    {
02939       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
02940       rpt_mutex_lock(&myrpt->lock);
02941       remque((struct qelem *)mytele);
02942       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
02943       rpt_mutex_unlock(&myrpt->lock);
02944       free(mytele);     
02945       pthread_exit(NULL);
02946    }
02947 #ifdef   AST_CDR_FLAG_POST_DISABLED
02948    ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
02949 #endif
02950    rpt_mutex_lock(&myrpt->lock);
02951    mytele->chan = mychannel;
02952    rpt_mutex_unlock(&myrpt->lock);
02953    /* make a conference for the tx */
02954    ci.chan = 0;
02955    /* If there's an ID queued, or tail message queued, */
02956    /* only connect the ID audio to the local tx conference so */
02957    /* linked systems can't hear it */
02958    ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
02959       (mytele->mode == TAILMSG) || (mytele->mode == LINKUNKEY)) || (mytele->mode == TIMEOUT) ?
02960          myrpt->txconf : myrpt->conf);
02961    ci.confmode = DAHDI_CONF_CONFANN;
02962    /* first put the channel on the conference in announce mode */
02963    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
02964    {
02965       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02966       rpt_mutex_lock(&myrpt->lock);
02967       remque((struct qelem *)mytele);
02968       rpt_mutex_unlock(&myrpt->lock);
02969       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
02970       free(mytele);     
02971       ast_hangup(mychannel);
02972       pthread_exit(NULL);
02973    }
02974    ast_stopstream(mychannel);
02975    switch(mytele->mode)
02976    {
02977        case ID:
02978        case ID1:
02979       /* wait a bit */
02980       wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
02981       res = telem_any(myrpt,mychannel, ident); 
02982       imdone=1;   
02983       break;
02984       
02985        case TAILMSG:
02986       res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language); 
02987       break;
02988       
02989        case IDTALKOVER:
02990          p = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
02991          if(p)
02992          res = telem_any(myrpt,mychannel, p); 
02993       imdone=1;   
02994          break;
02995             
02996        case PROC:
02997       /* wait a little bit longer */
02998       wait_interval(myrpt, DLY_TELEM, mychannel);
02999       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
03000       if(res < 0){ /* Then default message */
03001          res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
03002       }
03003       break;
03004        case TERM:
03005       /* wait a little bit longer */
03006       wait_interval(myrpt, DLY_CALLTERM, mychannel);
03007       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
03008       if(res < 0){ /* Then default message */
03009          res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
03010       }
03011       break;
03012        case COMPLETE:
03013       /* wait a little bit */
03014       wait_interval(myrpt, DLY_TELEM, mychannel);
03015       res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03016       break;
03017        case MACRO_NOTFOUND:
03018       /* wait a little bit */
03019       wait_interval(myrpt, DLY_TELEM, mychannel);
03020       res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
03021       break;
03022        case MACRO_BUSY:
03023       /* wait a little bit */
03024       wait_interval(myrpt, DLY_TELEM, mychannel);
03025       res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
03026       break;
03027        case UNKEY:
03028       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
03029          imdone = 1;
03030          break;
03031       }
03032          
03033       /*
03034       * Reset the Unkey to CT timer
03035       */
03036 
03037       x = get_wait_interval(myrpt, DLY_UNKEY);
03038       rpt_mutex_lock(&myrpt->lock);
03039       myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
03040       rpt_mutex_unlock(&myrpt->lock);
03041 
03042       /*
03043       * If there's one already queued, don't do another
03044       */
03045 
03046       tlist = myrpt->tele.next;
03047       unkeys_queued = 0;
03048                 if (tlist != &myrpt->tele)
03049                 {
03050                         rpt_mutex_lock(&myrpt->lock);
03051                         while(tlist != &myrpt->tele){
03052                                 if (tlist->mode == UNKEY) unkeys_queued++;
03053                                 tlist = tlist->next;
03054                         }
03055                         rpt_mutex_unlock(&myrpt->lock);
03056       }
03057       if( unkeys_queued > 1){
03058          imdone = 1;
03059          break;
03060       }
03061 
03062       /* Wait for the telemetry timer to expire */
03063       /* Periodically check the timer since it can be re-initialized above */
03064       while(myrpt->unkeytocttimer)
03065       {
03066          int ctint;
03067          if(myrpt->unkeytocttimer > 100)
03068             ctint = 100;
03069          else
03070             ctint = myrpt->unkeytocttimer;
03071          ast_safe_sleep(mychannel, ctint);
03072          rpt_mutex_lock(&myrpt->lock);
03073          if(myrpt->unkeytocttimer < ctint)
03074             myrpt->unkeytocttimer = 0;
03075          else
03076             myrpt->unkeytocttimer -= ctint;
03077          rpt_mutex_unlock(&myrpt->lock);
03078       }
03079    
03080       /*
03081       * Now, the carrier on the rptr rx should be gone. 
03082       * If it re-appeared, then forget about sending the CT
03083       */
03084       if(myrpt->keyed){
03085          imdone = 1;
03086          break;
03087       }
03088       
03089       rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
03090       myrpt->dailykerchunks++;
03091       myrpt->totalkerchunks++;
03092       rpt_mutex_unlock(&myrpt->lock);
03093    
03094       haslink = 0;
03095       hastx = 0;
03096       hasremote = 0;    
03097       l = myrpt->links.next;
03098       if (l != &myrpt->links)
03099       {
03100          rpt_mutex_lock(&myrpt->lock);
03101          while(l != &myrpt->links)
03102          {
03103             if (l->name[0] == '0')
03104             {
03105                l = l->next;
03106                continue;
03107             }
03108             haslink = 1;
03109             if (l->mode) {
03110                hastx++;
03111                if (l->isremote) hasremote++;
03112             }
03113             l = l->next;
03114          }
03115          rpt_mutex_unlock(&myrpt->lock);
03116       }
03117       if (haslink)
03118       {
03119 
03120          res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
03121          if(res)
03122             ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
03123          
03124       
03125          /* if in remote cmd mode, indicate it */
03126          if (myrpt->cmdnode[0])
03127          {
03128             ast_safe_sleep(mychannel,200);
03129             res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
03130             if(res)
03131                ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
03132             ast_stopstream(mychannel);
03133          }
03134       }
03135       else if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
03136          ct_copy = ast_strdupa(ct);
03137          res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
03138          if(res)
03139             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
03140       }  
03141       if (hasremote && (!myrpt->cmdnode[0]))
03142       {
03143          /* set for all to hear */
03144          ci.chan = 0;
03145          ci.confno = myrpt->conf;
03146          ci.confmode = DAHDI_CONF_CONFANN;
03147          /* first put the channel on the conference in announce mode */
03148          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
03149          {
03150             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
03151             rpt_mutex_lock(&myrpt->lock);
03152             remque((struct qelem *)mytele);
03153             rpt_mutex_unlock(&myrpt->lock);
03154             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03155             free(mytele);     
03156             ast_hangup(mychannel);
03157             pthread_exit(NULL);
03158          }
03159          if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
03160             ast_safe_sleep(mychannel,200);
03161             ct_copy = ast_strdupa(ct);
03162             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
03163             if(res)
03164                ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
03165          }  
03166       }
03167 #if   defined(_MDC_DECODE_H_) && defined(MDC_SAY_WHEN_DOING_CT)
03168       if (myrpt->lastunit)
03169       {
03170          char mystr[10];
03171 
03172          ast_safe_sleep(mychannel,200);
03173          /* set for all to hear */
03174          ci.chan = 0;
03175          ci.confno = myrpt->txconf;
03176          ci.confmode = DAHDI_CONF_CONFANN;
03177          /* first put the channel on the conference in announce mode */
03178          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
03179          {
03180             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
03181             rpt_mutex_lock(&myrpt->lock);
03182             remque((struct qelem *)mytele);
03183             rpt_mutex_unlock(&myrpt->lock);
03184             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03185             free(mytele);     
03186             ast_hangup(mychannel);
03187             pthread_exit(NULL);
03188          }
03189          sprintf(mystr,"%04x",myrpt->lastunit);
03190          myrpt->lastunit = 0;
03191          ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
03192          break;
03193       }
03194 #endif
03195       imdone = 1;
03196       break;
03197        case LINKUNKEY:
03198       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
03199          imdone = 1;
03200          break;
03201       }
03202          
03203       /*
03204       * Reset the Unkey to CT timer
03205       */
03206 
03207       x = get_wait_interval(myrpt, DLY_LINKUNKEY);
03208       mytele->mylink.linkunkeytocttimer = x; /* Must be protected as it is changed below */
03209 
03210       /*
03211       * If there's one already queued, don't do another
03212       */
03213 
03214       tlist = myrpt->tele.next;
03215       unkeys_queued = 0;
03216                 if (tlist != &myrpt->tele)
03217                 {
03218                         rpt_mutex_lock(&myrpt->lock);
03219                         while(tlist != &myrpt->tele){
03220                                 if (tlist->mode == LINKUNKEY) unkeys_queued++;
03221                                 tlist = tlist->next;
03222                         }
03223                         rpt_mutex_unlock(&myrpt->lock);
03224       }
03225       if( unkeys_queued > 1){
03226          imdone = 1;
03227          break;
03228       }
03229 
03230       /* Wait for the telemetry timer to expire */
03231       /* Periodically check the timer since it can be re-initialized above */
03232       while(mytele->mylink.linkunkeytocttimer)
03233       {
03234          int ctint;
03235          if(mytele->mylink.linkunkeytocttimer > 100)
03236             ctint = 100;
03237          else
03238             ctint = mytele->mylink.linkunkeytocttimer;
03239          ast_safe_sleep(mychannel, ctint);
03240          rpt_mutex_lock(&myrpt->lock);
03241          if(mytele->mylink.linkunkeytocttimer < ctint)
03242             mytele->mylink.linkunkeytocttimer = 0;
03243          else
03244             mytele->mylink.linkunkeytocttimer -= ctint;
03245          rpt_mutex_unlock(&myrpt->lock);
03246       }
03247    
03248       if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "linkunkeyct"))){ /* Unlinked Courtesy Tone */
03249          ct_copy = ast_strdupa(ct);
03250          res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
03251          if(res)
03252             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
03253       }  
03254       imdone = 1;
03255       break;
03256        case REMDISC:
03257       /* wait a little bit */
03258       wait_interval(myrpt, DLY_TELEM, mychannel);
03259       l = myrpt->links.next;
03260       haslink = 0;
03261       /* dont report if a link for this one still on system */
03262       if (l != &myrpt->links)
03263       {
03264          rpt_mutex_lock(&myrpt->lock);
03265          while(l != &myrpt->links)
03266          {
03267             if (l->name[0] == '0')
03268             {
03269                l = l->next;
03270                continue;
03271             }
03272             if (!strcmp(l->name,mytele->mylink.name))
03273             {
03274                haslink = 1;
03275                break;
03276             }
03277             l = l->next;
03278          }
03279          rpt_mutex_unlock(&myrpt->lock);
03280       }
03281       if (haslink)
03282       {
03283          imdone = 1;
03284          break;
03285       }
03286       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03287       if (!res) 
03288          res = ast_waitstream(mychannel, "");
03289       else
03290           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03291       ast_stopstream(mychannel);
03292       ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
03293       res = ast_streamfile(mychannel, ((mytele->mylink.hasconnected) ? 
03294          "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
03295       break;
03296        case REMALREADY:
03297       /* wait a little bit */
03298       wait_interval(myrpt, DLY_TELEM, mychannel);
03299       res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
03300       break;
03301        case REMNOTFOUND:
03302       /* wait a little bit */
03303       wait_interval(myrpt, DLY_TELEM, mychannel);
03304       res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
03305       break;
03306        case REMGO:
03307       /* wait a little bit */
03308       wait_interval(myrpt, DLY_TELEM, mychannel);
03309       res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
03310       break;
03311        case CONNECTED:
03312       /* wait a little bit */
03313       wait_interval(myrpt, DLY_TELEM,  mychannel);
03314       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03315       if (!res) 
03316          res = ast_waitstream(mychannel, "");
03317       else
03318           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03319       ast_stopstream(mychannel);
03320       ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
03321       res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
03322       if (!res) 
03323          res = ast_waitstream(mychannel, "");
03324       else
03325           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03326       ast_stopstream(mychannel);
03327       res = ast_streamfile(mychannel, "digits/2", mychannel->language);
03328       if (!res) 
03329          res = ast_waitstream(mychannel, "");
03330       else
03331           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03332       ast_stopstream(mychannel);
03333       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03334       if (!res) 
03335          res = ast_waitstream(mychannel, "");
03336       else
03337           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03338       ast_stopstream(mychannel);
03339       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03340       imdone = 1;
03341       break;
03342        case CONNFAIL:
03343       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03344       if (!res) 
03345          res = ast_waitstream(mychannel, "");
03346       else
03347           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03348       ast_stopstream(mychannel);
03349       ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
03350       res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
03351       break;
03352        case MEMNOTFOUND:
03353       /* wait a little bit */
03354       wait_interval(myrpt, DLY_TELEM, mychannel);
03355       res = ast_streamfile(mychannel, "rpt/memory_notfound", mychannel->language);
03356       break;
03357        case SETREMOTE:
03358       ast_mutex_lock(&myrpt->remlock);
03359       res = 0;
03360       if(!strcmp(myrpt->remote, remote_rig_ft897))
03361       {
03362          res = set_ft897(myrpt);
03363       }
03364       if(!strcmp(myrpt->remote, remote_rig_ic706))
03365       {
03366          res = set_ic706(myrpt);
03367       }
03368 #ifdef HAVE_IOPERM
03369       else if(!strcmp(myrpt->remote, remote_rig_rbi))
03370       {
03371          if (ioperm(myrpt->p.iobase,1,1) == -1)
03372          {
03373             rpt_mutex_unlock(&myrpt->lock);
03374             ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
03375             res = -1;
03376          }
03377          else res = setrbi(myrpt);
03378       }
03379 #endif
03380       else if(!strcmp(myrpt->remote, remote_rig_kenwood))
03381       {
03382          res = setkenwood(myrpt);
03383          if (ast_safe_sleep(mychannel,200) == -1)
03384          {
03385             ast_mutex_unlock(&myrpt->remlock);
03386             res = -1;
03387             break;
03388          }
03389          i = DAHDI_FLUSH_EVENT;
03390          if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_FLUSH,&i) == -1)
03391          {
03392             ast_mutex_unlock(&myrpt->remlock);
03393             ast_log(LOG_ERROR,"Cant flush events");
03394             res = -1;
03395             break;
03396          }
03397          if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_GET_PARAMS,&par) == -1)
03398          {
03399             ast_mutex_unlock(&myrpt->remlock);
03400             ast_log(LOG_ERROR,"Cant get params");
03401             res = -1;
03402             break;
03403          }
03404          myrpt->remoterx = 
03405             (par.rxisoffhook || (myrpt->tele.next != &myrpt->tele));
03406       }
03407       ast_mutex_unlock(&myrpt->remlock);
03408       if (!res)
03409       {
03410          imdone = 1;
03411          break;
03412       }
03413       /* fall thru to invalid freq */
03414        case INVFREQ:
03415       /* wait a little bit */
03416       wait_interval(myrpt, DLY_TELEM, mychannel);
03417       res = ast_streamfile(mychannel, "rpt/invalid-freq", mychannel->language);
03418       break;
03419        case REMMODE:
03420       cp = 0;
03421       wait_interval(myrpt, DLY_TELEM, mychannel);
03422       switch(myrpt->remmode)
03423       {
03424           case REM_MODE_FM:
03425          saycharstr(mychannel,"FM");
03426          break;
03427           case REM_MODE_USB:
03428          saycharstr(mychannel,"USB");
03429          break;
03430           case REM_MODE_LSB:
03431          saycharstr(mychannel,"LSB");
03432          break;
03433           case REM_MODE_AM:
03434          saycharstr(mychannel,"AM");
03435          break;
03436       }
03437       wait_interval(myrpt, DLY_COMP, mychannel);
03438       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03439       break;
03440        case LOGINREQ:
03441       wait_interval(myrpt, DLY_TELEM, mychannel);
03442       sayfile(mychannel,"rpt/login");
03443       saycharstr(mychannel,myrpt->name);
03444       break;
03445        case REMLOGIN:
03446       wait_interval(myrpt, DLY_TELEM, mychannel);
03447       saycharstr(mychannel,myrpt->loginuser);
03448       sayfile(mychannel,"rpt/node");
03449       saycharstr(mychannel,myrpt->name);
03450       wait_interval(myrpt, DLY_COMP, mychannel);
03451       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03452       break;
03453        case REMXXX:
03454       wait_interval(myrpt, DLY_TELEM, mychannel);
03455       res = 0;
03456       switch(mytele->submode)
03457       {
03458           case 100: /* RX PL Off */
03459          sayfile(mychannel, "rpt/rxpl");
03460          sayfile(mychannel, "rpt/off");
03461          break;
03462           case 101: /* RX PL On */
03463          sayfile(mychannel, "rpt/rxpl");
03464          sayfile(mychannel, "rpt/on");
03465          break;
03466           case 102: /* TX PL Off */
03467          sayfile(mychannel, "rpt/txpl");
03468          sayfile(mychannel, "rpt/off");
03469          break;
03470           case 103: /* TX PL On */
03471          sayfile(mychannel, "rpt/txpl");
03472          sayfile(mychannel, "rpt/on");
03473          break;
03474           case 104: /* Low Power */
03475          sayfile(mychannel, "rpt/lopwr");
03476          break;
03477           case 105: /* Medium Power */
03478          sayfile(mychannel, "rpt/medpwr");
03479          break;
03480           case 106: /* Hi Power */
03481          sayfile(mychannel, "rpt/hipwr");
03482          break;
03483           case 113: /* Scan down slow */
03484          sayfile(mychannel,"rpt/down");
03485          sayfile(mychannel, "rpt/slow");
03486          break;
03487           case 114: /* Scan down quick */
03488          sayfile(mychannel,"rpt/down");
03489          sayfile(mychannel, "rpt/quick");
03490          break;
03491           case 115: /* Scan down fast */
03492          sayfile(mychannel,"rpt/down");
03493          sayfile(mychannel, "rpt/fast");
03494          break;
03495           case 116: /* Scan up slow */
03496          sayfile(mychannel,"rpt/up");
03497          sayfile(mychannel, "rpt/slow");
03498          break;
03499           case 117: /* Scan up quick */
03500          sayfile(mychannel,"rpt/up");
03501          sayfile(mychannel, "rpt/quick");
03502          break;
03503           case 118: /* Scan up fast */
03504          sayfile(mychannel,"rpt/up");
03505          sayfile(mychannel, "rpt/fast");
03506          break;
03507           default:
03508          res = -1;
03509       }
03510       wait_interval(myrpt, DLY_COMP, mychannel);
03511       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03512       break;
03513        case SCAN:
03514       ast_mutex_lock(&myrpt->remlock);
03515       if (myrpt->hfscanstop)
03516       {
03517          myrpt->hfscanstatus = 0;
03518          myrpt->hfscanmode = 0;
03519          myrpt->hfscanstop = 0;
03520          mytele->mode = SCANSTAT;
03521          ast_mutex_unlock(&myrpt->remlock);
03522          if (ast_safe_sleep(mychannel,1000) == -1) break;
03523          sayfile(mychannel, "rpt/stop"); 
03524          imdone = 1;
03525          break;
03526       }
03527       if (myrpt->hfscanstatus > -2) service_scan(myrpt);
03528       i = myrpt->hfscanstatus;
03529       myrpt->hfscanstatus = 0;
03530       if (i) mytele->mode = SCANSTAT;
03531       ast_mutex_unlock(&myrpt->remlock);
03532       if (i < 0) sayfile(mychannel, "rpt/stop"); 
03533       else if (i > 0) saynum(mychannel,i);
03534       imdone = 1;
03535       break;
03536        case TUNE:
03537       ast_mutex_lock(&myrpt->remlock);
03538       if (!strcmp(myrpt->remote,remote_rig_ic706))
03539       {
03540          set_mode_ic706(myrpt, REM_MODE_AM);
03541          if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
03542          ast_safe_sleep(mychannel,500);
03543          set_mode_ic706(myrpt, myrpt->remmode);
03544          myrpt->tunerequest = 0;
03545          ast_mutex_unlock(&myrpt->remlock);
03546          imdone = 1;
03547          break;
03548       }
03549       set_mode_ft897(myrpt, REM_MODE_AM);
03550       simple_command_ft897(myrpt, 8);
03551       if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
03552       simple_command_ft897(myrpt, 0x88);
03553       ast_safe_sleep(mychannel,500);
03554       set_mode_ft897(myrpt, myrpt->remmode);
03555       myrpt->tunerequest = 0;
03556       ast_mutex_unlock(&myrpt->remlock);
03557       imdone = 1;
03558       break;
03559        case REMSHORTSTATUS:
03560        case REMLONGSTATUS: 
03561       wait_interval(myrpt, DLY_TELEM, mychannel);
03562       res = sayfile(mychannel,"rpt/node");
03563       if(!res)
03564          res = saycharstr(mychannel, myrpt->name);
03565       if(!res)
03566          res = sayfile(mychannel,"rpt/frequency");
03567       if(!res)
03568          res = split_freq(mhz, decimals, myrpt->freq);
03569       if (!multimode_capable(myrpt)) decimals[3] = 0;
03570       if(!res){
03571          m = atoi(mhz);
03572          if(m < 100)
03573             res = saynum(mychannel, m);
03574          else
03575             res = saycharstr(mychannel, mhz);
03576       }
03577       if(!res)
03578          res = sayfile(mychannel, "letters/dot");
03579       if(!res)
03580          res = saycharstr(mychannel, decimals);
03581    
03582       if(res)  break;
03583       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
03584          switch(myrpt->offset){
03585    
03586             case REM_MINUS:
03587                res = sayfile(mychannel,"rpt/minus");
03588                break;
03589             
03590             case REM_SIMPLEX:
03591                res = sayfile(mychannel,"rpt/simplex");
03592                break;
03593                
03594             case REM_PLUS:
03595                res = sayfile(mychannel,"rpt/plus");
03596                break;
03597                
03598             default:
03599                break;
03600          }
03601       }
03602       else{ /* Must be USB, LSB, or AM */
03603          switch(myrpt->remmode){
03604 
03605             case REM_MODE_USB:
03606                res = saycharstr(mychannel, "USB");
03607                break;
03608 
03609             case REM_MODE_LSB:
03610                res = saycharstr(mychannel, "LSB");
03611                break;
03612 
03613             case REM_MODE_AM:
03614                res = saycharstr(mychannel, "AM");
03615                break;
03616 
03617 
03618             default:
03619                break;
03620          }
03621       }
03622 
03623       if (res == -1) break;
03624 
03625       if(mytele->mode == REMSHORTSTATUS){ /* Short status? */
03626          wait_interval(myrpt, DLY_COMP, mychannel);
03627          if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03628          break;
03629       }
03630 
03631       if (strcmp(myrpt->remote,remote_rig_ic706))
03632       {
03633          switch(myrpt->powerlevel){
03634 
03635             case REM_LOWPWR:
03636                res = sayfile(mychannel,"rpt/lopwr") ;
03637                break;
03638             case REM_MEDPWR:
03639                res = sayfile(mychannel,"rpt/medpwr");
03640                break;
03641             case REM_HIPWR:
03642                res = sayfile(mychannel,"rpt/hipwr"); 
03643                break;
03644             }
03645       }
03646 
03647       rbimode = ((!strncmp(myrpt->remote,remote_rig_rbi,3))
03648         || (!strncmp(myrpt->remote,remote_rig_ic706,3)));
03649       if (res || (sayfile(mychannel,"rpt/rxpl") == -1)) break;
03650       if (rbimode && (sayfile(mychannel,"rpt/txpl") == -1)) break;
03651       if ((sayfile(mychannel,"rpt/frequency") == -1) ||
03652          (saycharstr(mychannel,myrpt->rxpl) == -1)) break;
03653       if ((!rbimode) && ((sayfile(mychannel,"rpt/txpl") == -1) ||
03654          (sayfile(mychannel,"rpt/frequency") == -1) ||
03655          (saycharstr(mychannel,myrpt->txpl) == -1))) break;
03656       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
03657          if ((sayfile(mychannel,"rpt/rxpl") == -1) ||
03658             (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1) ||
03659             (sayfile(mychannel,"rpt/txpl") == -1) ||
03660             (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1))
03661             {
03662                break;
03663             }
03664       }
03665       wait_interval(myrpt, DLY_COMP, mychannel);
03666       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03667       break;
03668        case STATUS:
03669       /* wait a little bit */
03670       wait_interval(myrpt, DLY_TELEM, mychannel);
03671       hastx = 0;
03672       linkbase.next = &linkbase;
03673       linkbase.prev = &linkbase;
03674       rpt_mutex_lock(&myrpt->lock);
03675       /* make our own list of links */
03676       l = myrpt->links.next;
03677       while(l != &myrpt->links)
03678       {
03679          if (l->name[0] == '0')
03680          {
03681             l = l->next;
03682             continue;
03683          }
03684          l1 = malloc(sizeof(struct rpt_link));
03685          if (!l1)
03686          {
03687             ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
03688             remque((struct qelem *)mytele);
03689             rpt_mutex_unlock(&myrpt->lock);
03690             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03691             free(mytele);     
03692             ast_hangup(mychannel);
03693             pthread_exit(NULL);
03694          }
03695          memcpy(l1,l,sizeof(struct rpt_link));
03696          l1->next = l1->prev = NULL;
03697          insque((struct qelem *)l1,(struct qelem *)linkbase.next);
03698          l = l->next;
03699       }
03700       rpt_mutex_unlock(&myrpt->lock);
03701       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03702       if (!res) 
03703          res = ast_waitstream(mychannel, "");
03704       else
03705           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03706       ast_stopstream(mychannel);
03707       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03708       if (!res) 
03709          res = ast_waitstream(mychannel, "");
03710       else
03711           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03712       ast_stopstream(mychannel);
03713       if (myrpt->callmode)
03714       {
03715          hastx = 1;
03716          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
03717          if (!res) 
03718             res = ast_waitstream(mychannel, "");
03719          else
03720              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03721          ast_stopstream(mychannel);
03722       }
03723       l = linkbase.next;
03724       while(l != &linkbase)
03725       {
03726          char *s;
03727 
03728          hastx = 1;
03729          res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03730          if (!res) 
03731             res = ast_waitstream(mychannel, "");
03732          else
03733             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03734          ast_stopstream(mychannel);
03735          ast_say_character_str(mychannel,l->name,NULL,mychannel->language);
03736          if (!res) 
03737             res = ast_waitstream(mychannel, "");
03738          else
03739              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03740          ast_stopstream(mychannel);
03741          s = "rpt/tranceive";
03742          if (!l->mode) s = "rpt/monitor";
03743          if (!l->thisconnected) s = "rpt/connecting";
03744          res = ast_streamfile(mychannel, s, mychannel->language);
03745          if (!res) 
03746             res = ast_waitstream(mychannel, "");
03747          else
03748             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03749          ast_stopstream(mychannel);
03750          l = l->next;
03751       }        
03752       if (!hastx)
03753       {
03754          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
03755          if (!res) 
03756             res = ast_waitstream(mychannel, "");
03757          else
03758              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03759          ast_stopstream(mychannel);
03760       }
03761       /* destroy our local link queue */
03762       l = linkbase.next;
03763       while(l != &linkbase)
03764       {
03765          l1 = l;
03766          l = l->next;
03767          remque((struct qelem *)l1);
03768          free(l1);
03769       }        
03770       imdone = 1;
03771       break;
03772        case FULLSTATUS:
03773       rpt_mutex_lock(&myrpt->lock);
03774       /* get all the nodes */
03775       __mklinklist(myrpt,NULL,lbuf);
03776       rpt_mutex_unlock(&myrpt->lock);
03777       /* parse em */
03778       ns = finddelim(lbuf,strs,MAXLINKLIST);
03779       /* sort em */
03780       if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
03781       /* wait a little bit */
03782       wait_interval(myrpt, DLY_TELEM, mychannel);
03783       hastx = 0;
03784       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03785       if (!res) 
03786          res = ast_waitstream(mychannel, "");
03787       else
03788           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03789       ast_stopstream(mychannel);
03790       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03791       if (!res) 
03792          res = ast_waitstream(mychannel, "");
03793       else
03794           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03795       ast_stopstream(mychannel);
03796       if (myrpt->callmode)
03797       {
03798          hastx = 1;
03799          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
03800          if (!res) 
03801             res = ast_waitstream(mychannel, "");
03802          else
03803              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03804          ast_stopstream(mychannel);
03805       }
03806       /* go thru all the nodes in list */
03807       for(i = 0; i < ns; i++)
03808       {
03809          char *s,mode = 'T';
03810 
03811          /* if a mode spec at first, handle it */
03812          if ((*strs[i] < '0') || (*strs[i] > '9'))
03813          {
03814             mode = *strs[i];
03815             strs[i]++;
03816          }
03817 
03818          hastx = 1;
03819          res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03820          if (!res) 
03821             res = ast_waitstream(mychannel, "");
03822          else
03823             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03824          ast_stopstream(mychannel);
03825          ast_say_character_str(mychannel,strs[i],NULL,mychannel->language);
03826          if (!res) 
03827             res = ast_waitstream(mychannel, "");
03828          else
03829              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03830          ast_stopstream(mychannel);
03831          s = "rpt/tranceive";
03832          if (mode == 'R') s = "rpt/monitor";
03833          if (mode == 'C') s = "rpt/connecting";
03834          res = ast_streamfile(mychannel, s, mychannel->language);
03835          if (!res) 
03836             res = ast_waitstream(mychannel, "");
03837          else
03838             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03839          ast_stopstream(mychannel);
03840       }        
03841       if (!hastx)
03842       {
03843          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
03844          if (!res) 
03845             res = ast_waitstream(mychannel, "");
03846          else
03847              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03848          ast_stopstream(mychannel);
03849       }
03850       imdone = 1;
03851       break;
03852 
03853        case LASTNODEKEY: /* Identify last node which keyed us up */
03854       rpt_mutex_lock(&myrpt->lock);
03855       if(myrpt->lastnodewhichkeyedusup)
03856          p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
03857       else
03858          p = NULL;
03859       rpt_mutex_unlock(&myrpt->lock);
03860       if(!p){
03861          imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
03862          break;
03863       }
03864       wait_interval(myrpt, DLY_TELEM, mychannel);
03865       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03866       if (!res) 
03867          res = ast_waitstream(mychannel, "");
03868       else
03869           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03870       ast_stopstream(mychannel);
03871       ast_say_character_str(mychannel, p, NULL, mychannel->language);
03872       if (!res) 
03873          res = ast_waitstream(mychannel, "");
03874       else
03875          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03876       ast_stopstream(mychannel);
03877       imdone = 1;
03878       break;      
03879 
03880        case UNAUTHTX: /* Say unauthorized transmit frequency */
03881       wait_interval(myrpt, DLY_TELEM, mychannel);
03882       res = ast_streamfile(mychannel, "rpt/unauthtx", mychannel->language);
03883       if (!res) 
03884          res = ast_waitstream(mychannel, "");
03885       else
03886           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03887       ast_stopstream(mychannel);
03888       imdone = 1;
03889       break;
03890       
03891 
03892        case TIMEOUT:
03893       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03894       if (!res) 
03895          res = ast_waitstream(mychannel, "");
03896       else
03897           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03898       ast_stopstream(mychannel);
03899       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03900       res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
03901       break;
03902       
03903        case TIMEOUT_WARNING:
03904       time(&t);
03905       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03906       if (!res) 
03907          res = ast_waitstream(mychannel, "");
03908       else
03909           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03910       ast_stopstream(mychannel);
03911       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03912       res = ast_streamfile(mychannel, "rpt/timeout-warning", mychannel->language);
03913       if (!res) 
03914          res = ast_waitstream(mychannel, "");
03915       else
03916           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03917       ast_stopstream(mychannel);
03918       if(!res) /* Say number of seconds */
03919          ast_say_number(mychannel, myrpt->p.remotetimeout - 
03920              (t - myrpt->last_activity_time), 
03921             "", mychannel->language, (char *) NULL);
03922       if (!res) 
03923          res = ast_waitstream(mychannel, "");
03924       ast_stopstream(mychannel); 
03925       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
03926       break;
03927 
03928        case ACT_TIMEOUT_WARNING:
03929       time(&t);
03930       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03931       if (!res) 
03932          res = ast_waitstream(mychannel, "");
03933       else
03934           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03935       ast_stopstream(mychannel);
03936       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03937       res = ast_streamfile(mychannel, "rpt/act-timeout-warning", mychannel->language);
03938       if (!res) 
03939          res = ast_waitstream(mychannel, "");
03940       else
03941           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03942       ast_stopstream(mychannel);
03943       if(!res) /* Say number of seconds */
03944          ast_say_number(mychannel, myrpt->p.remoteinacttimeout - 
03945              (t - myrpt->last_activity_time), 
03946             "", mychannel->language, (char *) NULL);
03947       if (!res) 
03948          res = ast_waitstream(mychannel, "");
03949       ast_stopstream(mychannel); 
03950       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
03951       break;
03952       
03953        case STATS_TIME:
03954          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
03955       t = time(NULL);
03956       rpt_localtime(&t, &localtm);
03957       /* Say the phase of the day is before the time */
03958       if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
03959          p = "rpt/goodmorning";
03960       else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
03961          p = "rpt/goodafternoon";
03962       else
03963          p = "rpt/goodevening";
03964       if (sayfile(mychannel,p) == -1)
03965       {
03966          imdone = 1;
03967          break;
03968       }
03969       /* Say the time is ... */     
03970       if (sayfile(mychannel,"rpt/thetimeis") == -1)
03971       {
03972          imdone = 1;
03973          break;
03974       }
03975       /* Say the time */            
03976          res = ast_say_time(mychannel, t, "", mychannel->language);
03977       if (!res) 
03978          res = ast_waitstream(mychannel, "");
03979       ast_stopstream(mychannel);    
03980       imdone = 1;
03981          break;
03982        case STATS_VERSION:
03983       p = strstr(tdesc, "version"); 
03984       if(!p)
03985          break;   
03986       if(sscanf(p, "version %30d.%30d", &vmajor, &vminor) != 2)
03987          break;
03988          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
03989       /* Say "version" */
03990       if (sayfile(mychannel,"rpt/version") == -1)
03991       {
03992          imdone = 1;
03993          break;
03994       }
03995       if(!res) /* Say "X" */
03996          ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
03997       if (!res) 
03998          res = ast_waitstream(mychannel, "");
03999       ast_stopstream(mychannel); 
04000       if (saycharstr(mychannel,".") == -1)
04001       {
04002          imdone = 1;
04003          break;
04004       }
04005       if(!res) /* Say "Y" */
04006          ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
04007       if (!res){
04008          res = ast_waitstream(mychannel, "");
04009          ast_stopstream(mychannel);
04010       }  
04011       else
04012           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04013       imdone = 1;
04014          break;
04015        case ARB_ALPHA:
04016          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
04017          if(mytele->param)
04018             saycharstr(mychannel, mytele->param);
04019          imdone = 1;
04020       break;
04021        case REV_PATCH:
04022          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
04023          if(mytele->param) {
04024 
04025          /* Parts of this section taken from app_parkandannounce */
04026          char *tpl_working, *tpl_current;
04027          char *tmp[100], *myparm;
04028          int looptemp=0,i=0, dres = 0;
04029    
04030 
04031          tpl_working = strdupa(mytele->param);
04032          myparm = strsep(&tpl_working,",");
04033          tpl_current=strsep(&tpl_working, ":");
04034 
04035          while(tpl_current && looptemp < sizeof(tmp)) {
04036             tmp[looptemp]=tpl_current;
04037             looptemp++;
04038             tpl_current=strsep(&tpl_working,":");
04039          }
04040 
04041          for(i=0; i<looptemp; i++) {
04042             if(!strcmp(tmp[i], "PARKED")) {
04043                ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
04044             } else if(!strcmp(tmp[i], "NODE")) {
04045                ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
04046             } else {
04047                dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
04048                if(!dres) {
04049                   dres = ast_waitstream(mychannel, "");
04050                } else {
04051                   ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
04052                   dres = 0;
04053                }
04054             }
04055          }
04056       }
04057          imdone = 1;
04058       break;
04059        case TEST_TONE:
04060       imdone = 1;
04061       if (myrpt->stopgen) break;
04062       myrpt->stopgen = -1;
04063            if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
04064       {
04065          myrpt->stopgen = 0;
04066          break;
04067       }
04068            while(mychannel->generatordata && (myrpt->stopgen <= 0)) {
04069          if (ast_safe_sleep(mychannel,1)) break;
04070             imdone = 1;
04071          }
04072       myrpt->stopgen = 0;
04073       break;
04074        default:
04075          break;
04076    }
04077    if (!imdone)
04078    {
04079       if (!res) 
04080          res = ast_waitstream(mychannel, "");
04081       else {
04082          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04083          res = 0;
04084       }
04085    }
04086    ast_stopstream(mychannel);
04087    rpt_mutex_lock(&myrpt->lock);
04088    if (mytele->mode == TAILMSG)
04089    {
04090       if (!res)
04091       {
04092          myrpt->tailmessagen++;
04093          if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
04094       }
04095       else
04096       {
04097          myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
04098       }
04099    }
04100    remque((struct qelem *)mytele);
04101    rpt_mutex_unlock(&myrpt->lock);
04102    free(mytele);     
04103    ast_hangup(mychannel);
04104 #ifdef  APP_RPT_LOCK_DEBUG
04105    {
04106       struct lockthread *t;
04107 
04108       sleep(5);
04109       ast_mutex_lock(&locklock);
04110       t = get_lockthread(pthread_self());
04111       if (t) memset(t,0,sizeof(struct lockthread));
04112       ast_mutex_unlock(&locklock);
04113    }        
04114 #endif
04115    pthread_exit(NULL);
04116 }
04117 
04118 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
04119 {
04120 struct rpt_tele *tele;
04121 struct rpt_link *mylink = (struct rpt_link *) data;
04122 int res;
04123 pthread_attr_t attr;
04124 
04125    tele = malloc(sizeof(struct rpt_tele));
04126    if (!tele)
04127    {
04128       ast_log(LOG_WARNING, "Unable to allocate memory\n");
04129       pthread_exit(NULL);
04130       return;
04131    }
04132    /* zero it out */
04133    memset((char *)tele,0,sizeof(struct rpt_tele));
04134    tele->rpt = myrpt;
04135    tele->mode = mode;
04136    rpt_mutex_lock(&myrpt->lock);
04137    if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED) ||
04138        (mode == LINKUNKEY)){
04139       memset(&tele->mylink,0,sizeof(struct rpt_link));
04140       if (mylink){
04141          memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
04142       }
04143    }
04144    else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
04145       strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
04146       tele->param[TELEPARAMSIZE - 1] = 0;
04147    }
04148    if (mode == REMXXX) tele->submode = (intptr_t) data;
04149    insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
04150    rpt_mutex_unlock(&myrpt->lock);
04151         pthread_attr_init(&attr);
04152         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
04153    res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
04154    if(res < 0){
04155       rpt_mutex_lock(&myrpt->lock);
04156       remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
04157       rpt_mutex_unlock(&myrpt->lock);  
04158       ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
04159    }
04160    return;
04161 }
04162 
04163 static void *rpt_call(void *this)
04164 {
04165 struct dahdi_confinfo ci;  /* conference info */
04166 struct   rpt *myrpt = (struct rpt *)this;
04167 int   res;
04168 int stopped,congstarted,dialtimer,lastcidx,aborted;
04169 struct ast_channel *mychannel,*genchannel;
04170 
04171 
04172    myrpt->mydtmf = 0;
04173    /* allocate a pseudo-channel thru asterisk */
04174    mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
04175    if (!mychannel)
04176    {
04177       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
04178       pthread_exit(NULL);
04179    }
04180 #ifdef   AST_CDR_FLAG_POST_DISABLED
04181    ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
04182 #endif
04183    ci.chan = 0;
04184    ci.confno = myrpt->conf; /* use the pseudo conference */
04185    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
04186       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
04187    /* first put the channel on the conference */
04188    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04189    {
04190       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04191       ast_hangup(mychannel);
04192       myrpt->callmode = 0;
04193       pthread_exit(NULL);
04194    }
04195    /* allocate a pseudo-channel thru asterisk */
04196    genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
04197    if (!genchannel)
04198    {
04199       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
04200       ast_hangup(mychannel);
04201       pthread_exit(NULL);
04202    }
04203 #ifdef   AST_CDR_FLAG_POST_DISABLED
04204    ast_set_flag(genchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
04205 #endif
04206    ci.chan = 0;
04207    ci.confno = myrpt->conf;
04208    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
04209       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
04210    /* first put the channel on the conference */
04211    if (ioctl(genchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04212    {
04213       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04214       ast_hangup(mychannel);
04215       ast_hangup(genchannel);
04216       myrpt->callmode = 0;
04217       pthread_exit(NULL);
04218    }
04219    if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
04220    {
04221       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
04222       ast_hangup(mychannel);
04223       ast_hangup(genchannel);
04224       myrpt->callmode = 0;
04225       pthread_exit(NULL);
04226    }
04227    if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
04228    {
04229       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
04230       ast_hangup(mychannel);
04231       ast_hangup(genchannel);
04232       myrpt->callmode = 0;
04233       pthread_exit(NULL);
04234    }
04235    /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
04236    if ((!myrpt->patchquiet) && (tone_zone_play_tone(mychannel->fds[0],DAHDI_TONE_DIALTONE) < 0))
04237    {
04238       ast_log(LOG_WARNING, "Cannot start dialtone\n");
04239       ast_hangup(mychannel);
04240       ast_hangup(genchannel);
04241       myrpt->callmode = 0;
04242       pthread_exit(NULL);
04243    }
04244    stopped = 0;
04245    congstarted = 0;
04246    dialtimer = 0;
04247    lastcidx = 0;
04248    aborted = 0;
04249 
04250 
04251    while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
04252    {
04253 
04254       if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
04255          dialtimer = 0;
04256          lastcidx = myrpt->cidx;
04257       }     
04258 
04259       if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){ 
04260          rpt_mutex_lock(&myrpt->lock);
04261          aborted = 1;
04262          myrpt->callmode = 0;
04263          rpt_mutex_unlock(&myrpt->lock);
04264          break;
04265       }
04266    
04267       if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
04268       {
04269          stopped = 1;
04270          /* stop dial tone */
04271          tone_zone_play_tone(mychannel->fds[0],-1);
04272       }
04273       if (myrpt->callmode == 4)
04274       {
04275          if(!congstarted){
04276             congstarted = 1;
04277             /* start congestion tone */
04278             tone_zone_play_tone(mychannel->fds[0],DAHDI_TONE_CONGESTION);
04279          }
04280       }
04281       res = ast_safe_sleep(mychannel, MSWAIT);
04282       if (res < 0)
04283       {
04284          ast_hangup(mychannel);
04285          ast_hangup(genchannel);
04286          rpt_mutex_lock(&myrpt->lock);
04287          myrpt->callmode = 0;
04288          rpt_mutex_unlock(&myrpt->lock);
04289          pthread_exit(NULL);
04290       }
04291       dialtimer += MSWAIT;
04292    }
04293    /* stop any tone generation */
04294    tone_zone_play_tone(mychannel->fds[0],-1);
04295    /* end if done */
04296    if (!myrpt->callmode)
04297    {
04298       ast_hangup(mychannel);
04299       ast_hangup(genchannel);
04300       rpt_mutex_lock(&myrpt->lock);
04301       myrpt->callmode = 0;
04302       rpt_mutex_unlock(&myrpt->lock);
04303       if((!myrpt->patchquiet) && aborted)
04304          rpt_telemetry(myrpt, TERM, NULL);
04305       pthread_exit(NULL);        
04306    }
04307 
04308    if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
04309       char *name, *loc, *instr;
04310       instr = strdup(myrpt->p.ourcallerid);
04311       if(instr){
04312          ast_callerid_parse(instr, &name, &loc);
04313          if(loc){
04314             if(mychannel->cid.cid_num)
04315                free(mychannel->cid.cid_num);
04316             mychannel->cid.cid_num = strdup(loc);
04317          }
04318          if(name){
04319             if(mychannel->cid.cid_name)
04320                free(mychannel->cid.cid_name);
04321             mychannel->cid.cid_name = strdup(name);
04322          }
04323          free(instr);
04324       }
04325    }
04326 
04327    ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
04328    ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
04329    
04330    if (myrpt->p.acctcode)
04331       ast_cdr_setaccount(mychannel,myrpt->p.acctcode);
04332    mychannel->priority = 1;
04333    ast_channel_undefer_dtmf(mychannel);
04334    if (ast_pbx_start(mychannel) < 0)
04335    {
04336       ast_log(LOG_WARNING, "Unable to start PBX!!\n");
04337       ast_hangup(mychannel);
04338       ast_hangup(genchannel);
04339       rpt_mutex_lock(&myrpt->lock);
04340       myrpt->callmode = 0;
04341       rpt_mutex_unlock(&myrpt->lock);
04342       pthread_exit(NULL);
04343    }
04344    usleep(10000);
04345    rpt_mutex_lock(&myrpt->lock);
04346    myrpt->callmode = 3;
04347    /* set appropriate conference for the pseudo */
04348    ci.chan = 0;
04349    ci.confno = myrpt->conf;
04350    ci.confmode = (myrpt->p.duplex == 2) ? DAHDI_CONF_CONFANNMON :
04351       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
04352    /* first put the channel on the conference in announce mode */
04353    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04354    {
04355       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04356       ast_hangup(mychannel);
04357       ast_hangup(genchannel);
04358       myrpt->callmode = 0;
04359       pthread_exit(NULL);
04360    }
04361    while(myrpt->callmode)
04362    {
04363       if ((!mychannel->pbx) && (myrpt->callmode != 4))
04364       {
04365          if(myrpt->patchfarenddisconnect){ /* If patch is setup for far end disconnect */
04366             myrpt->callmode = 0;
04367             if(!myrpt->patchquiet){
04368                rpt_mutex_unlock(&myrpt->lock);
04369                rpt_telemetry(myrpt, TERM, NULL);
04370                rpt_mutex_lock(&myrpt->lock);
04371             }
04372          }
04373          else{ /* Send congestion until patch is downed by command */
04374             myrpt->callmode = 4;
04375             rpt_mutex_unlock(&myrpt->lock);
04376             /* start congestion tone */
04377             tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
04378             rpt_mutex_lock(&myrpt->lock);
04379          }
04380       }
04381       if (myrpt->mydtmf)
04382       {
04383          struct ast_frame wf = {AST_FRAME_DTMF, } ;
04384          wf.subclass = myrpt->mydtmf;
04385          rpt_mutex_unlock(&myrpt->lock);
04386          ast_queue_frame(mychannel,&wf);
04387          ast_senddigit(genchannel,myrpt->mydtmf);
04388          rpt_mutex_lock(&myrpt->lock);
04389          myrpt->mydtmf = 0;
04390       }
04391       rpt_mutex_unlock(&myrpt->lock);
04392       usleep(MSWAIT * 1000);
04393       rpt_mutex_lock(&myrpt->lock);
04394    }
04395    rpt_mutex_unlock(&myrpt->lock);
04396    tone_zone_play_tone(genchannel->fds[0],-1);
04397    if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
04398    ast_hangup(genchannel);
04399    rpt_mutex_lock(&myrpt->lock);
04400    myrpt->callmode = 0;
04401    rpt_mutex_unlock(&myrpt->lock);
04402    /* set appropriate conference for the pseudo */
04403    ci.chan = 0;
04404    ci.confno = myrpt->conf;
04405    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
04406       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
04407    /* first put the channel on the conference in announce mode */
04408    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04409    {
04410       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04411    }
04412    pthread_exit(NULL);
04413 }
04414 
04415 static void send_link_dtmf(struct rpt *myrpt,char c)
04416 {
04417 char  str[300];
04418 struct   ast_frame wf;
04419 struct   rpt_link *l;
04420 
04421    snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
04422    wf.frametype = AST_FRAME_TEXT;
04423    wf.subclass = 0;
04424    wf.offset = 0;
04425    wf.mallocd = 0;
04426    wf.datalen = strlen(str) + 1;
04427    wf.samples = 0;
04428    l = myrpt->links.next;
04429    /* first, see if our dude is there */
04430    while(l != &myrpt->links)
04431    {
04432       if (l->name[0] == '0') 
04433       {
04434          l = l->next;
04435          continue;
04436       }
04437       /* if we found it, write it and were done */
04438       if (!strcmp(l->name,myrpt->cmdnode))
04439       {
04440          wf.data = str;
04441          if (l->chan) ast_write(l->chan,&wf);
04442          return;
04443       }
04444       l = l->next;
04445    }
04446    l = myrpt->links.next;
04447    /* if not, give it to everyone */
04448    while(l != &myrpt->links)
04449    {
04450       wf.data = str;
04451       if (l->chan) ast_write(l->chan,&wf);
04452       l = l->next;
04453    }
04454    return;
04455 }
04456 
04457 /* 
04458  * Connect a link 
04459  *
04460  * Return values:
04461  * -1: Error
04462  *  0: Success
04463  *  1: No match yet
04464  *  2: Already connected to this node
04465  */
04466 
04467 static int connect_link(struct rpt *myrpt, char* node, int mode, int perma)
04468 {
04469    char *val, *s, *s1, *s2, *tele;
04470    char lstr[MAXLINKLIST],*strs[MAXLINKLIST];
04471    char tmp[300], deststr[300] = "",modechange = 0;
04472    struct rpt_link *l;
04473    int reconnects = 0;
04474    int i,n;
04475    struct dahdi_confinfo ci;  /* conference info */
04476 
04477    val = node_lookup(myrpt,node);
04478    if (!val){
04479       if(strlen(node) >= myrpt->longestnode)
04480          return -1; /* No such node */
04481       return 1; /* No match yet */
04482    }
04483    if(debug > 3){
04484       ast_log(LOG_NOTICE,"Connect attempt to node %s\n", node);
04485       ast_log(LOG_NOTICE,"Mode: %s\n",(mode)?"Transceive":"Monitor");
04486       ast_log(LOG_NOTICE,"Connection type: %s\n",(perma)?"Permalink":"Normal");
04487    }
04488 
04489    strncpy(tmp,val,sizeof(tmp) - 1);
04490    s = tmp;
04491    s1 = strsep(&s,",");
04492    s2 = strsep(&s,",");
04493    rpt_mutex_lock(&myrpt->lock);
04494    l = myrpt->links.next;
04495    /* try to find this one in queue */
04496    while(l != &myrpt->links){
04497       if (l->name[0] == '0') 
04498       {
04499          l = l->next;
04500          continue;
04501       }
04502    /* if found matching string */
04503       if (!strcmp(l->name, node))
04504          break;
04505       l = l->next;
04506    }
04507    /* if found */
04508    if (l != &myrpt->links){ 
04509    /* if already in this mode, just ignore */
04510       if ((l->mode) || (!l->chan)) {
04511          rpt_mutex_unlock(&myrpt->lock);
04512          return 2; /* Already linked */
04513       }
04514       reconnects = l->reconnects;
04515       rpt_mutex_unlock(&myrpt->lock);
04516       if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
04517       l->retries = l->max_retries + 1;
04518       l->disced = 2;
04519       modechange = 1;
04520    } else
04521    {
04522       __mklinklist(myrpt,NULL,lstr);
04523       rpt_mutex_unlock(&myrpt->lock);
04524       n = finddelim(lstr,strs,MAXLINKLIST);
04525       for(i = 0; i < n; i++)
04526       {
04527          if ((*strs[i] < '0') || 
04528              (*strs[i] > '9')) strs[i]++;
04529          if (!strcmp(strs[i],node))
04530          {
04531             return 2; /* Already linked */
04532          }
04533       }
04534    }
04535    strncpy(myrpt->lastlinknode,node,MAXNODESTR - 1);
04536    /* establish call */
04537    l = malloc(sizeof(struct rpt_link));
04538    if (!l)
04539    {
04540       ast_log(LOG_WARNING, "Unable to malloc\n");
04541       return -1;
04542    }
04543    /* zero the silly thing */
04544    memset((char *)l,0,sizeof(struct rpt_link));
04545    l->mode = mode;
04546    l->outbound = 1;
04547    l->thisconnected = 0;
04548    strncpy(l->name, node, MAXNODESTR - 1);
04549    l->isremote = (s && ast_true(s));
04550    if (modechange) l->connected = 1;
04551    l->hasconnected = l->perma = perma;
04552 #ifdef ALLOW_LOCAL_CHANNELS
04553    if ((strncasecmp(s1,"iax2/", 5) == 0) || (strncasecmp(s1, "local/", 6) == 0))
04554          strncpy(deststr, s1, sizeof(deststr));
04555    else
04556            snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
04557 #else
04558    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
04559 #endif
04560    tele = strchr(deststr, '/');
04561    if (!tele){
04562       ast_log(LOG_WARNING,"link3:Dial number (%s) must be in format tech/number\n",deststr);
04563       free(l);
04564       return -1;
04565    }
04566    *tele++ = 0;
04567    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
04568    if (l->chan){
04569       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
04570       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
04571 #ifdef   AST_CDR_FLAG_POST_DISABLED
04572       ast_set_flag(l->chan->cdr,AST_CDR_FLAG_POST_DISABLED);
04573 #endif
04574       l->chan->whentohangup = 0;
04575       l->chan->appl = "Apprpt";
04576       l->chan->data = "(Remote Rx)";
04577       if (debug > 3)
04578          ast_log(LOG_NOTICE, "rpt (remote) initiating call to %s/%s on %s\n",
04579       deststr, tele, l->chan->name);
04580       if(l->chan->cid.cid_num)
04581          free(l->chan->cid.cid_num);
04582       l->chan->cid.cid_num = strdup(myrpt->name);
04583       ast_call(l->chan,tele,999);
04584    }
04585    else {
04586       if(debug > 3) 
04587          ast_log(LOG_NOTICE, "Unable to place call to %s/%s on %s\n",
04588       deststr,tele,l->chan->name);
04589       if (myrpt->p.archivedir)
04590       {
04591          char str[100];
04592          sprintf(str,"LINKFAIL,%s",l->name);
04593          donodelog(myrpt,str);
04594       }
04595       free(l);
04596       return -1;
04597    }
04598    /* allocate a pseudo-channel thru asterisk */
04599    l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
04600    if (!l->pchan){
04601       ast_log(LOG_WARNING,"rpt connect: Sorry unable to obtain pseudo channel\n");
04602       ast_hangup(l->chan);
04603       free(l);
04604       return -1;
04605    }
04606    ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
04607    ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
04608 #ifdef   AST_CDR_FLAG_POST_DISABLED
04609    ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
04610 #endif
04611    /* make a conference for the tx */
04612    ci.chan = 0;
04613    ci.confno = myrpt->conf;
04614    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
04615    /* first put the channel on the conference in proper mode */
04616    if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1)
04617    {
04618       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04619       ast_hangup(l->chan);
04620       ast_hangup(l->pchan);
04621       free(l);
04622       return -1;
04623    }
04624    rpt_mutex_lock(&myrpt->lock);
04625    l->reconnects = reconnects;
04626    /* insert at end of queue */
04627    l->max_retries = MAX_RETRIES;
04628    if (perma)
04629       l->max_retries = MAX_RETRIES_PERM;
04630    if (l->isremote) l->retries = l->max_retries + 1;
04631    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
04632    __kickshort(myrpt);
04633    rpt_mutex_unlock(&myrpt->lock);
04634    return 0;
04635 }
04636 
04637 
04638 
04639 /*
04640 * Internet linking function 
04641 */
04642 
04643 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
04644 {
04645 
04646    char *val, *s, *s1, *s2;
04647    char tmp[300];
04648    char digitbuf[MAXNODESTR],*strs[MAXLINKLIST];
04649    char mode,perma;
04650    struct rpt_link *l;
04651    int i,r;
04652 
04653    if(!param)
04654       return DC_ERROR;
04655       
04656          
04657    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable )
04658       return DC_ERROR;
04659 
04660    strncpy(digitbuf,digits,MAXNODESTR - 1);
04661 
04662    if(debug > 6)
04663       printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
04664       
04665    switch(myatoi(param)){
04666       case 11: /* Perm Link off */
04667       case 1: /* Link off */
04668          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
04669             strcpy(digitbuf,myrpt->lastlinknode);
04670          val = node_lookup(myrpt,digitbuf);
04671          if (!val){
04672             if(strlen(digitbuf) >= myrpt->longestnode)
04673                return DC_ERROR;
04674             break;
04675          }
04676          strncpy(tmp,val,sizeof(tmp) - 1);
04677          s = tmp;
04678          s1 = strsep(&s,",");
04679          s2 = strsep(&s,",");
04680          rpt_mutex_lock(&myrpt->lock);
04681          l = myrpt->links.next;
04682          /* try to find this one in queue */
04683          while(l != &myrpt->links){
04684             if (l->name[0] == '0') 
04685             {
04686                l = l->next;
04687                continue;
04688             }
04689             /* if found matching string */
04690             if (!strcmp(l->name, digitbuf))
04691                break;
04692             l = l->next;
04693          }
04694          if (l != &myrpt->links){ /* if found */
04695             struct   ast_frame wf;
04696 
04697             /* must use perm command on perm link */
04698             if ((myatoi(param) < 10) && 
04699                 (l->max_retries > MAX_RETRIES))
04700             {
04701                rpt_mutex_unlock(&myrpt->lock);
04702                return DC_COMPLETE;
04703             }
04704             strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
04705             l->retries = l->max_retries + 1;
04706             l->disced = 1;
04707             rpt_mutex_unlock(&myrpt->lock);
04708             wf.frametype = AST_FRAME_TEXT;
04709             wf.subclass = 0;
04710             wf.offset = 0;
04711             wf.mallocd = 0;
04712             wf.datalen = strlen(discstr) + 1;
04713             wf.samples = 0;
04714             wf.data = discstr;
04715             if (l->chan)
04716             {
04717                ast_write(l->chan,&wf);
04718                if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
04719                ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
04720             }
04721             rpt_telemetry(myrpt, COMPLETE, NULL);
04722             return DC_COMPLETE;
04723          }
04724          rpt_mutex_unlock(&myrpt->lock);  
04725          return DC_COMPLETE;
04726       case 2: /* Link Monitor */
04727       case 3: /* Link transceive */
04728       case 12: /* Link Monitor permanent */
04729       case 13: /* Link transceive permanent */
04730          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
04731             strcpy(digitbuf,myrpt->lastlinknode);
04732          /* Attempt connection  */
04733          perma = (atoi(param) > 10) ? 1 : 0;
04734          mode = (atoi(param) & 1) ? 1 : 0;
04735          r = connect_link(myrpt, digitbuf, mode, perma);
04736          switch(r){
04737             case 0:
04738                rpt_telemetry(myrpt, COMPLETE, NULL);
04739                return DC_COMPLETE;
04740 
04741             case 1:
04742                break;
04743             
04744             case 2:
04745                rpt_telemetry(myrpt, REMALREADY, NULL);
04746                return DC_COMPLETE;
04747             
04748             default:
04749                rpt_telemetry(myrpt, CONNFAIL, NULL);
04750                return DC_COMPLETE;
04751          }
04752          break;
04753 
04754       case 4: /* Enter Command Mode */
04755       
04756          /* if doesnt allow link cmd, or no links active, return */
04757          if (((command_source != SOURCE_RPT) && 
04758             (command_source != SOURCE_PHONE) &&
04759             (command_source != SOURCE_DPHONE)) ||
04760              (myrpt->links.next == &myrpt->links))
04761             return DC_COMPLETE;
04762          
04763          /* if already in cmd mode, or selected self, fughetabahtit */
04764          if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
04765          
04766             rpt_telemetry(myrpt, REMALREADY, NULL);
04767             return DC_COMPLETE;
04768          }
04769          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
04770             strcpy(digitbuf,myrpt->lastlinknode);
04771          /* node must at least exist in list */
04772          val = node_lookup(myrpt,digitbuf);
04773          if (!val){
04774             if(strlen(digitbuf) >= myrpt->longestnode)
04775                return DC_ERROR;
04776             break;
04777          
04778          }
04779          rpt_mutex_lock(&myrpt->lock);
04780          strcpy(myrpt->lastlinknode,digitbuf);
04781          strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
04782          rpt_mutex_unlock(&myrpt->lock);
04783          rpt_telemetry(myrpt, REMGO, NULL);  
04784          return DC_COMPLETE;
04785          
04786       case 5: /* Status */
04787          rpt_telemetry(myrpt, STATUS, NULL);
04788          return DC_COMPLETE;
04789 
04790       case 15: /* Full Status */
04791          rpt_telemetry(myrpt, FULLSTATUS, NULL);
04792          return DC_COMPLETE;
04793          
04794          
04795       case 6: /* All Links Off, including permalinks */
04796                        rpt_mutex_lock(&myrpt->lock);
04797          myrpt->savednodes[0] = 0;
04798                         l = myrpt->links.next;
04799                         /* loop through all links */
04800                         while(l != &myrpt->links){
04801             struct   ast_frame wf;
04802                                 if (l->name[0] == '0') /* Skip any IAXRPT monitoring */
04803                                 {
04804                                         l = l->next;
04805                                         continue;
04806                                 }
04807             /* Make a string of disconnected nodes for possible restoration */
04808             sprintf(tmp,"%c%c%s",(l->mode) ? 'X' : 'M',(l->perma) ? 'P':'T',l->name);
04809             if(strlen(tmp) + strlen(myrpt->savednodes) + 1 < MAXNODESTR){ 
04810                if(myrpt->savednodes[0])
04811                   strcat(myrpt->savednodes, ",");
04812                strcat(myrpt->savednodes, tmp);
04813             }
04814                               l->retries = l->max_retries + 1;
04815                                 l->disced = 2; /* Silently disconnect */
04816                                 rpt_mutex_unlock(&myrpt->lock);
04817             /* ast_log(LOG_NOTICE,"dumping link %s\n",l->name); */
04818                                 
04819                                 wf.frametype = AST_FRAME_TEXT;
04820                                 wf.subclass = 0;
04821                                 wf.offset = 0;
04822                                 wf.mallocd = 0;
04823                                 wf.datalen = strlen(discstr) + 1;
04824                                 wf.samples = 0;
04825                                 wf.data = discstr;
04826                                 if (l->chan)
04827                                 {
04828                                         ast_write(l->chan,&wf);
04829                                         ast_safe_sleep(l->chan,250); /* It's dead already, why check the return value? */
04830                                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
04831                                 }
04832             rpt_mutex_lock(&myrpt->lock);
04833                                 l = l->next;
04834                         }
04835          rpt_mutex_unlock(&myrpt->lock);
04836          if(debug > 3)
04837             ast_log(LOG_NOTICE,"Nodes disconnected: %s\n",myrpt->savednodes);
04838                         rpt_telemetry(myrpt, COMPLETE, NULL);
04839          return DC_COMPLETE;
04840 
04841       case 7: /* Identify last node which keyed us up */
04842          rpt_telemetry(myrpt, LASTNODEKEY, NULL);
04843          break;
04844 
04845 
04846 #ifdef   _MDC_DECODE_H_
04847       case 8:
04848          myrpt->lastunit = 0xd00d; 
04849          mdc1200_notify(myrpt,NULL,myrpt->lastunit);
04850          mdc1200_send(myrpt,myrpt->lastunit);
04851          break;
04852 #endif
04853 
04854       case 16: /* Restore links disconnected with "disconnect all links" command */
04855          strcpy(tmp, myrpt->savednodes); /* Make a copy */
04856          finddelim(tmp, strs, MAXLINKLIST); /* convert into substrings */
04857          for(i = 0; tmp[0] && strs[i] != NULL && i < MAXLINKLIST; i++){
04858             s1 = strs[i];
04859             mode = (s1[0] == 'X') ? 1 : 0;
04860             perma = (s1[1] == 'P') ? 1 : 0;
04861             connect_link(myrpt, s1 + 2, mode, perma); /* Try to reconnect */
04862          }
04863                         rpt_telemetry(myrpt, COMPLETE, NULL);
04864          break;
04865    
04866       case 200:
04867       case 201:
04868       case 202:
04869       case 203:
04870       case 204:
04871       case 205:
04872       case 206:
04873       case 207:
04874       case 208:
04875       case 209:
04876       case 210:
04877       case 211:
04878       case 212:
04879       case 213:
04880       case 214:
04881       case 215:
04882          if (((myrpt->p.propagate_dtmf) && 
04883               (command_source == SOURCE_LNK)) ||
04884              ((myrpt->p.propagate_phonedtmf) &&
04885             ((command_source == SOURCE_PHONE) ||
04886                 (command_source == SOURCE_DPHONE))))
04887                do_dtmf_local(myrpt,
04888                   remdtmfstr[myatoi(param) - 200]);
04889       default:
04890          return DC_ERROR;
04891          
04892    }
04893    
04894    return DC_INDETERMINATE;
04895 }  
04896 
04897 /*
04898 * Autopatch up
04899 */
04900 
04901 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
04902 {
04903    pthread_attr_t attr;
04904    int i, index, paramlength;
04905    char *lparam;
04906    char *value = NULL;
04907    char *paramlist[20];
04908 
04909    static char *keywords[] = {
04910    "context",
04911    "dialtime",
04912    "farenddisconnect",
04913    "noct",
04914    "quiet",
04915    NULL
04916    };
04917       
04918    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
04919       return DC_ERROR;
04920       
04921    if(debug)
04922       printf("@@@@ Autopatch up\n");
04923 
04924    if(!myrpt->callmode){
04925       /* Set defaults */
04926       myrpt->patchnoct = 0;
04927       myrpt->patchdialtime = 0;
04928       myrpt->patchfarenddisconnect = 0;
04929       myrpt->patchquiet = 0;
04930       strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
04931 
04932       if(param){
04933          /* Process parameter list */
04934          lparam = ast_strdupa(param);
04935          if(!lparam){
04936             ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
04937             return DC_ERROR;  
04938          }
04939          paramlength = finddelim(lparam, paramlist, 20);          
04940          for(i = 0; i < paramlength; i++){
04941             index = matchkeyword(paramlist[i], &value, keywords);
04942             if(value)
04943                value = skipchars(value, "= ");
04944             switch(index){
04945 
04946                case 1: /* context */
04947                   strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ;
04948                   break;
04949                   
04950                case 2: /* dialtime */
04951                   myrpt->patchdialtime = atoi(value);
04952                   break;
04953 
04954                case 3: /* farenddisconnect */
04955                   myrpt->patchfarenddisconnect = atoi(value);
04956                   break;
04957 
04958                case 4:  /* noct */
04959                   myrpt->patchnoct = atoi(value);
04960                   break;
04961 
04962                case 5: /* quiet */
04963                   myrpt->patchquiet = atoi(value);
04964                   break;
04965                            
04966                default:
04967                   break;
04968             }
04969          }
04970       }
04971    }
04972                
04973    rpt_mutex_lock(&myrpt->lock);
04974 
04975    /* if on call, force * into current audio stream */
04976    
04977    if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
04978       myrpt->mydtmf = myrpt->p.endchar;
04979    }
04980    if (myrpt->callmode){
04981       rpt_mutex_unlock(&myrpt->lock);
04982       return DC_COMPLETE;
04983    }
04984    myrpt->callmode = 1;
04985    myrpt->cidx = 0;
04986    myrpt->exten[myrpt->cidx] = 0;
04987    rpt_mutex_unlock(&myrpt->lock);
04988    pthread_attr_init(&attr);
04989    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
04990    ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
04991    return DC_COMPLETE;
04992 }
04993 
04994 /*
04995 * Autopatch down
04996 */
04997 
04998 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
04999 {
05000    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
05001       return DC_ERROR;
05002    
05003    if(debug)
05004       printf("@@@@ Autopatch down\n");
05005       
05006    rpt_mutex_lock(&myrpt->lock);
05007    
05008    if (!myrpt->callmode){
05009       rpt_mutex_unlock(&myrpt->lock);
05010       return DC_COMPLETE;
05011    }
05012    
05013    myrpt->callmode = 0;
05014    rpt_mutex_unlock(&myrpt->lock);
05015    rpt_telemetry(myrpt, TERM, NULL);
05016    return DC_COMPLETE;
05017 }
05018 
05019 /*
05020 * Status
05021 */
05022 
05023 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
05024 {
05025 
05026    if (!param)
05027       return DC_ERROR;
05028 
05029    if ((myrpt->p.s[myrpt->p.sysstate_cur].txdisable) || (myrpt->p.s[myrpt->p.sysstate_cur].userfundisable))
05030       return DC_ERROR;
05031 
05032    if(debug)
05033       printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
05034    
05035    switch(myatoi(param)){
05036       case 1: /* System ID */
05037          rpt_telemetry(myrpt, ID1, NULL);
05038          return DC_COMPLETE;
05039       case 2: /* System Time */
05040          rpt_telemetry(myrpt, STATS_TIME, NULL);
05041          return DC_COMPLETE;
05042       case 3: /* app_rpt.c version */
05043          rpt_telemetry(myrpt, STATS_VERSION, NULL);
05044       default:
05045          return DC_ERROR;
05046    }
05047    return DC_INDETERMINATE;
05048 }
05049 
05050 /*
05051 *  Macro-oni (without Salami)
05052 */
05053 
05054 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
05055 {
05056 
05057 char  *val;
05058 int   i;
05059    if (myrpt->remote)
05060       return DC_ERROR;
05061 
05062    if(debug) 
05063       printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
05064    
05065    if(strlen(digitbuf) < 1) /* needs 1 digit */
05066       return DC_INDETERMINATE;
05067          
05068    for(i = 0 ; i < digitbuf[i] ; i++) {
05069       if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
05070          return DC_ERROR;
05071    }
05072    
05073    if (*digitbuf == '0') val = myrpt->p.startupmacro;
05074    else val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
05075    /* param was 1 for local buf */
05076    if (!val){
05077                 if (strlen(digitbuf) < myrpt->macro_longest)
05078                         return DC_INDETERMINATE;
05079       rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
05080       return DC_COMPLETE;
05081    }        
05082    rpt_mutex_lock(&myrpt->lock);
05083    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
05084    {
05085       rpt_mutex_unlock(&myrpt->lock);
05086       rpt_telemetry(myrpt, MACRO_BUSY, NULL);
05087       return DC_ERROR;
05088    }
05089    myrpt->macrotimer = MACROTIME;
05090    strncat(myrpt->macrobuf, val, MAXMACRO - strlen(myrpt->macrobuf) - 1);
05091    rpt_mutex_unlock(&myrpt->lock);
05092    return DC_COMPLETE;  
05093 }
05094 
05095 /*
05096 * COP - Control operator
05097 */
05098 
05099 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
05100 {
05101    char string[16];
05102    int res;
05103 
05104    if(!param)
05105       return DC_ERROR;
05106    
05107    switch(myatoi(param)){
05108       case 1: /* System reset */
05109          res = system("killall -9 asterisk");
05110          return DC_COMPLETE;
05111 
05112       case 2:
05113          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 0;
05114          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
05115          return DC_COMPLETE;
05116          
05117       case 3:
05118          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 1;
05119          return DC_COMPLETE;
05120          
05121       case 4: /* test tone on */
05122          if (myrpt->stopgen < 0) 
05123          {
05124             myrpt->stopgen = 1;
05125          }
05126          else 
05127          {
05128             myrpt->stopgen = 0;
05129             rpt_telemetry(myrpt, TEST_TONE, NULL);
05130          }
05131          return DC_COMPLETE;
05132 
05133       case 5: /* Disgorge variables to log for debug purposes */
05134          myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
05135          return DC_COMPLETE;
05136 
05137       case 6: /* Simulate COR being activated (phone only) */
05138          if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
05139          return DC_DOKEY;  
05140 
05141 
05142       case 7: /* Time out timer enable */
05143          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 0;
05144          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTENA");
05145          return DC_COMPLETE;
05146          
05147       case 8: /* Time out timer disable */
05148          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 1;
05149          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTDIS");
05150          return DC_COMPLETE;
05151 
05152                 case 9: /* Autopatch enable */
05153                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 0;
05154                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APENA");
05155                         return DC_COMPLETE;
05156 
05157                 case 10: /* Autopatch disable */
05158                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 1;
05159                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APDIS");
05160                         return DC_COMPLETE;
05161 
05162                 case 11: /* Link Enable */
05163                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 0;
05164                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKENA");
05165                         return DC_COMPLETE;
05166 
05167                 case 12: /* Link Disable */
05168                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 1;
05169                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKDIS");
05170                         return DC_COMPLETE;
05171 
05172       case 13: /* Query System State */
05173          string[0] = string[1] = 'S';
05174          string[2] = myrpt->p.sysstate_cur + '0';
05175          string[3] = '\0';
05176          rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
05177          return DC_COMPLETE;
05178 
05179       case 14: /* Change System State */
05180          if(strlen(digitbuf) == 0)
05181             break;
05182          if((digitbuf[0] < '0') || (digitbuf[0] > '9'))
05183             return DC_ERROR;
05184          myrpt->p.sysstate_cur = digitbuf[0] - '0';
05185                         string[0] = string[1] = 'S';
05186                         string[2] = myrpt->p.sysstate_cur + '0';
05187                         string[3] = '\0';
05188                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
05189                         return DC_COMPLETE;
05190 
05191                 case 15: /* Scheduler Enable */
05192                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 0;
05193                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKENA");
05194                         return DC_COMPLETE;
05195 
05196                 case 16: /* Scheduler Disable */
05197                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 1;
05198                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKDIS");
05199                         return DC_COMPLETE;
05200 
05201                 case 17: /* User functions Enable */
05202                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 0;
05203                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFENA");
05204                         return DC_COMPLETE;
05205 
05206                 case 18: /* User Functions Disable */
05207                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 1;
05208                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFDIS");
05209                         return DC_COMPLETE;
05210 
05211                 case 19: /* Alternate Tail Enable */
05212                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 1;
05213                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATENA");
05214                         return DC_COMPLETE;
05215 
05216                 case 20: /* Alternate Tail Disable */
05217                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 0;
05218                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATDIS");
05219                         return DC_COMPLETE;
05220    }  
05221    return DC_INDETERMINATE;
05222 }
05223 
05224 /*
05225 * Collect digits one by one until something matches
05226 */
05227 
05228 static int collect_function_digits(struct rpt *myrpt, char *digits, 
05229    int command_source, struct rpt_link *mylink)
05230 {
05231    int i;
05232    char *stringp,*action,*param,*functiondigits;
05233    char function_table_name[30] = "";
05234    char workstring[200];
05235    
05236    struct ast_variable *vp;
05237    
05238    if(debug)   
05239       printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
05240    
05241    if (command_source == SOURCE_DPHONE) {
05242       if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
05243       strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1);
05244       }
05245    else if (command_source == SOURCE_PHONE) {
05246       if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
05247       strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1);
05248       }
05249    else if (command_source == SOURCE_LNK)
05250       strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1);
05251    else
05252       strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1);
05253    vp = ast_variable_browse(myrpt->cfg, function_table_name);
05254    while(vp) {
05255       if(!strncasecmp(vp->name, digits, strlen(vp->name)))
05256          break;
05257       vp = vp->next;
05258    }  
05259    if(!vp) {
05260       int n;
05261 
05262       n = myrpt->longestfunc;
05263       if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
05264       else 
05265       if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
05266       else 
05267       if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
05268       
05269       if(strlen(digits) >= n)
05270          return DC_ERROR;
05271       else
05272          return DC_INDETERMINATE;
05273    }  
05274    /* Found a match, retrieve value part and parse */
05275    strncpy(workstring, vp->value, sizeof(workstring) - 1 );
05276    stringp = workstring;
05277    action = strsep(&stringp, ",");
05278    param = stringp;
05279    if(debug)
05280       printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
05281    /* Look up the action */
05282    for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
05283       if(!strncasecmp(action, function_table[i].action, strlen(action)))
05284          break;
05285    }
05286    if(debug)
05287       printf("@@@@ table index i = %d\n",i);
05288    if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
05289       /* Error, action not in table */
05290       return DC_ERROR;
05291    }
05292    if(function_table[i].function == NULL){
05293       /* Error, function undefined */
05294       if(debug)
05295          printf("@@@@ NULL for action: %s\n",action);
05296       return DC_ERROR;
05297    }
05298    functiondigits = digits + strlen(vp->name);
05299    return (*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
05300 }
05301 
05302 
05303 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
05304    char *str)
05305 {
05306 /* XXX ATTENTION: if you change the size of these arrays you MUST
05307  * change the limits in corresponding sscanf() calls below. */
05308 char  tmp[512],cmd[300] = "",dest[300],src[300],c;
05309 int   seq, res;
05310 struct rpt_link *l;
05311 struct   ast_frame wf;
05312 
05313    wf.frametype = AST_FRAME_TEXT;
05314    wf.subclass = 0;
05315    wf.offset = 0;
05316    wf.mallocd = 0;
05317    wf.datalen = strlen(str) + 1;
05318    wf.samples = 0;
05319    /* put string in our buffer */
05320    strncpy(tmp,str,sizeof(tmp) - 1);
05321 
05322         if (!strcmp(tmp,discstr))
05323         {
05324                 mylink->disced = 1;
05325       mylink->retries = mylink->max_retries + 1;
05326                 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
05327                 return;
05328         }
05329    if (tmp[0] == 'L')
05330    {
05331       rpt_mutex_lock(&myrpt->lock);
05332       strcpy(mylink->linklist,tmp + 2);
05333       time(&mylink->linklistreceived);
05334       rpt_mutex_unlock(&myrpt->lock);
05335       if (debug > 6) ast_log(LOG_NOTICE,"@@@@ node %s received node list %s from node %s\n",
05336          myrpt->name,tmp,mylink->name);
05337       return;
05338    }
05339    if (tmp[0] == 'I')
05340    {
05341       /* XXX WARNING: be very careful with the limits on the folowing
05342        * sscanf() call, make sure they match the values defined above */
05343       if (sscanf(tmp,"%299s %299s %30x",cmd,src,&seq) != 3)
05344       {
05345          ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
05346          return;
05347       }
05348       mdc1200_notify(myrpt,src,seq);
05349       strcpy(dest,"*");
05350    }
05351    else
05352    {
05353       /* XXX WARNING: be very careful with the limits on the folowing
05354        * sscanf() call, make sure they match the values defined above */
05355       if (sscanf(tmp,"%299s %299s %299s %30d %1c",cmd,dest,src,&seq,&c) != 5)
05356       {
05357          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
05358          return;
05359       }
05360       if (strcmp(cmd,"D"))
05361       {
05362          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
05363          return;
05364       }
05365    }
05366    if (dest[0] == '0')
05367    {
05368       strcpy(dest,myrpt->name);
05369    }     
05370 
05371    /* if not for me, redistribute to all links */
05372    if (strcmp(dest,myrpt->name))
05373    {
05374       l = myrpt->links.next;
05375       /* see if this is one in list */
05376       while(l != &myrpt->links)
05377       {
05378          if (l->name[0] == '0') 
05379          {
05380             l = l->next;
05381             continue;
05382          }
05383          /* dont send back from where it came */
05384          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
05385          {
05386             l = l->next;
05387             continue;
05388          }
05389          /* if it is, send it and we're done */
05390          if (!strcmp(l->name,dest))
05391          {
05392             /* send, but not to src */
05393             if (strcmp(l->name,src)) {
05394                wf.data = str;
05395                if (l->chan) ast_write(l->chan,&wf);
05396             }
05397             return;
05398          }
05399          l = l->next;
05400       }
05401       l = myrpt->links.next;
05402       /* otherwise, send it to all of em */
05403       while(l != &myrpt->links)
05404       {
05405          if (l->name[0] == '0') 
05406          {
05407             l = l->next;
05408             continue;
05409          }
05410          /* dont send back from where it came */
05411          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
05412          {
05413             l = l->next;
05414             continue;
05415          }
05416          /* send, but not to src */
05417          if (strcmp(l->name,src)) {
05418             wf.data = str;
05419             if (l->chan) ast_write(l->chan,&wf); 
05420          }
05421          l = l->next;
05422       }
05423       return;
05424    }
05425    if (myrpt->p.archivedir)
05426    {
05427       char str[100];
05428 
05429       sprintf(str,"DTMF,%s,%c",mylink->name,c);
05430       donodelog(myrpt,str);
05431    }
05432    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
05433    if (!c) return;
05434    rpt_mutex_lock(&myrpt->lock);
05435    if (c == myrpt->p.endchar) myrpt->stopgen = 1;
05436    if (myrpt->callmode == 1)
05437    {
05438       myrpt->exten[myrpt->cidx++] = c;
05439       myrpt->exten[myrpt->cidx] = 0;
05440       /* if this exists */
05441       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
05442       {
05443          myrpt->callmode = 2;
05444          if(!myrpt->patchquiet){
05445             rpt_mutex_unlock(&myrpt->lock);
05446             rpt_telemetry(myrpt,PROC,NULL); 
05447             rpt_mutex_lock(&myrpt->lock);
05448          }
05449       }
05450       /* if can continue, do so */
05451       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL)) 
05452       {
05453          /* call has failed, inform user */
05454          myrpt->callmode = 4;
05455       }
05456    }
05457    if (c == myrpt->p.funcchar)
05458    {
05459       myrpt->rem_dtmfidx = 0;
05460       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
05461       time(&myrpt->rem_dtmf_time);
05462       rpt_mutex_unlock(&myrpt->lock);
05463       return;
05464    } 
05465    else if (myrpt->rem_dtmfidx < 0)
05466    {
05467       if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
05468       {
05469          myrpt->mydtmf = c;
05470       }
05471       if (myrpt->p.propagate_dtmf) do_dtmf_local(myrpt,c);
05472       if (myrpt->p.propagate_phonedtmf) do_dtmf_phone(myrpt,mylink,c);
05473       rpt_mutex_unlock(&myrpt->lock);
05474       return;
05475    }
05476    else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
05477    {
05478       time(&myrpt->rem_dtmf_time);
05479       if (myrpt->rem_dtmfidx < MAXDTMF)
05480       {
05481          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
05482          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
05483          
05484          rpt_mutex_unlock(&myrpt->lock);
05485          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
05486          res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
05487          rpt_mutex_lock(&myrpt->lock);
05488          
05489          switch(res){
05490 
05491             case DC_INDETERMINATE:
05492                break;
05493             
05494             case DC_REQ_FLUSH:
05495                myrpt->rem_dtmfidx = 0;
05496                myrpt->rem_dtmfbuf[0] = 0;
05497                break;
05498             
05499             
05500             case DC_COMPLETE:
05501             case DC_COMPLETEQUIET:
05502                myrpt->totalexecdcommands++;
05503                myrpt->dailyexecdcommands++;
05504                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
05505                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
05506                myrpt->rem_dtmfbuf[0] = 0;
05507                myrpt->rem_dtmfidx = -1;
05508                myrpt->rem_dtmf_time = 0;
05509                break;
05510             
05511             case DC_ERROR:
05512             default:
05513                myrpt->rem_dtmfbuf[0] = 0;
05514                myrpt->rem_dtmfidx = -1;
05515                myrpt->rem_dtmf_time = 0;
05516                break;
05517          }
05518       }
05519 
05520    }
05521    rpt_mutex_unlock(&myrpt->lock);
05522    return;
05523 }
05524 
05525 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
05526    char c)
05527 {
05528 
05529 char  cmd[300];
05530 int   res;
05531 
05532    if (myrpt->p.archivedir)
05533    {
05534       char str[100];
05535 
05536       sprintf(str,"DTMF(P),%s,%c",mylink->name,c);
05537       donodelog(myrpt,str);
05538    }
05539    rpt_mutex_lock(&myrpt->lock);
05540    if (c == myrpt->p.endchar)
05541    {
05542       if (mylink->lastrx)
05543       {
05544          mylink->lastrx = 0;
05545          rpt_mutex_unlock(&myrpt->lock);
05546          return;
05547       }
05548       myrpt->stopgen = 1;
05549       if (myrpt->cmdnode[0])
05550       {
05551          myrpt->cmdnode[0] = 0;
05552          myrpt->dtmfidx = -1;
05553          myrpt->dtmfbuf[0] = 0;
05554          rpt_mutex_unlock(&myrpt->lock);
05555          rpt_telemetry(myrpt,COMPLETE,NULL);
05556          return;
05557       }
05558    }
05559    if (myrpt->cmdnode[0])
05560    {
05561       rpt_mutex_unlock(&myrpt->lock);
05562       send_link_dtmf(myrpt,c);
05563       return;
05564    }
05565    if (myrpt->callmode == 1)
05566    {
05567       myrpt->exten[myrpt->cidx++] = c;
05568       myrpt->exten[myrpt->cidx] = 0;
05569       /* if this exists */
05570       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
05571       {
05572          myrpt->callmode = 2;
05573          if(!myrpt->patchquiet){
05574             rpt_mutex_unlock(&myrpt->lock);
05575             rpt_telemetry(myrpt,PROC,NULL); 
05576             rpt_mutex_lock(&myrpt->lock);
05577          }
05578       }
05579       /* if can continue, do so */
05580       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL)) 
05581       {
05582          /* call has failed, inform user */
05583          myrpt->callmode = 4;
05584       }
05585    }
05586    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
05587    {
05588       myrpt->mydtmf = c;
05589    }
05590    if (c == myrpt->p.funcchar)
05591    {
05592       myrpt->rem_dtmfidx = 0;
05593       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
05594       time(&myrpt->rem_dtmf_time);
05595       rpt_mutex_unlock(&myrpt->lock);
05596       return;
05597    } 
05598    else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
05599    {
05600       time(&myrpt->rem_dtmf_time);
05601       if (myrpt->rem_dtmfidx < MAXDTMF)
05602       {
05603          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
05604          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
05605          
05606          rpt_mutex_unlock(&myrpt->lock);
05607          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
05608          switch(mylink->phonemode)
05609          {
05610              case 1:
05611             res = collect_function_digits(myrpt, cmd, 
05612                SOURCE_PHONE, mylink);
05613             break;
05614              case 2:
05615             res = collect_function_digits(myrpt, cmd, 
05616                SOURCE_DPHONE,mylink);
05617             break;
05618              default:
05619             res = collect_function_digits(myrpt, cmd, 
05620                SOURCE_LNK, mylink);
05621             break;
05622          }
05623 
05624          rpt_mutex_lock(&myrpt->lock);
05625          
05626          switch(res){
05627 
05628             case DC_INDETERMINATE:
05629                break;
05630             
05631             case DC_DOKEY:
05632                mylink->lastrx = 1;
05633                break;
05634             
05635             case DC_REQ_FLUSH:
05636                myrpt->rem_dtmfidx = 0;
05637                myrpt->rem_dtmfbuf[0] = 0;
05638                break;
05639             
05640             
05641             case DC_COMPLETE:
05642             case DC_COMPLETEQUIET:
05643                myrpt->totalexecdcommands++;
05644                myrpt->dailyexecdcommands++;
05645                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
05646                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
05647                myrpt->rem_dtmfbuf[0] = 0;
05648                myrpt->rem_dtmfidx = -1;
05649                myrpt->rem_dtmf_time = 0;
05650                break;
05651             
05652             case DC_ERROR:
05653             default:
05654                myrpt->rem_dtmfbuf[0] = 0;
05655                myrpt->rem_dtmfidx = -1;
05656                myrpt->rem_dtmf_time = 0;
05657                break;
05658          }
05659       }
05660 
05661    }
05662    rpt_mutex_unlock(&myrpt->lock);
05663    return;
05664 }
05665 
05666 /* Doug Hall RBI-1 serial data definitions:
05667  *
05668  * Byte 0: Expansion external outputs 
05669  * Byte 1: 
05670  * Bits 0-3 are BAND as follows:
05671  * Bits 4-5 are POWER bits as follows:
05672  *    00 - Low Power
05673  *    01 - Hi Power
05674  *    02 - Med Power
05675  * Bits 6-7 are always set
05676  * Byte 2:
05677  * Bits 0-3 MHZ in BCD format
05678  * Bits 4-5 are offset as follows:
05679  *    00 - minus
05680  *    01 - plus
05681  *    02 - simplex
05682  *    03 - minus minus (whatever that is)
05683  * Bit 6 is the 0/5 KHZ bit
05684  * Bit 7 is always set
05685  * Byte 3:
05686  * Bits 0-3 are 10 KHZ in BCD format
05687  * Bits 4-7 are 100 KHZ in BCD format
05688  * Byte 4: PL Tone code and encode/decode enable bits
05689  * Bits 0-5 are PL tone code (comspec binary codes)
05690  * Bit 6 is encode enable/disable
05691  * Bit 7 is decode enable/disable
05692  */
05693 
05694 /* take the frequency from the 10 mhz digits (and up) and convert it
05695    to a band number */
05696 
05697 static int rbi_mhztoband(char *str)
05698 {
05699 int   i;
05700 
05701    i = atoi(str) / 10; /* get the 10's of mhz */
05702    switch(i)
05703    {
05704        case 2:
05705       return 10;
05706        case 5:
05707       return 11;
05708        case 14:
05709       return 2;
05710        case 22:
05711       return 3;
05712        case 44:
05713       return 4;
05714        case 124:
05715       return 0;
05716        case 125:
05717       return 1;
05718        case 126:
05719       return 8;
05720        case 127:
05721       return 5;
05722        case 128:
05723       return 6;
05724        case 129:
05725       return 7;
05726        default:
05727       break;
05728    }
05729    return -1;
05730 }
05731 
05732 /* take a PL frequency and turn it into a code */
05733 static int rbi_pltocode(char *str)
05734 {
05735 int i;
05736 char *s;
05737 
05738    s = strchr(str,'.');
05739    i = 0;
05740    if (s) i = atoi(s + 1);
05741    i += atoi(str) * 10;
05742    switch(i)
05743    {
05744        case 670:
05745       return 0;
05746        case 719:
05747       return 1;
05748        case 744:
05749       return 2;
05750        case 770:
05751       return 3;
05752        case 797:
05753       return 4;
05754        case 825:
05755       return 5;
05756        case 854:
05757       return 6;
05758        case 885:
05759       return 7;
05760        case 915:
05761       return 8;
05762        case 948:
05763       return 9;
05764        case 974:
05765       return 10;
05766        case 1000:
05767       return 11;
05768        case 1035:
05769       return 12;
05770        case 1072:
05771       return 13;
05772        case 1109:
05773       return 14;
05774        case 1148:
05775       return 15;
05776        case 1188:
05777       return 16;
05778        case 1230:
05779       return 17;
05780        case 1273:
05781       return 18;
05782        case 1318:
05783       return 19;
05784        case 1365:
05785       return 20;
05786        case 1413:
05787       return 21;
05788        case 1462:
05789       return 22;
05790        case 1514:
05791       return 23;
05792        case 1567:
05793       return 24;
05794        case 1622:
05795       return 25;
05796        case 1679:
05797       return 26;
05798        case 1738:
05799       return 27;
05800        case 1799:
05801       return 28;
05802        case 1862:
05803       return 29;
05804        case 1928:
05805       return 30;
05806        case 2035:
05807       return 31;
05808        case 2107:
05809       return 32;
05810        case 2181:
05811       return 33;
05812        case 2257:
05813       return 34;
05814        case 2336:
05815       return 35;
05816        case 2418:
05817       return 36;
05818        case 2503:
05819       return 37;
05820    }
05821    return -1;
05822 }
05823 
05824 /*
05825 * Shift out a formatted serial bit stream
05826 */
05827 
05828 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
05829     {
05830 #ifdef __i386__
05831     int i,j;
05832     unsigned char od,d;
05833     static volatile long long delayvar;
05834 
05835     for(i = 0 ; i < 5 ; i++){
05836         od = *data++; 
05837         for(j = 0 ; j < 8 ; j++){
05838             d = od & 1;
05839             outb(d,myrpt->p.iobase);
05840        /* >= 15 us */
05841        for(delayvar = 1; delayvar < 15000; delayvar++); 
05842             od >>= 1;
05843             outb(d | 2,myrpt->p.iobase);
05844        /* >= 30 us */
05845        for(delayvar = 1; delayvar < 30000; delayvar++); 
05846             outb(d,myrpt->p.iobase);
05847        /* >= 10 us */
05848        for(delayvar = 1; delayvar < 10000; delayvar++); 
05849             }
05850         }
05851    /* >= 50 us */
05852         for(delayvar = 1; delayvar < 50000; delayvar++); 
05853 #endif
05854     }
05855 
05856 static void rbi_out(struct rpt *myrpt,unsigned char *data)
05857 {
05858 struct dahdi_radio_param r;
05859 
05860    memset(&r,0,sizeof(struct dahdi_radio_param));
05861    r.radpar = DAHDI_RADPAR_REMMODE;
05862    r.data = DAHDI_RADPAR_REM_RBI1;
05863    /* if setparam ioctl fails, its probably not a pciradio card */
05864    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
05865    {
05866       rbi_out_parallel(myrpt,data);
05867       return;
05868    }
05869    r.radpar = DAHDI_RADPAR_REMCOMMAND;
05870    memcpy(&r.data,data,5);
05871    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
05872    {
05873       ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->zaprxchannel->name);
05874       return;
05875    }
05876 }
05877 
05878 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, 
05879    unsigned char *rxbuf, int rxmaxbytes, int asciiflag)
05880 {
05881    int i,j,index,oldmode,olddata;
05882    struct dahdi_radio_param prm;
05883    char c;
05884 
05885    if(debug){
05886       printf("String output was: ");
05887       for(i = 0; i < txbytes; i++)
05888          printf("%02X ", (unsigned char ) txbuf[i]);
05889       printf("\n");
05890    }
05891    if (myrpt->iofd > 0)  /* if to do out a serial port */
05892    {
05893       if (rxmaxbytes && rxbuf) tcflush(myrpt->iofd,TCIFLUSH);     
05894       if (write(myrpt->iofd,txbuf,txbytes) != txbytes) return -1;
05895       if ((!rxmaxbytes) || (rxbuf == NULL)) return(0);
05896       memset(rxbuf,0,rxmaxbytes);
05897       for(i = 0; i < rxmaxbytes; i++)
05898       {
05899          j = read(myrpt->iofd,&c,1);
05900          if (j < 1) return(i);
05901          rxbuf[i] = c;
05902          if (asciiflag & 1)
05903          {
05904             rxbuf[i + 1] = 0;
05905             if (c == '\r') break;
05906          }
05907       }              
05908       if(debug){
05909          printf("String returned was: ");
05910          for(j = 0; j < i; j++)
05911             printf("%02X ", (unsigned char ) rxbuf[j]);
05912          printf("\n");
05913       }
05914       return(i);
05915    }
05916 
05917    /* if not a zap channel, cant use pciradio stuff */
05918    if (myrpt->rxchannel != myrpt->zaprxchannel) return -1;  
05919 
05920    prm.radpar = DAHDI_RADPAR_UIOMODE;
05921    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
05922    oldmode = prm.data;
05923    prm.radpar = DAHDI_RADPAR_UIODATA;
05924    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
05925    olddata = prm.data;
05926         prm.radpar = DAHDI_RADPAR_REMMODE;
05927         if (asciiflag & 1)  prm.data = DAHDI_RADPAR_REM_SERIAL_ASCII;
05928         else prm.data = DAHDI_RADPAR_REM_SERIAL;
05929    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
05930    if (asciiflag & 2)
05931    {
05932       i = DAHDI_ONHOOK;
05933       if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
05934       usleep(100000);
05935    }
05936         prm.radpar = DAHDI_RADPAR_REMCOMMAND;
05937         prm.data = rxmaxbytes;
05938         memcpy(prm.buf,txbuf,txbytes);
05939         prm.index = txbytes;
05940    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
05941         if (rxbuf)
05942         {
05943                 *rxbuf = 0;
05944                 memcpy(rxbuf,prm.buf,prm.index);
05945         }
05946    index = prm.index;
05947         prm.radpar = DAHDI_RADPAR_REMMODE;
05948         prm.data = DAHDI_RADPAR_REM_NONE;
05949    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
05950    if (asciiflag & 2)
05951    {
05952       i = DAHDI_OFFHOOK;
05953       if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
05954    }
05955    prm.radpar = DAHDI_RADPAR_UIOMODE;
05956    prm.data = oldmode;
05957    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
05958    prm.radpar = DAHDI_RADPAR_UIODATA;
05959    prm.data = olddata;
05960    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
05961         return(index);
05962 }
05963 
05964 static int civ_cmd(struct rpt *myrpt,unsigned char *cmd, int cmdlen)
05965 {
05966 unsigned char rxbuf[100];
05967 int   i,rv ;
05968 
05969    rv = serial_remote_io(myrpt,cmd,cmdlen,rxbuf,cmdlen + 6,0);
05970    if (rv == -1) return(-1);
05971    if (rv != (cmdlen + 6)) return(1);
05972    for(i = 0; i < 6; i++)
05973       if (rxbuf[i] != cmd[i]) return(1);
05974    if (rxbuf[cmdlen] != 0xfe) return(1);
05975    if (rxbuf[cmdlen + 1] != 0xfe) return(1);
05976    if (rxbuf[cmdlen + 4] != 0xfb) return(1);
05977    if (rxbuf[cmdlen + 5] != 0xfd) return(1);
05978    return(0);
05979 }
05980 
05981 static int sendkenwood(struct rpt *myrpt,char *txstr, char *rxstr)
05982 {
05983 int   i;
05984 
05985    if (debug) printf("Send to kenwood: %s\n",txstr);
05986    i = serial_remote_io(myrpt, (unsigned char *)txstr, strlen(txstr), 
05987       (unsigned char *)rxstr,RAD_SERIAL_BUFLEN - 1,3);
05988    if (i < 0) return -1;
05989    if ((i > 0) && (rxstr[i - 1] == '\r'))
05990       rxstr[i-- - 1] = 0;
05991    if (debug) printf("Got from kenwood: %s\n",rxstr);
05992    return(i);
05993 }
05994 
05995 /* take a PL frequency and turn it into a code */
05996 static int kenwood_pltocode(char *str)
05997 {
05998 int i;
05999 char *s;
06000 
06001    s = strchr(str,'.');
06002    i = 0;
06003    if (s) i = atoi(s + 1);
06004    i += atoi(str) * 10;
06005    switch(i)
06006    {
06007        case 670:
06008       return 1;
06009        case 719:
06010       return 3;
06011        case 744:
06012       return 4;
06013        case 770:
06014       return 5;
06015        case 797:
06016       return 6;
06017        case 825:
06018       return 7;
06019        case 854:
06020       return 8;
06021        case 885:
06022       return 9;
06023        case 915:
06024       return 10;
06025        case 948:
06026       return 11;
06027        case 974:
06028       return 12;
06029        case 1000:
06030       return 13;
06031        case 1035:
06032       return 14;
06033        case 1072:
06034       return 15;
06035        case 1109:
06036       return 16;
06037        case 1148:
06038       return 17;
06039        case 1188:
06040       return 18;
06041        case 1230:
06042       return 19;
06043        case 1273:
06044       return 20;
06045        case 1318:
06046       return 21;
06047        case 1365:
06048       return 22;
06049        case 1413:
06050       return 23;
06051        case 1462:
06052       return 24;
06053        case 1514:
06054       return 25;
06055        case 1567:
06056       return 26;
06057        case 1622:
06058       return 27;
06059        case 1679:
06060       return 28;
06061        case 1738:
06062       return 29;
06063        case 1799:
06064       return 30;
06065        case 1862:
06066       return 31;
06067        case 1928:
06068       return 32;
06069        case 2035:
06070       return 33;
06071        case 2107:
06072       return 34;
06073        case 2181:
06074       return 35;
06075        case 2257:
06076       return 36;
06077        case 2336:
06078       return 37;
06079        case 2418:
06080       return 38;
06081        case 2503:
06082       return 39;
06083    }
06084    return -1;
06085 }
06086 
06087 static int sendrxkenwood(struct rpt *myrpt, char *txstr, char *rxstr, 
06088    char *cmpstr)
06089 {
06090 int   i,j;
06091 
06092    for(i = 0;i < KENWOOD_RETRIES;i++)
06093    {
06094       j = sendkenwood(myrpt,txstr,rxstr);
06095       if (j < 0) return(j);
06096       if (j == 0) continue;
06097       if (!strncmp(rxstr,cmpstr,strlen(cmpstr))) return(0);
06098    }
06099    return(-1);
06100 }     
06101 
06102 static int setkenwood(struct rpt *myrpt)
06103 {
06104 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
06105 char mhz[MAXREMSTR],offset[20],band,decimals[MAXREMSTR],band1,band2;
06106    
06107 int offsets[] = {0,2,1};
06108 int powers[] = {2,1,0};
06109 
06110    if (sendrxkenwood(myrpt,"VMC 0,0\r",rxstr,"VMC") < 0) return -1;
06111    split_freq(mhz, decimals, myrpt->freq);
06112    if (atoi(mhz) > 400)
06113    {
06114       band = '6';
06115       band1 = '1';
06116       band2 = '5';
06117       strcpy(offset,"005000000");
06118    }
06119    else
06120    {
06121       band = '2';
06122       band1 = '0';
06123       band2 = '2';
06124       strcpy(offset,"000600000");
06125    }
06126    strcpy(freq,"000000");
06127    strncpy(freq,decimals,strlen(decimals));
06128    sprintf(txstr,"VW %c,%05d%s,0,%d,0,%d,%d,,%02d,,%02d,%s\r",
06129       band,atoi(mhz),freq,offsets[(int)myrpt->offset],
06130       (myrpt->txplon != 0),(myrpt->rxplon != 0),
06131       kenwood_pltocode(myrpt->txpl),kenwood_pltocode(myrpt->rxpl),
06132       offset);
06133    if (sendrxkenwood(myrpt,txstr,rxstr,"VW") < 0) return -1;
06134    sprintf(txstr,"RBN %c\r",band2);
06135    if (sendrxkenwood(myrpt,txstr,rxstr,"RBN") < 0) return -1;
06136    sprintf(txstr,"PC %c,%d\r",band1,powers[(int)myrpt->powerlevel]);
06137    if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
06138    return 0;
06139 }
06140 
06141 static int setrbi(struct rpt *myrpt)
06142 {
06143 char tmp[MAXREMSTR] = "",*s;
06144 unsigned char rbicmd[5];
06145 int   band,txoffset = 0,txpower = 0,rxpl;
06146 
06147    /* must be a remote system */
06148    if (!myrpt->remote) return(0);
06149    /* must have rbi hardware */
06150    if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
06151    if (setrbi_check(myrpt) == -1) return(-1);
06152    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
06153    s = strchr(tmp,'.');
06154    /* if no decimal, is invalid */
06155    
06156    if (s == NULL){
06157       if(debug)
06158          printf("@@@@ Frequency needs a decimal\n");
06159       return -1;
06160    }
06161    
06162    *s++ = 0;
06163    if (strlen(tmp) < 2){
06164       if(debug)
06165          printf("@@@@ Bad MHz digits: %s\n", tmp);
06166       return -1;
06167    }
06168     
06169    if (strlen(s) < 3){
06170       if(debug)
06171          printf("@@@@ Bad KHz digits: %s\n", s);
06172       return -1;
06173    }
06174 
06175    if ((s[2] != '0') && (s[2] != '5')){
06176       if(debug)
06177          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
06178       return -1;
06179    }
06180     
06181    band = rbi_mhztoband(tmp);
06182    if (band == -1){
06183       if(debug)
06184          printf("@@@@ Bad Band: %s\n", tmp);
06185       return -1;
06186    }
06187    
06188    rxpl = rbi_pltocode(myrpt->rxpl);
06189    
06190    if (rxpl == -1){
06191       if(debug)
06192          printf("@@@@ Bad TX PL: %s\n", myrpt->rxpl);
06193       return -1;
06194    }
06195 
06196    
06197    switch(myrpt->offset)
06198    {
06199        case REM_MINUS:
06200       txoffset = 0;
06201       break;
06202        case REM_PLUS:
06203       txoffset = 0x10;
06204       break;
06205        case REM_SIMPLEX:
06206       txoffset = 0x20;
06207       break;
06208    }
06209    switch(myrpt->powerlevel)
06210    {
06211        case REM_LOWPWR:
06212       txpower = 0;
06213       break;
06214        case REM_MEDPWR:
06215       txpower = 0x20;
06216       break;
06217        case REM_HIPWR:
06218       txpower = 0x10;
06219       break;
06220    }
06221    rbicmd[0] = 0;
06222    rbicmd[1] = band | txpower | 0xc0;
06223    rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
06224    if (s[2] == '5') rbicmd[2] |= 0x40;
06225    rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
06226    rbicmd[4] = rxpl;
06227    if (myrpt->txplon) rbicmd[4] |= 0x40;
06228    if (myrpt->rxplon) rbicmd[4] |= 0x80;
06229    rbi_out(myrpt,rbicmd);
06230    return 0;
06231 }
06232 
06233 static int setrbi_check(struct rpt *myrpt)
06234 {
06235 char tmp[MAXREMSTR] = "",*s;
06236 int   band,txpl;
06237 
06238    /* must be a remote system */
06239    if (!myrpt->remote) return(0);
06240    /* must have rbi hardware */
06241    if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
06242    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
06243    s = strchr(tmp,'.');
06244    /* if no decimal, is invalid */
06245    
06246    if (s == NULL){
06247       if(debug)
06248          printf("@@@@ Frequency needs a decimal\n");
06249       return -1;
06250    }
06251    
06252    *s++ = 0;
06253    if (strlen(tmp) < 2){
06254       if(debug)
06255          printf("@@@@ Bad MHz digits: %s\n", tmp);
06256       return -1;
06257    }
06258     
06259    if (strlen(s) < 3){
06260       if(debug)
06261          printf("@@@@ Bad KHz digits: %s\n", s);
06262       return -1;
06263    }
06264 
06265    if ((s[2] != '0') && (s[2] != '5')){
06266       if(debug)
06267          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
06268       return -1;
06269    }
06270     
06271    band = rbi_mhztoband(tmp);
06272    if (band == -1){
06273       if(debug)
06274          printf("@@@@ Bad Band: %s\n", tmp);
06275       return -1;
06276    }
06277    
06278    txpl = rbi_pltocode(myrpt->txpl);
06279    
06280    if (txpl == -1){
06281       if(debug)
06282          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
06283       return -1;
06284    }
06285    return 0;
06286 }
06287 
06288 static int check_freq_kenwood(int m, int d, int *defmode)
06289 {
06290    int dflmd = REM_MODE_FM;
06291 
06292    if (m == 144){ /* 2 meters */
06293       if(d < 10100)
06294          return -1;
06295    }
06296    else if((m >= 145) && (m < 148)){
06297       ;
06298    }
06299    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
06300       ;
06301    }
06302    else
06303       return -1;
06304    
06305    if(defmode)
06306       *defmode = dflmd; 
06307 
06308 
06309    return 0;
06310 }
06311 
06312 
06313 /* Check for valid rbi frequency */
06314 /* Hard coded limits now, configurable later, maybe? */
06315 
06316 static int check_freq_rbi(int m, int d, int *defmode)
06317 {
06318    int dflmd = REM_MODE_FM;
06319 
06320    if(m == 50){ /* 6 meters */
06321       if(d < 10100)
06322          return -1;
06323    }
06324    else if((m >= 51) && ( m < 54)){
06325                 ;
06326    }
06327    else if(m == 144){ /* 2 meters */
06328       if(d < 10100)
06329          return -1;
06330    }
06331    else if((m >= 145) && (m < 148)){
06332       ;
06333    }
06334    else if((m >= 222) && (m < 225)){ /* 1.25 meters */
06335       ;
06336    }
06337    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
06338       ;
06339    }
06340    else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
06341       ;
06342    }
06343    else
06344       return -1;
06345    
06346    if(defmode)
06347       *defmode = dflmd; 
06348 
06349 
06350    return 0;
06351 }
06352 
06353 /*
06354  * Convert decimals of frequency to int
06355  */
06356 
06357 static int decimals2int(char *fraction)
06358 {
06359    int i;
06360    char len = strlen(fraction);
06361    int multiplier = 100000;
06362    int res = 0;
06363 
06364    if(!len)
06365       return 0;
06366    for( i = 0 ; i < len ; i++, multiplier /= 10)
06367       res += (fraction[i] - '0') * multiplier;
06368    return res;
06369 }
06370 
06371 
06372 /*
06373 * Split frequency into mhz and decimals
06374 */
06375  
06376 static int split_freq(char *mhz, char *decimals, char *freq)
06377 {
06378    char freq_copy[MAXREMSTR];
06379    char *decp;
06380 
06381    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
06382    if(decp){
06383       *decp++ = 0;
06384       strncpy(mhz, freq_copy, MAXREMSTR);
06385       strcpy(decimals, "00000");
06386       strncpy(decimals, decp, strlen(decp));
06387       decimals[5] = 0;
06388       return 0;
06389    }
06390    else
06391       return -1;
06392 
06393 }
06394    
06395 /*
06396 * Split ctcss frequency into hertz and decimal
06397 */
06398  
06399 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
06400 {
06401    char freq_copy[MAXREMSTR];
06402    char *decp;
06403 
06404    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
06405    if(decp){
06406       *decp++ = 0;
06407       strncpy(hertz, freq_copy, MAXREMSTR);
06408       strncpy(decimal, decp, strlen(decp));
06409       decimal[strlen(decp)] = '\0';
06410       return 0;
06411    }
06412    else
06413       return -1;
06414 }
06415 
06416 
06417 
06418 /*
06419 * FT-897 I/O handlers
06420 */
06421 
06422 /* Check to see that the frequency is valid */
06423 /* Hard coded limits now, configurable later, maybe? */
06424 
06425 
06426 static int check_freq_ft897(int m, int d, int *defmode)
06427 {
06428    int dflmd = REM_MODE_FM;
06429 
06430    if(m == 1){ /* 160 meters */
06431       dflmd =  REM_MODE_LSB; 
06432       if(d < 80000)
06433          return -1;
06434    }
06435    else if(m == 3){ /* 80 meters */
06436       dflmd = REM_MODE_LSB;
06437       if(d < 50000)
06438          return -1;
06439    }
06440    else if(m == 7){ /* 40 meters */
06441       dflmd = REM_MODE_LSB;
06442       if(d > 30000)
06443          return -1;
06444    }
06445    else if(m == 14){ /* 20 meters */
06446       dflmd = REM_MODE_USB;
06447       if(d > 35000)
06448          return -1;
06449    }
06450    else if(m == 18){ /* 17 meters */
06451       dflmd = REM_MODE_USB;
06452       if((d < 6800) || (d > 16800))
06453          return -1;
06454    }
06455    else if(m == 21){ /* 15 meters */
06456       dflmd = REM_MODE_USB;
06457       if((d < 20000) || (d > 45000))
06458          return -1;
06459    }
06460    else if(m == 24){ /* 12 meters */
06461       dflmd = REM_MODE_USB;
06462       if((d < 89000) || (d > 99000))
06463          return -1;
06464    }
06465    else if(m == 28){ /* 10 meters */
06466       dflmd = REM_MODE_USB;
06467    }
06468    else if(m == 29){ 
06469       if(d >= 51000)
06470          dflmd = REM_MODE_FM;
06471       else
06472          dflmd = REM_MODE_USB;
06473       if(d > 70000)
06474          return -1;
06475    }
06476    else if(m == 50){ /* 6 meters */
06477       if(d >= 30000)
06478          dflmd = REM_MODE_FM;
06479       else
06480          dflmd = REM_MODE_USB;
06481 
06482    }
06483    else if((m >= 51) && ( m < 54)){
06484       dflmd = REM_MODE_FM;
06485    }
06486    else if(m == 144){ /* 2 meters */
06487       if(d >= 30000)
06488          dflmd = REM_MODE_FM;
06489       else
06490          dflmd = REM_MODE_USB;
06491    }
06492    else if((m >= 145) && (m < 148)){
06493       dflmd = REM_MODE_FM;
06494    }
06495    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
06496       if(m  < 438)
06497          dflmd = REM_MODE_USB;
06498       else
06499          dflmd = REM_MODE_FM;
06500       ;
06501    }
06502    else
06503       return -1;
06504 
06505    if(defmode)
06506       *defmode = dflmd;
06507 
06508    return 0;
06509 }
06510 
06511 /*
06512 * Set a new frequency for the FT897
06513 */
06514 
06515 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
06516 {
06517    unsigned char cmdstr[5];
06518    int fd,m,d;
06519    char mhz[MAXREMSTR];
06520    char decimals[MAXREMSTR];
06521 
06522    fd = 0;
06523    if(debug) 
06524       printf("New frequency: %s\n",newfreq);
06525 
06526    if(split_freq(mhz, decimals, newfreq))
06527       return -1; 
06528 
06529    m = atoi(mhz);
06530    d = atoi(decimals);
06531 
06532    /* The FT-897 likes packed BCD frequencies */
06533 
06534    cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10);        /* 100MHz 10Mhz */
06535    cmdstr[1] = ((m % 10) << 4) + (d / 10000);         /* 1MHz 100KHz */
06536    cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100);  /* 10KHz 1KHz */
06537    cmdstr[3] = (((d % 100)/10) << 4) + (d % 10);         /* 100Hz 10Hz */
06538    cmdstr[4] = 0x01;                /* command */
06539 
06540    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06541 
06542 }
06543 
06544 /* ft-897 simple commands */
06545 
06546 static int simple_command_ft897(struct rpt *myrpt, char command)
06547 {
06548    unsigned char cmdstr[5];
06549    
06550    memset(cmdstr, 0, 5);
06551 
06552    cmdstr[4] = command; 
06553 
06554    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06555 
06556 }
06557 
06558 /* ft-897 offset */
06559 
06560 static int set_offset_ft897(struct rpt *myrpt, char offset)
06561 {
06562    unsigned char cmdstr[5];
06563    
06564    memset(cmdstr, 0, 5);
06565 
06566    switch(offset){
06567       case  REM_SIMPLEX:
06568          cmdstr[0] = 0x89;
06569          break;
06570 
06571       case  REM_MINUS:
06572          cmdstr[0] = 0x09;
06573          break;
06574       
06575       case  REM_PLUS:
06576          cmdstr[0] = 0x49;
06577          break;   
06578 
06579       default:
06580          return -1;
06581    }
06582 
06583    cmdstr[4] = 0x09; 
06584 
06585    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06586 }
06587 
06588 /* ft-897 mode */
06589 
06590 static int set_mode_ft897(struct rpt *myrpt, char newmode)
06591 {
06592    unsigned char cmdstr[5];
06593    
06594    memset(cmdstr, 0, 5);
06595    
06596    switch(newmode){
06597       case  REM_MODE_FM:
06598          cmdstr[0] = 0x08;
06599          break;
06600 
06601       case  REM_MODE_USB:
06602          cmdstr[0] = 0x01;
06603          break;
06604 
06605       case  REM_MODE_LSB:
06606          cmdstr[0] = 0x00;
06607          break;
06608 
06609       case  REM_MODE_AM:
06610          cmdstr[0] = 0x04;
06611          break;
06612       
06613       default:
06614          return -1;
06615    }
06616    cmdstr[4] = 0x07; 
06617 
06618    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06619 }
06620 
06621 /* Set tone encode and decode modes */
06622 
06623 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
06624 {
06625    unsigned char cmdstr[5];
06626    
06627    memset(cmdstr, 0, 5);
06628    
06629    if(rxplon && txplon)
06630       cmdstr[0] = 0x2A; /* Encode and Decode */
06631    else if (!rxplon && txplon)
06632       cmdstr[0] = 0x4A; /* Encode only */
06633    else if (rxplon && !txplon)
06634       cmdstr[0] = 0x3A; /* Encode only */
06635    else
06636       cmdstr[0] = 0x8A; /* OFF */
06637 
06638    cmdstr[4] = 0x0A; 
06639 
06640    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06641 }
06642 
06643 
06644 /* Set transmit and receive ctcss tone frequencies */
06645 
06646 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
06647 {
06648    unsigned char cmdstr[5];
06649    char hertz[MAXREMSTR],decimal[MAXREMSTR];
06650    int h,d; 
06651 
06652    memset(cmdstr, 0, 5);
06653 
06654    if(split_ctcss_freq(hertz, decimal, txtone))
06655       return -1; 
06656 
06657    h = atoi(hertz);
06658    d = atoi(decimal);
06659    
06660    cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
06661    cmdstr[1] = ((h % 10) << 4) + (d % 10);
06662    
06663    if(rxtone){
06664    
06665       if(split_ctcss_freq(hertz, decimal, rxtone))
06666          return -1; 
06667 
06668       h = atoi(hertz);
06669       d = atoi(decimal);
06670    
06671       cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
06672       cmdstr[3] = ((h % 10) << 4) + (d % 10);
06673    }
06674    cmdstr[4] = 0x0B; 
06675 
06676    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06677 }  
06678 
06679 
06680 
06681 static int set_ft897(struct rpt *myrpt)
06682 {
06683    int res;
06684    
06685    if(debug)
06686       printf("@@@@ lock on\n");
06687 
06688    res = simple_command_ft897(myrpt, 0x00);  /* LOCK on */  
06689 
06690    if(debug)
06691       printf("@@@@ ptt off\n");
06692 
06693    if(!res)
06694       res = simple_command_ft897(myrpt, 0x88);     /* PTT off */
06695 
06696    if(debug)
06697       printf("Modulation mode\n");
06698 
06699    if(!res)
06700       res = set_mode_ft897(myrpt, myrpt->remmode);    /* Modulation mode */
06701 
06702    if(debug)
06703       printf("Split off\n");
06704 
06705    if(!res)
06706       simple_command_ft897(myrpt, 0x82);        /* Split off */
06707 
06708    if(debug)
06709       printf("Frequency\n");
06710 
06711    if(!res)
06712       res = set_freq_ft897(myrpt, myrpt->freq);    /* Frequency */
06713    if((myrpt->remmode == REM_MODE_FM)){
06714       if(debug)
06715          printf("Offset\n");
06716       if(!res)
06717          res = set_offset_ft897(myrpt, myrpt->offset);   /* Offset if FM */
06718       if((!res)&&(myrpt->rxplon || myrpt->txplon)){
06719          if(debug)
06720             printf("CTCSS tone freqs.\n");
06721          res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
06722       }
06723       if(!res){
06724          if(debug)
06725             printf("CTCSS mode\n");
06726          res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
06727       }
06728    }
06729    if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
06730       if(debug)
06731          printf("Clarifier off\n");
06732       simple_command_ft897(myrpt, 0x85);        /* Clarifier off if LSB or USB */
06733    }
06734    return res;
06735 }
06736 
06737 static int closerem_ft897(struct rpt *myrpt)
06738 {
06739    simple_command_ft897(myrpt, 0x88); /* PTT off */
06740    return 0;
06741 }  
06742 
06743 /*
06744 * Bump frequency up or down by a small amount 
06745 * Return 0 if the new frequnecy is valid, or -1 if invalid
06746 * Interval is in Hz, resolution is 10Hz 
06747 */
06748 
06749 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
06750 {
06751    int m,d;
06752    char mhz[MAXREMSTR], decimals[MAXREMSTR];
06753 
06754    if(debug)
06755       printf("Before bump: %s\n", myrpt->freq);
06756 
06757    if(split_freq(mhz, decimals, myrpt->freq))
06758       return -1;
06759    
06760    m = atoi(mhz);
06761    d = atoi(decimals);
06762 
06763    d += (interval / 10); /* 10Hz resolution */
06764    if(d < 0){
06765       m--;
06766       d += 100000;
06767    }
06768    else if(d >= 100000){
06769       m++;
06770       d -= 100000;
06771    }
06772 
06773    if(check_freq_ft897(m, d, NULL)){
06774       if(debug)
06775          printf("Bump freq invalid\n");
06776       return -1;
06777    }
06778 
06779    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
06780 
06781    if(debug)
06782       printf("After bump: %s\n", myrpt->freq);
06783 
06784    return set_freq_ft897(myrpt, myrpt->freq);   
06785 }
06786 
06787 
06788 
06789 /*
06790 * IC-706 I/O handlers
06791 */
06792 
06793 /* Check to see that the frequency is valid */
06794 /* Hard coded limits now, configurable later, maybe? */
06795 
06796 
06797 static int check_freq_ic706(int m, int d, int *defmode)
06798 {
06799    int dflmd = REM_MODE_FM;
06800 
06801    if(m == 1){ /* 160 meters */
06802       dflmd =  REM_MODE_LSB; 
06803       if(d < 80000)
06804          return -1;
06805    }
06806    else if(m == 3){ /* 80 meters */
06807       dflmd = REM_MODE_LSB;
06808       if(d < 50000)
06809          return -1;
06810    }
06811    else if(m == 7){ /* 40 meters */
06812       dflmd = REM_MODE_LSB;
06813       if(d > 30000)
06814          return -1;
06815    }
06816    else if(m == 14){ /* 20 meters */
06817       dflmd = REM_MODE_USB;
06818       if(d > 35000)
06819          return -1;
06820    }
06821    else if(m == 18){ /* 17 meters */
06822       dflmd = REM_MODE_USB;
06823       if((d < 6800) || (d > 16800))
06824          return -1;
06825    }
06826    else if(m == 21){ /* 15 meters */
06827       dflmd = REM_MODE_USB;
06828       if((d < 20000) || (d > 45000))
06829          return -1;
06830    }
06831    else if(m == 24){ /* 12 meters */
06832       dflmd = REM_MODE_USB;
06833       if((d < 89000) || (d > 99000))
06834          return -1;
06835    }
06836    else if(m == 28){ /* 10 meters */
06837       dflmd = REM_MODE_USB;
06838    }
06839    else if(m == 29){ 
06840       if(d >= 51000)
06841          dflmd = REM_MODE_FM;
06842       else
06843          dflmd = REM_MODE_USB;
06844       if(d > 70000)
06845          return -1;
06846    }
06847    else if(m == 50){ /* 6 meters */
06848       if(d >= 30000)
06849          dflmd = REM_MODE_FM;
06850       else
06851          dflmd = REM_MODE_USB;
06852 
06853    }
06854    else if((m >= 51) && ( m < 54)){
06855       dflmd = REM_MODE_FM;
06856    }
06857    else if(m == 144){ /* 2 meters */
06858       if(d >= 30000)
06859          dflmd = REM_MODE_FM;
06860       else
06861          dflmd = REM_MODE_USB;
06862    }
06863    else if((m >= 145) && (m < 148)){
06864       dflmd = REM_MODE_FM;
06865    }
06866    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
06867       if(m  < 438)
06868          dflmd = REM_MODE_USB;
06869       else
06870          dflmd = REM_MODE_FM;
06871       ;
06872    }
06873    else
06874       return -1;
06875 
06876    if(defmode)
06877       *defmode = dflmd;
06878 
06879    return 0;
06880 }
06881 
06882 /* take a PL frequency and turn it into a code */
06883 static int ic706_pltocode(char *str)
06884 {
06885 int i;
06886 char *s;
06887 
06888    s = strchr(str,'.');
06889    i = 0;
06890    if (s) i = atoi(s + 1);
06891    i += atoi(str) * 10;
06892    switch(i)
06893    {
06894        case 670:
06895       return 0;
06896        case 693:
06897       return 1;
06898        case 719:
06899       return 2;
06900        case 744:
06901       return 3;
06902        case 770:
06903       return 4;
06904        case 797:
06905       return 5;
06906        case 825:
06907       return 6;
06908        case 854:
06909       return 7;
06910        case 885:
06911       return 8;
06912        case 915:
06913       return 9;
06914        case 948:
06915       return 10;
06916        case 974:
06917       return 11;
06918        case 1000:
06919       return 12;
06920        case 1035:
06921       return 13;
06922        case 1072:
06923       return 14;
06924        case 1109:
06925       return 15;
06926        case 1148:
06927       return 16;
06928        case 1188:
06929       return 17;
06930        case 1230:
06931       return 18;
06932        case 1273:
06933       return 19;
06934        case 1318:
06935       return 20;
06936        case 1365:
06937       return 21;
06938        case 1413:
06939       return 22;
06940        case 1462:
06941       return 23;
06942        case 1514:
06943       return 24;
06944        case 1567:
06945       return 25;
06946        case 1598:
06947       return 26;
06948        case 1622:
06949       return 27;
06950        case 1655:
06951       return 28;     
06952        case 1679:
06953       return 29;
06954        case 1713:
06955       return 30;
06956        case 1738:
06957       return 31;
06958        case 1773:
06959       return 32;
06960        case 1799:
06961       return 33;
06962             case 1835:
06963       return 34;
06964        case 1862:
06965       return 35;
06966        case 1899:
06967       return 36;
06968        case 1928:
06969       return 37;
06970        case 1966:
06971       return 38;
06972        case 1995:
06973       return 39;
06974        case 2035:
06975       return 40;
06976        case 2065:
06977       return 41;
06978        case 2107:
06979       return 42;
06980        case 2181:
06981       return 43;
06982        case 2257:
06983       return 44;
06984        case 2291:
06985       return 45;
06986        case 2336:
06987       return 46;
06988        case 2418:
06989       return 47;
06990        case 2503:
06991       return 48;
06992        case 2541:
06993       return 49;
06994    }
06995    return -1;
06996 }
06997 
06998 /* ic-706 simple commands */
06999 
07000 static int simple_command_ic706(struct rpt *myrpt, char command, char subcommand)
07001 {
07002    unsigned char cmdstr[10];
07003    
07004    cmdstr[0] = cmdstr[1] = 0xfe;
07005    cmdstr[2] = myrpt->p.civaddr;
07006    cmdstr[3] = 0xe0;
07007    cmdstr[4] = command;
07008    cmdstr[5] = subcommand;
07009    cmdstr[6] = 0xfd;
07010 
07011    return(civ_cmd(myrpt,cmdstr,7));
07012 }
07013 
07014 /*
07015 * Set a new frequency for the ic706
07016 */
07017 
07018 static int set_freq_ic706(struct rpt *myrpt, char *newfreq)
07019 {
07020    unsigned char cmdstr[20];
07021    char mhz[MAXREMSTR], decimals[MAXREMSTR];
07022    int fd,m,d;
07023 
07024    fd = 0;
07025    if(debug) 
07026       printf("New frequency: %s\n",newfreq);
07027 
07028    if(split_freq(mhz, decimals, newfreq))
07029       return -1; 
07030 
07031    m = atoi(mhz);
07032    d = atoi(decimals);
07033 
07034    /* The ic-706 likes packed BCD frequencies */
07035 
07036    cmdstr[0] = cmdstr[1] = 0xfe;
07037    cmdstr[2] = myrpt->p.civaddr;
07038    cmdstr[3] = 0xe0;
07039    cmdstr[4] = 5;
07040    cmdstr[5] = ((d % 10) << 4);
07041    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
07042    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
07043    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
07044    cmdstr[9] = (m / 100);
07045    cmdstr[10] = 0xfd;
07046 
07047    return(civ_cmd(myrpt,cmdstr,11));
07048 }
07049 
07050 /* ic-706 offset */
07051 
07052 static int set_offset_ic706(struct rpt *myrpt, char offset)
07053 {
07054    unsigned char c;
07055 
07056    switch(offset){
07057       case  REM_SIMPLEX:
07058          c = 0x10;
07059          break;
07060 
07061       case  REM_MINUS:
07062          c = 0x11;
07063          break;
07064       
07065       case  REM_PLUS:
07066          c = 0x12;
07067          break;   
07068 
07069       default:
07070          return -1;
07071    }
07072 
07073    return simple_command_ic706(myrpt,0x0f,c);
07074 
07075 }
07076 
07077 /* ic-706 mode */
07078 
07079 static int set_mode_ic706(struct rpt *myrpt, char newmode)
07080 {
07081    unsigned char c;
07082    
07083    switch(newmode){
07084       case  REM_MODE_FM:
07085          c = 5;
07086          break;
07087 
07088       case  REM_MODE_USB:
07089          c = 1;
07090          break;
07091 
07092       case  REM_MODE_LSB:
07093          c = 0;
07094          break;
07095 
07096       case  REM_MODE_AM:
07097          c = 2;
07098          break;
07099       
07100       default:
07101          return -1;
07102    }
07103    return simple_command_ic706(myrpt,6,c);
07104 }
07105 
07106 /* Set tone encode and decode modes */
07107 
07108 static int set_ctcss_mode_ic706(struct rpt *myrpt, char txplon, char rxplon)
07109 {
07110    unsigned char cmdstr[10];
07111    int rv;
07112 
07113    cmdstr[0] = cmdstr[1] = 0xfe;
07114    cmdstr[2] = myrpt->p.civaddr;
07115    cmdstr[3] = 0xe0;
07116    cmdstr[4] = 0x16;
07117    cmdstr[5] = 0x42;
07118    cmdstr[6] = (txplon != 0);
07119    cmdstr[7] = 0xfd;
07120 
07121    rv = civ_cmd(myrpt,cmdstr,8);
07122    if (rv) return(-1);
07123 
07124    cmdstr[0] = cmdstr[1] = 0xfe;
07125    cmdstr[2] = myrpt->p.civaddr;
07126    cmdstr[3] = 0xe0;
07127    cmdstr[4] = 0x16;
07128    cmdstr[5] = 0x43;
07129    cmdstr[6] = (rxplon != 0);
07130    cmdstr[7] = 0xfd;
07131 
07132    return(civ_cmd(myrpt,cmdstr,8));
07133 }
07134 
07135 #if 0
07136 /* Set transmit and receive ctcss tone frequencies */
07137 
07138 static int set_ctcss_freq_ic706(struct rpt *myrpt, char *txtone, char *rxtone)
07139 {
07140    unsigned char cmdstr[10];
07141    char hertz[MAXREMSTR],decimal[MAXREMSTR];
07142    int h,d,rv;
07143 
07144    memset(cmdstr, 0, 5);
07145 
07146    if(split_ctcss_freq(hertz, decimal, txtone))
07147       return -1; 
07148 
07149    h = atoi(hertz);
07150    d = atoi(decimal);
07151    
07152    cmdstr[0] = cmdstr[1] = 0xfe;
07153    cmdstr[2] = myrpt->p.civaddr;
07154    cmdstr[3] = 0xe0;
07155    cmdstr[4] = 0x1b;
07156    cmdstr[5] = 0;
07157    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
07158    cmdstr[7] = ((h % 10) << 4) + (d % 10);
07159    cmdstr[8] = 0xfd;
07160 
07161    rv = civ_cmd(myrpt,cmdstr,9);
07162    if (rv) return(-1);
07163 
07164    if (!rxtone) return(0);
07165 
07166    if(split_ctcss_freq(hertz, decimal, rxtone))
07167       return -1; 
07168 
07169    h = atoi(hertz);
07170    d = atoi(decimal);
07171 
07172    cmdstr[0] = cmdstr[1] = 0xfe;
07173    cmdstr[2] = myrpt->p.civaddr;
07174    cmdstr[3] = 0xe0;
07175    cmdstr[4] = 0x1b;
07176    cmdstr[5] = 1;
07177    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
07178    cmdstr[7] = ((h % 10) << 4) + (d % 10);
07179    cmdstr[8] = 0xfd;
07180    return(civ_cmd(myrpt,cmdstr,9));
07181 }  
07182 #endif
07183 
07184 static int vfo_ic706(struct rpt *myrpt)
07185 {
07186    unsigned char cmdstr[10];
07187    
07188    cmdstr[0] = cmdstr[1] = 0xfe;
07189    cmdstr[2] = myrpt->p.civaddr;
07190    cmdstr[3] = 0xe0;
07191    cmdstr[4] = 7;
07192    cmdstr[5] = 0xfd;
07193 
07194    return(civ_cmd(myrpt,cmdstr,6));
07195 }
07196 
07197 static int mem2vfo_ic706(struct rpt *myrpt)
07198 {
07199    unsigned char cmdstr[10];
07200    
07201    cmdstr[0] = cmdstr[1] = 0xfe;
07202    cmdstr[2] = myrpt->p.civaddr;
07203    cmdstr[3] = 0xe0;
07204    cmdstr[4] = 0x0a;
07205    cmdstr[5] = 0xfd;
07206 
07207    return(civ_cmd(myrpt,cmdstr,6));
07208 }
07209 
07210 static int select_mem_ic706(struct rpt *myrpt, int slot)
07211 {
07212    unsigned char cmdstr[10];
07213    
07214    cmdstr[0] = cmdstr[1] = 0xfe;
07215    cmdstr[2] = myrpt->p.civaddr;
07216    cmdstr[3] = 0xe0;
07217    cmdstr[4] = 8;
07218    cmdstr[5] = 0;
07219    cmdstr[6] = ((slot / 10) << 4) + (slot % 10);
07220    cmdstr[7] = 0xfd;
07221 
07222    return(civ_cmd(myrpt,cmdstr,8));
07223 }
07224 
07225 static int set_ic706(struct rpt *myrpt)
07226 {
07227    int res = 0,i;
07228    
07229    if(debug)
07230       printf("Set to VFO A\n");
07231 
07232    if (!res)
07233       res = simple_command_ic706(myrpt,7,0);
07234 
07235 
07236    if((myrpt->remmode == REM_MODE_FM))
07237    {
07238       i = ic706_pltocode(myrpt->rxpl);
07239       if (i == -1) return -1;
07240       if(debug)
07241          printf("Select memory number\n");
07242       if (!res)
07243          res = select_mem_ic706(myrpt,i + IC706_PL_MEMORY_OFFSET);
07244       if(debug)
07245          printf("Transfer memory to VFO\n");
07246       if (!res)
07247          res = mem2vfo_ic706(myrpt);
07248    }
07249       
07250    if(debug)
07251       printf("Set to VFO\n");
07252 
07253    if (!res)
07254       res = vfo_ic706(myrpt);
07255 
07256    if(debug)
07257       printf("Modulation mode\n");
07258 
07259    if (!res)
07260       res = set_mode_ic706(myrpt, myrpt->remmode);    /* Modulation mode */
07261 
07262    if(debug)
07263       printf("Split off\n");
07264 
07265    if(!res)
07266       simple_command_ic706(myrpt, 0x82,0);         /* Split off */
07267 
07268    if(debug)
07269       printf("Frequency\n");
07270 
07271    if(!res)
07272       res = set_freq_ic706(myrpt, myrpt->freq);    /* Frequency */
07273    if((myrpt->remmode == REM_MODE_FM)){
07274       if(debug)
07275          printf("Offset\n");
07276       if(!res)
07277          res = set_offset_ic706(myrpt, myrpt->offset);   /* Offset if FM */
07278       if(!res){
07279          if(debug)
07280             printf("CTCSS mode\n");
07281          res = set_ctcss_mode_ic706(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
07282       }
07283    }
07284    return res;
07285 }
07286 
07287 /*
07288 * Bump frequency up or down by a small amount 
07289 * Return 0 if the new frequnecy is valid, or -1 if invalid
07290 * Interval is in Hz, resolution is 10Hz 
07291 */
07292 
07293 static int multimode_bump_freq_ic706(struct rpt *myrpt, int interval)
07294 {
07295    int m,d;
07296    char mhz[MAXREMSTR], decimals[MAXREMSTR];
07297    unsigned char cmdstr[20];
07298 
07299    if(debug)
07300       printf("Before bump: %s\n", myrpt->freq);
07301 
07302    if(split_freq(mhz, decimals, myrpt->freq))
07303       return -1;
07304    
07305    m = atoi(mhz);
07306    d = atoi(decimals);
07307 
07308    d += (interval / 10); /* 10Hz resolution */
07309    if(d < 0){
07310       m--;
07311       d += 100000;
07312    }
07313    else if(d >= 100000){
07314       m++;
07315       d -= 100000;
07316    }
07317 
07318    if(check_freq_ic706(m, d, NULL)){
07319       if(debug)
07320          printf("Bump freq invalid\n");
07321       return -1;
07322    }
07323 
07324    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
07325 
07326    if(debug)
07327       printf("After bump: %s\n", myrpt->freq);
07328 
07329    /* The ic-706 likes packed BCD frequencies */
07330 
07331    cmdstr[0] = cmdstr[1] = 0xfe;
07332    cmdstr[2] = myrpt->p.civaddr;
07333    cmdstr[3] = 0xe0;
07334    cmdstr[4] = 0;
07335    cmdstr[5] = ((d % 10) << 4);
07336    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
07337    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
07338    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
07339    cmdstr[9] = (m / 100);
07340    cmdstr[10] = 0xfd;
07341 
07342    return(serial_remote_io(myrpt,cmdstr,11,NULL,0,0));
07343 }
07344 
07345 
07346 
07347 /*
07348 * Dispatch to correct I/O handler 
07349 */
07350 
07351 static int setrem(struct rpt *myrpt)
07352 {
07353 char  str[300];
07354 char  *offsets[] = {"MINUS","SIMPLEX","PLUS"};
07355 char  *powerlevels[] = {"LOW","MEDIUM","HIGH"};
07356 char  *modes[] = {"FM","USB","LSB","AM"};
07357 int   res = -1;
07358 
07359    if (myrpt->p.archivedir)
07360    {
07361       sprintf(str,"FREQ,%s,%s,%s,%s,%s,%s,%d,%d",myrpt->freq,
07362          modes[(int)myrpt->remmode],
07363          myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
07364          powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
07365          myrpt->rxplon);
07366       donodelog(myrpt,str);
07367    }
07368    if(!strcmp(myrpt->remote, remote_rig_ft897))
07369    {
07370       rpt_telemetry(myrpt,SETREMOTE,NULL);
07371       res = 0;
07372    }
07373    if(!strcmp(myrpt->remote, remote_rig_ic706))
07374    {
07375       rpt_telemetry(myrpt,SETREMOTE,NULL);
07376       res = 0;
07377    }
07378    else if(!strcmp(myrpt->remote, remote_rig_rbi))
07379    {
07380       res = setrbi_check(myrpt);
07381       if (!res)
07382       {
07383          rpt_telemetry(myrpt,SETREMOTE,NULL);
07384          res = 0;
07385       }
07386    }
07387    else if(!strcmp(myrpt->remote, remote_rig_kenwood)) {
07388       rpt_telemetry(myrpt,SETREMOTE,NULL);
07389       res = 0;
07390    }
07391    else
07392       res = 0;
07393 
07394    if (res < 0) ast_log(LOG_ERROR,"Unable to send remote command on node %s\n",myrpt->name);
07395 
07396    return res;
07397 }
07398 
07399 static int closerem(struct rpt *myrpt)
07400 {
07401    if(!strcmp(myrpt->remote, remote_rig_ft897))
07402       return closerem_ft897(myrpt);
07403    else
07404       return 0;
07405 }
07406 
07407 /*
07408 * Dispatch to correct RX frequency checker
07409 */
07410 
07411 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
07412 {
07413    if(!strcmp(myrpt->remote, remote_rig_ft897))
07414       return check_freq_ft897(m, d, defmode);
07415    else if(!strcmp(myrpt->remote, remote_rig_ic706))
07416       return check_freq_ic706(m, d, defmode);
07417    else if(!strcmp(myrpt->remote, remote_rig_rbi))
07418       return check_freq_rbi(m, d, defmode);
07419    else if(!strcmp(myrpt->remote, remote_rig_kenwood))
07420       return check_freq_kenwood(m, d, defmode);
07421    else
07422       return -1;
07423 }
07424 
07425 /*
07426  * Check TX frequency before transmitting
07427  */
07428 
07429 static char check_tx_freq(struct rpt *myrpt)
07430 {
07431    int i;
07432    int radio_mhz, radio_decimals, ulimit_mhz, ulimit_decimals, llimit_mhz, llimit_decimals;
07433    char radio_mhz_char[MAXREMSTR];
07434    char radio_decimals_char[MAXREMSTR];
07435    char limit_mhz_char[MAXREMSTR];
07436    char limit_decimals_char[MAXREMSTR];
07437    char limits[256];
07438    char *limit_ranges[40];
07439    struct ast_variable *limitlist;
07440    
07441 
07442    /* Must have user logged in and tx_limits defined */
07443 
07444    if(!myrpt->p.txlimitsstanzaname || !myrpt->loginuser[0] || !myrpt->loginlevel[0]){
07445       if(debug > 3){
07446          ast_log(LOG_NOTICE, "No tx band table defined, or no user logged in\n");
07447       }
07448       return 1; /* Assume it's ok otherwise */
07449    }
07450 
07451    /* Retrieve the band table for the loginlevel */
07452    limitlist = ast_variable_browse(myrpt->cfg, myrpt->p.txlimitsstanzaname);
07453 
07454    if(!limitlist){
07455       ast_log(LOG_WARNING, "No entries in %s band table stanza\n", myrpt->p.txlimitsstanzaname);
07456       return 0;
07457    }
07458 
07459    split_freq(radio_mhz_char, radio_decimals_char, myrpt->freq);
07460    radio_mhz = atoi(radio_mhz_char);
07461    radio_decimals = decimals2int(radio_decimals_char);
07462 
07463 
07464    if(debug > 3){
07465       ast_log(LOG_NOTICE, "Login User = %s, login level = %s\n", myrpt->loginuser, myrpt->loginlevel);
07466    }
07467 
07468    /* Find our entry */
07469 
07470    for(;limitlist; limitlist=limitlist->next){
07471       if(!strcmp(limitlist->name, myrpt->loginlevel))
07472          break;
07473    }
07474 
07475    if(!limitlist){
07476       ast_log(LOG_WARNING, "Can't find %s entry in band table stanza %s\n", myrpt->loginlevel, myrpt->p.txlimitsstanzaname);
07477       return 0;
07478    }
07479    
07480    if(debug > 3){
07481       ast_log(LOG_NOTICE, "Auth %s = %s\n", limitlist->name, limitlist->value);
07482    }
07483 
07484    /* Parse the limits */
07485 
07486    strncpy(limits, limitlist->value, 256);
07487    limits[255] = 0;
07488    finddelim(limits, limit_ranges, 40);
07489    for(i = 0; i < 40 && limit_ranges[i] ; i++){
07490       char range[40];
07491       char *r,*s;
07492       strncpy(range, limit_ranges[i], 40);
07493       range[39] = 0;
07494                 if(debug > 3){
07495          ast_log(LOG_NOTICE, "Checking to see if %s is within limits of %s\n", myrpt->freq, range);
07496                 }        
07497    
07498       r = strchr(range, '-');
07499       if(!r){
07500          ast_log(LOG_WARNING, "Malformed range in %s tx band table entry\n", limitlist->name);
07501          return 0;
07502       }
07503       *r++ = 0;
07504       s = eatwhite(range);
07505       r = eatwhite(r);
07506       split_freq(limit_mhz_char, limit_decimals_char, s);
07507       llimit_mhz = atoi(limit_mhz_char);
07508       llimit_decimals = decimals2int(limit_decimals_char);
07509       split_freq(limit_mhz_char, limit_decimals_char, r);
07510       ulimit_mhz = atoi(limit_mhz_char);
07511       ulimit_decimals = decimals2int(limit_decimals_char);
07512          
07513       if((radio_mhz >= llimit_mhz) && (radio_mhz <= ulimit_mhz)){
07514          if(radio_mhz == llimit_mhz){ /* CASE 1: TX freq is in llimit mhz portion of band */
07515             if(radio_decimals >= llimit_decimals){ /* Cannot be below llimit decimals */
07516                if(llimit_mhz == ulimit_mhz){ /* If bandwidth < 1Mhz, check ulimit decimals */
07517                   if(radio_decimals <= ulimit_decimals){
07518                      return 1;
07519                   }
07520                   else{
07521                      if(debug > 3)
07522                         ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 1\n");
07523                      return 0;
07524                   }
07525                }
07526                else{
07527                   return 1;
07528                }
07529             }
07530             else{ /* Is below llimit decimals */
07531                if(debug > 3)
07532                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 2\n");
07533                return 0;
07534             }
07535          }
07536          else if(radio_mhz == ulimit_mhz){ /* CASE 2: TX freq not in llimit mhz portion of band */
07537             if(radio_decimals <= ulimit_decimals){
07538                return 1;
07539             }
07540             else{ /* Is above ulimit decimals */
07541                if(debug > 3)
07542                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 3\n");
07543                return 0;
07544             }
07545          }
07546          else /* CASE 3: TX freq within a multi-Mhz band and ok */
07547             return 1; 
07548       }
07549    }
07550    if(debug > 3) /* No match found in TX band table */
07551       ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 4\n");
07552    return 0;
07553 }
07554 
07555 
07556 /*
07557 * Dispatch to correct frequency bumping function
07558 */
07559 
07560 static int multimode_bump_freq(struct rpt *myrpt, int interval)
07561 {
07562    if(!strcmp(myrpt->remote, remote_rig_ft897))
07563       return multimode_bump_freq_ft897(myrpt, interval);
07564    else if(!strcmp(myrpt->remote, remote_rig_ic706))
07565       return multimode_bump_freq_ic706(myrpt, interval);
07566    else
07567       return -1;
07568 }
07569 
07570 
07571 /*
07572 * Queue announcment that scan has been stopped 
07573 */
07574 
07575 static void stop_scan(struct rpt *myrpt)
07576 {
07577    myrpt->hfscanstop = 1;
07578    rpt_telemetry(myrpt,SCAN,0);
07579 }
07580 
07581 /*
07582 * This is called periodically when in scan mode
07583 */
07584 
07585 
07586 static int service_scan(struct rpt *myrpt)
07587 {
07588    int res, interval;
07589    char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
07590 
07591    switch(myrpt->hfscanmode){
07592 
07593       case HF_SCAN_DOWN_SLOW:
07594          interval = -10; /* 100Hz /sec */
07595          break;
07596 
07597       case HF_SCAN_DOWN_QUICK:
07598          interval = -50; /* 500Hz /sec */
07599          break;
07600 
07601       case HF_SCAN_DOWN_FAST:
07602          interval = -200; /* 2KHz /sec */
07603          break;
07604 
07605       case HF_SCAN_UP_SLOW:
07606          interval = 10; /* 100Hz /sec */
07607          break;
07608 
07609       case HF_SCAN_UP_QUICK:
07610          interval = 50; /* 500 Hz/sec */
07611          break;
07612 
07613       case HF_SCAN_UP_FAST:
07614          interval = 200; /* 2KHz /sec */
07615          break;
07616 
07617       default:
07618          myrpt->hfscanmode = 0; /* Huh? */
07619          return -1;
07620    }
07621 
07622    res = split_freq(mhz, decimals, myrpt->freq);
07623       
07624    if(!res){
07625       k100 =decimals[0];
07626       k10 = decimals[1];
07627       res = multimode_bump_freq(myrpt, interval);
07628    }
07629 
07630    if(!res)
07631       res = split_freq(mhz, decimals, myrpt->freq);
07632 
07633 
07634    if(res){
07635       myrpt->hfscanmode = 0;
07636       myrpt->hfscanstatus = -2;
07637       return -1;
07638    }
07639 
07640    /* Announce 10KHz boundaries */
07641    if(k10 != decimals[1]){
07642       int myhund = (interval < 0) ? k100 : decimals[0];
07643       int myten = (interval < 0) ? k10 : decimals[1];
07644       myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
07645    } else myrpt->hfscanstatus = 0;
07646    return res;
07647 
07648 }
07649 
07650 /*
07651  * Retrieve a memory channel
07652  * Return 0 if sucessful,
07653  * -1 if channel not found,
07654  *  1 if parse error
07655  */
07656 
07657 static int retreive_memory(struct rpt *myrpt, char *memory)
07658 {
07659    char tmp[30], *s, *s1, *val;
07660 
07661    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, memory);
07662    if (!val){
07663       return -1;
07664    }        
07665    strncpy(tmp,val,sizeof(tmp) - 1);
07666    tmp[sizeof(tmp)-1] = 0;
07667 
07668    s = strchr(tmp,',');
07669    if (!s)
07670       return 1; 
07671    *s++ = 0;
07672    s1 = strchr(s,',');
07673    if (!s1)
07674       return 1;
07675    *s1++ = 0;
07676    strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
07677    strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
07678    strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
07679    myrpt->remmode = REM_MODE_FM;
07680    myrpt->offset = REM_SIMPLEX;
07681    myrpt->powerlevel = REM_MEDPWR;
07682    myrpt->txplon = myrpt->rxplon = 0;
07683    while(*s1){
07684       switch(*s1++){
07685          case 'A':
07686          case 'a':
07687             strcpy(myrpt->rxpl, "100.0");
07688             strcpy(myrpt->txpl, "100.0");
07689             myrpt->remmode = REM_MODE_AM; 
07690             break;
07691          case 'B':
07692          case 'b':
07693             strcpy(myrpt->rxpl, "100.0");
07694             strcpy(myrpt->txpl, "100.0");
07695             myrpt->remmode = REM_MODE_LSB;
07696             break;
07697          case 'F':
07698             myrpt->remmode = REM_MODE_FM;
07699             break;
07700          case 'L':
07701          case 'l':
07702             myrpt->powerlevel = REM_LOWPWR;
07703             break;               
07704          case 'H':
07705          case 'h':
07706             myrpt->powerlevel = REM_HIPWR;
07707             break;
07708                
07709          case 'M':
07710          case 'm':
07711             myrpt->powerlevel = REM_MEDPWR;
07712             break;
07713                   
07714          case '-':
07715             myrpt->offset = REM_MINUS;
07716             break;
07717                   
07718          case '+':
07719             myrpt->offset = REM_PLUS;
07720             break;
07721                   
07722          case 'S':
07723          case 's':
07724             myrpt->offset = REM_SIMPLEX;
07725             break;
07726                   
07727          case 'T':
07728          case 't':
07729             myrpt->txplon = 1;
07730             break;
07731                   
07732          case 'R':
07733          case 'r':
07734             myrpt->rxplon = 1;
07735             break;
07736 
07737          case 'U':
07738          case 'u':
07739             strcpy(myrpt->rxpl, "100.0");
07740             strcpy(myrpt->txpl, "100.0");
07741             myrpt->remmode = REM_MODE_USB;
07742             break;
07743          default:
07744             return 1;
07745       }
07746    }
07747    return 0;
07748 }
07749 
07750 
07751 
07752 /*
07753 * Remote base function
07754 */
07755 
07756 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
07757 {
07758    char *s,*s1,*s2;
07759    int i,j,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode=0;
07760    intptr_t p;
07761    char multimode = 0;
07762    char oc,*cp,*cp1,*cp2;
07763    char tmp[20], freq[20] = "", savestr[20] = "";
07764    char mhz[MAXREMSTR], decimals[MAXREMSTR];
07765 
07766    if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
07767       return DC_ERROR;
07768       
07769    p = myatoi(param);
07770 
07771    if ((p != 99) && (p != 5) && (p != 140) && myrpt->p.authlevel && 
07772       (!myrpt->loginlevel[0])) return DC_ERROR;
07773    multimode = multimode_capable(myrpt);
07774 
07775    switch(p){
07776 
07777       case 1:  /* retrieve memory */
07778          if(strlen(digitbuf) < 2) /* needs 2 digits */
07779             break;
07780          
07781          for(i = 0 ; i < 2 ; i++){
07782             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
07783                return DC_ERROR;
07784          }
07785        
07786          r = retreive_memory(myrpt, digitbuf);
07787          if (r < 0){
07788             rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
07789             return DC_COMPLETE;
07790          }
07791          if (r > 0){
07792             return DC_ERROR;
07793          }
07794          if (setrem(myrpt) == -1) return DC_ERROR;
07795          return DC_COMPLETE;  
07796          
07797       case 2:  /* set freq and offset */
07798       
07799          
07800             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
07801             if(digitbuf[i] == '*'){
07802                j++;
07803                continue;
07804             }
07805             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
07806                goto invalid_freq;
07807             else{
07808                if(j == 0)
07809                   l++; /* # of digits before first * */
07810                if(j == 1)
07811                   k++; /* # of digits after first * */
07812             }
07813          }
07814       
07815          i = strlen(digitbuf) - 1;
07816          if(multimode){
07817             if((j > 2) || (l > 3) || (k > 6))
07818                goto invalid_freq; /* &^@#! */
07819          }
07820          else{
07821             if((j > 2) || (l > 4) || (k > 3))
07822                goto invalid_freq; /* &^@#! */
07823          }
07824 
07825          /* Wait for M+*K+* */
07826 
07827          if(j < 2)
07828             break; /* Not yet */
07829 
07830          /* We have a frequency */
07831 
07832          strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
07833          
07834          s = tmp;
07835          s1 = strsep(&s, "*"); /* Pick off MHz */
07836          s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
07837          ls2 = strlen(s2); 
07838          
07839          switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
07840             case 1:
07841                ht = 0;
07842                k = 100 * atoi(s2);
07843                break;
07844             
07845             case 2:
07846                ht = 0;
07847                k = 10 * atoi(s2);
07848                break;
07849                
07850             case 3:
07851                if(!multimode){
07852                   if((s2[2] != '0')&&(s2[2] != '5'))
07853                      goto invalid_freq;
07854                }
07855                ht = 0;
07856                k = atoi(s2);
07857                   break;
07858             case 4:
07859                k = atoi(s2)/10;
07860                ht = 10 * (atoi(s2+(ls2-1)));
07861                break;
07862 
07863             case 5:
07864                k = atoi(s2)/100;
07865                ht = (atoi(s2+(ls2-2)));
07866                break;
07867                
07868             default:
07869                goto invalid_freq;
07870          }
07871 
07872          /* Check frequency for validity and establish a default mode */
07873          
07874          snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
07875 
07876          if(debug)
07877             printf("New frequency: %s\n", freq);      
07878    
07879          split_freq(mhz, decimals, freq);
07880          m = atoi(mhz);
07881          d = atoi(decimals);
07882 
07883                         if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
07884                                 goto invalid_freq;
07885 
07886 
07887          if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
07888             break; /* Not yet */
07889 
07890 
07891          offset = REM_SIMPLEX; /* Assume simplex */
07892 
07893          if(defmode == REM_MODE_FM){
07894             oc = *s; /* Pick off offset */
07895          
07896             if (oc){
07897                switch(oc){
07898                   case '1':
07899                      offset = REM_MINUS;
07900                      break;
07901                   
07902                   case '2':
07903                      offset = REM_SIMPLEX;
07904                   break;
07905                   
07906                   case '3':
07907                      offset = REM_PLUS;
07908                      break;
07909                   
07910                   default:
07911                      goto invalid_freq;
07912                } 
07913             } 
07914          }  
07915          offsave = myrpt->offset;
07916          modesave = myrpt->remmode;
07917          strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
07918          strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
07919          myrpt->offset = offset;
07920          myrpt->remmode = defmode;
07921 
07922          if (setrem(myrpt) == -1){
07923             myrpt->offset = offsave;
07924             myrpt->remmode = modesave;
07925             strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
07926             goto invalid_freq;
07927          }
07928 
07929          return DC_COMPLETE;
07930 
07931 invalid_freq:
07932          rpt_telemetry(myrpt,INVFREQ,NULL);
07933          return DC_ERROR; 
07934       
07935       case 3: /* set rx PL tone */
07936             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
07937             if(digitbuf[i] == '*'){
07938                j++;
07939                continue;
07940             }
07941             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
07942                return DC_ERROR;
07943             else{
07944                if(j)
07945                   l++;
07946                else
07947                   k++;
07948             }
07949          }
07950          if((j > 1) || (k > 3) || (l > 1))
07951             return DC_ERROR; /* &$@^! */
07952          i = strlen(digitbuf) - 1;
07953          if((j != 1) || (k < 2)|| (l != 1))
07954             break; /* Not yet */
07955          if(debug)
07956             printf("PL digits entered %s\n", digitbuf);
07957             
07958          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
07959          /* see if we have at least 1 */
07960          s = strchr(tmp,'*');
07961          if(s)
07962             *s = '.';
07963          strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
07964          strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
07965          if(!strcmp(myrpt->remote, remote_rig_rbi))
07966          {
07967             strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
07968          }
07969          if (setrem(myrpt) == -1){
07970             strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
07971             return DC_ERROR;
07972          }
07973       
07974       
07975          return DC_COMPLETE;
07976       
07977       case 4: /* set tx PL tone */
07978          /* cant set tx tone on RBI (rx tone does both) */
07979          if(!strcmp(myrpt->remote, remote_rig_rbi))
07980             return DC_ERROR;
07981          if(!strcmp(myrpt->remote, remote_rig_ic706))
07982             return DC_ERROR;
07983             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
07984             if(digitbuf[i] == '*'){
07985                j++;
07986                continue;
07987             }
07988             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
07989                return DC_ERROR;
07990             else{
07991                if(j)
07992                   l++;
07993                else
07994                   k++;
07995             }
07996          }
07997          if((j > 1) || (k > 3) || (l > 1))
07998             return DC_ERROR; /* &$@^! */
07999          i = strlen(digitbuf) - 1;
08000          if((j != 1) || (k < 2)|| (l != 1))
08001             break; /* Not yet */
08002          if(debug)
08003             printf("PL digits entered %s\n", digitbuf);
08004             
08005          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
08006          /* see if we have at least 1 */
08007          s = strchr(tmp,'*');
08008          if(s)
08009             *s = '.';
08010          strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1);
08011          strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
08012          
08013          if (setrem(myrpt) == -1){
08014             strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
08015             return DC_ERROR;
08016          }
08017       
08018       
08019          return DC_COMPLETE;
08020       
08021 
08022       case 6: /* MODE (FM,USB,LSB,AM) */
08023          if(strlen(digitbuf) < 1)
08024             break;
08025 
08026          if(!multimode)
08027             return DC_ERROR; /* Multimode radios only */
08028 
08029          switch(*digitbuf){
08030             case '1':
08031                split_freq(mhz, decimals, myrpt->freq); 
08032                m=atoi(mhz);
08033                if(m < 29) /* No FM allowed below 29MHz! */
08034                   return DC_ERROR;
08035                myrpt->remmode = REM_MODE_FM;
08036                
08037                rpt_telemetry(myrpt,REMMODE,NULL);
08038                break;
08039 
08040             case '2':
08041                myrpt->remmode = REM_MODE_USB;
08042                rpt_telemetry(myrpt,REMMODE,NULL);
08043                break;   
08044 
08045             case '3':
08046                myrpt->remmode = REM_MODE_LSB;
08047                rpt_telemetry(myrpt,REMMODE,NULL);
08048                break;
08049             
08050             case '4':
08051                myrpt->remmode = REM_MODE_AM;
08052                rpt_telemetry(myrpt,REMMODE,NULL);
08053                break;
08054       
08055             default:
08056                return DC_ERROR;
08057          }
08058 
08059          if(setrem(myrpt))
08060             return DC_ERROR;
08061          return DC_COMPLETEQUIET;
08062       case 99:
08063          /* cant log in when logged in */
08064          if (myrpt->loginlevel[0]) 
08065             return DC_ERROR;
08066          *myrpt->loginuser = 0;
08067          myrpt->loginlevel[0] = 0;
08068          cp = strdup(param);
08069          cp1 = strchr(cp,',');
08070          ast_mutex_lock(&myrpt->lock);
08071          if (cp1) 
08072          {
08073             *cp1 = 0;
08074             cp2 = strchr(cp1 + 1,',');
08075             if (cp2) 
08076             {
08077                *cp2 = 0;
08078                strncpy(myrpt->loginlevel,cp2 + 1,
08079                   sizeof(myrpt->loginlevel) - 1);
08080             }
08081             strncpy(myrpt->loginuser,cp1 + 1,sizeof(myrpt->loginuser));
08082             ast_mutex_unlock(&myrpt->lock);
08083             if (myrpt->p.archivedir)
08084             {
08085                char str[100];
08086 
08087                sprintf(str,"LOGIN,%s,%s",
08088                    myrpt->loginuser,myrpt->loginlevel);
08089                donodelog(myrpt,str);
08090             }
08091             if (debug) 
08092                printf("loginuser %s level %s\n",myrpt->