Wed Aug 15 01:24:14 2007

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 
00022 /*! \file
00023  *
00024  * \brief Radio Repeater / Remote Base program 
00025  *  version 0.70 07/22/07
00026  * 
00027  * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
00028  *
00029  * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
00030  * 
00031  * See http://www.zapatatelephony.org/app_rpt.html
00032  *
00033  *
00034  * Repeater / Remote Functions:
00035  * "Simple" Mode:  * - autopatch access, # - autopatch hangup
00036  * Normal mode:
00037  * See the function list in rpt.conf (autopatchup, autopatchdn)
00038  * autopatchup can optionally take comma delimited setting=value pairs:
00039  *  
00040  *
00041  * context=string    :  Override default context with "string"
00042  * dialtime=ms       :  Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
00043  * farenddisconnect=1      :  Automatically disconnect when called party hangs up
00044  * noct=1         :  Don't send repeater courtesy tone during autopatch calls
00045  * quiet=1        :  Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
00046  *
00047  *
00048  * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
00049  *
00050  *  To send an asterisk (*) while dialing or talking on phone,
00051  *  use the autopatch acess code.
00052  *
00053  *
00054  * status cmds:
00055  *
00056  *  1 - Force ID
00057  *  2 - Give Time of Day
00058  *  3 - Give software Version
00059  *
00060  * cop (control operator) cmds:
00061  *
00062  *  1 - System warm boot
00063  *  2 - System enable
00064  *  3 - System disable
00065  *  4 - Test Tone On/Off
00066  *  5 - Dump System Variables on Console (debug)
00067  *  6 - PTT (phone mode only)
00068  *  7 - Time out timer enable
00069  *  8 - Time out timer disable
00070  *  9 - Autopatch enable
00071  *  10 - Autopatch disable
00072  *  11 - Link enable
00073  *  12 - Link disable
00074  *  13 - Query System State
00075  *  14 - Change System State
00076  *  15 - Scheduler Enable
00077  *  16 - Scheduler Disable
00078  *  17 - User functions (time, id, etc) enable
00079  *  18 - User functions (time, id, etc) disable
00080  *  19 - Select alternate hang timer
00081  *  20 - Select standard hang timer 
00082  *
00083  * ilink cmds:
00084  *
00085  *  1 - Disconnect specified link
00086  *  2 - Connect specified link -- monitor only
00087  *  3 - Connect specified link -- tranceive
00088  *  4 - Enter command mode on specified link
00089  *  5 - System status
00090  *  6 - Disconnect all links
00091  *  11 - Disconnect a previously permanently connected link
00092  *  12 - Permanently connect specified link -- monitor only
00093  *  13 - Permanently connect specified link -- tranceive
00094  *  15 - Full system status (all nodes)
00095  *  16 - Reconnect links disconnected with "disconnect all links"
00096  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
00097  *
00098  * remote cmds:
00099  *
00100  *  1 - Recall Memory MM  (*000-*099) (Gets memory from rpt.conf)
00101  *  2 - Set VFO MMMMM*KKK*O   (Mhz digits, Khz digits, Offset)
00102  *  3 - Set Rx PL Tone HHH*D*
00103  *  4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
00104  *  5 - Link Status (long)
00105  *  6 - Set operating mode M (FM, USB, LSB, AM, etc)
00106  *  100 - RX PL off (Default)
00107  *  101 - RX PL On
00108  *  102 - TX PL Off (Default)
00109  *  103 - TX PL On
00110  *  104 - Low Power
00111  *  105 - Med Power
00112  *  106 - Hi Power
00113  *  107 - Bump Down 20 Hz
00114  *  108 - Bump Down 100 Hz
00115  *  109 - Bump Down 500 Hz
00116  *  110 - Bump Up 20 Hz
00117  *  111 - Bump Up 100 Hz
00118  *  112 - Bump Up 500 Hz
00119  *  113 - Scan Down Slow
00120  *  114 - Scan Down Medium
00121  *  115 - Scan Down Fast
00122  *  116 - Scan Up Slow
00123  *  117 - Scan Up Medium
00124  *  118 - Scan Up Fast
00125  *  119 - Transmit allowing auto-tune
00126  *  140 - Link Status (brief)
00127  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
00128  *
00129  *
00130  * 'duplex' modes:  (defaults to duplex=2)
00131  *
00132  * 0 - Only remote links key Tx and no main repeat audio.
00133  * 1 - Everything other then main Rx keys Tx, no main repeat audio.
00134  * 2 - Normal mode
00135  * 3 - Normal except no main repeat audio.
00136  * 4 - Normal except no main repeat audio during autopatch only
00137  *
00138 */
00139 
00140 /*** MODULEINFO
00141    <depend>zaptel</depend>
00142    <depend>tonezone</depend>
00143    <defaultenabled>no</defaultenabled>
00144  ***/
00145 
00146 /* Un-comment the following to include support for MDC-1200 digital tone
00147    signalling protocol (using KA6SQG's GPL'ed implementation) */
00148 /* #include "mdc_decode.c" */
00149 
00150 /* Un-comment the following to include support for notch filters in the
00151    rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
00152 /* #include "rpt_notch.c" */
00153 
00154 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
00155 
00156 #define  MAXDTMF 32
00157 #define  MAXMACRO 2048
00158 #define  MAXLINKLIST 512
00159 #define  LINKLISTTIME 10000
00160 #define  LINKLISTSHORTTIME 200
00161 #define  MACROTIME 100
00162 #define  MACROPTIME 500
00163 #define  DTMF_TIMEOUT 3
00164 #define  KENWOOD_RETRIES 5
00165 
00166 #define  AUTHTELLTIME 7000
00167 #define  AUTHTXTIME 1000
00168 #define  AUTHLOGOUTTIME 25000
00169 
00170 #ifdef   __RPT_NOTCH
00171 #define  MAXFILTERS 10
00172 #endif
00173 
00174 #define  DISC_TIME 10000  /* report disc after 10 seconds of no connect */
00175 #define  MAX_RETRIES 5
00176 #define  MAX_RETRIES_PERM 1000000000
00177 
00178 #define  REDUNDANT_TX_TIME 2000
00179 
00180 #define  RETRY_TIMER_MS 5000
00181 
00182 #define  START_DELAY 10
00183 
00184 #define MAXPEERSTR 31
00185 #define  MAXREMSTR 15
00186 
00187 #define  DELIMCHR ','
00188 #define  QUOTECHR 34
00189 
00190 #define  MONITOR_DISK_BLOCKS_PER_MINUTE 38
00191 
00192 #define  DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000
00193 #define  DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60)
00194 #define  DEFAULT_REMOTE_TIMEOUT (60 * 60)
00195 #define  DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60)
00196 #define  DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30
00197 
00198 #define  NODES "nodes"
00199 #define  EXTNODES "extnodes"
00200 #define MEMORY "memory"
00201 #define MACRO "macro"
00202 #define  FUNCTIONS "functions"
00203 #define TELEMETRY "telemetry"
00204 #define MORSE "morse"
00205 #define  FUNCCHAR '*'
00206 #define  ENDCHAR '#'
00207 #define  EXTNODEFILE "/var/lib/asterisk/rpt_extnodes"
00208 
00209 #define  DEFAULT_IOBASE 0x378
00210 
00211 #define  DEFAULT_CIV_ADDR 0x58
00212 
00213 #define  MAXCONNECTTIME 5000
00214 
00215 #define MAXNODESTR 300
00216 
00217 #define MAXPATCHCONTEXT 100
00218 
00219 #define ACTIONSIZE 32
00220 
00221 #define TELEPARAMSIZE 256
00222 
00223 #define REM_SCANTIME 100
00224 
00225 #define  DTMF_LOCAL_TIME 250
00226 #define  DTMF_LOCAL_STARTTIME 500
00227 
00228 #define  IC706_PL_MEMORY_OFFSET 50
00229 
00230 enum {REM_OFF,REM_MONITOR,REM_TX};
00231 
00232 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
00233    CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME,
00234    STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
00235    TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS,
00236    MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS,
00237    REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE,
00238    TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX};
00239 
00240 
00241 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
00242 
00243 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
00244 
00245 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY};
00246 
00247 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE};
00248 
00249 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY};
00250 
00251 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
00252 
00253 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
00254       HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
00255 
00256 #include "asterisk.h"
00257 
00258 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 77846 $")
00259 
00260 #include <signal.h>
00261 #include <stdio.h>
00262 #include <unistd.h>
00263 #include <string.h>
00264 #include <stdlib.h>
00265 #include <search.h>
00266 #include <sys/types.h>
00267 #include <sys/stat.h>
00268 #include <errno.h>
00269 #include <dirent.h>
00270 #include <ctype.h>
00271 #include <sys/stat.h>
00272 #include <sys/time.h>
00273 #include <sys/file.h>
00274 #include <sys/ioctl.h>
00275 #include <sys/io.h>
00276 #include <sys/vfs.h>
00277 #include <math.h>
00278 #ifdef OLD_ASTERISK
00279 #include <linux/zaptel.h>
00280 #include <tonezone.h>
00281 #else
00282 #include <zaptel/zaptel.h>
00283 #include <zaptel/tonezone.h>
00284 #endif
00285 #include <netinet/in.h>
00286 #include <arpa/inet.h>
00287 
00288 #include "asterisk/utils.h"
00289 #include "asterisk/lock.h"
00290 #include "asterisk/file.h"
00291 #include "asterisk/logger.h"
00292 #include "asterisk/channel.h"
00293 #include "asterisk/callerid.h"
00294 #include "asterisk/pbx.h"
00295 #include "asterisk/module.h"
00296 #include "asterisk/translate.h"
00297 #include "asterisk/features.h"
00298 #include "asterisk/options.h"
00299 #include "asterisk/cli.h"
00300 #include "asterisk/config.h"
00301 #include "asterisk/say.h"
00302 #include "asterisk/localtime.h"
00303 #include "asterisk/cdr.h"
00304 #include <termios.h>
00305 
00306 /* Start a tone-list going */
00307 int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
00308 /*! Stop the tones from playing */
00309 void ast_playtones_stop(struct ast_channel *chan);
00310 
00311 static  char *tdesc = "Radio Repeater / Remote Base  version 0.70  07/22/2007";
00312 
00313 static char *app = "Rpt";
00314 
00315 static char *synopsis = "Radio Repeater/Remote Base Control System";
00316 
00317 static char *descrip = 
00318 "  Rpt(nodename[|options]):  Radio Remote Link or Remote Base Link Endpoint Process.\n"
00319 "\n"
00320 "    Not specifying an option puts it in normal endpoint mode (where source\n"
00321 "    IP and nodename are verified).\n"
00322 "\n"
00323 "    Options are as follows:\n"
00324 "\n"
00325 "        X - Normal endpoint mode WITHOUT security check. Only specify\n"
00326 "            this if you have checked security already (like with an IAX2\n"
00327 "            user/password or something).\n"
00328 "\n"
00329 "        Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
00330 "            Reverse Autopatch. Caller is put on hold, and announcement (as\n"
00331 "            specified by the 'announce-string') is played on radio system.\n"
00332 "            Users of radio system can access autopatch, dial specified\n"
00333 "            code, and pick up call. Announce-string is list of names of\n"
00334 "            recordings, or \"PARKED\" to substitute code for un-parking,\n"
00335 "            or \"NODE\" to substitute node number.\n"
00336 "\n"
00337 "        P - Phone Control mode. This allows a regular phone user to have\n"
00338 "            full control and audio access to the radio system. For the\n"
00339 "            user to have DTMF control, the 'phone_functions' parameter\n"
00340 "            must be specified for the node in 'rpt.conf'. An additional\n"
00341 "            function (cop,6) must be listed so that PTT control is available.\n"
00342 "\n"
00343 "        D - Dumb Phone Control mode. This allows a regular phone user to\n"
00344 "            have full control and audio access to the radio system. In this\n"
00345 "            mode, the PTT is activated for the entire length of the call.\n"
00346 "            For the user to have DTMF control (not generally recomended in\n"
00347 "            this mode), the 'dphone_functions' parameter must be specified\n"
00348 "            for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
00349 "            available to the phone user.\n"
00350 "\n";
00351 
00352 static int debug = 0;  /* Set this >0 for extra debug output */
00353 static int nrpts = 0;
00354 
00355 static char remdtmfstr[] = "0123456789*#ABCD";
00356 
00357 enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
00358 
00359 int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
00360 
00361 #define NRPTSTAT 7
00362 
00363 struct rpt_chan_stat
00364 {
00365    struct timeval last;
00366    long long total;
00367    unsigned long count;
00368    unsigned long largest;
00369    struct timeval largest_time;
00370 };
00371 
00372 char *discstr = "!!DISCONNECT!!";
00373 static char *remote_rig_ft897="ft897";
00374 static char *remote_rig_rbi="rbi";
00375 static char *remote_rig_kenwood="kenwood";
00376 static char *remote_rig_ic706="ic706";
00377 
00378 #ifdef   OLD_ASTERISK
00379 STANDARD_LOCAL_USER;
00380 LOCAL_USER_DECL;
00381 #endif
00382 
00383 #define  MSWAIT 200
00384 #define  HANGTIME 5000
00385 #define  TOTIME 180000
00386 #define  IDTIME 300000
00387 #define  MAXRPTS 20
00388 #define MAX_STAT_LINKS 32
00389 #define POLITEID 30000
00390 #define FUNCTDELAY 1500
00391 
00392 #define  MAXXLAT 20
00393 #define  MAXXLATTIME 3
00394 
00395 #define MAX_SYSSTATES 10
00396 
00397 struct rpt_xlat
00398 {
00399 char  funccharseq[MAXXLAT];
00400 char  endcharseq[MAXXLAT];
00401 char  passchars[MAXXLAT];
00402 int   funcindex;
00403 int   endindex;
00404 time_t   lastone;
00405 } ;
00406 
00407 static time_t  starttime = 0;
00408 
00409 static  pthread_t rpt_master_thread;
00410 
00411 struct rpt;
00412 
00413 struct rpt_link
00414 {
00415    struct rpt_link *next;
00416    struct rpt_link *prev;
00417    char  mode;       /* 1 if in tx mode */
00418    char  isremote;
00419    char  phonemode;
00420    char  name[MAXNODESTR]; /* identifier (routing) string */
00421    char  lasttx;
00422    char  lastrx;
00423    char  lastrx1;
00424    char  connected;
00425    char  hasconnected;
00426    char  perma;
00427    char  thisconnected;
00428    char  outbound;
00429    char  disced;
00430    char  killme;
00431    long  elaptime;
00432    long  disctime;
00433    long  retrytimer;
00434    long  retxtimer;
00435    long  rerxtimer;
00436    int   retries;
00437    int   max_retries;
00438    int   reconnects;
00439    long long connecttime;
00440    struct ast_channel *chan;  
00441    struct ast_channel *pchan; 
00442    char  linklist[MAXLINKLIST];
00443    time_t   linklistreceived;
00444    long  linklisttimer;
00445    int   dtmfed;
00446    int linkunkeytocttimer;
00447    struct   ast_frame *lastf1,*lastf2;
00448    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00449 } ;
00450 
00451 struct rpt_lstat
00452 {
00453    struct   rpt_lstat *next;
00454    struct   rpt_lstat *prev;
00455    char  peer[MAXPEERSTR];
00456    char  name[MAXNODESTR];
00457    char  mode;
00458    char  outbound;
00459    char  reconnects;
00460    char  thisconnected;
00461    long long   connecttime;
00462    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00463 } ;
00464 
00465 struct rpt_tele
00466 {
00467    struct rpt_tele *next;
00468    struct rpt_tele *prev;
00469    struct rpt *rpt;
00470    struct ast_channel *chan;
00471    int   mode;
00472    struct rpt_link mylink;
00473    char param[TELEPARAMSIZE];
00474    int   submode;
00475    pthread_t threadid;
00476 } ;
00477 
00478 struct function_table_tag
00479 {
00480    char action[ACTIONSIZE];
00481    int (*function)(struct rpt *myrpt, char *param, char *digitbuf, 
00482       int command_source, struct rpt_link *mylink);
00483 } ;
00484 
00485 /* Used to store the morse code patterns */
00486 
00487 struct morse_bits
00488 {       
00489    int len;
00490    int ddcomb;
00491 } ;
00492 
00493 struct telem_defaults
00494 {
00495    char name[20];
00496    char value[80];
00497 } ;
00498 
00499 
00500 struct sysstate
00501 {
00502    char txdisable;
00503    char totdisable;
00504    char linkfundisable;
00505    char autopatchdisable;
00506    char schedulerdisable;
00507    char userfundisable;
00508    char alternatetail;
00509 };
00510 
00511 static struct rpt
00512 {
00513    ast_mutex_t lock;
00514    ast_mutex_t remlock;
00515    struct ast_config *cfg;
00516    char reload;
00517 
00518    char *name;
00519    char *rxchanname;
00520    char *txchanname;
00521    char *remote;
00522    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00523    unsigned int scram;
00524 
00525    struct {
00526       char *ourcontext;
00527       char *ourcallerid;
00528       char *acctcode;
00529       char *ident;
00530       char *tonezone;
00531       char simple;
00532       char *functions;
00533       char *link_functions;
00534       char *phone_functions;
00535       char *dphone_functions;
00536       char *nodes;
00537       char *extnodes;
00538       char *extnodefile;
00539       int hangtime;
00540       int althangtime;
00541       int totime;
00542       int idtime;
00543       int tailmessagetime;
00544       int tailsquashedtime;
00545       int duplex;
00546       int politeid;
00547       char *tailmessages[500];
00548       int tailmessagemax;
00549       char  *memory;
00550       char  *macro;
00551       char  *startupmacro;
00552       int iobase;
00553       char *ioport;
00554       char funcchar;
00555       char endchar;
00556       char nobusyout;
00557       char notelemtx;
00558       char propagate_dtmf;
00559       char propagate_phonedtmf;
00560       char linktolink;
00561       unsigned char civaddr;
00562       struct rpt_xlat inxlat;
00563       struct rpt_xlat outxlat;
00564       char *archivedir;
00565       int authlevel;
00566       char *csstanzaname;
00567       char *skedstanzaname;
00568       char *txlimitsstanzaname;
00569       long monminblocks;
00570       int remoteinacttimeout;
00571       int remotetimeout;
00572       int remotetimeoutwarning;
00573       int remotetimeoutwarningfreq;
00574       int sysstate_cur;
00575       struct sysstate s[MAX_SYSSTATES];
00576    } p;
00577    struct rpt_link links;
00578    int unkeytocttimer;
00579    char keyed;
00580    char exttx;
00581    char localtx;
00582    char remoterx;
00583    char remotetx;
00584    char remoteon;
00585    char remtxfreqok;
00586    char tounkeyed;
00587    char tonotify;
00588    char dtmfbuf[MAXDTMF];
00589    char macrobuf[MAXMACRO];
00590    char rem_dtmfbuf[MAXDTMF];
00591    char lastdtmfcommand[MAXDTMF];
00592    char cmdnode[50];
00593    struct ast_channel *rxchannel,*txchannel, *monchannel;
00594    struct ast_channel *pchannel,*txpchannel;
00595    struct ast_frame *lastf1,*lastf2;
00596    struct rpt_tele tele;
00597    struct timeval lasttv,curtv;
00598    pthread_t rpt_call_thread,rpt_thread;
00599    time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
00600    int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
00601    int mustid,tailid;
00602    int tailevent;
00603    int telemrefcount;
00604    int dtmfidx,rem_dtmfidx;
00605    int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
00606    int totalexecdcommands, dailyexecdcommands;
00607    long  retxtimer;
00608    long  rerxtimer;
00609    long long totaltxtime;
00610    char mydtmf;
00611    char exten[AST_MAX_EXTENSION];
00612    char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
00613    char offset;
00614    char powerlevel;
00615    char txplon;
00616    char rxplon;
00617    char remmode;
00618    char tunerequest;
00619    char hfscanmode;
00620    int hfscanstatus;
00621    char hfscanstop;
00622    char lastlinknode[MAXNODESTR];
00623    char savednodes[MAXNODESTR];
00624    int stopgen;
00625    char patchfarenddisconnect;
00626    char patchnoct;
00627    char patchquiet;
00628    char patchcontext[MAXPATCHCONTEXT];
00629    int patchdialtime;
00630    int macro_longest;
00631    int phone_longestfunc;
00632    int dphone_longestfunc;
00633    int link_longestfunc;
00634    int longestfunc;
00635    int longestnode;
00636    int threadrestarts;     
00637    int tailmessagen;
00638    time_t disgorgetime;
00639    time_t lastthreadrestarttime;
00640    long  macrotimer;
00641    char  lastnodewhichkeyedusup[MAXNODESTR];
00642    int   dtmf_local_timer;
00643    char  dtmf_local_str[100];
00644    struct ast_filestream *monstream;
00645    char  loginuser[50];
00646    char  loginlevel[10];
00647    long  authtelltimer;
00648    long  authtimer;
00649    int iofd;
00650    time_t start_time,last_activity_time;
00651 #ifdef   __RPT_NOTCH
00652    struct rptfilter
00653    {
00654       char  desc[100];
00655       float x0;
00656       float x1;
00657       float x2;
00658       float y0;
00659       float y1;
00660       float y2;
00661       float gain;
00662       float const0;
00663       float const1;
00664       float const2;
00665    } filters[MAXFILTERS];
00666 #endif
00667 #ifdef   _MDC_DECODE_H_
00668    mdc_decoder_t *mdc;
00669    unsigned short lastunit;
00670 #endif
00671 } rpt_vars[MAXRPTS]; 
00672 
00673 struct nodelog {
00674 struct nodelog *next;
00675 struct nodelog *prev;
00676 time_t   timestamp;
00677 char archivedir[MAXNODESTR];
00678 char str[MAXNODESTR * 2];
00679 } nodelog;
00680 
00681 static int service_scan(struct rpt *myrpt);
00682 static int set_mode_ft897(struct rpt *myrpt, char newmode);
00683 static int set_mode_ic706(struct rpt *myrpt, char newmode);
00684 static int simple_command_ft897(struct rpt *myrpt, char command);
00685 static int setrem(struct rpt *myrpt);
00686 
00687 AST_MUTEX_DEFINE_STATIC(nodeloglock);
00688 
00689 AST_MUTEX_DEFINE_STATIC(nodelookuplock);
00690 
00691 #ifdef   APP_RPT_LOCK_DEBUG
00692 
00693 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
00694 
00695 #define  MAXLOCKTHREAD 100
00696 
00697 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
00698 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
00699 
00700 struct lockthread
00701 {
00702    pthread_t id;
00703    int lockcount;
00704    int lastlock;
00705    int lastunlock;
00706 } lockthreads[MAXLOCKTHREAD];
00707 
00708 
00709 struct by_lightning
00710 {
00711    int line;
00712    struct timeval tv;
00713    struct rpt *rpt;
00714    struct lockthread lockthread;
00715 } lock_ring[32];
00716 
00717 int lock_ring_index = 0;
00718 
00719 AST_MUTEX_DEFINE_STATIC(locklock);
00720 
00721 static struct lockthread *get_lockthread(pthread_t id)
00722 {
00723 int   i;
00724 
00725    for(i = 0; i < MAXLOCKTHREAD; i++)
00726    {
00727       if (lockthreads[i].id == id) return(&lockthreads[i]);
00728    }
00729    return(NULL);
00730 }
00731 
00732 static struct lockthread *put_lockthread(pthread_t id)
00733 {
00734 int   i;
00735 
00736    for(i = 0; i < MAXLOCKTHREAD; i++)
00737    {
00738       if (lockthreads[i].id == id)
00739          return(&lockthreads[i]);
00740    }
00741    for(i = 0; i < MAXLOCKTHREAD; i++)
00742    {
00743       if (!lockthreads[i].id)
00744       {
00745          lockthreads[i].lockcount = 0;
00746          lockthreads[i].lastlock = 0;
00747          lockthreads[i].lastunlock = 0;
00748          lockthreads[i].id = id;
00749          return(&lockthreads[i]);
00750       }
00751    }
00752    return(NULL);
00753 }
00754 
00755 
00756 static void rpt_mutex_spew(void)
00757 {
00758    struct by_lightning lock_ring_copy[32];
00759    int lock_ring_index_copy;
00760    int i,j;
00761    long long diff;
00762    char a[100];
00763    struct timeval lasttv;
00764 
00765    ast_mutex_lock(&locklock);
00766    memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
00767    lock_ring_index_copy = lock_ring_index;
00768    ast_mutex_unlock(&locklock);
00769 
00770    lasttv.tv_sec = lasttv.tv_usec = 0;
00771    for(i = 0 ; i < 32 ; i++)
00772    {
00773       j = (i + lock_ring_index_copy) % 32;
00774       strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
00775          localtime(&lock_ring_copy[j].tv.tv_sec));
00776       diff = 0;
00777       if(lasttv.tv_sec)
00778       {
00779          diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
00780             * 1000000;
00781          diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
00782       }
00783       lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
00784       lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
00785       if (!lock_ring_copy[j].tv.tv_sec) continue;
00786       if (lock_ring_copy[j].line < 0)
00787       {
00788          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00789             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);
00790       }
00791       else
00792       {
00793          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00794             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);
00795       }
00796    }
00797 }
00798 
00799 
00800 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
00801 {
00802 struct lockthread *t;
00803 pthread_t id;
00804 
00805    id = pthread_self();
00806    ast_mutex_lock(&locklock);
00807    t = put_lockthread(id);
00808    if (!t)
00809    {
00810       ast_mutex_unlock(&locklock);
00811       return;
00812    }
00813    if (t->lockcount)
00814    {
00815       int lastline = t->lastlock;
00816       ast_mutex_unlock(&locklock);
00817       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);
00818       rpt_mutex_spew();
00819       return;
00820    }
00821    t->lastlock = line;
00822    t->lockcount = 1;
00823    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
00824    lock_ring[lock_ring_index].rpt = myrpt;
00825    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
00826    lock_ring[lock_ring_index++].line = line;
00827    if(lock_ring_index == 32)
00828       lock_ring_index = 0;
00829    ast_mutex_unlock(&locklock);
00830    ast_mutex_lock(lockp);
00831 }
00832 
00833 
00834 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
00835 {
00836 struct lockthread *t;
00837 pthread_t id;
00838 
00839    id = pthread_self();
00840    ast_mutex_lock(&locklock);
00841    t = put_lockthread(id);
00842    if (!t)
00843    {
00844       ast_mutex_unlock(&locklock);
00845       return;
00846    }
00847    if (!t->lockcount)
00848    {
00849       int lastline = t->lastunlock;
00850       ast_mutex_unlock(&locklock);
00851       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);
00852       rpt_mutex_spew();
00853       return;
00854    }
00855    t->lastunlock = line;
00856    t->lockcount = 0;
00857    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
00858    lock_ring[lock_ring_index].rpt = myrpt;
00859    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
00860    lock_ring[lock_ring_index++].line = -line;
00861    if(lock_ring_index == 32)
00862       lock_ring_index = 0;
00863    ast_mutex_unlock(&locklock);
00864    ast_mutex_unlock(lockp);
00865 }
00866 
00867 #else  /* APP_RPT_LOCK_DEBUG */
00868 
00869 #define rpt_mutex_lock(x) ast_mutex_lock(x)
00870 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
00871 
00872 #endif  /* APP_RPT_LOCK_DEBUG */
00873 
00874 /*
00875 * Return 1 if rig is multimode capable
00876 */
00877 
00878 static int multimode_capable(struct rpt *myrpt)
00879 {
00880    if(!strcmp(myrpt->remote, remote_rig_ft897))
00881       return 1;
00882    if(!strcmp(myrpt->remote, remote_rig_ic706))
00883       return 1;
00884    return 0;
00885 }  
00886 
00887 /*
00888 * CLI extensions
00889 */
00890 
00891 /* Debug mode */
00892 static int rpt_do_debug(int fd, int argc, char *argv[]);
00893 static int rpt_do_dump(int fd, int argc, char *argv[]);
00894 static int rpt_do_stats(int fd, int argc, char *argv[]);
00895 static int rpt_do_lstats(int fd, int argc, char *argv[]);
00896 static int rpt_do_nodes(int fd, int argc, char *argv[]);
00897 static int rpt_do_reload(int fd, int argc, char *argv[]);
00898 static int rpt_do_restart(int fd, int argc, char *argv[]);
00899 static int rpt_do_fun(int fd, int argc, char *argv[]);
00900 
00901 static char debug_usage[] =
00902 "Usage: rpt debug level {0-7}\n"
00903 "       Enables debug messages in app_rpt\n";
00904 
00905 static char dump_usage[] =
00906 "Usage: rpt dump <nodename>\n"
00907 "       Dumps struct debug info to log\n";
00908 
00909 static char dump_stats[] =
00910 "Usage: rpt stats <nodename>\n"
00911 "       Dumps node statistics to console\n";
00912 
00913 static char dump_lstats[] =
00914 "Usage: rpt lstats <nodename>\n"
00915 "       Dumps link statistics to console\n";
00916 
00917 static char dump_nodes[] =
00918 "Usage: rpt nodes <nodename>\n"
00919 "       Dumps a list of directly and indirectly connected nodes to the console\n";
00920 
00921 static char reload_usage[] =
00922 "Usage: rpt reload\n"
00923 "       Reloads app_rpt running config parameters\n";
00924 
00925 static char restart_usage[] =
00926 "Usage: rpt restart\n"
00927 "       Restarts app_rpt\n";
00928 
00929 static char fun_usage[] =
00930 "Usage: rpt fun <nodename> <command>\n"
00931 "       Send a DTMF function to a node\n";
00932 
00933 
00934 static struct ast_cli_entry  cli_debug =
00935         { { "rpt", "debug", "level" }, rpt_do_debug, 
00936       "Enable app_rpt debugging", debug_usage };
00937 
00938 static struct ast_cli_entry  cli_dump =
00939         { { "rpt", "dump" }, rpt_do_dump,
00940       "Dump app_rpt structs for debugging", dump_usage };
00941 
00942 static struct ast_cli_entry  cli_stats =
00943         { { "rpt", "stats" }, rpt_do_stats,
00944       "Dump node statistics", dump_stats };
00945 
00946 static struct ast_cli_entry  cli_nodes =
00947         { { "rpt", "nodes" }, rpt_do_nodes,
00948       "Dump node list", dump_nodes };
00949 
00950 static struct ast_cli_entry  cli_lstats =
00951         { { "rpt", "lstats" }, rpt_do_lstats,
00952       "Dump link statistics", dump_lstats };
00953 
00954 static struct ast_cli_entry  cli_reload =
00955         { { "rpt", "reload" }, rpt_do_reload,
00956       "Reload app_rpt config", reload_usage };
00957 
00958 static struct ast_cli_entry  cli_restart =
00959         { { "rpt", "restart" }, rpt_do_restart,
00960       "Restart app_rpt", restart_usage };
00961 
00962 static struct ast_cli_entry  cli_fun =
00963         { { "rpt", "fun" }, rpt_do_fun,
00964       "Execute a DTMF function", fun_usage };
00965 
00966 /*
00967 * Telemetry defaults
00968 */
00969 
00970 
00971 static struct telem_defaults tele_defs[] = {
00972    {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
00973    {"ct2","|t(660,880,150,3072)"},
00974    {"ct3","|t(440,0,150,3072)"},
00975    {"ct4","|t(550,0,150,3072)"},
00976    {"ct5","|t(660,0,150,3072)"},
00977    {"ct6","|t(880,0,150,3072)"},
00978    {"ct7","|t(660,440,150,3072)"},
00979    {"ct8","|t(700,1100,150,3072)"},
00980    {"remotemon","|t(1600,0,75,2048)"},
00981    {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
00982    {"cmdmode","|t(900,904,200,2048)"},
00983    {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
00984 } ;
00985 
00986 /*
00987 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
00988 */
00989 
00990 static int setrbi(struct rpt *myrpt);
00991 static int set_ft897(struct rpt *myrpt);
00992 static int set_ic706(struct rpt *myrpt);
00993 static int setkenwood(struct rpt *myrpt);
00994 static int setrbi_check(struct rpt *myrpt);
00995 
00996 
00997 
00998 /*
00999 * Define function protos for function table here
01000 */
01001 
01002 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01003 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01004 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01005 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01006 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01007 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01008 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01009 /*
01010 * Function table
01011 */
01012 
01013 static struct function_table_tag function_table[] = {
01014    {"cop", function_cop},
01015    {"autopatchup", function_autopatchup},
01016    {"autopatchdn", function_autopatchdn},
01017    {"ilink", function_ilink},
01018    {"status", function_status},
01019    {"remote", function_remote},
01020    {"macro", function_macro}
01021 } ;
01022 
01023 static long diskavail(struct rpt *myrpt)
01024 {
01025 struct   statfs statfsbuf;
01026 
01027    if (!myrpt->p.archivedir) return(0);
01028    if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
01029    {
01030       ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
01031          myrpt->p.archivedir,myrpt->name);
01032       return(-1);
01033    }
01034    return(statfsbuf.f_bavail);
01035 }
01036 
01037 static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
01038 {
01039 struct        rpt_link *l;
01040 
01041        l = myrpt->links.next;
01042        /* go thru all the links */
01043        while(l != &myrpt->links)
01044        {
01045                if (!l->phonemode)
01046                {
01047                        l = l->next;
01048                        continue;
01049                }
01050                /* dont send to self */
01051                if (mylink && (l == mylink))
01052                {
01053                        l = l->next;
01054                        continue;
01055                }
01056                if (l->chan) ast_senddigit(l->chan,c);
01057                l = l->next;
01058        }
01059        return;
01060 }
01061 
01062 /* node logging function */
01063 static void donodelog(struct rpt *myrpt,char *str)
01064 {
01065 struct nodelog *nodep;
01066 char  datestr[100];
01067 
01068    if (!myrpt->p.archivedir) return;
01069    nodep = (struct nodelog *)malloc(sizeof(struct nodelog));
01070    if (nodep == NULL)
01071    {
01072       ast_log(LOG_ERROR,"Cannot get memory for node log");
01073       return;
01074    }
01075    time(&nodep->timestamp);
01076    strncpy(nodep->archivedir,myrpt->p.archivedir,
01077       sizeof(nodep->archivedir) - 1);
01078    strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
01079       localtime(&nodep->timestamp));
01080    snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
01081       myrpt->name,datestr,str);
01082    ast_mutex_lock(&nodeloglock);
01083    insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
01084    ast_mutex_unlock(&nodeloglock);
01085 }
01086 
01087 /* must be called locked */
01088 static void do_dtmf_local(struct rpt *myrpt, char c)
01089 {
01090 int   i;
01091 char  digit;
01092 static const char* dtmf_tones[] = {
01093    "!941+1336/200,!0/200", /* 0 */
01094    "!697+1209/200,!0/200", /* 1 */
01095    "!697+1336/200,!0/200", /* 2 */
01096    "!697+1477/200,!0/200", /* 3 */
01097    "!770+1209/200,!0/200", /* 4 */
01098    "!770+1336/200,!0/200", /* 5 */
01099    "!770+1477/200,!0/200", /* 6 */
01100    "!852+1209/200,!0/200", /* 7 */
01101    "!852+1336/200,!0/200", /* 8 */
01102    "!852+1477/200,!0/200", /* 9 */
01103    "!697+1633/200,!0/200", /* A */
01104    "!770+1633/200,!0/200", /* B */
01105    "!852+1633/200,!0/200", /* C */
01106    "!941+1633/200,!0/200", /* D */
01107    "!941+1209/200,!0/200", /* * */
01108    "!941+1477/200,!0/200" };  /* # */
01109 
01110 
01111    if (c)
01112    {
01113       snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
01114       if (!myrpt->dtmf_local_timer) 
01115           myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
01116    }
01117    /* if at timeout */
01118    if (myrpt->dtmf_local_timer == 1)
01119    {
01120       /* if anything in the string */
01121       if (myrpt->dtmf_local_str[0])
01122       {
01123          digit = myrpt->dtmf_local_str[0];
01124          myrpt->dtmf_local_str[0] = 0;
01125          for(i = 1; myrpt->dtmf_local_str[i]; i++)
01126          {
01127             myrpt->dtmf_local_str[i - 1] =
01128                myrpt->dtmf_local_str[i];
01129          }
01130          myrpt->dtmf_local_str[i - 1] = 0;
01131          myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
01132          rpt_mutex_unlock(&myrpt->lock);
01133          if (digit >= '0' && digit <='9')
01134             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
01135          else if (digit >= 'A' && digit <= 'D')
01136             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
01137          else if (digit == '*')
01138             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
01139          else if (digit == '#')
01140             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
01141          else {
01142             /* not handled */
01143             ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name);
01144          }
01145          rpt_mutex_lock(&myrpt->lock);
01146       }
01147       else
01148       {
01149          myrpt->dtmf_local_timer = 0;
01150       }
01151    }
01152 }
01153 
01154 static int openserial(char *fname)
01155 {
01156    struct termios mode;
01157    int fd;
01158 
01159    fd = open(fname,O_RDWR);
01160    if (fd == -1)
01161    {
01162       ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
01163       return -1;
01164    }
01165    memset(&mode, 0, sizeof(mode));
01166    if (tcgetattr(fd, &mode)) {
01167       ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
01168       return -1;
01169    }
01170 #ifndef SOLARIS
01171    cfmakeraw(&mode);
01172 #else
01173         mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
01174                         |INLCR|IGNCR|ICRNL|IXON);
01175         mode.c_oflag &= ~OPOST;
01176         mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
01177         mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
01178         mode.c_cflag |= CS8;
01179    mode.c_cc[TIME] = 3;
01180    mode.c_cc[MAX] = 1;
01181 #endif
01182 
01183    cfsetispeed(&mode, B9600);
01184    cfsetospeed(&mode, B9600);
01185    if (tcsetattr(fd, TCSANOW, &mode)) 
01186       ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
01187    return(fd); 
01188 }
01189 
01190 static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
01191 {
01192 time_t   now;
01193 int   gotone;
01194 
01195    time(&now);
01196    gotone = 0;
01197    /* if too much time, reset the skate machine */
01198    if ((now - xlat->lastone) > MAXXLATTIME)
01199    {
01200       xlat->funcindex = xlat->endindex = 0;
01201    }
01202    if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
01203    {
01204       time(&xlat->lastone);
01205       gotone = 1;
01206       if (!xlat->funccharseq[xlat->funcindex])
01207       {
01208          xlat->funcindex = xlat->endindex = 0;
01209          return(myrpt->p.funcchar);
01210       }
01211    } else xlat->funcindex = 0;
01212    if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
01213    {
01214       time(&xlat->lastone);
01215       gotone = 1;
01216       if (!xlat->endcharseq[xlat->endindex])
01217       {
01218          xlat->funcindex = xlat->endindex = 0;
01219          return(myrpt->p.endchar);
01220       }
01221    } else xlat->endindex = 0;
01222    /* if in middle of decode seq, send nothing back */
01223    if (gotone) return(0);
01224    /* if no pass chars specified, return em all */
01225    if (!xlat->passchars[0]) return(c);
01226    /* if a "pass char", pass it */
01227    if (strchr(xlat->passchars,c)) return(c);
01228    return(0);
01229 }
01230 
01231 /*
01232  * Return a pointer to the first non-whitespace character
01233  */
01234 
01235 static char *eatwhite(char *s)
01236 {
01237    while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
01238       if(!*s)
01239          break;
01240       s++;
01241    }
01242    return s;
01243 }
01244 
01245 /*
01246 * Break up a delimited string into a table of substrings
01247 *
01248 * str - delimited string ( will be modified )
01249 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
01250 * limit- maximum number of substrings to process
01251 */
01252    
01253 
01254 
01255 static int finddelim(char *str, char *strp[], int limit)
01256 {
01257 int     i,l,inquo;
01258 
01259         inquo = 0;
01260         i = 0;
01261         strp[i++] = str;
01262         if (!*str)
01263            {
01264                 strp[0] = 0;
01265                 return(0);
01266            }
01267         for(l = 0; *str && (l < limit) ; str++)
01268            {
01269                 if (*str == QUOTECHR)
01270                    {
01271                         if (inquo)
01272                            {
01273                                 *str = 0;
01274                                 inquo = 0;
01275                            }
01276                         else
01277                            {
01278                                 strp[i - 1] = str + 1;
01279                                 inquo = 1;
01280                            }
01281       }
01282                 if ((*str == DELIMCHR) && (!inquo))
01283                 {
01284                         *str = 0;
01285          l++;
01286                         strp[i++] = str + 1;
01287                 }
01288            }
01289         strp[i] = 0;
01290         return(i);
01291 
01292 }
01293 
01294 /* must be called locked */
01295 static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
01296 {
01297 struct rpt_link *l;
01298 char mode;
01299 int   i,spos;
01300 
01301    buf[0] = 0; /* clear output buffer */
01302    /* go thru all links */
01303    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01304    {
01305       /* if is not a real link, ignore it */
01306       if (l->name[0] == '0') continue;
01307       /* dont count our stuff */
01308       if (l == mylink) continue;
01309       if (mylink && (!strcmp(l->name,mylink->name))) continue;
01310       /* figure out mode to report */
01311       mode = 'T'; /* use Tranceive by default */
01312       if (!l->mode) mode = 'R'; /* indicate RX for our mode */
01313       if (!l->thisconnected)  mode = 'C'; /* indicate connecting */
01314       spos = strlen(buf); /* current buf size (b4 we add our stuff) */
01315       if (spos)
01316       {
01317          strcat(buf,",");
01318          spos++;
01319       }
01320       /* add nodes into buffer */
01321       if (l->linklist[0])
01322       {
01323          snprintf(buf + spos,MAXLINKLIST - spos,
01324             "%c%s,%s",mode,l->name,l->linklist);
01325       }
01326       else /* if no nodes, add this node into buffer */
01327       {
01328          snprintf(buf + spos,MAXLINKLIST - spos,
01329             "%c%s",mode,l->name);
01330       }
01331       /* if we are in tranceive mode, let all modes stand */
01332       if (mode == 'T') continue;
01333       /* downgrade everyone on this node if appropriate */
01334       for(i = spos; buf[i]; i++)
01335       {
01336          if (buf[i] == 'T') buf[i] = mode;
01337          if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
01338       }
01339    }
01340    return;
01341 }
01342 
01343 /* must be called locked */
01344 static void __kickshort(struct rpt *myrpt)
01345 {
01346 struct rpt_link *l;
01347 
01348    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01349    {
01350       /* if is not a real link, ignore it */
01351       if (l->name[0] == '0') continue;
01352       l->linklisttimer = LINKLISTSHORTTIME;
01353    }
01354    return;
01355 }
01356 
01357 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
01358 {
01359 
01360 char *val;
01361 int longestnode,j;
01362 struct stat mystat;
01363 static time_t last = 0;
01364 static struct ast_config *ourcfg = NULL;
01365 struct ast_variable *vp;
01366 
01367    /* try to look it up locally first */
01368    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
01369    if (val) return(val);
01370    ast_mutex_lock(&nodelookuplock);
01371    /* if file does not exist */
01372    if (stat(myrpt->p.extnodefile,&mystat) == -1)
01373    {
01374       if (ourcfg) ast_config_destroy(ourcfg);
01375       ourcfg = NULL;
01376       ast_mutex_unlock(&nodelookuplock);
01377       return(NULL);
01378    }
01379    /* if we need to reload */
01380    if (mystat.st_mtime > last)
01381    {
01382       if (ourcfg) ast_config_destroy(ourcfg);
01383       ourcfg = ast_config_load(myrpt->p.extnodefile);
01384       /* if file not there, just bail */
01385       if (!ourcfg)
01386       {
01387          ast_mutex_unlock(&nodelookuplock);
01388          return(NULL);
01389       }
01390       /* reset "last" time */
01391       last = mystat.st_mtime;
01392 
01393       /* determine longest node length again */    
01394       longestnode = 0;
01395       vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
01396       while(vp){
01397          j = strlen(vp->name);
01398          if (j > longestnode)
01399             longestnode = j;
01400          vp = vp->next;
01401       }
01402 
01403       vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
01404       while(vp){
01405          j = strlen(vp->name);
01406          if (j > longestnode)
01407             longestnode = j;
01408          vp = vp->next;
01409       }
01410 
01411       myrpt->longestnode = longestnode;
01412    }
01413    val = NULL;
01414    if (ourcfg)
01415       val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
01416    ast_mutex_unlock(&nodelookuplock);
01417    return(val);
01418 }
01419 
01420 /*
01421 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
01422 * If param is passed in non-null, then it will be set to the first character past the match
01423 */
01424 
01425 static int matchkeyword(char *string, char **param, char *keywords[])
01426 {
01427 int   i,ls;
01428    for( i = 0 ; keywords[i] ; i++){
01429       ls = strlen(keywords[i]);
01430       if(!ls){
01431          *param = NULL;
01432          return 0;
01433       }
01434       if(!strncmp(string, keywords[i], ls)){
01435          if(param)
01436             *param = string + ls;
01437          return i + 1; 
01438       }
01439    }
01440    param = NULL;
01441    return 0;
01442 }
01443 
01444 /*
01445 * Skip characters in string which are in charlist, and return a pointer to the
01446 * first non-matching character
01447 */
01448 
01449 static char *skipchars(char *string, char *charlist)
01450 {
01451 int i;   
01452    while(*string){
01453       for(i = 0; charlist[i] ; i++){
01454          if(*string == charlist[i]){
01455             string++;
01456             break;
01457          }
01458       }
01459       if(!charlist[i])
01460          return string;
01461    }
01462    return string;
01463 }  
01464                
01465 
01466 
01467 static int myatoi(char *str)
01468 {
01469 int   ret;
01470 
01471    if (str == NULL) return -1;
01472    /* leave this %i alone, non-base-10 input is useful here */
01473    if (sscanf(str,"%i",&ret) != 1) return -1;
01474    return ret;
01475 }
01476 
01477 static int mycompar(const void *a, const void *b)
01478 {
01479 char  **x = (char **) a;
01480 char  **y = (char **) b;
01481 int   xoff,yoff;
01482 
01483    if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
01484    if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
01485    return(strcmp((*x) + xoff,(*y) + yoff));
01486 }
01487 
01488 #ifdef   __RPT_NOTCH
01489 
01490 /* rpt filter routine */
01491 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
01492 {
01493 int   i,j;
01494 struct   rptfilter *f;
01495 
01496    for(i = 0; i < len; i++)
01497    {
01498       for(j = 0; j < MAXFILTERS; j++)
01499       {
01500          f = &myrpt->filters[j];
01501          if (!*f->desc) continue;
01502          f->x0 = f->x1; f->x1 = f->x2;
01503               f->x2 = ((float)buf[i]) / f->gain;
01504               f->y0 = f->y1; f->y1 = f->y2;
01505               f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
01506                            + (f->const1 * f->y0) + (f->const2 * f->y1);
01507          buf[i] = (short)f->y2;
01508       }
01509    }
01510 }
01511 
01512 #endif
01513 
01514 
01515 /*
01516  Get the time for the machine's time zone
01517  Note: Asterisk requires a copy of localtime
01518  in the /etc directory for this to work properly.
01519  If /etc/localtime is not present, you will get
01520  GMT time! This is especially important on systems
01521  running embedded linux distributions as they don't usually
01522  have support for locales. 
01523 
01524  If OLD_ASTERISK is defined, then the older localtime_r
01525  function will be used. The /etc/localtime file is not
01526  required in this case. This provides backward compatibility
01527  with Asterisk 1.2 systems.
01528 
01529 */
01530 
01531 static void rpt_localtime( time_t * t, struct tm *lt)
01532 {
01533 #ifdef OLD_ASTERISK
01534    localtime_r(t, lt);
01535 #else
01536    ast_localtime(t, lt, NULL);
01537 #endif
01538 }
01539 
01540 /* Retrieve an int from a config file */
01541                                                                                 
01542 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
01543 {
01544         char *var;
01545         int ret;
01546    char include_zero = 0;
01547 
01548    if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
01549       min = -min;
01550       include_zero = 1;
01551    }           
01552                                                                      
01553         var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
01554         if(var){
01555                 ret = myatoi(var);
01556       if(include_zero && !ret)
01557          return 0;
01558                 if(ret < min)
01559                         ret = min;
01560                 if(ret > max)
01561                         ret = max;
01562         }
01563         else
01564                 ret = defl;
01565         return ret;
01566 }
01567 
01568 
01569 static void load_rpt_vars(int n,int init)
01570 {
01571 char *this,*val;
01572 int   i,j,longestnode;
01573 struct ast_variable *vp;
01574 struct ast_config *cfg;
01575 char *strs[100];
01576 char s1[256];
01577 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
01578             "ufena","ufdis","atena","atdis",NULL};
01579 
01580    if (option_verbose > 2)
01581       ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
01582          (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
01583    ast_mutex_lock(&rpt_vars[n].lock);
01584    if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
01585    cfg = ast_config_load("rpt.conf");
01586    if (!cfg) {
01587       ast_mutex_unlock(&rpt_vars[n].lock);
01588       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
01589       pthread_exit(NULL);
01590    }
01591    rpt_vars[n].cfg = cfg; 
01592    this = rpt_vars[n].name;
01593    memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
01594    if (init)
01595    {
01596       char *cp;
01597       int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
01598 
01599       cp = (char *) &rpt_vars[n].p;
01600       memset(cp + sizeof(rpt_vars[n].p),0,
01601          sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
01602       rpt_vars[n].tele.next = &rpt_vars[n].tele;
01603       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
01604       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
01605       rpt_vars[n].tailmessagen = 0;
01606    }
01607 #ifdef   __RPT_NOTCH
01608    /* zot out filters stuff */
01609    memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
01610 #endif
01611    val = (char *) ast_variable_retrieve(cfg,this,"context");
01612    if (val) rpt_vars[n].p.ourcontext = val;
01613    else rpt_vars[n].p.ourcontext = this;
01614    val = (char *) ast_variable_retrieve(cfg,this,"callerid");
01615    if (val) rpt_vars[n].p.ourcallerid = val;
01616    val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
01617    if (val) rpt_vars[n].p.acctcode = val;
01618    val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
01619    if (val) rpt_vars[n].p.ident = val;
01620    val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
01621    if (val) rpt_vars[n].p.hangtime = atoi(val);
01622       else rpt_vars[n].p.hangtime = HANGTIME;
01623    val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
01624    if (val) rpt_vars[n].p.althangtime = atoi(val);
01625       else rpt_vars[n].p.althangtime = HANGTIME;
01626    val = (char *) ast_variable_retrieve(cfg,this,"totime");
01627    if (val) rpt_vars[n].p.totime = atoi(val);
01628       else rpt_vars[n].p.totime = TOTIME;
01629    rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);    
01630    rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);     
01631    rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
01632    rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME);   /* Enforce a min max including zero */
01633    rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
01634    val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
01635    if (val) rpt_vars[n].p.tonezone = val;
01636    rpt_vars[n].p.tailmessages[0] = 0;
01637    rpt_vars[n].p.tailmessagemax = 0;
01638    val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
01639    if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
01640    val = (char *) ast_variable_retrieve(cfg,this,"memory");
01641    if (!val) val = MEMORY;
01642    rpt_vars[n].p.memory = val;
01643    val = (char *) ast_variable_retrieve(cfg,this,"macro");
01644    if (!val) val = MACRO;
01645    rpt_vars[n].p.macro = val;
01646    val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
01647    if (val) rpt_vars[n].p.startupmacro = val;
01648    val = (char *) ast_variable_retrieve(cfg,this,"iobase");
01649    /* do not use atoi() here, we need to be able to have
01650       the input specified in hex or decimal so we use
01651       sscanf with a %i */
01652    if ((!val) || (sscanf(val,"%i",&rpt_vars[n].p.iobase) != 1))
01653    rpt_vars[n].p.iobase = DEFAULT_IOBASE;
01654    val = (char *) ast_variable_retrieve(cfg,this,"ioport");
01655    rpt_vars[n].p.ioport = val;
01656    val = (char *) ast_variable_retrieve(cfg,this,"functions");
01657    if (!val)
01658       {
01659          val = FUNCTIONS;
01660          rpt_vars[n].p.simple = 1;
01661       } 
01662    rpt_vars[n].p.functions = val;
01663    val =  (char *) ast_variable_retrieve(cfg,this,"link_functions");
01664    if (val) rpt_vars[n].p.link_functions = val;
01665    else 
01666       rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
01667    val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
01668    if (val) rpt_vars[n].p.phone_functions = val;
01669    val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
01670    if (val) rpt_vars[n].p.dphone_functions = val;
01671    val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
01672    if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
01673       rpt_vars[n].p.funcchar = *val;      
01674    val = (char *) ast_variable_retrieve(cfg,this,"endchar");
01675    if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
01676       rpt_vars[n].p.endchar = *val;    
01677    val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
01678    if (val) rpt_vars[n].p.nobusyout = ast_true(val);
01679    val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
01680    if (val) rpt_vars[n].p.notelemtx = ast_true(val);
01681    val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
01682    if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
01683    val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
01684    if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
01685    val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
01686    if (val) rpt_vars[n].p.linktolink = ast_true(val);
01687    val = (char *) ast_variable_retrieve(cfg,this,"nodes");
01688    if (!val) val = NODES;
01689    rpt_vars[n].p.nodes = val;
01690    val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
01691    if (!val) val = EXTNODES;
01692    rpt_vars[n].p.extnodes = val;
01693    val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
01694    if (!val) val = EXTNODEFILE;
01695    rpt_vars[n].p.extnodefile = val;
01696    val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
01697    if (val) rpt_vars[n].p.archivedir = val;
01698    val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
01699    if (val) rpt_vars[n].p.authlevel = atoi(val); 
01700    else rpt_vars[n].p.authlevel = 0;
01701    val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
01702    if (val) rpt_vars[n].p.monminblocks = atol(val); 
01703    else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
01704    val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
01705    if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); 
01706    else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
01707    val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
01708    if (val) rpt_vars[n].p.civaddr = atoi(val); 
01709    else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
01710    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
01711    if (val) rpt_vars[n].p.remotetimeout = atoi(val); 
01712    else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
01713    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
01714    if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); 
01715    else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
01716    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
01717    if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); 
01718    else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
01719 #ifdef   __RPT_NOTCH
01720    val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
01721    if (val) {
01722       i = finddelim(val,strs,MAXFILTERS * 2);
01723       i &= ~1; /* force an even number, rounded down */
01724       if (i >= 2) for(j = 0; j < i; j += 2)
01725       {
01726          rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
01727            &rpt_vars[n].filters[j >> 1].gain,
01728              &rpt_vars[n].filters[j >> 1].const0,
01729             &rpt_vars[n].filters[j >> 1].const1,
01730                 &rpt_vars[n].filters[j >> 1].const2);
01731          sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
01732             strs[j],strs[j + 1]);
01733       }
01734 
01735    }
01736 #endif
01737    val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
01738    if (val) {
01739       memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
01740       i = finddelim(val,strs,3);
01741       if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
01742       if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
01743       if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
01744    }
01745    val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
01746    if (val) {
01747       memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
01748       i = finddelim(val,strs,3);
01749       if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
01750       if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
01751       if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
01752    }
01753    /* retreive the stanza name for the control states if there is one */
01754    val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
01755    rpt_vars[n].p.csstanzaname = val;
01756       
01757    /* retreive the stanza name for the scheduler if there is one */
01758    val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
01759    rpt_vars[n].p.skedstanzaname = val;
01760 
01761    /* retreive the stanza name for the txlimits */
01762    val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
01763    rpt_vars[n].p.txlimitsstanzaname = val;
01764 
01765    longestnode = 0;
01766 
01767    vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
01768       
01769    while(vp){
01770       j = strlen(vp->name);
01771       if (j > longestnode)
01772          longestnode = j;
01773       vp = vp->next;
01774    }
01775 
01776    rpt_vars[n].longestnode = longestnode;
01777       
01778    /*
01779    * For this repeater, Determine the length of the longest function 
01780    */
01781    rpt_vars[n].longestfunc = 0;
01782    vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
01783    while(vp){
01784       j = strlen(vp->name);
01785       if (j > rpt_vars[n].longestfunc)
01786          rpt_vars[n].longestfunc = j;
01787       vp = vp->next;
01788    }
01789    /*
01790    * For this repeater, Determine the length of the longest function 
01791    */
01792    rpt_vars[n].link_longestfunc = 0;
01793    vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
01794    while(vp){
01795       j = strlen(vp->name);
01796       if (j > rpt_vars[n].link_longestfunc)
01797          rpt_vars[n].link_longestfunc = j;
01798       vp = vp->next;
01799    }
01800    rpt_vars[n].phone_longestfunc = 0;
01801    if (rpt_vars[n].p.phone_functions)
01802    {
01803       vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
01804       while(vp){
01805          j = strlen(vp->name);
01806          if (j > rpt_vars[n].phone_longestfunc)
01807             rpt_vars[n].phone_longestfunc = j;
01808          vp = vp->next;
01809       }
01810    }
01811    rpt_vars[n].dphone_longestfunc = 0;
01812    if (rpt_vars[n].p.dphone_functions)
01813    {
01814       vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
01815       while(vp){
01816          j = strlen(vp->name);
01817          if (j > rpt_vars[n].dphone_longestfunc)
01818             rpt_vars[n].dphone_longestfunc = j;
01819          vp = vp->next;
01820       }
01821    }
01822    rpt_vars[n].macro_longest = 1;
01823    vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
01824    while(vp){
01825       j = strlen(vp->name);
01826       if (j > rpt_vars[n].macro_longest)
01827          rpt_vars[n].macro_longest = j;
01828       vp = vp->next;
01829    }
01830    
01831    /* Browse for control states */
01832    if(rpt_vars[n].p.csstanzaname)
01833       vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
01834    else
01835       vp = NULL;
01836    for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
01837       int k,nukw,statenum;
01838       statenum=atoi(vp->name);
01839       strncpy(s1, vp->value, 255);
01840       s1[255] = 0;
01841       nukw  = finddelim(s1,strs,32);
01842       
01843       for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */  
01844          for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
01845             if(!strcmp(strs[k],cs_keywords[j])){
01846                switch(j){
01847                   case 0: /* rptena */
01848                      rpt_vars[n].p.s[statenum].txdisable = 0;
01849                      break;
01850                   case 1: /* rptdis */
01851                      rpt_vars[n].p.s[statenum].txdisable = 1;
01852                      break;
01853          
01854                   case 2: /* apena */
01855                      rpt_vars[n].p.s[statenum].autopatchdisable = 0;
01856                      break;
01857 
01858                   case 3: /* apdis */
01859                      rpt_vars[n].p.s[statenum].autopatchdisable = 1;
01860                      break;
01861 
01862                   case 4: /* lnkena */
01863                      rpt_vars[n].p.s[statenum].linkfundisable = 0;
01864                      break;
01865    
01866                   case 5: /* lnkdis */
01867                      rpt_vars[n].p.s[statenum].linkfundisable = 1;
01868                      break;
01869 
01870                   case 6: /* totena */
01871                      rpt_vars[n].p.s[statenum].totdisable = 0;
01872                      break;
01873                
01874                   case 7: /* totdis */
01875                      rpt_vars[n].p.s[statenum].totdisable = 1;
01876                      break;
01877 
01878                   case 8: /* skena */
01879                      rpt_vars[n].p.s[statenum].schedulerdisable = 0;
01880                      break;
01881 
01882                   case 9: /* skdis */
01883                      rpt_vars[n].p.s[statenum].schedulerdisable = 1;
01884                      break;
01885 
01886                   case 10: /* ufena */
01887                      rpt_vars[n].p.s[statenum].userfundisable = 0;
01888                      break;
01889 
01890                   case 11: /* ufdis */
01891                      rpt_vars[n].p.s[statenum].userfundisable = 1;
01892                      break;
01893 
01894                   case 12: /* atena */
01895                      rpt_vars[n].p.s[statenum].alternatetail = 1;
01896                      break;
01897 
01898                   case 13: /* atdis */
01899                      rpt_vars[n].p.s[statenum].alternatetail = 0;
01900                      break;
01901          
01902                   default:
01903                      ast_log(LOG_WARNING,
01904                         "Unhandled control state keyword %s", cs_keywords[i]);
01905                      break;
01906                }
01907             }
01908          }
01909       }
01910       vp = vp->next;
01911    }
01912    ast_mutex_unlock(&rpt_vars[n].lock);
01913 }
01914 
01915 /*
01916 * Enable or disable debug output at a given level at the console
01917 */
01918                                                                                                                                  
01919 static int rpt_do_debug(int fd, int argc, char *argv[])
01920 {
01921    int newlevel;
01922 
01923         if (argc != 4)
01924                 return RESULT_SHOWUSAGE;
01925         newlevel = myatoi(argv[3]);
01926         if((newlevel < 0) || (newlevel > 7))
01927                 return RESULT_SHOWUSAGE;
01928         if(newlevel)
01929                 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
01930         else
01931                 ast_cli(fd, "app_rpt Debugging disabled\n");
01932 
01933         debug = newlevel;                                                                                                                          
01934         return RESULT_SUCCESS;
01935 }
01936 
01937 /*
01938 * Dump rpt struct debugging onto console
01939 */
01940                                                                                                                                  
01941 static int rpt_do_dump(int fd, int argc, char *argv[])
01942 {
01943    int i;
01944 
01945         if (argc != 3)
01946                 return RESULT_SHOWUSAGE;
01947 
01948    for(i = 0; i < nrpts; i++)
01949    {
01950       if (!strcmp(argv[2],rpt_vars[i].name))
01951       {
01952          rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
01953               ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
01954               return RESULT_SUCCESS;
01955       }
01956    }
01957    return RESULT_FAILURE;
01958 }
01959 
01960 /*
01961 * Dump statistics onto console
01962 */
01963 
01964 static int rpt_do_stats(int fd, int argc, char *argv[])
01965 {
01966    int i,j;
01967    int dailytxtime, dailykerchunks;
01968    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
01969    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
01970    long long totaltxtime;
01971    struct   rpt_link *l;
01972    char *listoflinks[MAX_STAT_LINKS];  
01973    char *lastnodewhichkeyedusup, *lastdtmfcommand;
01974    char *tot_state, *ider_state, *patch_state;
01975    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
01976    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
01977    struct rpt *myrpt;
01978 
01979    static char *not_applicable = "N/A";
01980 
01981    if(argc != 3)
01982       return RESULT_SHOWUSAGE;
01983 
01984    for(i = 0 ; i < MAX_STAT_LINKS; i++)
01985       listoflinks[i] = NULL;
01986 
01987    tot_state = ider_state = 
01988    patch_state = reverse_patch_state = 
01989    input_signal = called_number = 
01990    lastdtmfcommand = not_applicable;
01991 
01992    for(i = 0; i < nrpts; i++)
01993    {
01994       if (!strcmp(argv[2],rpt_vars[i].name)){
01995          /* Make a copy of all stat variables while locked */
01996          myrpt = &rpt_vars[i];
01997          rpt_mutex_lock(&myrpt->lock); /* LOCK */
01998 
01999          dailytxtime = myrpt->dailytxtime;
02000          totaltxtime = myrpt->totaltxtime;
02001          dailykeyups = myrpt->dailykeyups;
02002          totalkeyups = myrpt->totalkeyups;
02003          dailykerchunks = myrpt->dailykerchunks;
02004          totalkerchunks = myrpt->totalkerchunks;
02005          dailyexecdcommands = myrpt->dailyexecdcommands;
02006          totalexecdcommands = myrpt->totalexecdcommands;
02007          timeouts = myrpt->timeouts;
02008 
02009          /* Traverse the list of connected nodes */
02010          reverse_patch_state = "DOWN";
02011          j = 0;
02012          l = myrpt->links.next;
02013          while(l && (l != &myrpt->links)){
02014             if (l->name[0] == '0'){ /* Skip '0' nodes */
02015                reverse_patch_state = "UP";
02016                l = l->next;
02017                continue;
02018             }
02019             listoflinks[j] = ast_strdupa(l->name);
02020             if(listoflinks[j])
02021                j++;
02022             l = l->next;
02023          }
02024 
02025          lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);       
02026          if((!lastnodewhichkeyedusup) || (!strlen(lastnodewhichkeyedusup)))
02027             lastnodewhichkeyedusup = not_applicable;
02028 
02029          if(myrpt->keyed)
02030             input_signal = "YES";
02031          else
02032             input_signal = "NO";
02033 
02034          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
02035             sys_ena = "DISABLED";
02036          else
02037             sys_ena = "ENABLED";
02038 
02039          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
02040             tot_ena = "DISABLED";
02041          else
02042             tot_ena = "ENABLED";
02043 
02044          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
02045             link_ena = "DISABLED";
02046          else
02047             link_ena = "ENABLED";
02048 
02049          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
02050             patch_ena = "DISABLED";
02051          else
02052             patch_ena = "ENABLED";
02053 
02054          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
02055             sch_ena = "DISABLED";
02056          else
02057             sch_ena = "ENABLED";
02058 
02059          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
02060             user_funs = "DISABLED";
02061          else
02062             user_funs = "ENABLED";
02063 
02064          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
02065             tail_type = "ALTERNATE";
02066          else
02067             tail_type = "STANDARD";
02068 
02069          if(!myrpt->totimer)
02070             tot_state = "TIMED OUT!";
02071          else if(myrpt->totimer != myrpt->p.totime)
02072             tot_state = "ARMED";
02073          else
02074             tot_state = "RESET";
02075 
02076          if(myrpt->tailid)
02077             ider_state = "QUEUED IN TAIL";
02078          else if(myrpt->mustid)
02079             ider_state = "QUEUED FOR CLEANUP";
02080          else
02081             ider_state = "CLEAN";
02082 
02083          switch(myrpt->callmode){
02084             case 1:
02085                patch_state = "DIALING";
02086                break;
02087             case 2:
02088                patch_state = "CONNECTING";
02089                break;
02090             case 3:
02091                patch_state = "UP";
02092                break;
02093 
02094             case 4:
02095                patch_state = "CALL FAILED";
02096                break;
02097 
02098             default:
02099                patch_state = "DOWN";
02100          }
02101 
02102          if(strlen(myrpt->exten)){
02103             called_number = ast_strdupa(myrpt->exten);
02104             if(!called_number)
02105                called_number = not_applicable;
02106          }
02107 
02108          if(strlen(myrpt->lastdtmfcommand)){
02109             lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
02110             if(!lastdtmfcommand)
02111                lastdtmfcommand = not_applicable;
02112          }
02113 
02114          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02115 
02116          ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
02117          ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
02118          ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
02119          ast_cli(fd, "System...........................................: %s\n", sys_ena);
02120          ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
02121          ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
02122          ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
02123          ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
02124          ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
02125          ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
02126          ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
02127          ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
02128          ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
02129          ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
02130          ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
02131          ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
02132          ast_cli(fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
02133          hours = dailytxtime/3600000;
02134          dailytxtime %= 3600000;
02135          minutes = dailytxtime/60000;
02136          dailytxtime %= 60000;
02137          seconds = dailytxtime/1000;
02138          dailytxtime %= 1000;
02139 
02140          ast_cli(fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
02141             hours, minutes, seconds, dailytxtime);
02142 
02143          hours = (int) totaltxtime/3600000;
02144          totaltxtime %= 3600000;
02145          minutes = (int) totaltxtime/60000;
02146          totaltxtime %= 60000;
02147          seconds = (int)  totaltxtime/1000;
02148          totaltxtime %= 1000;
02149 
02150          ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
02151              hours, minutes, seconds, (int) totaltxtime);
02152          ast_cli(fd, "Nodes currently connected to us..................: ");
02153          for(j = 0 ;; j++){
02154             if(!listoflinks[j]){
02155                if(!j){
02156                   ast_cli(fd,"<NONE>");
02157                }
02158                break;
02159             }
02160             ast_cli(fd, "%s", listoflinks[j]);
02161             if(j % 4 == 3){
02162                ast_cli(fd, "\n");
02163                ast_cli(fd, "                                                 : ");
02164             }
02165             else{
02166                if(listoflinks[j + 1])
02167                   ast_cli(fd, ", ");
02168             }
02169          }
02170          ast_cli(fd,"\n");
02171 
02172          ast_cli(fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
02173          ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
02174          ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
02175          ast_cli(fd, "Autopatch called number..........................: %s\n", called_number);
02176          ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
02177          ast_cli(fd, "User linking commands............................: %s\n", link_ena);
02178          ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
02179               return RESULT_SUCCESS;
02180       }
02181    }
02182    return RESULT_FAILURE;
02183 }
02184 
02185 /*
02186 * Link stats function
02187 */
02188 
02189 static int rpt_do_lstats(int fd, int argc, char *argv[])
02190 {
02191    int i,j;
02192    char *connstate;
02193    struct rpt *myrpt;
02194    struct rpt_link *l;
02195    struct rpt_lstat *s,*t;
02196    struct rpt_lstat s_head;
02197    if(argc != 3)
02198       return RESULT_SHOWUSAGE;
02199 
02200    s = NULL;
02201    s_head.next = &s_head;
02202    s_head.prev = &s_head;
02203 
02204    for(i = 0; i < nrpts; i++)
02205    {
02206       if (!strcmp(argv[2],rpt_vars[i].name)){
02207          /* Make a copy of all stat variables while locked */
02208          myrpt = &rpt_vars[i];
02209          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02210          /* Traverse the list of connected nodes */
02211          j = 0;
02212          l = myrpt->links.next;
02213          while(l && (l != &myrpt->links)){
02214             if (l->name[0] == '0'){ /* Skip '0' nodes */
02215                l = l->next;
02216                continue;
02217             }
02218             if((s = (struct rpt_lstat *) malloc(sizeof(struct rpt_lstat))) == NULL){
02219                ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
02220                rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02221                return RESULT_FAILURE;
02222             }
02223             memset(s, 0, sizeof(struct rpt_lstat));
02224             strncpy(s->name, l->name, MAXREMSTR - 1);
02225             if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
02226             else strcpy(s->peer,"(none)");
02227             s->mode = l->mode;
02228             s->outbound = l->outbound;
02229             s->reconnects = l->reconnects;
02230             s->connecttime = l->connecttime;
02231             s->thisconnected = l->thisconnected;
02232             memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
02233             insque((struct qelem *) s, (struct qelem *) s_head.next);
02234             memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
02235             l = l->next;
02236          }
02237          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02238          ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME        CONNECT STATE\n");
02239          ast_cli(fd, "----      ----                ----------  ---------  ------------        -------------\n");
02240 
02241          for(s = s_head.next; s != &s_head; s = s->next){
02242             int hours, minutes, seconds;
02243             long long connecttime = s->connecttime;
02244             char conntime[21];
02245             hours = (int) connecttime/3600000;
02246             connecttime %= 3600000;
02247             minutes = (int) connecttime/60000;
02248             connecttime %= 60000;
02249             seconds = (int)  connecttime/1000;
02250             connecttime %= 1000;
02251             snprintf(conntime, 20, "%02d:%02d:%02d.%d",
02252                hours, minutes, seconds, (int) connecttime);
02253             conntime[20] = 0;
02254             if(s->thisconnected)
02255                connstate  = "ESTABLISHED";
02256             else
02257                connstate = "CONNECTING";
02258             ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
02259                s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
02260          }  
02261          /* destroy our local link queue */
02262          s = s_head.next;
02263          while(s != &s_head){
02264             t = s;
02265             s = s->next;
02266             remque((struct qelem *)t);
02267             free(t);
02268          }        
02269          return RESULT_SUCCESS;
02270       }
02271    }
02272    return RESULT_FAILURE;
02273 }
02274 
02275 /*
02276 * List all nodes connected, directly or indirectly
02277 */
02278 
02279 static int rpt_do_nodes(int fd, int argc, char *argv[])
02280 {
02281    int i,j;
02282    char ns;
02283    char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
02284    struct rpt *myrpt;
02285    if(argc != 3)
02286       return RESULT_SHOWUSAGE;
02287 
02288    for(i = 0; i < nrpts; i++)
02289    {
02290       if (!strcmp(argv[2],rpt_vars[i].name)){
02291          /* Make a copy of all stat variables while locked */
02292          myrpt = &rpt_vars[i];
02293          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02294          __mklinklist(myrpt,NULL,lbuf);
02295          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02296          /* parse em */
02297          ns = finddelim(lbuf,strs,MAXLINKLIST);
02298          /* sort em */
02299          if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
02300          ast_cli(fd,"\n");
02301          ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
02302          for(j = 0 ;; j++){
02303             if(!strs[j]){
02304                if(!j){
02305                   ast_cli(fd,"<NONE>");
02306                }
02307                break;
02308             }
02309             ast_cli(fd, "%s", strs[j]);
02310             if(j % 8 == 7){
02311                ast_cli(fd, "\n");
02312             }
02313             else{
02314                if(strs[j + 1])
02315                   ast_cli(fd, ", ");
02316             }
02317          }
02318          ast_cli(fd,"\n\n");
02319          return RESULT_SUCCESS;
02320       }
02321    }
02322    return RESULT_FAILURE;
02323 }
02324 
02325 /*
02326 * reload vars 
02327 */
02328 
02329 static int rpt_do_reload(int fd, int argc, char *argv[])
02330 {
02331 int   n;
02332 
02333         if (argc > 2) return RESULT_SHOWUSAGE;
02334 
02335    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
02336 
02337    return RESULT_FAILURE;
02338 }
02339 
02340 /*
02341 * restart app_rpt
02342 */
02343                                                                                                                                  
02344 static int rpt_do_restart(int fd, int argc, char *argv[])
02345 {
02346 int   i;
02347 
02348         if (argc > 2) return RESULT_SHOWUSAGE;
02349    for(i = 0; i < nrpts; i++)
02350    {
02351       if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
02352    }
02353    return RESULT_FAILURE;
02354 }
02355 
02356 
02357 /*
02358 * send an app_rpt DTMF function from the CLI
02359 */
02360                                                                                                                                  
02361 static int rpt_do_fun(int fd, int argc, char *argv[])
02362 {
02363    int   i,busy=0;
02364 
02365         if (argc != 4) return RESULT_SHOWUSAGE;
02366 
02367    for(i = 0; i < nrpts; i++){
02368       if(!strcmp(argv[2], rpt_vars[i].name)){
02369          struct rpt *myrpt = &rpt_vars[i];
02370          rpt_mutex_lock(&myrpt->lock);
02371          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
02372             rpt_mutex_unlock(&myrpt->lock);
02373             busy=1;
02374          }
02375          if(!busy){
02376             myrpt->macrotimer = MACROTIME;
02377             strncat(myrpt->macrobuf,argv[3],MAXMACRO - 1);
02378          }
02379          rpt_mutex_unlock(&myrpt->lock);
02380       }
02381    }
02382    if(busy){
02383       ast_cli(fd, "Function decoder busy");
02384    }
02385    return RESULT_FAILURE;
02386 }
02387 
02388 
02389 
02390 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
02391 {
02392    int res;
02393 
02394         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
02395                 return res;
02396                                                                                                                                             
02397         while(chan->generatordata) {
02398       if (ast_safe_sleep(chan,1)) return -1;
02399    }
02400 
02401         return 0;
02402 }
02403 
02404 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
02405 {
02406    return play_tone_pair(chan, freq, 0, duration, amplitude);
02407 }
02408 
02409 static int play_silence(struct ast_channel *chan, int duration)
02410 {
02411    return play_tone_pair(chan, 0, 0, duration, 0);
02412 }
02413 
02414 
02415 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
02416 {
02417 
02418 static struct morse_bits mbits[] = {
02419       {0, 0}, /* SPACE */
02420       {0, 0}, 
02421       {6, 18},/* " */
02422       {0, 0},
02423       {7, 72},/* $ */
02424       {0, 0},
02425       {0, 0},
02426       {6, 30},/* ' */
02427       {5, 13},/* ( */
02428       {6, 29},/* ) */
02429       {0, 0},
02430       {5, 10},/* + */
02431       {6, 51},/* , */
02432       {6, 33},/* - */
02433       {6, 42},/* . */
02434       {5, 9}, /* / */
02435       {5, 31},/* 0 */
02436       {5, 30},/* 1 */
02437       {5, 28},/* 2 */
02438       {5, 24},/* 3 */
02439       {5, 16},/* 4 */
02440       {5, 0}, /* 5 */
02441       {5, 1}, /* 6 */
02442       {5, 3}, /* 7 */
02443       {5, 7}, /* 8 */
02444       {5, 15},/* 9 */
02445       {6, 7}, /* : */
02446       {6, 21},/* ; */
02447       {0, 0},
02448       {5, 33},/* = */
02449       {0, 0},
02450       {6, 12},/* ? */
02451       {0, 0},
02452          {2, 2}, /* A */
02453       {4, 1}, /* B */
02454       {4, 5}, /* C */
02455       {3, 1}, /* D */
02456       {1, 0}, /* E */
02457       {4, 4}, /* F */
02458       {3, 3}, /* G */
02459       {4, 0}, /* H */
02460       {2, 0}, /* I */
02461       {4, 14},/* J */
02462       {3, 5}, /* K */
02463       {4, 2}, /* L */
02464       {2, 3}, /* M */
02465       {2, 1}, /* N */
02466       {3, 7}, /* O */
02467       {4, 6}, /* P */
02468       {4, 11},/* Q */
02469       {3, 2}, /* R */
02470       {3, 0}, /* S */
02471       {1, 1}, /* T */
02472       {3, 4}, /* U */
02473       {4, 8}, /* V */
02474       {3, 6}, /* W */
02475       {4, 9}, /* X */
02476       {4, 13},/* Y */
02477       {4, 3}  /* Z */
02478    };
02479 
02480 
02481    int dottime;
02482    int dashtime;
02483    int intralettertime;
02484    int interlettertime;
02485    int interwordtime;
02486    int len, ddcomb;
02487    int res;
02488    int c;
02489    int i;
02490    int flags;
02491          
02492    res = 0;
02493    
02494    /* Approximate the dot time from the speed arg. */
02495    
02496    dottime = 900/speed;
02497    
02498    /* Establish timing releationships */
02499    
02500    dashtime = 3 * dottime;
02501    intralettertime = dottime;
02502    interlettertime = dottime * 4 ;
02503    interwordtime = dottime * 7;
02504    
02505    for(;(*string) && (!res); string++){
02506    
02507       c = *string;
02508       
02509       /* Convert lower case to upper case */
02510       
02511       if((c >= 'a') && (c <= 'z'))
02512          c -= 0x20;
02513       
02514       /* Can't deal with any char code greater than Z, skip it */
02515       
02516       if(c  > 'Z')
02517          continue;
02518       
02519       /* If space char, wait the inter word time */
02520                
02521       if(c == ' '){
02522          if(!res)
02523             res = play_silence(chan, interwordtime);
02524          continue;
02525       }
02526       
02527       /* Subtract out control char offset to match our table */
02528       
02529       c -= 0x20;
02530       
02531       /* Get the character data */
02532       
02533       len = mbits[c].len;
02534       ddcomb = mbits[c].ddcomb;
02535       
02536       /* Send the character */
02537       
02538       for(; len ; len--){
02539          if(!res)
02540             res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
02541          if(!res)
02542             res = play_silence(chan, intralettertime);
02543          ddcomb >>= 1;
02544       }
02545       
02546       /* Wait the interletter time */
02547       
02548       if(!res)
02549          res = play_silence(chan, interlettertime - intralettertime);
02550    }
02551    
02552    /* Wait for all the frames to be sent */
02553    
02554    if (!res) 
02555       res = ast_waitstream(chan, "");
02556    ast_stopstream(chan);
02557    
02558    /*
02559    * Wait for the zaptel driver to physically write the tone blocks to the hardware
02560    */
02561 
02562    for(i = 0; i < 20 ; i++){
02563       flags =  ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT; 
02564       res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
02565       if(flags & ZT_IOMUX_WRITEEMPTY)
02566          break;
02567       if( ast_safe_sleep(chan, 50)){
02568          res = -1;
02569          break;
02570       }
02571    }
02572 
02573    
02574    return res;
02575 }
02576 
02577 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
02578 {
02579    char *stringp;
02580    char *tonesubset;
02581    int f1,f2;
02582    int duration;
02583    int amplitude;
02584    int res;
02585    int i;
02586    int flags;
02587    
02588    res = 0;
02589    
02590    stringp = ast_strdupa(tonestring);
02591 
02592    for(;tonestring;){
02593       tonesubset = strsep(&stringp,")");
02594       if(!tonesubset)
02595          break;
02596       if(sscanf(tonesubset,"(%d,%d,%d,%d", &f1, &f2, &duration, &amplitude) != 4)
02597          break;
02598       res = play_tone_pair(chan, f1, f2, duration, amplitude);
02599       if(res)
02600          break;
02601    }
02602    if(!res)
02603       res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
02604    
02605    if (!res) 
02606       res = ast_waitstream(chan, "");
02607    ast_stopstream(chan);
02608 
02609    /*
02610    * Wait for the zaptel driver to physically write the tone blocks to the hardware
02611    */
02612 
02613    for(i = 0; i < 20 ; i++){
02614       flags =  ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT; 
02615       res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
02616       if(flags & ZT_IOMUX_WRITEEMPTY)
02617          break;
02618       if( ast_safe_sleep(chan, 50)){
02619          res = -1;
02620          break;
02621       }
02622    }
02623       
02624    return res;
02625       
02626 }
02627 
02628 static int sayfile(struct ast_channel *mychannel,char *fname)
02629 {
02630 int   res;
02631 
02632    res = ast_streamfile(mychannel, fname, mychannel->language);
02633    if (!res) 
02634       res = ast_waitstream(mychannel, "");
02635    else
02636        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02637    ast_stopstream(mychannel);
02638    return res;
02639 }
02640 
02641 static int saycharstr(struct ast_channel *mychannel,char *str)
02642 {
02643 int   res;
02644 
02645    res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
02646    if (!res) 
02647       res = ast_waitstream(mychannel, "");
02648    else
02649        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02650    ast_stopstream(mychannel);
02651    return res;
02652 }
02653 
02654 static int saynum(struct ast_channel *mychannel, int num)
02655 {
02656    int res;
02657    res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
02658    if(!res)
02659       res = ast_waitstream(mychannel, "");
02660    else
02661       ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02662    ast_stopstream(mychannel);
02663    return res;
02664 }
02665 
02666 
02667 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
02668 {
02669    int res;
02670    char c;
02671    
02672    static int morsespeed;
02673    static int morsefreq;
02674    static int morseampl;
02675    static int morseidfreq = 0;
02676    static int morseidampl;
02677    static char mcat[] = MORSE;
02678    
02679    res = 0;
02680    
02681    if(!morseidfreq){ /* Get the morse parameters if not already loaded */
02682       morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
02683          morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
02684          morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
02685       morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
02686       morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330); 
02687    }
02688    
02689    /* Is it a file, or a tone sequence? */
02690          
02691    if(entry[0] == '|'){
02692       c = entry[1];
02693       if((c >= 'a')&&(c <= 'z'))
02694          c -= 0x20;
02695    
02696       switch(c){
02697          case 'I': /* Morse ID */
02698             res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
02699             break;
02700          
02701          case 'M': /* Morse Message */
02702             res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
02703             break;
02704          
02705          case 'T': /* Tone sequence */
02706             res = send_tone_telemetry(chan, entry + 2);
02707             break;
02708          default:
02709             res = -1;
02710       }
02711    }
02712    else
02713       res = sayfile(chan, entry); /* File */
02714    return res;
02715 }
02716 
02717 /*
02718 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
02719 *
02720 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
02721 */
02722 
02723 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
02724 {
02725    
02726    int res;
02727    int i;
02728    char *entry;
02729    char *telemetry;
02730    char *telemetry_save;
02731 
02732    res = 0;
02733    telemetry_save = NULL;
02734    entry = NULL;
02735    
02736    /* Retrieve the section name for telemetry from the node section */
02737    telemetry = (char *) ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
02738    if(telemetry ){
02739       telemetry_save = ast_strdupa(telemetry);
02740       if(!telemetry_save){
02741          ast_log(LOG_WARNING,"ast_strdupa() failed in telem_lookup()\n");
02742          return res;
02743       }
02744       entry = (char *) ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
02745    }
02746    
02747    /* Try to look up the telemetry name */   
02748 
02749    if(!entry){
02750       /* Telemetry name wasn't found in the config file, use the default */
02751       for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
02752          if(!strcasecmp(tele_defs[i].name, name))
02753             entry = tele_defs[i].value;
02754       }
02755    }
02756    if(entry){  
02757       if(strlen(entry))
02758          telem_any(myrpt,chan, entry);
02759    }
02760    else{
02761       res = -1;
02762    }
02763    return res;
02764 }
02765 
02766 /*
02767 * Retrieve a wait interval
02768 */
02769 
02770 static int get_wait_interval(struct rpt *myrpt, int type)
02771 {
02772         int interval;
02773         char *wait_times;
02774         char *wait_times_save;
02775                                                                                                                   
02776         wait_times_save = NULL;
02777         wait_times = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
02778                                                                                                                   
02779         if(wait_times){
02780                 wait_times_save = ast_strdupa(wait_times);
02781                 if(!wait_times_save){
02782                         ast_log(LOG_WARNING, "Out of memory in wait_interval()\n");
02783                         wait_times = NULL;
02784                 }
02785         }
02786                                                                                                                   
02787         switch(type){
02788                 case DLY_TELEM:
02789                         if(wait_times)
02790                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
02791                         else
02792                                 interval = 1000;
02793                         break;
02794                                                                                                                   
02795                 case DLY_ID:
02796                         if(wait_times)
02797                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
02798                         else
02799                                 interval = 500;
02800                         break;
02801                                                                                                                   
02802                 case DLY_UNKEY:
02803                         if(wait_times)
02804                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",500,5000,1000);
02805                         else
02806                                 interval = 1000;
02807                         break;
02808                                                                                                                   
02809                 case DLY_LINKUNKEY:
02810                         if(wait_times)
02811                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "linkunkeywait",500,5000,1000);
02812                         else
02813                                 interval = 1000;
02814                         break;
02815                                                                                                                   
02816                 case DLY_CALLTERM:
02817                         if(wait_times)
02818                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
02819                         else
02820                                 interval = 1500;
02821                         break;
02822                                                                                                                   
02823                 case DLY_COMP:
02824                         if(wait_times)
02825                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "compwait",500,5000,200);
02826                         else
02827                                 interval = 200;
02828                         break;
02829                                                                                                                   
02830                 default:
02831                         return 0;
02832         }
02833    return interval;
02834 }                                                                                                                  
02835 
02836 
02837 /*
02838 * Wait a configurable interval of time 
02839 */
02840 
02841 
02842 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
02843 {
02844    int interval;
02845    interval = get_wait_interval(myrpt, type);
02846    if(debug)
02847       ast_log(LOG_NOTICE," Delay interval = %d\n", interval);
02848    if(interval)
02849       ast_safe_sleep(chan,interval);
02850    if(debug)
02851       ast_log(LOG_NOTICE,"Delay complete\n");
02852    return;
02853 }
02854 
02855 static int split_freq(char *mhz, char *decimals, char *freq);
02856 
02857 static void *rpt_tele_thread(void *this)
02858 {
02859 ZT_CONFINFO ci;  /* conference info */
02860 int   res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
02861 struct   rpt_tele *mytele = (struct rpt_tele *)this;
02862 struct  rpt_tele *tlist;
02863 struct   rpt *myrpt;
02864 struct   rpt_link *l,*l1,linkbase;
02865 struct   ast_channel *mychannel;
02866 int vmajor, vminor, m;
02867 char *p,*ct,*ct_copy,*ident, *nodename,*cp;
02868 time_t t;
02869 struct tm localtm;
02870 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
02871 int   i,ns,rbimode;
02872 char mhz[MAXREMSTR];
02873 char decimals[MAXREMSTR];
02874 struct zt_params par;
02875 
02876 
02877    /* get a pointer to myrpt */
02878    myrpt = mytele->rpt;
02879 
02880    /* Snag copies of a few key myrpt variables */
02881    rpt_mutex_lock(&myrpt->lock);
02882    nodename = ast_strdupa(myrpt->name);
02883    if (myrpt->p.ident) ident = ast_strdupa(myrpt->p.ident);
02884    else ident = "";
02885    rpt_mutex_unlock(&myrpt->lock);
02886    
02887    /* allocate a pseudo-channel thru asterisk */
02888    mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
02889    if (!mychannel)
02890    {
02891       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
02892       rpt_mutex_lock(&myrpt->lock);
02893       remque((struct qelem *)mytele);
02894       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
02895       rpt_mutex_unlock(&myrpt->lock);
02896       free(mytele);     
02897       pthread_exit(NULL);
02898    }
02899    rpt_mutex_lock(&myrpt->lock);
02900    mytele->chan = mychannel;
02901    rpt_mutex_unlock(&myrpt->lock);
02902    /* make a conference for the tx */
02903    ci.chan = 0;
02904    /* If there's an ID queued, or tail message queued, */
02905    /* only connect the ID audio to the local tx conference so */
02906    /* linked systems can't hear it */
02907    ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
02908       (mytele->mode == TAILMSG) || (mytele->mode == LINKUNKEY)) || (mytele->mode == TIMEOUT) ?
02909          myrpt->txconf : myrpt->conf);
02910    ci.confmode = ZT_CONF_CONFANN;
02911    /* first put the channel on the conference in announce mode */
02912    if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
02913    {
02914       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02915       rpt_mutex_lock(&myrpt->lock);
02916       remque((struct qelem *)mytele);
02917       rpt_mutex_unlock(&myrpt->lock);
02918       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
02919       free(mytele);     
02920       ast_hangup(mychannel);
02921       pthread_exit(NULL);
02922    }
02923    ast_stopstream(mychannel);
02924    switch(mytele->mode)
02925    {
02926        case ID:
02927        case ID1:
02928       /* wait a bit */
02929       wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
02930       res = telem_any(myrpt,mychannel, ident); 
02931       imdone=1;   
02932       break;
02933       
02934        case TAILMSG:
02935       res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language); 
02936       break;
02937       
02938        case IDTALKOVER:
02939          p = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
02940          if(p)
02941          res = telem_any(myrpt,mychannel, p); 
02942       imdone=1;   
02943          break;
02944             
02945        case PROC:
02946       /* wait a little bit longer */
02947       wait_interval(myrpt, DLY_TELEM, mychannel);
02948       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
02949       if(res < 0){ /* Then default message */
02950          res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
02951       }
02952       break;
02953        case TERM:
02954       /* wait a little bit longer */
02955       wait_interval(myrpt, DLY_CALLTERM, mychannel);
02956       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
02957       if(res < 0){ /* Then default message */
02958          res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
02959       }
02960       break;
02961        case COMPLETE:
02962       /* wait a little bit */
02963       wait_interval(myrpt, DLY_TELEM, mychannel);
02964       res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
02965       break;
02966        case MACRO_NOTFOUND:
02967       /* wait a little bit */
02968       wait_interval(myrpt, DLY_TELEM, mychannel);
02969       res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
02970       break;
02971        case MACRO_BUSY:
02972       /* wait a little bit */
02973       wait_interval(myrpt, DLY_TELEM, mychannel);
02974       res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
02975       break;
02976        case UNKEY:
02977       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
02978          imdone = 1;
02979          break;
02980       }
02981          
02982       /*
02983       * Reset the Unkey to CT timer
02984       */
02985 
02986       x = get_wait_interval(myrpt, DLY_UNKEY);
02987       rpt_mutex_lock(&myrpt->lock);
02988       myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
02989       rpt_mutex_unlock(&myrpt->lock);
02990 
02991       /*
02992       * If there's one already queued, don't do another
02993       */
02994 
02995       tlist = myrpt->tele.next;
02996       unkeys_queued = 0;
02997                 if (tlist != &myrpt->tele)
02998                 {
02999                         rpt_mutex_lock(&myrpt->lock);
03000                         while(tlist != &myrpt->tele){
03001                                 if (tlist->mode == UNKEY) unkeys_queued++;
03002                                 tlist = tlist->next;
03003                         }
03004                         rpt_mutex_unlock(&myrpt->lock);
03005       }
03006       if( unkeys_queued > 1){
03007          imdone = 1;
03008          break;
03009       }
03010 
03011       /* Wait for the telemetry timer to expire */
03012       /* Periodically check the timer since it can be re-initialized above */
03013       while(myrpt->unkeytocttimer)
03014       {
03015          int ctint;
03016          if(myrpt->unkeytocttimer > 100)
03017             ctint = 100;
03018          else
03019             ctint = myrpt->unkeytocttimer;
03020          ast_safe_sleep(mychannel, ctint);
03021          rpt_mutex_lock(&myrpt->lock);
03022          if(myrpt->unkeytocttimer < ctint)
03023             myrpt->unkeytocttimer = 0;
03024          else
03025             myrpt->unkeytocttimer -= ctint;
03026          rpt_mutex_unlock(&myrpt->lock);
03027       }
03028    
03029       /*
03030       * Now, the carrier on the rptr rx should be gone. 
03031       * If it re-appeared, then forget about sending the CT
03032       */
03033       if(myrpt->keyed){
03034          imdone = 1;
03035          break;
03036       }
03037       
03038       rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
03039       myrpt->dailykerchunks++;
03040       myrpt->totalkerchunks++;
03041       rpt_mutex_unlock(&myrpt->lock);
03042    
03043       haslink = 0;
03044       hastx = 0;
03045       hasremote = 0;    
03046       l = myrpt->links.next;
03047       if (l != &myrpt->links)
03048       {
03049          rpt_mutex_lock(&myrpt->lock);
03050          while(l != &myrpt->links)
03051          {
03052             if (l->name[0] == '0')
03053             {
03054                l = l->next;
03055                continue;
03056             }
03057             haslink = 1;
03058             if (l->mode) {
03059                hastx++;
03060                if (l->isremote) hasremote++;
03061             }
03062             l = l->next;
03063          }
03064          rpt_mutex_unlock(&myrpt->lock);
03065       }
03066       if (haslink)
03067       {
03068 
03069          res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
03070          if(res)
03071             ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
03072          
03073       
03074          /* if in remote cmd mode, indicate it */
03075          if (myrpt->cmdnode[0])
03076          {
03077             ast_safe_sleep(mychannel,200);
03078             res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
03079             if(res)
03080                ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
03081             ast_stopstream(mychannel);
03082          }
03083       }
03084       else if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
03085          ct_copy = ast_strdupa(ct);
03086          res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
03087          if(res)
03088             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
03089       }  
03090       if (hasremote && (!myrpt->cmdnode[0]))
03091       {
03092          /* set for all to hear */
03093          ci.chan = 0;
03094          ci.confno = myrpt->conf;
03095          ci.confmode = ZT_CONF_CONFANN;
03096          /* first put the channel on the conference in announce mode */
03097          if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
03098          {
03099             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
03100             rpt_mutex_lock(&myrpt->lock);
03101             remque((struct qelem *)mytele);
03102             rpt_mutex_unlock(&myrpt->lock);
03103             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03104             free(mytele);     
03105             ast_hangup(mychannel);
03106             pthread_exit(NULL);
03107          }
03108          if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
03109             ast_safe_sleep(mychannel,200);
03110             ct_copy = ast_strdupa(ct);
03111             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
03112             if(res)
03113                ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
03114          }  
03115       }
03116 #ifdef   _MDC_DECODE_H_
03117       if (myrpt->lastunit)
03118       {
03119          char mystr[10];
03120 
03121          ast_safe_sleep(mychannel,200);
03122          /* set for all to hear */
03123          ci.chan = 0;
03124          ci.confno = myrpt->txconf;
03125          ci.confmode = ZT_CONF_CONFANN;
03126          /* first put the channel on the conference in announce mode */
03127          if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
03128          {
03129             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
03130             rpt_mutex_lock(&myrpt->lock);
03131             remque((struct qelem *)mytele);
03132             rpt_mutex_unlock(&myrpt->lock);
03133             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03134             free(mytele);     
03135             ast_hangup(mychannel);
03136             pthread_exit(NULL);
03137          }
03138          sprintf(mystr,"%04x",myrpt->lastunit);
03139          myrpt->lastunit = 0;
03140          ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
03141          break;
03142       }
03143 #endif
03144       imdone = 1;
03145       break;
03146        case LINKUNKEY:
03147       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
03148          imdone = 1;
03149          break;
03150       }
03151          
03152       /*
03153       * Reset the Unkey to CT timer
03154       */
03155 
03156       x = get_wait_interval(myrpt, DLY_LINKUNKEY);
03157       mytele->mylink.linkunkeytocttimer = x; /* Must be protected as it is changed below */
03158 
03159       /*
03160       * If there's one already queued, don't do another
03161       */
03162 
03163       tlist = myrpt->tele.next;
03164       unkeys_queued = 0;
03165                 if (tlist != &myrpt->tele)
03166                 {
03167                         rpt_mutex_lock(&myrpt->lock);
03168                         while(tlist != &myrpt->tele){
03169                                 if (tlist->mode == LINKUNKEY) unkeys_queued++;
03170                                 tlist = tlist->next;
03171                         }
03172                         rpt_mutex_unlock(&myrpt->lock);
03173       }
03174       if( unkeys_queued > 1){
03175          imdone = 1;
03176          break;
03177       }
03178 
03179       /* Wait for the telemetry timer to expire */
03180       /* Periodically check the timer since it can be re-initialized above */
03181       while(mytele->mylink.linkunkeytocttimer)
03182       {
03183          int ctint;
03184          if(mytele->mylink.linkunkeytocttimer > 100)
03185             ctint = 100;
03186          else
03187             ctint = mytele->mylink.linkunkeytocttimer;
03188          ast_safe_sleep(mychannel, ctint);
03189          rpt_mutex_lock(&myrpt->lock);
03190          if(mytele->mylink.linkunkeytocttimer < ctint)
03191             mytele->mylink.linkunkeytocttimer = 0;
03192          else
03193             mytele->mylink.linkunkeytocttimer -= ctint;
03194          rpt_mutex_unlock(&myrpt->lock);
03195       }
03196    
03197       if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "linkunkeyct"))){ /* Unlinked Courtesy Tone */
03198          ct_copy = ast_strdupa(ct);
03199          res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
03200          if(res)
03201             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
03202       }  
03203       imdone = 1;
03204       break;
03205        case REMDISC:
03206       /* wait a little bit */
03207       wait_interval(myrpt, DLY_TELEM, mychannel);
03208       l = myrpt->links.next;
03209       haslink = 0;
03210       /* dont report if a link for this one still on system */
03211       if (l != &myrpt->links)
03212       {
03213          rpt_mutex_lock(&myrpt->lock);
03214          while(l != &myrpt->links)
03215          {
03216             if (l->name[0] == '0')
03217             {
03218                l = l->next;
03219                continue;
03220             }
03221             if (!strcmp(l->name,mytele->mylink.name))
03222             {
03223                haslink = 1;
03224                break;
03225             }
03226             l = l->next;
03227          }
03228          rpt_mutex_unlock(&myrpt->lock);
03229       }
03230       if (haslink)
03231       {
03232          imdone = 1;
03233          break;
03234       }
03235       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03236       if (!res) 
03237          res = ast_waitstream(mychannel, "");
03238       else
03239           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03240       ast_stopstream(mychannel);
03241       ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
03242       res = ast_streamfile(mychannel, ((mytele->mylink.hasconnected) ? 
03243          "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
03244       break;
03245        case REMALREADY:
03246       /* wait a little bit */
03247       wait_interval(myrpt, DLY_TELEM, mychannel);
03248       res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
03249       break;
03250        case REMNOTFOUND:
03251       /* wait a little bit */
03252       wait_interval(myrpt, DLY_TELEM, mychannel);
03253       res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
03254       break;
03255        case REMGO:
03256       /* wait a little bit */
03257       wait_interval(myrpt, DLY_TELEM, mychannel);
03258       res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
03259       break;
03260        case CONNECTED:
03261       /* wait a little bit */
03262       wait_interval(myrpt, DLY_TELEM,  mychannel);
03263       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03264       if (!res) 
03265          res = ast_waitstream(mychannel, "");
03266       else
03267           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03268       ast_stopstream(mychannel);
03269       ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
03270       res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
03271       if (!res) 
03272          res = ast_waitstream(mychannel, "");
03273       else
03274           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03275       ast_stopstream(mychannel);
03276       res = ast_streamfile(mychannel, "digits/2", mychannel->language);
03277       if (!res) 
03278          res = ast_waitstream(mychannel, "");
03279       else
03280           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03281       ast_stopstream(mychannel);
03282       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03283       if (!res) 
03284          res = ast_waitstream(mychannel, "");
03285       else
03286           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03287       ast_stopstream(mychannel);
03288       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03289       imdone = 1;
03290       break;
03291        case CONNFAIL:
03292       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03293       if (!res) 
03294          res = ast_waitstream(mychannel, "");
03295       else
03296           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03297       ast_stopstream(mychannel);
03298       ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
03299       res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
03300       break;
03301        case MEMNOTFOUND:
03302       /* wait a little bit */
03303       wait_interval(myrpt, DLY_TELEM, mychannel);
03304       res = ast_streamfile(mychannel, "rpt/memory_notfound", mychannel->language);
03305       break;
03306        case SETREMOTE:
03307       ast_mutex_lock(&myrpt->remlock);
03308       res = 0;
03309       if(!strcmp(myrpt->remote, remote_rig_ft897))
03310       {
03311          res = set_ft897(myrpt);
03312       }
03313       if(!strcmp(myrpt->remote, remote_rig_ic706))
03314       {
03315          res = set_ic706(myrpt);
03316       }
03317       else if(!strcmp(myrpt->remote, remote_rig_rbi))
03318       {
03319          if (ioperm(myrpt->p.iobase,1,1) == -1)
03320          {
03321             rpt_mutex_unlock(&myrpt->lock);
03322             ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
03323             res = -1;
03324          }
03325          else res = setrbi(myrpt);
03326       }
03327       else if(!strcmp(myrpt->remote, remote_rig_kenwood))
03328       {
03329          res = setkenwood(myrpt);
03330          if (ast_safe_sleep(mychannel,200) == -1)
03331          {
03332             ast_mutex_unlock(&myrpt->remlock);
03333             res = -1;
03334             break;
03335          }
03336          i = ZT_FLUSH_EVENT;
03337          if (ioctl(myrpt->txchannel->fds[0],ZT_FLUSH,&i) == -1)
03338          {
03339             ast_mutex_unlock(&myrpt->remlock);
03340             ast_log(LOG_ERROR,"Cant flush events");
03341             res = -1;
03342             break;
03343          }
03344          if (ioctl(myrpt->rxchannel->fds[0],ZT_GET_PARAMS,&par) == -1)
03345          {
03346             ast_mutex_unlock(&myrpt->remlock);
03347             ast_log(LOG_ERROR,"Cant get params");
03348             res = -1;
03349             break;
03350          }
03351          myrpt->remoterx = 
03352             (par.rxisoffhook || (myrpt->tele.next != &myrpt->tele));
03353       }
03354       ast_mutex_unlock(&myrpt->remlock);
03355       if (!res)
03356       {
03357          imdone = 1;
03358          break;
03359       }
03360       /* fall thru to invalid freq */
03361        case INVFREQ:
03362       /* wait a little bit */
03363       wait_interval(myrpt, DLY_TELEM, mychannel);
03364       res = ast_streamfile(mychannel, "rpt/invalid-freq", mychannel->language);
03365       break;
03366        case REMMODE:
03367       cp = 0;
03368       wait_interval(myrpt, DLY_TELEM, mychannel);
03369       switch(myrpt->remmode)
03370       {
03371           case REM_MODE_FM:
03372          saycharstr(mychannel,"FM");
03373          break;
03374           case REM_MODE_USB:
03375          saycharstr(mychannel,"USB");
03376          break;
03377           case REM_MODE_LSB:
03378          saycharstr(mychannel,"LSB");
03379          break;
03380           case REM_MODE_AM:
03381          saycharstr(mychannel,"AM");
03382          break;
03383       }
03384       wait_interval(myrpt, DLY_COMP, mychannel);
03385       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03386       break;
03387        case LOGINREQ:
03388       wait_interval(myrpt, DLY_TELEM, mychannel);
03389       sayfile(mychannel,"rpt/login");
03390       saycharstr(mychannel,myrpt->name);
03391       break;
03392        case REMLOGIN:
03393       wait_interval(myrpt, DLY_TELEM, mychannel);
03394       saycharstr(mychannel,myrpt->loginuser);
03395       sayfile(mychannel,"rpt/node");
03396       saycharstr(mychannel,myrpt->name);
03397       wait_interval(myrpt, DLY_COMP, mychannel);
03398       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03399       break;
03400        case REMXXX:
03401       wait_interval(myrpt, DLY_TELEM, mychannel);
03402       res = 0;
03403       switch(mytele->submode)
03404       {
03405           case 100: /* RX PL Off */
03406          sayfile(mychannel, "rpt/rxpl");
03407          sayfile(mychannel, "rpt/off");
03408          break;
03409           case 101: /* RX PL On */
03410          sayfile(mychannel, "rpt/rxpl");
03411          sayfile(mychannel, "rpt/on");
03412          break;
03413           case 102: /* TX PL Off */
03414          sayfile(mychannel, "rpt/txpl");
03415          sayfile(mychannel, "rpt/off");
03416          break;
03417           case 103: /* TX PL On */
03418          sayfile(mychannel, "rpt/txpl");
03419          sayfile(mychannel, "rpt/on");
03420          break;
03421           case 104: /* Low Power */
03422          sayfile(mychannel, "rpt/lopwr");
03423          break;
03424           case 105: /* Medium Power */
03425          sayfile(mychannel, "rpt/medpwr");
03426          break;
03427           case 106: /* Hi Power */
03428          sayfile(mychannel, "rpt/hipwr");
03429          break;
03430           case 113: /* Scan down slow */
03431          sayfile(mychannel,"rpt/down");
03432          sayfile(mychannel, "rpt/slow");
03433          break;
03434           case 114: /* Scan down quick */
03435          sayfile(mychannel,"rpt/down");
03436          sayfile(mychannel, "rpt/quick");
03437          break;
03438           case 115: /* Scan down fast */
03439          sayfile(mychannel,"rpt/down");
03440          sayfile(mychannel, "rpt/fast");
03441          break;
03442           case 116: /* Scan up slow */
03443          sayfile(mychannel,"rpt/up");
03444          sayfile(mychannel, "rpt/slow");
03445          break;
03446           case 117: /* Scan up quick */
03447          sayfile(mychannel,"rpt/up");
03448          sayfile(mychannel, "rpt/quick");
03449          break;
03450           case 118: /* Scan up fast */
03451          sayfile(mychannel,"rpt/up");
03452          sayfile(mychannel, "rpt/fast");
03453          break;
03454           default:
03455          res = -1;
03456       }
03457       wait_interval(myrpt, DLY_COMP, mychannel);
03458       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03459       break;
03460        case SCAN:
03461       ast_mutex_lock(&myrpt->remlock);
03462       if (myrpt->hfscanstop)
03463       {
03464          myrpt->hfscanstatus = 0;
03465          myrpt->hfscanmode = 0;
03466          myrpt->hfscanstop = 0;
03467          mytele->mode = SCANSTAT;
03468          ast_mutex_unlock(&myrpt->remlock);
03469          if (ast_safe_sleep(mychannel,1000) == -1) break;
03470          sayfile(mychannel, "rpt/stop"); 
03471          imdone = 1;
03472          break;
03473       }
03474       if (myrpt->hfscanstatus > -2) service_scan(myrpt);
03475       i = myrpt->hfscanstatus;
03476       myrpt->hfscanstatus = 0;
03477       if (i) mytele->mode = SCANSTAT;
03478       ast_mutex_unlock(&myrpt->remlock);
03479       if (i < 0) sayfile(mychannel, "rpt/stop"); 
03480       else if (i > 0) saynum(mychannel,i);
03481       imdone = 1;
03482       break;
03483        case TUNE:
03484       ast_mutex_lock(&myrpt->remlock);
03485       if (!strcmp(myrpt->remote,remote_rig_ic706))
03486       {
03487          set_mode_ic706(myrpt, REM_MODE_AM);
03488          if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
03489          ast_safe_sleep(mychannel,500);
03490          set_mode_ic706(myrpt, myrpt->remmode);
03491          myrpt->tunerequest = 0;
03492          ast_mutex_unlock(&myrpt->remlock);
03493          imdone = 1;
03494          break;
03495       }
03496       set_mode_ft897(myrpt, REM_MODE_AM);
03497       simple_command_ft897(myrpt, 8);
03498       if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
03499       simple_command_ft897(myrpt, 0x88);
03500       ast_safe_sleep(mychannel,500);
03501       set_mode_ft897(myrpt, myrpt->remmode);
03502       myrpt->tunerequest = 0;
03503       ast_mutex_unlock(&myrpt->remlock);
03504       imdone = 1;
03505       break;
03506        case REMSHORTSTATUS:
03507        case REMLONGSTATUS: 
03508       wait_interval(myrpt, DLY_TELEM, mychannel);
03509       res = sayfile(mychannel,"rpt/node");
03510       if(!res)
03511          res = saycharstr(mychannel, myrpt->name);
03512       if(!res)
03513          res = sayfile(mychannel,"rpt/frequency");
03514       if(!res)
03515          res = split_freq(mhz, decimals, myrpt->freq);
03516       if (!multimode_capable(myrpt)) decimals[3] = 0;
03517       if(!res){
03518          m = atoi(mhz);
03519          if(m < 100)
03520             res = saynum(mychannel, m);
03521          else
03522             res = saycharstr(mychannel, mhz);
03523       }
03524       if(!res)
03525          res = sayfile(mychannel, "letters/dot");
03526       if(!res)
03527          res = saycharstr(mychannel, decimals);
03528    
03529       if(res)  break;
03530       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
03531          switch(myrpt->offset){
03532    
03533             case REM_MINUS:
03534                res = sayfile(mychannel,"rpt/minus");
03535                break;
03536             
03537             case REM_SIMPLEX:
03538                res = sayfile(mychannel,"rpt/simplex");
03539                break;
03540                
03541             case REM_PLUS:
03542                res = sayfile(mychannel,"rpt/plus");
03543                break;
03544                
03545             default:
03546                break;
03547          }
03548       }
03549       else{ /* Must be USB, LSB, or AM */
03550          switch(myrpt->remmode){
03551 
03552             case REM_MODE_USB:
03553                res = saycharstr(mychannel, "USB");
03554                break;
03555 
03556             case REM_MODE_LSB:
03557                res = saycharstr(mychannel, "LSB");
03558                break;
03559 
03560             case REM_MODE_AM:
03561                res = saycharstr(mychannel, "AM");
03562                break;
03563 
03564 
03565             default:
03566                break;
03567          }
03568       }
03569 
03570       if (res == -1) break;
03571 
03572       if(mytele->mode == REMSHORTSTATUS){ /* Short status? */
03573          wait_interval(myrpt, DLY_COMP, mychannel);
03574          if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03575          break;
03576       }
03577 
03578       if (strcmp(myrpt->remote,remote_rig_ic706))
03579       {
03580          switch(myrpt->powerlevel){
03581 
03582             case REM_LOWPWR:
03583                res = sayfile(mychannel,"rpt/lopwr") ;
03584                break;
03585             case REM_MEDPWR:
03586                res = sayfile(mychannel,"rpt/medpwr");
03587                break;
03588             case REM_HIPWR:
03589                res = sayfile(mychannel,"rpt/hipwr"); 
03590                break;
03591             }
03592       }
03593 
03594       rbimode = ((!strncmp(myrpt->remote,remote_rig_rbi,3))
03595         || (!strncmp(myrpt->remote,remote_rig_ic706,3)));
03596       if (res || (sayfile(mychannel,"rpt/rxpl") == -1)) break;
03597       if (rbimode && (sayfile(mychannel,"rpt/txpl") == -1)) break;
03598       if ((sayfile(mychannel,"rpt/frequency") == -1) ||
03599          (saycharstr(mychannel,myrpt->rxpl) == -1)) break;
03600       if ((!rbimode) && ((sayfile(mychannel,"rpt/txpl") == -1) ||
03601          (sayfile(mychannel,"rpt/frequency") == -1) ||
03602          (saycharstr(mychannel,myrpt->txpl) == -1))) break;
03603       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
03604          if ((sayfile(mychannel,"rpt/rxpl") == -1) ||
03605             (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1) ||
03606             (sayfile(mychannel,"rpt/txpl") == -1) ||
03607             (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1))
03608             {
03609                break;
03610             }
03611       }
03612       wait_interval(myrpt, DLY_COMP, mychannel);
03613       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03614       break;
03615        case STATUS:
03616       /* wait a little bit */
03617       wait_interval(myrpt, DLY_TELEM, mychannel);
03618       hastx = 0;
03619       linkbase.next = &linkbase;
03620       linkbase.prev = &linkbase;
03621       rpt_mutex_lock(&myrpt->lock);
03622       /* make our own list of links */
03623       l = myrpt->links.next;
03624       while(l != &myrpt->links)
03625       {
03626          if (l->name[0] == '0')
03627          {
03628             l = l->next;
03629             continue;
03630          }
03631          l1 = malloc(sizeof(struct rpt_link));
03632          if (!l1)
03633          {
03634             ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
03635             remque((struct qelem *)mytele);
03636             rpt_mutex_unlock(&myrpt->lock);
03637             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03638             free(mytele);     
03639             ast_hangup(mychannel);
03640             pthread_exit(NULL);
03641          }
03642          memcpy(l1,l,sizeof(struct rpt_link));
03643          l1->next = l1->prev = NULL;
03644          insque((struct qelem *)l1,(struct qelem *)linkbase.next);
03645          l = l->next;
03646       }
03647       rpt_mutex_unlock(&myrpt->lock);
03648       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03649       if (!res) 
03650          res = ast_waitstream(mychannel, "");
03651       else
03652           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03653       ast_stopstream(mychannel);
03654       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03655       if (!res) 
03656          res = ast_waitstream(mychannel, "");
03657       else
03658           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03659       ast_stopstream(mychannel);
03660       if (myrpt->callmode)
03661       {
03662          hastx = 1;
03663          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
03664          if (!res) 
03665             res = ast_waitstream(mychannel, "");
03666          else
03667              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03668          ast_stopstream(mychannel);
03669       }
03670       l = linkbase.next;
03671       while(l != &linkbase)
03672       {
03673          char *s;
03674 
03675          hastx = 1;
03676          res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03677          if (!res) 
03678             res = ast_waitstream(mychannel, "");
03679          else
03680             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03681          ast_stopstream(mychannel);
03682          ast_say_character_str(mychannel,l->name,NULL,mychannel->language);
03683          if (!res) 
03684             res = ast_waitstream(mychannel, "");
03685          else
03686              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03687          ast_stopstream(mychannel);
03688          s = "rpt/tranceive";
03689          if (!l->mode) s = "rpt/monitor";
03690          if (!l->thisconnected) s = "rpt/connecting";
03691          res = ast_streamfile(mychannel, s, mychannel->language);
03692          if (!res) 
03693             res = ast_waitstream(mychannel, "");
03694          else
03695             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03696          ast_stopstream(mychannel);
03697          l = l->next;
03698       }        
03699       if (!hastx)
03700       {
03701          res = ast_streamfile(mychannel, "rpt/repeat_only", 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       }
03708       /* destroy our local link queue */
03709       l = linkbase.next;
03710       while(l != &linkbase)
03711       {
03712          l1 = l;
03713          l = l->next;
03714          remque((struct qelem *)l1);
03715          free(l1);
03716       }        
03717       imdone = 1;
03718       break;
03719        case FULLSTATUS:
03720       rpt_mutex_lock(&myrpt->lock);
03721       /* get all the nodes */
03722       __mklinklist(myrpt,NULL,lbuf);
03723       rpt_mutex_unlock(&myrpt->lock);
03724       /* parse em */
03725       ns = finddelim(lbuf,strs,MAXLINKLIST);
03726       /* sort em */
03727       if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
03728       /* wait a little bit */
03729       wait_interval(myrpt, DLY_TELEM, mychannel);
03730       hastx = 0;
03731       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03732       if (!res) 
03733          res = ast_waitstream(mychannel, "");
03734       else
03735           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03736       ast_stopstream(mychannel);
03737       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03738       if (!res) 
03739          res = ast_waitstream(mychannel, "");
03740       else
03741           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03742       ast_stopstream(mychannel);
03743       if (myrpt->callmode)
03744       {
03745          hastx = 1;
03746          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
03747          if (!res) 
03748             res = ast_waitstream(mychannel, "");
03749          else
03750              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03751          ast_stopstream(mychannel);
03752       }
03753       /* go thru all the nodes in list */
03754       for(i = 0; i < ns; i++)
03755       {
03756          char *s,mode = 'T';
03757 
03758          /* if a mode spec at first, handle it */
03759          if ((*strs[i] < '0') || (*strs[i] > '9'))
03760          {
03761             mode = *strs[i];
03762             strs[i]++;
03763          }
03764 
03765          hastx = 1;
03766          res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03767          if (!res) 
03768             res = ast_waitstream(mychannel, "");
03769          else
03770             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03771          ast_stopstream(mychannel);
03772          ast_say_character_str(mychannel,strs[i],NULL,mychannel->language);
03773          if (!res) 
03774             res = ast_waitstream(mychannel, "");
03775          else
03776              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03777          ast_stopstream(mychannel);
03778          s = "rpt/tranceive";
03779          if (mode == 'R') s = "rpt/monitor";
03780          if (mode == 'C') s = "rpt/connecting";
03781          res = ast_streamfile(mychannel, s, mychannel->language);
03782          if (!res) 
03783             res = ast_waitstream(mychannel, "");
03784          else
03785             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03786          ast_stopstream(mychannel);
03787       }        
03788       if (!hastx)
03789       {
03790          res = ast_streamfile(mychannel, "rpt/repeat_only", 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       }
03797       imdone = 1;
03798       break;
03799 
03800        case LASTNODEKEY: /* Identify last node which keyed us up */
03801       rpt_mutex_lock(&myrpt->lock);
03802       if(myrpt->lastnodewhichkeyedusup)
03803          p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
03804       else
03805          p = NULL;
03806       rpt_mutex_unlock(&myrpt->lock);
03807       if(!p){
03808          imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
03809          break;
03810       }
03811       wait_interval(myrpt, DLY_TELEM, mychannel);
03812       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03813       if (!res) 
03814          res = ast_waitstream(mychannel, "");
03815       else
03816           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03817       ast_stopstream(mychannel);
03818       ast_say_character_str(mychannel, p, NULL, mychannel->language);
03819       if (!res) 
03820          res = ast_waitstream(mychannel, "");
03821       else
03822          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03823       ast_stopstream(mychannel);
03824       imdone = 1;
03825       break;      
03826 
03827        case UNAUTHTX: /* Say unauthorized transmit frequency */
03828       wait_interval(myrpt, DLY_TELEM, mychannel);
03829       res = ast_streamfile(mychannel, "rpt/unauthtx", mychannel->language);
03830       if (!res) 
03831          res = ast_waitstream(mychannel, "");
03832       else
03833           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03834       ast_stopstream(mychannel);
03835       imdone = 1;
03836       break;
03837       
03838 
03839        case TIMEOUT:
03840       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03841       if (!res) 
03842          res = ast_waitstream(mychannel, "");
03843       else
03844           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03845       ast_stopstream(mychannel);
03846       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03847       res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
03848       break;
03849       
03850        case TIMEOUT_WARNING:
03851       time(&t);
03852       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03853       if (!res) 
03854          res = ast_waitstream(mychannel, "");
03855       else
03856           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03857       ast_stopstream(mychannel);
03858       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03859       res = ast_streamfile(mychannel, "rpt/timeout-warning", mychannel->language);
03860       if (!res) 
03861          res = ast_waitstream(mychannel, "");
03862       else
03863           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03864       ast_stopstream(mychannel);
03865       if(!res) /* Say number of seconds */
03866          ast_say_number(mychannel, myrpt->p.remotetimeout - 
03867              (t - myrpt->last_activity_time), 
03868             "", mychannel->language, (char *) NULL);
03869       if (!res) 
03870          res = ast_waitstream(mychannel, "");
03871       ast_stopstream(mychannel); 
03872       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
03873       break;
03874 
03875        case ACT_TIMEOUT_WARNING:
03876       time(&t);
03877       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03878       if (!res) 
03879          res = ast_waitstream(mychannel, "");
03880       else
03881           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03882       ast_stopstream(mychannel);
03883       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03884       res = ast_streamfile(mychannel, "rpt/act-timeout-warning", mychannel->language);
03885       if (!res) 
03886          res = ast_waitstream(mychannel, "");
03887       else
03888           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03889       ast_stopstream(mychannel);
03890       if(!res) /* Say number of seconds */
03891          ast_say_number(mychannel, myrpt->p.remoteinacttimeout - 
03892              (t - myrpt->last_activity_time), 
03893             "", mychannel->language, (char *) NULL);
03894       if (!res) 
03895          res = ast_waitstream(mychannel, "");
03896       ast_stopstream(mychannel); 
03897       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
03898       break;
03899       
03900        case STATS_TIME:
03901          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
03902       t = time(NULL);
03903       rpt_localtime(&t, &localtm);
03904       /* Say the phase of the day is before the time */
03905       if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
03906          p = "rpt/goodmorning";
03907       else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
03908          p = "rpt/goodafternoon";
03909       else
03910          p = "rpt/goodevening";
03911       if (sayfile(mychannel,p) == -1)
03912       {
03913          imdone = 1;
03914          break;
03915       }
03916       /* Say the time is ... */     
03917       if (sayfile(mychannel,"rpt/thetimeis") == -1)
03918       {
03919          imdone = 1;
03920          break;
03921       }
03922       /* Say the time */            
03923          res = ast_say_time(mychannel, t, "", mychannel->language);
03924       if (!res) 
03925          res = ast_waitstream(mychannel, "");
03926       ast_stopstream(mychannel);    
03927       imdone = 1;
03928          break;
03929        case STATS_VERSION:
03930       p = strstr(tdesc, "version"); 
03931       if(!p)
03932          break;   
03933       if(sscanf(p, "version %d.%d", &vmajor, &vminor) != 2)
03934          break;
03935          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
03936       /* Say "version" */
03937       if (sayfile(mychannel,"rpt/version") == -1)
03938       {
03939          imdone = 1;
03940          break;
03941       }
03942       if(!res) /* Say "X" */
03943          ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
03944       if (!res) 
03945          res = ast_waitstream(mychannel, "");
03946       ast_stopstream(mychannel); 
03947       if (saycharstr(mychannel,".") == -1)
03948       {
03949          imdone = 1;
03950          break;
03951       }
03952       if(!res) /* Say "Y" */
03953          ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
03954       if (!res){
03955          res = ast_waitstream(mychannel, "");
03956          ast_stopstream(mychannel);
03957       }  
03958       else
03959           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03960       imdone = 1;
03961          break;
03962        case ARB_ALPHA:
03963          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
03964          if(mytele->param)
03965             saycharstr(mychannel, mytele->param);
03966          imdone = 1;
03967       break;
03968        case REV_PATCH:
03969          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
03970          if(mytele->param) {
03971 
03972          /* Parts of this section taken from app_parkandannounce */
03973          char *tpl_working, *tpl_current;
03974          char *tmp[100], *myparm;
03975          int looptemp=0,i=0, dres = 0;
03976    
03977 
03978          tpl_working = strdupa(mytele->param);
03979          myparm = strsep(&tpl_working,",");
03980          tpl_current=strsep(&tpl_working, ":");
03981 
03982          while(tpl_current && looptemp < sizeof(tmp)) {
03983             tmp[looptemp]=tpl_current;
03984             looptemp++;
03985             tpl_current=strsep(&tpl_working,":");
03986          }
03987 
03988          for(i=0; i<looptemp; i++) {
03989             if(!strcmp(tmp[i], "PARKED")) {
03990                ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
03991             } else if(!strcmp(tmp[i], "NODE")) {
03992                ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
03993             } else {
03994                dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
03995                if(!dres) {
03996                   dres = ast_waitstream(mychannel, "");
03997                } else {
03998                   ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
03999                   dres = 0;
04000                }
04001             }
04002          }
04003       }
04004          imdone = 1;
04005       break;
04006        case TEST_TONE:
04007       imdone = 1;
04008       if (myrpt->stopgen) break;
04009       myrpt->stopgen = -1;
04010            if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
04011       {
04012          myrpt->stopgen = 0;
04013          break;
04014       }
04015            while(mychannel->generatordata && (myrpt->stopgen <= 0)) {
04016          if (ast_safe_sleep(mychannel,1)) break;
04017             imdone = 1;
04018          }
04019       myrpt->stopgen = 0;
04020       break;
04021        default:
04022          break;
04023    }
04024    if (!imdone)
04025    {
04026       if (!res) 
04027          res = ast_waitstream(mychannel, "");
04028       else {
04029          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04030          res = 0;
04031       }
04032    }
04033    ast_stopstream(mychannel);
04034    rpt_mutex_lock(&myrpt->lock);
04035    if (mytele->mode == TAILMSG)
04036    {
04037       if (!res)
04038       {
04039          myrpt->tailmessagen++;
04040          if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
04041       }
04042       else
04043       {
04044          myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
04045       }
04046    }
04047    remque((struct qelem *)mytele);
04048    rpt_mutex_unlock(&myrpt->lock);
04049    free(mytele);     
04050    ast_hangup(mychannel);
04051 #ifdef  APP_RPT_LOCK_DEBUG
04052    {
04053       struct lockthread *t;
04054 
04055       sleep(5);
04056       ast_mutex_lock(&locklock);
04057       t = get_lockthread(pthread_self());
04058       if (t) memset(t,0,sizeof(struct lockthread));
04059       ast_mutex_unlock(&locklock);
04060    }        
04061 #endif
04062    pthread_exit(NULL);
04063 }
04064 
04065 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
04066 {
04067 struct rpt_tele *tele;
04068 struct rpt_link *mylink = (struct rpt_link *) data;
04069 int res;
04070 pthread_attr_t attr;
04071 
04072    tele = malloc(sizeof(struct rpt_tele));
04073    if (!tele)
04074    {
04075       ast_log(LOG_WARNING, "Unable to allocate memory\n");
04076       pthread_exit(NULL);
04077       return;
04078    }
04079    /* zero it out */
04080    memset((char *)tele,0,sizeof(struct rpt_tele));
04081    tele->rpt = myrpt;
04082    tele->mode = mode;
04083    rpt_mutex_lock(&myrpt->lock);
04084    if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED) ||
04085        (mode == LINKUNKEY)){
04086       memset(&tele->mylink,0,sizeof(struct rpt_link));
04087       if (mylink){
04088          memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
04089       }
04090    }
04091    else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
04092       strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
04093       tele->param[TELEPARAMSIZE - 1] = 0;
04094    }
04095    if (mode == REMXXX) tele->submode = (int) data;
04096    insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
04097    rpt_mutex_unlock(&myrpt->lock);
04098         pthread_attr_init(&attr);
04099         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
04100    res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
04101    if(res < 0){
04102       rpt_mutex_lock(&myrpt->lock);
04103       remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
04104       rpt_mutex_unlock(&myrpt->lock);  
04105       ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
04106    }
04107    return;
04108 }
04109 
04110 static void *rpt_call(void *this)
04111 {
04112 ZT_CONFINFO ci;  /* conference info */
04113 struct   rpt *myrpt = (struct rpt *)this;
04114 int   res;
04115 int stopped,congstarted,dialtimer,lastcidx,aborted;
04116 struct ast_channel *mychannel,*genchannel;
04117 
04118 
04119    myrpt->mydtmf = 0;
04120    /* allocate a pseudo-channel thru asterisk */
04121    mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
04122    if (!mychannel)
04123    {
04124       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
04125       pthread_exit(NULL);
04126    }
04127    ci.chan = 0;
04128    ci.confno = myrpt->conf; /* use the pseudo conference */
04129    ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
04130       | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
04131    /* first put the channel on the conference */
04132    if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
04133    {
04134       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04135       ast_hangup(mychannel);
04136       myrpt->callmode = 0;
04137       pthread_exit(NULL);
04138    }
04139    /* allocate a pseudo-channel thru asterisk */
04140    genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
04141    if (!genchannel)
04142    {
04143       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
04144       ast_hangup(mychannel);
04145       pthread_exit(NULL);
04146    }
04147    ci.chan = 0;
04148    ci.confno = myrpt->conf;
04149    ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
04150       | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
04151    /* first put the channel on the conference */
04152    if (ioctl(genchannel->fds[0],ZT_SETCONF,&ci) == -1)
04153    {
04154       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04155       ast_hangup(mychannel);
04156       ast_hangup(genchannel);
04157       myrpt->callmode = 0;
04158       pthread_exit(NULL);
04159    }
04160    if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
04161    {
04162       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
04163       ast_hangup(mychannel);
04164       ast_hangup(genchannel);
04165       myrpt->callmode = 0;
04166       pthread_exit(NULL);
04167    }
04168    if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
04169    {
04170       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
04171       ast_hangup(mychannel);
04172       ast_hangup(genchannel);
04173       myrpt->callmode = 0;
04174       pthread_exit(NULL);
04175    }
04176    /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
04177    if ((!myrpt->patchquiet) && (tone_zone_play_tone(mychannel->fds[0],ZT_TONE_DIALTONE) < 0))
04178    {
04179       ast_log(LOG_WARNING, "Cannot start dialtone\n");
04180       ast_hangup(mychannel);
04181       ast_hangup(genchannel);
04182       myrpt->callmode = 0;
04183       pthread_exit(NULL);
04184    }
04185    stopped = 0;
04186    congstarted = 0;
04187    dialtimer = 0;
04188    lastcidx = 0;
04189    aborted = 0;
04190 
04191 
04192    while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
04193    {
04194 
04195       if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
04196          dialtimer = 0;
04197          lastcidx = myrpt->cidx;
04198       }     
04199 
04200       if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){ 
04201          rpt_mutex_lock(&myrpt->lock);
04202          aborted = 1;
04203          myrpt->callmode = 0;
04204          rpt_mutex_unlock(&myrpt->lock);
04205          break;
04206       }
04207    
04208       if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
04209       {
04210          stopped = 1;
04211          /* stop dial tone */
04212          tone_zone_play_tone(mychannel->fds[0],-1);
04213       }
04214       if (myrpt->callmode == 4)
04215       {
04216          if(!congstarted){
04217             congstarted = 1;
04218             /* start congestion tone */
04219             tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION);
04220          }
04221       }
04222       res = ast_safe_sleep(mychannel, MSWAIT);
04223       if (res < 0)
04224       {
04225          ast_hangup(mychannel);
04226          ast_hangup(genchannel);
04227          rpt_mutex_lock(&myrpt->lock);
04228          myrpt->callmode = 0;
04229          rpt_mutex_unlock(&myrpt->lock);
04230          pthread_exit(NULL);
04231       }
04232       dialtimer += MSWAIT;
04233    }
04234    /* stop any tone generation */
04235    tone_zone_play_tone(mychannel->fds[0],-1);
04236    /* end if done */
04237    if (!myrpt->callmode)
04238    {
04239       ast_hangup(mychannel);
04240       ast_hangup(genchannel);
04241       rpt_mutex_lock(&myrpt->lock);
04242       myrpt->callmode = 0;
04243       rpt_mutex_unlock(&myrpt->lock);
04244       if((!myrpt->patchquiet) && aborted)
04245          rpt_telemetry(myrpt, TERM, NULL);
04246       pthread_exit(NULL);        
04247    }
04248 
04249    if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
04250       char *name, *loc, *instr;
04251       instr = strdup(myrpt->p.ourcallerid);
04252       if(instr){
04253          ast_callerid_parse(instr, &name, &loc);
04254          if(loc){
04255             if(mychannel->cid.cid_num)
04256                free(mychannel->cid.cid_num);
04257             mychannel->cid.cid_num = strdup(loc);
04258          }
04259          if(name){
04260             if(mychannel->cid.cid_name)
04261                free(mychannel->cid.cid_name);
04262             mychannel->cid.cid_name = strdup(name);
04263          }
04264          free(instr);
04265       }
04266    }
04267 
04268    ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
04269    ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
04270    
04271    if (myrpt->p.acctcode)
04272       ast_cdr_setaccount(mychannel,myrpt->p.acctcode);
04273    mychannel->priority = 1;
04274    ast_channel_undefer_dtmf(mychannel);
04275    if (ast_pbx_start(mychannel) < 0)
04276    {
04277       ast_log(LOG_WARNING, "Unable to start PBX!!\n");
04278       ast_hangup(mychannel);
04279       ast_hangup(genchannel);
04280       rpt_mutex_lock(&myrpt->lock);
04281       myrpt->callmode = 0;
04282       rpt_mutex_unlock(&myrpt->lock);
04283       pthread_exit(NULL);
04284    }
04285    usleep(10000);
04286    rpt_mutex_lock(&myrpt->lock);
04287    myrpt->callmode = 3;
04288    /* set appropriate conference for the pseudo */
04289    ci.chan = 0;
04290    ci.confno = myrpt->conf;
04291    ci.confmode = (myrpt->p.duplex == 2) ? ZT_CONF_CONFANNMON :
04292       (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
04293    /* first put the channel on the conference in announce mode */
04294    if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
04295    {
04296       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04297       ast_hangup(mychannel);
04298       ast_hangup(genchannel);
04299       myrpt->callmode = 0;
04300       pthread_exit(NULL);
04301    }
04302    while(myrpt->callmode)
04303    {
04304       if ((!mychannel->pbx) && (myrpt->callmode != 4))
04305       {
04306          if(myrpt->patchfarenddisconnect){ /* If patch is setup for far end disconnect */
04307             myrpt->callmode = 0;
04308             if(!myrpt->patchquiet){
04309                rpt_mutex_unlock(&myrpt->lock);
04310                rpt_telemetry(myrpt, TERM, NULL);
04311                rpt_mutex_lock(&myrpt->lock);
04312             }
04313          }
04314          else{ /* Send congestion until patch is downed by command */
04315             myrpt->callmode = 4;
04316             rpt_mutex_unlock(&myrpt->lock);
04317             /* start congestion tone */
04318             tone_zone_play_tone(genchannel->fds[0],ZT_TONE_CONGESTION);
04319             rpt_mutex_lock(&myrpt->lock);
04320          }
04321       }
04322       if (myrpt->mydtmf)
04323       {
04324          struct ast_frame wf = {AST_FRAME_DTMF, } ;
04325          wf.subclass = myrpt->mydtmf;
04326          rpt_mutex_unlock(&myrpt->lock);
04327          ast_queue_frame(mychannel,&wf);
04328          ast_senddigit(genchannel,myrpt->mydtmf);
04329          rpt_mutex_lock(&myrpt->lock);
04330          myrpt->mydtmf = 0;
04331       }
04332       rpt_mutex_unlock(&myrpt->lock);
04333       usleep(MSWAIT * 1000);
04334       rpt_mutex_lock(&myrpt->lock);
04335    }
04336    rpt_mutex_unlock(&myrpt->lock);
04337    tone_zone_play_tone(genchannel->fds[0],-1);
04338    if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
04339    ast_hangup(genchannel);
04340    rpt_mutex_lock(&myrpt->lock);
04341    myrpt->callmode = 0;
04342    rpt_mutex_unlock(&myrpt->lock);
04343    /* set appropriate conference for the pseudo */
04344    ci.chan = 0;
04345    ci.confno = myrpt->conf;
04346    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON :
04347       (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
04348    /* first put the channel on the conference in announce mode */
04349    if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
04350    {
04351       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04352    }
04353    pthread_exit(NULL);
04354 }
04355 
04356 static void send_link_dtmf(struct rpt *myrpt,char c)
04357 {
04358 char  str[300];
04359 struct   ast_frame wf;
04360 struct   rpt_link *l;
04361 
04362    snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
04363    wf.frametype = AST_FRAME_TEXT;
04364    wf.subclass = 0;
04365    wf.offset = 0;
04366    wf.mallocd = 0;
04367    wf.datalen = strlen(str) + 1;
04368    wf.samples = 0;
04369    l = myrpt->links.next;
04370    /* first, see if our dude is there */
04371    while(l != &myrpt->links)
04372    {
04373       if (l->name[0] == '0') 
04374       {
04375          l = l->next;
04376          continue;
04377       }
04378       /* if we found it, write it and were done */
04379       if (!strcmp(l->name,myrpt->cmdnode))
04380       {
04381          wf.data = str;
04382          if (l->chan) ast_write(l->chan,&wf);
04383          return;
04384       }
04385       l = l->next;
04386    }
04387    l = myrpt->links.next;
04388    /* if not, give it to everyone */
04389    while(l != &myrpt->links)
04390    {
04391       wf.data = str;
04392       if (l->chan) ast_write(l->chan,&wf);
04393       l = l->next;
04394    }
04395    return;
04396 }
04397 
04398 /* 
04399  * Connect a link 
04400  *
04401  * Return values:
04402  * -1: Error
04403  *  0: Success
04404  *  1: No match yet
04405  *  2: Already connected to this node
04406  */
04407 
04408 static int connect_link(struct rpt *myrpt, char* node, int mode, int perma)
04409 {
04410    char *val, *s, *s1, *s2, *tele;
04411    char lstr[MAXLINKLIST],*strs[MAXLINKLIST];
04412    char tmp[300], deststr[300] = "",modechange = 0;
04413    struct rpt_link *l;
04414    int reconnects = 0;
04415    int i,n;
04416    ZT_CONFINFO ci;  /* conference info */
04417 
04418    val = node_lookup(myrpt,node);
04419    if (!val){
04420       if(strlen(node) >= myrpt->longestnode)
04421          return -1; /* No such node */
04422       return 1; /* No match yet */
04423    }
04424    if(debug > 3){
04425       ast_log(LOG_NOTICE,"Connect attempt to node %s\n", node);
04426       ast_log(LOG_NOTICE,"Mode: %s\n",(mode)?"Transceive":"Monitor");
04427       ast_log(LOG_NOTICE,"Connection type: %s\n",(perma)?"Permalink":"Normal");
04428    }
04429 
04430    strncpy(tmp,val,sizeof(tmp) - 1);
04431    s = tmp;
04432    s1 = strsep(&s,",");
04433    s2 = strsep(&s,",");
04434    rpt_mutex_lock(&myrpt->lock);
04435    l = myrpt->links.next;
04436    /* try to find this one in queue */
04437    while(l != &myrpt->links){
04438       if (l->name[0] == '0') 
04439       {
04440          l = l->next;
04441          continue;
04442       }
04443    /* if found matching string */
04444       if (!strcmp(l->name, node))
04445          break;
04446       l = l->next;
04447    }
04448    /* if found */
04449    if (l != &myrpt->links){ 
04450    /* if already in this mode, just ignore */
04451       if ((l->mode) || (!l->chan)) {
04452          rpt_mutex_unlock(&myrpt->lock);
04453          return 2; /* Already linked */
04454       }
04455       reconnects = l->reconnects;
04456       rpt_mutex_unlock(&myrpt->lock);
04457       if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
04458       l->retries = l->max_retries + 1;
04459       l->disced = 2;
04460       modechange = 1;
04461    } else
04462    {
04463       __mklinklist(myrpt,NULL,lstr);
04464       rpt_mutex_unlock(&myrpt->lock);
04465       n = finddelim(lstr,strs,MAXLINKLIST);
04466       for(i = 0; i < n; i++)
04467       {
04468          if ((*strs[i] < '0') || 
04469              (*strs[i] > '9')) strs[i]++;
04470          if (!strcmp(strs[i],node))
04471          {
04472             return 2; /* Already linked */
04473          }
04474       }
04475    }
04476    strncpy(myrpt->lastlinknode,node,MAXNODESTR - 1);
04477    /* establish call */
04478    l = malloc(sizeof(struct rpt_link));
04479    if (!l)
04480    {
04481       ast_log(LOG_WARNING, "Unable to malloc\n");
04482       return -1;
04483    }
04484    /* zero the silly thing */
04485    memset((char *)l,0,sizeof(struct rpt_link));
04486    l->mode = mode;
04487    l->outbound = 1;
04488    l->thisconnected = 0;
04489    strncpy(l->name, node, MAXNODESTR - 1);
04490    l->isremote = (s && ast_true(s));
04491    if (modechange) l->connected = 1;
04492    l->hasconnected = l->perma = perma;
04493    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
04494    tele = strchr(deststr, '/');
04495    if (!tele){
04496       ast_log(LOG_WARNING,"link3:Dial number (%s) must be in format tech/number\n",deststr);
04497       free(l);
04498       return -1;
04499    }
04500    *tele++ = 0;
04501    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
04502    if (l->chan){
04503       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
04504       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
04505       l->chan->whentohangup = 0;
04506       l->chan->appl = "Apprpt";
04507       l->chan->data = "(Remote Rx)";
04508       if (debug > 3)
04509          ast_log(LOG_NOTICE, "rpt (remote) initiating call to %s/%s on %s\n",
04510       deststr, tele, l->chan->name);
04511       if(l->chan->cid.cid_num)
04512          free(l->chan->cid.cid_num);
04513       l->chan->cid.cid_num = strdup(myrpt->name);
04514       ast_call(l->chan,tele,999);
04515    }
04516    else {
04517       if(debug > 3) 
04518          ast_log(LOG_NOTICE, "Unable to place call to %s/%s on %s\n",
04519       deststr,tele,l->chan->name);
04520       if (myrpt->p.archivedir)
04521       {
04522          char str[100];
04523          sprintf(str,"LINKFAIL,%s",l->name);
04524          donodelog(myrpt,str);
04525       }
04526       free(l);
04527       return -1;
04528    }
04529    /* allocate a pseudo-channel thru asterisk */
04530    l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
04531    if (!l->pchan){
04532       ast_log(LOG_WARNING,"rpt connect: Sorry unable to obtain pseudo channel\n");
04533       ast_hangup(l->chan);
04534       free(l);
04535       return -1;
04536    }
04537    ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
04538    ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
04539    /* make a conference for the tx */
04540    ci.chan = 0;
04541    ci.confno = myrpt->conf;
04542    ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
04543    /* first put the channel on the conference in proper mode */
04544    if (ioctl(l->pchan->fds[0], ZT_SETCONF, &ci) == -1)
04545    {
04546       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04547       ast_hangup(l->chan);
04548       ast_hangup(l->pchan);
04549       free(l);
04550       return -1;
04551    }
04552    rpt_mutex_lock(&myrpt->lock);
04553    l->reconnects = reconnects;
04554    /* insert at end of queue */
04555    l->max_retries = MAX_RETRIES;
04556    if (perma)
04557       l->max_retries = MAX_RETRIES_PERM;
04558    if (l->isremote) l->retries = l->max_retries + 1;
04559    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
04560    __kickshort(myrpt);
04561    rpt_mutex_unlock(&myrpt->lock);
04562    return 0;
04563 }
04564 
04565 
04566 
04567 /*
04568 * Internet linking function 
04569 */
04570 
04571 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
04572 {
04573 
04574    char *val, *s, *s1, *s2;
04575    char tmp[300];
04576    char digitbuf[MAXNODESTR],*strs[MAXLINKLIST];
04577    char mode,perma;
04578    struct rpt_link *l;
04579    int i,r;
04580 
04581    if(!param)
04582       return DC_ERROR;
04583       
04584          
04585    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable )
04586       return DC_ERROR;
04587 
04588    strncpy(digitbuf,digits,MAXNODESTR - 1);
04589 
04590    if(debug > 6)
04591       printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
04592       
04593    switch(myatoi(param)){
04594       case 11: /* Perm Link off */
04595       case 1: /* Link off */
04596          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
04597             strcpy(digitbuf,myrpt->lastlinknode);
04598          val = node_lookup(myrpt,digitbuf);
04599          if (!val){
04600             if(strlen(digitbuf) >= myrpt->longestnode)
04601                return DC_ERROR;
04602             break;
04603          }
04604          strncpy(tmp,val,sizeof(tmp) - 1);
04605          s = tmp;
04606          s1 = strsep(&s,",");
04607          s2 = strsep(&s,",");
04608          rpt_mutex_lock(&myrpt->lock);
04609          l = myrpt->links.next;
04610          /* try to find this one in queue */
04611          while(l != &myrpt->links){
04612             if (l->name[0] == '0') 
04613             {
04614                l = l->next;
04615                continue;
04616             }
04617             /* if found matching string */
04618             if (!strcmp(l->name, digitbuf))
04619                break;
04620             l = l->next;
04621          }
04622          if (l != &myrpt->links){ /* if found */
04623             struct   ast_frame wf;
04624 
04625             /* must use perm command on perm link */
04626             if ((myatoi(param) < 10) && 
04627                 (l->max_retries > MAX_RETRIES))
04628             {
04629                rpt_mutex_unlock(&myrpt->lock);
04630                return DC_COMPLETE;
04631             }
04632             strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
04633             l->retries = l->max_retries + 1;
04634             l->disced = 1;
04635             rpt_mutex_unlock(&myrpt->lock);
04636             wf.frametype = AST_FRAME_TEXT;
04637             wf.subclass = 0;
04638             wf.offset = 0;
04639             wf.mallocd = 0;
04640             wf.datalen = strlen(discstr) + 1;
04641             wf.samples = 0;
04642             wf.data = discstr;
04643             if (l->chan)
04644             {
04645                ast_write(l->chan,&wf);
04646                if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
04647                ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
04648             }
04649             rpt_telemetry(myrpt, COMPLETE, NULL);
04650             return DC_COMPLETE;
04651          }
04652          rpt_mutex_unlock(&myrpt->lock);  
04653          return DC_COMPLETE;
04654       case 2: /* Link Monitor */
04655       case 3: /* Link transceive */
04656       case 12: /* Link Monitor permanent */
04657       case 13: /* Link transceive permanent */
04658          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
04659             strcpy(digitbuf,myrpt->lastlinknode);
04660          /* Attempt connection  */
04661          perma = (atoi(param) > 10) ? 1 : 0;
04662          mode = (atoi(param) & 1) ? 1 : 0;
04663          r = connect_link(myrpt, digitbuf, mode, perma);
04664          switch(r){
04665             case 0:
04666                rpt_telemetry(myrpt, COMPLETE, NULL);
04667                return DC_COMPLETE;
04668 
04669             case 1:
04670                break;
04671             
04672             case 2:
04673                rpt_telemetry(myrpt, REMALREADY, NULL);
04674                return DC_COMPLETE;
04675             
04676             default:
04677                rpt_telemetry(myrpt, CONNFAIL, NULL);
04678                return DC_COMPLETE;
04679          }
04680          break;
04681 
04682       case 4: /* Enter Command Mode */
04683       
04684          /* if doesnt allow link cmd, or no links active, return */
04685          if (((command_source != SOURCE_RPT) && 
04686             (command_source != SOURCE_PHONE) &&
04687             (command_source != SOURCE_DPHONE)) ||
04688              (myrpt->links.next == &myrpt->links))
04689             return DC_COMPLETE;
04690          
04691          /* if already in cmd mode, or selected self, fughetabahtit */
04692          if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
04693          
04694             rpt_telemetry(myrpt, REMALREADY, NULL);
04695             return DC_COMPLETE;
04696          }
04697          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
04698             strcpy(digitbuf,myrpt->lastlinknode);
04699          /* node must at least exist in list */
04700          val = node_lookup(myrpt,digitbuf);
04701          if (!val){
04702             if(strlen(digitbuf) >= myrpt->longestnode)
04703                return DC_ERROR;
04704             break;
04705          
04706          }
04707          rpt_mutex_lock(&myrpt->lock);
04708          strcpy(myrpt->lastlinknode,digitbuf);
04709          strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
04710          rpt_mutex_unlock(&myrpt->lock);
04711          rpt_telemetry(myrpt, REMGO, NULL);  
04712          return DC_COMPLETE;
04713          
04714       case 5: /* Status */
04715          rpt_telemetry(myrpt, STATUS, NULL);
04716          return DC_COMPLETE;
04717 
04718       case 15: /* Full Status */
04719          rpt_telemetry(myrpt, FULLSTATUS, NULL);
04720          return DC_COMPLETE;
04721          
04722          
04723       case 6: /* All Links Off, including permalinks */
04724                        rpt_mutex_lock(&myrpt->lock);
04725          myrpt->savednodes[0] = 0;
04726                         l = myrpt->links.next;
04727                         /* loop through all links */
04728                         while(l != &myrpt->links){
04729             struct   ast_frame wf;
04730                                 if (l->name[0] == '0') /* Skip any IAXRPT monitoring */
04731                                 {
04732                                         l = l->next;
04733                                         continue;
04734                                 }
04735             /* Make a string of disconnected nodes for possible restoration */
04736             sprintf(tmp,"%c%c%s",(l->mode) ? 'X' : 'M',(l->perma) ? 'P':'T',l->name);
04737             if(strlen(tmp) + strlen(myrpt->savednodes) + 1 < MAXNODESTR){ 
04738                if(myrpt->savednodes[0])
04739                   strcat(myrpt->savednodes, ",");
04740                strcat(myrpt->savednodes, tmp);
04741             }
04742                               l->retries = l->max_retries + 1;
04743                                 l->disced = 2; /* Silently disconnect */
04744                                 rpt_mutex_unlock(&myrpt->lock);
04745             /* ast_log(LOG_NOTICE,"dumping link %s\n",l->name); */
04746                                 
04747                                 wf.frametype = AST_FRAME_TEXT;
04748                                 wf.subclass = 0;
04749                                 wf.offset = 0;
04750                                 wf.mallocd = 0;
04751                                 wf.datalen = strlen(discstr) + 1;
04752                                 wf.samples = 0;
04753                                 wf.data = discstr;
04754                                 if (l->chan)
04755                                 {
04756                                         ast_write(l->chan,&wf);
04757                                         ast_safe_sleep(l->chan,250); /* It's dead already, why check the return value? */
04758                                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
04759                                 }
04760             rpt_mutex_lock(&myrpt->lock);
04761                                 l = l->next;
04762                         }
04763          rpt_mutex_unlock(&myrpt->lock);
04764          if(debug > 3)
04765             ast_log(LOG_NOTICE,"Nodes disconnected: %s\n",myrpt->savednodes);
04766                         rpt_telemetry(myrpt, COMPLETE, NULL);
04767          return DC_COMPLETE;
04768 
04769       case 7: /* Identify last node which keyed us up */
04770          rpt_telemetry(myrpt, LASTNODEKEY, NULL);
04771          break;
04772 
04773 
04774       case 16: /* Restore links disconnected with "disconnect all links" command */
04775          strcpy(tmp, myrpt->savednodes); /* Make a copy */
04776          finddelim(tmp, strs, MAXLINKLIST); /* convert into substrings */
04777          for(i = 0; tmp[0] && strs[i] != NULL && i < MAXLINKLIST; i++){
04778             s1 = strs[i];
04779             mode = (s1[0] == 'X') ? 1 : 0;
04780             perma = (s1[1] == 'P') ? 1 : 0;
04781             connect_link(myrpt, s1 + 2, mode, perma); /* Try to reconnect */
04782          }
04783                         rpt_telemetry(myrpt, COMPLETE, NULL);
04784          break;
04785    
04786       case 200:
04787       case 201:
04788       case 202:
04789       case 203:
04790       case 204:
04791       case 205:
04792       case 206:
04793       case 207:
04794       case 208:
04795       case 209:
04796       case 210:
04797       case 211:
04798       case 212:
04799       case 213:
04800       case 214:
04801       case 215:
04802          if (((myrpt->p.propagate_dtmf) && 
04803               (command_source == SOURCE_LNK)) ||
04804              ((myrpt->p.propagate_phonedtmf) &&
04805             ((command_source == SOURCE_PHONE) ||
04806                 (command_source == SOURCE_DPHONE))))
04807                do_dtmf_local(myrpt,
04808                   remdtmfstr[myatoi(param) - 200]);
04809       default:
04810          return DC_ERROR;
04811          
04812    }
04813    
04814    return DC_INDETERMINATE;
04815 }  
04816 
04817 /*
04818 * Autopatch up
04819 */
04820 
04821 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
04822 {
04823    pthread_attr_t attr;
04824    int i, index, paramlength;
04825    char *lparam;
04826    char *value = NULL;
04827    char *paramlist[20];
04828 
04829    static char *keywords[] = {
04830    "context",
04831    "dialtime",
04832    "farenddisconnect",
04833    "noct",
04834    "quiet",
04835    NULL
04836    };
04837       
04838    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
04839       return DC_ERROR;
04840       
04841    if(debug)
04842       printf("@@@@ Autopatch up\n");
04843 
04844    if(!myrpt->callmode){
04845       /* Set defaults */
04846       myrpt->patchnoct = 0;
04847       myrpt->patchdialtime = 0;
04848       myrpt->patchfarenddisconnect = 0;
04849       myrpt->patchquiet = 0;
04850       strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
04851 
04852       if(param){
04853          /* Process parameter list */
04854          lparam = ast_strdupa(param);
04855          if(!lparam){
04856             ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
04857             return DC_ERROR;  
04858          }
04859          paramlength = finddelim(lparam, paramlist, 20);          
04860          for(i = 0; i < paramlength; i++){
04861             index = matchkeyword(paramlist[i], &value, keywords);
04862             if(value)
04863                value = skipchars(value, "= ");
04864             switch(index){
04865 
04866                case 1: /* context */
04867                   strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ;
04868                   break;
04869                   
04870                case 2: /* dialtime */
04871                   myrpt->patchdialtime = atoi(value);
04872                   break;
04873 
04874                case 3: /* farenddisconnect */
04875                   myrpt->patchfarenddisconnect = atoi(value);
04876                   break;
04877 
04878                case 4:  /* noct */
04879                   myrpt->patchnoct = atoi(value);
04880                   break;
04881 
04882                case 5: /* quiet */
04883                   myrpt->patchquiet = atoi(value);
04884                   break;
04885                            
04886                default:
04887                   break;
04888             }
04889          }
04890       }
04891    }
04892                
04893    rpt_mutex_lock(&myrpt->lock);
04894 
04895    /* if on call, force * into current audio stream */
04896    
04897    if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
04898       myrpt->mydtmf = myrpt->p.endchar;
04899    }
04900    if (myrpt->callmode){
04901       rpt_mutex_unlock(&myrpt->lock);
04902       return DC_COMPLETE;
04903    }
04904    myrpt->callmode = 1;
04905    myrpt->cidx = 0;
04906    myrpt->exten[myrpt->cidx] = 0;
04907    rpt_mutex_unlock(&myrpt->lock);
04908    pthread_attr_init(&attr);
04909    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
04910    ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
04911    return DC_COMPLETE;
04912 }
04913 
04914 /*
04915 * Autopatch down
04916 */
04917 
04918 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
04919 {
04920    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
04921       return DC_ERROR;
04922    
04923    if(debug)
04924       printf("@@@@ Autopatch down\n");
04925       
04926    rpt_mutex_lock(&myrpt->lock);
04927    
04928    if (!myrpt->callmode){
04929       rpt_mutex_unlock(&myrpt->lock);
04930       return DC_COMPLETE;
04931    }
04932    
04933    myrpt->callmode = 0;
04934    rpt_mutex_unlock(&myrpt->lock);
04935    rpt_telemetry(myrpt, TERM, NULL);
04936    return DC_COMPLETE;
04937 }
04938 
04939 /*
04940 * Status
04941 */
04942 
04943 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
04944 {
04945 
04946    if (!param)
04947       return DC_ERROR;
04948 
04949    if ((myrpt->p.s[myrpt->p.sysstate_cur].txdisable) || (myrpt->p.s[myrpt->p.sysstate_cur].userfundisable))
04950       return DC_ERROR;
04951 
04952    if(debug)
04953       printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
04954    
04955    switch(myatoi(param)){
04956       case 1: /* System ID */
04957          rpt_telemetry(myrpt, ID1, NULL);
04958          return DC_COMPLETE;
04959       case 2: /* System Time */
04960          rpt_telemetry(myrpt, STATS_TIME, NULL);
04961          return DC_COMPLETE;
04962       case 3: /* app_rpt.c version */
04963          rpt_telemetry(myrpt, STATS_VERSION, NULL);
04964       default:
04965          return DC_ERROR;
04966    }
04967    return DC_INDETERMINATE;
04968 }
04969 
04970 /*
04971 *  Macro-oni (without Salami)
04972 */
04973 
04974 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
04975 {
04976 
04977 char  *val;
04978 int   i;
04979    if (myrpt->remote)
04980       return DC_ERROR;
04981 
04982    if(debug) 
04983       printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
04984    
04985    if(strlen(digitbuf) < 1) /* needs 1 digit */
04986       return DC_INDETERMINATE;
04987          
04988    for(i = 0 ; i < digitbuf[i] ; i++) {
04989       if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
04990          return DC_ERROR;
04991    }
04992    
04993    if (*digitbuf == '0') val = myrpt->p.startupmacro;
04994    else val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
04995    /* param was 1 for local buf */
04996    if (!val){
04997                 if (strlen(digitbuf) < myrpt->macro_longest)
04998                         return DC_INDETERMINATE;
04999       rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
05000       return DC_COMPLETE;
05001    }        
05002    rpt_mutex_lock(&myrpt->lock);
05003    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
05004    {
05005       rpt_mutex_unlock(&myrpt->lock);
05006       rpt_telemetry(myrpt, MACRO_BUSY, NULL);
05007       return DC_ERROR;
05008    }
05009    myrpt->macrotimer = MACROTIME;
05010    strncat(myrpt->macrobuf,val,MAXMACRO - 1);
05011    rpt_mutex_unlock(&myrpt->lock);
05012    return DC_COMPLETE;  
05013 }
05014 
05015 /*
05016 * COP - Control operator
05017 */
05018 
05019 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
05020 {
05021    char string[16];
05022 
05023    if(!param)
05024       return DC_ERROR;
05025    
05026    switch(myatoi(param)){
05027       case 1: /* System reset */
05028          system("killall -9 asterisk");
05029          return DC_COMPLETE;
05030 
05031       case 2:
05032          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 0;
05033          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
05034          return DC_COMPLETE;
05035          
05036       case 3:
05037          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 1;
05038          return DC_COMPLETE;
05039          
05040       case 4: /* test tone on */
05041          if (myrpt->stopgen < 0) 
05042          {
05043             myrpt->stopgen = 1;
05044          }
05045          else 
05046          {
05047             myrpt->stopgen = 0;
05048             rpt_telemetry(myrpt, TEST_TONE, NULL);
05049          }
05050          return DC_COMPLETE;
05051 
05052       case 5: /* Disgorge variables to log for debug purposes */
05053          myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
05054          return DC_COMPLETE;
05055 
05056       case 6: /* Simulate COR being activated (phone only) */
05057          if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
05058          return DC_DOKEY;  
05059 
05060 
05061       case 7: /* Time out timer enable */
05062          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 0;
05063          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTENA");
05064          return DC_COMPLETE;
05065          
05066       case 8: /* Time out timer disable */
05067          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 1;
05068          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTDIS");
05069          return DC_COMPLETE;
05070 
05071                 case 9: /* Autopatch enable */
05072                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 0;
05073                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APENA");
05074                         return DC_COMPLETE;
05075 
05076                 case 10: /* Autopatch disable */
05077                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 1;
05078                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APDIS");
05079                         return DC_COMPLETE;
05080 
05081                 case 11: /* Link Enable */
05082                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 0;
05083                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKENA");
05084                         return DC_COMPLETE;
05085 
05086                 case 12: /* Link Disable */
05087                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 1;
05088                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKDIS");
05089                         return DC_COMPLETE;
05090 
05091       case 13: /* Query System State */
05092          string[0] = string[1] = 'S';
05093          string[2] = myrpt->p.sysstate_cur + '0';
05094          string[3] = '\0';
05095          rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
05096          return DC_COMPLETE;
05097 
05098       case 14: /* Change System State */
05099          if(strlen(digitbuf) == 0)
05100             break;
05101          if((digitbuf[0] < '0') || (digitbuf[0] > '9'))
05102             return DC_ERROR;
05103          myrpt->p.sysstate_cur = digitbuf[0] - '0';
05104                         string[0] = string[1] = 'S';
05105                         string[2] = myrpt->p.sysstate_cur + '0';
05106                         string[3] = '\0';
05107                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
05108                         return DC_COMPLETE;
05109 
05110                 case 15: /* Scheduler Enable */
05111                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 0;
05112                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKENA");
05113                         return DC_COMPLETE;
05114 
05115                 case 16: /* Scheduler Disable */
05116                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 1;
05117                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKDIS");
05118                         return DC_COMPLETE;
05119 
05120                 case 17: /* User functions Enable */
05121                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 0;
05122                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFENA");
05123                         return DC_COMPLETE;
05124 
05125                 case 18: /* User Functions Disable */
05126                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 1;
05127                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFDIS");
05128                         return DC_COMPLETE;
05129 
05130                 case 19: /* Alternate Tail Enable */
05131                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 1;
05132                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATENA");
05133                         return DC_COMPLETE;
05134 
05135                 case 20: /* Alternate Tail Disable */
05136                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 0;
05137                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATDIS");
05138                         return DC_COMPLETE;
05139    }  
05140    return DC_INDETERMINATE;
05141 }
05142 
05143 /*
05144 * Collect digits one by one until something matches
05145 */
05146 
05147 static int collect_function_digits(struct rpt *myrpt, char *digits, 
05148    int command_source, struct rpt_link *mylink)
05149 {
05150    int i;
05151    char *stringp,*action,*param,*functiondigits;
05152    char function_table_name[30] = "";
05153    char workstring[200];
05154    
05155    struct ast_variable *vp;
05156    
05157    if(debug)   
05158       printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
05159    
05160    if (command_source == SOURCE_DPHONE) {
05161       if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
05162       strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1);
05163       }
05164    else if (command_source == SOURCE_PHONE) {
05165       if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
05166       strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1);
05167       }
05168    else if (command_source == SOURCE_LNK)
05169       strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1);
05170    else
05171       strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1);
05172    vp = ast_variable_browse(myrpt->cfg, function_table_name);
05173    while(vp) {
05174       if(!strncasecmp(vp->name, digits, strlen(vp->name)))
05175          break;
05176       vp = vp->next;
05177    }  
05178    if(!vp) {
05179       int n;
05180 
05181       n = myrpt->longestfunc;
05182       if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
05183       else 
05184       if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
05185       else 
05186       if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
05187       
05188       if(strlen(digits) >= n)
05189          return DC_ERROR;
05190       else
05191          return DC_INDETERMINATE;
05192    }  
05193    /* Found a match, retrieve value part and parse */
05194    strncpy(workstring, vp->value, sizeof(workstring) - 1 );
05195    stringp = workstring;
05196    action = strsep(&stringp, ",");
05197    param = stringp;
05198    if(debug)
05199       printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
05200    /* Look up the action */
05201    for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
05202       if(!strncasecmp(action, function_table[i].action, strlen(action)))
05203          break;
05204    }
05205    if(debug)
05206       printf("@@@@ table index i = %d\n",i);
05207    if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
05208       /* Error, action not in table */
05209       return DC_ERROR;
05210    }
05211    if(function_table[i].function == NULL){
05212       /* Error, function undefined */
05213       if(debug)
05214          printf("@@@@ NULL for action: %s\n",action);
05215       return DC_ERROR;
05216    }
05217    functiondigits = digits + strlen(vp->name);
05218    return (*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
05219 }
05220 
05221 
05222 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
05223    char *str)
05224 {
05225 char  tmp[512],cmd[300] = "",dest[300],src[300],c;
05226 int   seq, res;
05227 struct rpt_link *l;
05228 struct   ast_frame wf;
05229 
05230    wf.frametype = AST_FRAME_TEXT;
05231    wf.subclass = 0;
05232    wf.offset = 0;
05233    wf.mallocd = 0;
05234    wf.datalen = strlen(str) + 1;
05235    wf.samples = 0;
05236    /* put string in our buffer */
05237    strncpy(tmp,str,sizeof(tmp) - 1);
05238 
05239         if (!strcmp(tmp,discstr))
05240         {
05241                 mylink->disced = 1;
05242       mylink->retries = mylink->max_retries + 1;
05243                 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
05244                 return;
05245         }
05246    if (tmp[0] == 'L')
05247    {
05248       rpt_mutex_lock(&myrpt->lock);
05249       strcpy(mylink->linklist,tmp + 2);
05250       time(&mylink->linklistreceived);
05251       rpt_mutex_unlock(&myrpt->lock);
05252       if (debug > 6) ast_log(LOG_NOTICE,"@@@@ node %s recieved node list %s from node %s\n",
05253          myrpt->name,tmp,mylink->name);
05254       return;
05255    }
05256    if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
05257    {
05258       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
05259       return;
05260    }
05261    if (strcmp(cmd,"D"))
05262    {
05263       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
05264       return;
05265    }
05266    if (dest[0] == '0')
05267    {
05268       strcpy(dest,myrpt->name);
05269    }     
05270 
05271    /* if not for me, redistribute to all links */
05272    if (strcmp(dest,myrpt->name))
05273    {
05274       l = myrpt->links.next;
05275       /* see if this is one in list */
05276       while(l != &myrpt->links)
05277       {
05278          if (l->name[0] == '0') 
05279          {
05280             l = l->next;
05281             continue;
05282          }
05283          /* dont send back from where it came */
05284          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
05285          {
05286             l = l->next;
05287             continue;
05288          }
05289          /* if it is, send it and we're done */
05290          if (!strcmp(l->name,dest))
05291          {
05292             /* send, but not to src */
05293             if (strcmp(l->name,src)) {
05294                wf.data = str;
05295                if (l->chan) ast_write(l->chan,&wf);
05296             }
05297             return;
05298          }
05299          l = l->next;
05300       }
05301       l = myrpt->links.next;
05302       /* otherwise, send it to all of em */
05303       while(l != &myrpt->links)
05304       {
05305          if (l->name[0] == '0') 
05306          {
05307             l = l->next;
05308             continue;
05309          }
05310          /* dont send back from where it came */
05311          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
05312          {
05313             l = l->next;
05314             continue;
05315          }
05316          /* send, but not to src */
05317          if (strcmp(l->name,src)) {
05318             wf.data = str;
05319             if (l->chan) ast_write(l->chan,&wf); 
05320          }
05321          l = l->next;
05322       }
05323       return;
05324    }
05325    if (myrpt->p.archivedir)
05326    {
05327       char str[100];
05328 
05329       sprintf(str,"DTMF,%s,%c",mylink->name,c);
05330       donodelog(myrpt,str);
05331    }
05332    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
05333    if (!c) return;
05334    rpt_mutex_lock(&myrpt->lock);
05335    if (c == myrpt->p.endchar) myrpt->stopgen = 1;
05336    if (myrpt->callmode == 1)
05337    {
05338       myrpt->exten[myrpt->cidx++] = c;
05339       myrpt->exten[myrpt->cidx] = 0;
05340       /* if this exists */
05341       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
05342       {
05343          myrpt->callmode = 2;
05344          if(!myrpt->patchquiet){
05345             rpt_mutex_unlock(&myrpt->lock);
05346             rpt_telemetry(myrpt,PROC,NULL); 
05347             rpt_mutex_lock(&myrpt->lock);
05348          }
05349       }
05350       /* if can continue, do so */
05351       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL)) 
05352       {
05353          /* call has failed, inform user */
05354          myrpt->callmode = 4;
05355       }
05356    }
05357    if (c == myrpt->p.funcchar)
05358    {
05359       myrpt->rem_dtmfidx = 0;
05360       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
05361       time(&myrpt->rem_dtmf_time);
05362       rpt_mutex_unlock(&myrpt->lock);
05363       return;
05364    } 
05365    else if (myrpt->rem_dtmfidx < 0)
05366    {
05367       if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
05368       {
05369          myrpt->mydtmf = c;
05370       }
05371       if (myrpt->p.propagate_dtmf) do_dtmf_local(myrpt,c);
05372       if (myrpt->p.propagate_phonedtmf) do_dtmf_phone(myrpt,mylink,c);
05373       rpt_mutex_unlock(&myrpt->lock);
05374       return;
05375    }
05376    else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
05377    {
05378       time(&myrpt->rem_dtmf_time);
05379       if (myrpt->rem_dtmfidx < MAXDTMF)
05380       {
05381          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
05382          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
05383          
05384          rpt_mutex_unlock(&myrpt->lock);
05385          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
05386          res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
05387          rpt_mutex_lock(&myrpt->lock);
05388          
05389          switch(res){
05390 
05391             case DC_INDETERMINATE:
05392                break;
05393             
05394             case DC_REQ_FLUSH:
05395                myrpt->rem_dtmfidx = 0;
05396                myrpt->rem_dtmfbuf[0] = 0;
05397                break;
05398             
05399             
05400             case DC_COMPLETE:
05401             case DC_COMPLETEQUIET:
05402                myrpt->totalexecdcommands++;
05403                myrpt->dailyexecdcommands++;
05404                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
05405                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
05406                myrpt->rem_dtmfbuf[0] = 0;
05407                myrpt->rem_dtmfidx = -1;
05408                myrpt->rem_dtmf_time = 0;
05409                break;
05410             
05411             case DC_ERROR:
05412             default:
05413                myrpt->rem_dtmfbuf[0] = 0;
05414                myrpt->rem_dtmfidx = -1;
05415                myrpt->rem_dtmf_time = 0;
05416                break;
05417          }
05418       }
05419 
05420    }
05421    rpt_mutex_unlock(&myrpt->lock);
05422    return;
05423 }
05424 
05425 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
05426    char c)
05427 {
05428 
05429 char  cmd[300];
05430 int   res;
05431 
05432    if (myrpt->p.archivedir)
05433    {
05434       char str[100];
05435 
05436       sprintf(str,"DTMF(P),%s,%c",mylink->name,c);
05437       donodelog(myrpt,str);
05438    }
05439    rpt_mutex_lock(&myrpt->lock);
05440    if (c == myrpt->p.endchar)
05441    {
05442       if (mylink->lastrx)
05443       {
05444          mylink->lastrx = 0;
05445          rpt_mutex_unlock(&myrpt->lock);
05446          return;
05447       }
05448       myrpt->stopgen = 1;
05449       if (myrpt->cmdnode[0])
05450       {
05451          myrpt->cmdnode[0] = 0;
05452          myrpt->dtmfidx = -1;
05453          myrpt->dtmfbuf[0] = 0;
05454          rpt_mutex_unlock(&myrpt->lock);
05455          rpt_telemetry(myrpt,COMPLETE,NULL);
05456          return;
05457       }
05458    }
05459    if (myrpt->cmdnode[0])
05460    {
05461       rpt_mutex_unlock(&myrpt->lock);
05462       send_link_dtmf(myrpt,c);
05463       return;
05464    }
05465    if (myrpt->callmode == 1)
05466    {
05467       myrpt->exten[myrpt->cidx++] = c;
05468       myrpt->exten[myrpt->cidx] = 0;
05469       /* if this exists */
05470       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
05471       {
05472          myrpt->callmode = 2;
05473          if(!myrpt->patchquiet){
05474             rpt_mutex_unlock(&myrpt->lock);
05475             rpt_telemetry(myrpt,PROC,NULL); 
05476             rpt_mutex_lock(&myrpt->lock);
05477          }
05478       }
05479       /* if can continue, do so */
05480       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL)) 
05481       {
05482          /* call has failed, inform user */
05483          myrpt->callmode = 4;
05484       }
05485    }
05486    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
05487    {
05488       myrpt->mydtmf = c;
05489    }
05490    if (c == myrpt->p.funcchar)
05491    {
05492       myrpt->rem_dtmfidx = 0;
05493       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
05494       time(&myrpt->rem_dtmf_time);
05495       rpt_mutex_unlock(&myrpt->lock);
05496       return;
05497    } 
05498    else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
05499    {
05500       time(&myrpt->rem_dtmf_time);
05501       if (myrpt->rem_dtmfidx < MAXDTMF)
05502       {
05503          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
05504          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
05505          
05506          rpt_mutex_unlock(&myrpt->lock);
05507          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
05508          switch(mylink->phonemode)
05509          {
05510              case 1:
05511             res = collect_function_digits(myrpt, cmd, 
05512                SOURCE_PHONE, mylink);
05513             break;
05514              case 2:
05515             res = collect_function_digits(myrpt, cmd, 
05516                SOURCE_DPHONE,mylink);
05517             break;
05518              default:
05519             res = collect_function_digits(myrpt, cmd, 
05520                SOURCE_LNK, mylink);
05521             break;
05522          }
05523 
05524          rpt_mutex_lock(&myrpt->lock);
05525          
05526          switch(res){
05527 
05528             case DC_INDETERMINATE:
05529                break;
05530             
05531             case DC_DOKEY:
05532                mylink->lastrx = 1;
05533                break;
05534             
05535             case DC_REQ_FLUSH:
05536                myrpt->rem_dtmfidx = 0;
05537                myrpt->rem_dtmfbuf[0] = 0;
05538                break;
05539             
05540             
05541             case DC_COMPLETE:
05542             case DC_COMPLETEQUIET:
05543                myrpt->totalexecdcommands++;
05544                myrpt->dailyexecdcommands++;
05545                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
05546                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
05547                myrpt->rem_dtmfbuf[0] = 0;
05548                myrpt->rem_dtmfidx = -1;
05549                myrpt->rem_dtmf_time = 0;
05550                break;
05551             
05552             case DC_ERROR:
05553             default:
05554                myrpt->rem_dtmfbuf[0] = 0;
05555                myrpt->rem_dtmfidx = -1;
05556                myrpt->rem_dtmf_time = 0;
05557                break;
05558          }
05559       }
05560 
05561    }
05562    rpt_mutex_unlock(&myrpt->lock);
05563    return;
05564 }
05565 
05566 /* Doug Hall RBI-1 serial data definitions:
05567  *
05568  * Byte 0: Expansion external outputs 
05569  * Byte 1: 
05570  * Bits 0-3 are BAND as follows:
05571  * Bits 4-5 are POWER bits as follows:
05572  *    00 - Low Power
05573  *    01 - Hi Power
05574  *    02 - Med Power
05575  * Bits 6-7 are always set
05576  * Byte 2:
05577  * Bits 0-3 MHZ in BCD format
05578  * Bits 4-5 are offset as follows:
05579  *    00 - minus
05580  *    01 - plus
05581  *    02 - simplex
05582  *    03 - minus minus (whatever that is)
05583  * Bit 6 is the 0/5 KHZ bit
05584  * Bit 7 is always set
05585  * Byte 3:
05586  * Bits 0-3 are 10 KHZ in BCD format
05587  * Bits 4-7 are 100 KHZ in BCD format
05588  * Byte 4: PL Tone code and encode/decode enable bits
05589  * Bits 0-5 are PL tone code (comspec binary codes)
05590  * Bit 6 is encode enable/disable
05591  * Bit 7 is decode enable/disable
05592  */
05593 
05594 /* take the frequency from the 10 mhz digits (and up) and convert it
05595    to a band number */
05596 
05597 static int rbi_mhztoband(char *str)
05598 {
05599 int   i;
05600 
05601    i = atoi(str) / 10; /* get the 10's of mhz */
05602    switch(i)
05603    {
05604        case 2:
05605       return 10;
05606        case 5:
05607       return 11;
05608        case 14:
05609       return 2;
05610        case 22:
05611       return 3;
05612        case 44:
05613       return 4;
05614        case 124:
05615       return 0;
05616        case 125:
05617       return 1;
05618        case 126:
05619       return 8;
05620        case 127:
05621       return 5;
05622        case 128:
05623       return 6;
05624        case 129:
05625       return 7;
05626        default:
05627       break;
05628    }
05629    return -1;
05630 }
05631 
05632 /* take a PL frequency and turn it into a code */
05633 static int rbi_pltocode(char *str)
05634 {
05635 int i;
05636 char *s;
05637 
05638    s = strchr(str,'.');
05639    i = 0;
05640    if (s) i = atoi(s + 1);
05641    i += atoi(str) * 10;
05642    switch(i)
05643    {
05644        case 670:
05645       return 0;
05646        case 719:
05647       return 1;
05648        case 744:
05649       return 2;
05650        case 770:
05651       return 3;
05652        case 797:
05653       return 4;
05654        case 825:
05655       return 5;
05656        case 854:
05657       return 6;
05658        case 885:
05659       return 7;
05660        case 915:
05661       return 8;
05662        case 948:
05663       return 9;
05664        case 974:
05665       return 10;
05666        case 1000:
05667       return 11;
05668        case 1035:
05669       return 12;
05670        case 1072:
05671       return 13;
05672        case 1109:
05673       return 14;
05674        case 1148:
05675       return 15;
05676        case 1188:
05677       return 16;
05678        case 1230:
05679       return 17;
05680        case 1273:
05681       return 18;
05682        case 1318:
05683       return 19;
05684        case 1365:
05685       return 20;
05686        case 1413:
05687       return 21;
05688        case 1462:
05689       return 22;
05690        case 1514:
05691       return 23;
05692        case 1567:
05693       return 24;
05694        case 1622:
05695       return 25;
05696        case 1679:
05697       return 26;
05698        case 1738:
05699       return 27;
05700        case 1799:
05701       return 28;
05702        case 1862:
05703       return 29;
05704        case 1928:
05705       return 30;
05706        case 2035:
05707       return 31;
05708        case 2107:
05709       return 32;
05710        case 2181:
05711       return 33;
05712        case 2257:
05713       return 34;
05714        case 2336:
05715       return 35;
05716        case 2418:
05717       return 36;
05718        case 2503:
05719       return 37;
05720    }
05721    return -1;
05722 }
05723 
05724 /*
05725 * Shift out a formatted serial bit stream
05726 */
05727 
05728 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
05729     {
05730     int i,j;
05731     unsigned char od,d;
05732     static volatile long long delayvar;
05733 
05734     for(i = 0 ; i < 5 ; i++){
05735         od = *data++; 
05736         for(j = 0 ; j < 8 ; j++){
05737             d = od & 1;
05738             outb(d,myrpt->p.iobase);
05739        /* >= 15 us */
05740        for(delayvar = 1; delayvar < 15000; delayvar++); 
05741             od >>= 1;
05742             outb(d | 2,myrpt->p.iobase);
05743        /* >= 30 us */
05744        for(delayvar = 1; delayvar < 30000; delayvar++); 
05745             outb(d,myrpt->p.iobase);
05746        /* >= 10 us */
05747        for(delayvar = 1; delayvar < 10000; delayvar++); 
05748             }
05749         }
05750    /* >= 50 us */
05751         for(delayvar = 1; delayvar < 50000; delayvar++); 
05752     }
05753 
05754 static void rbi_out(struct rpt *myrpt,unsigned char *data)
05755 {
05756 struct zt_radio_param r;
05757 
05758    memset(&r,0,sizeof(struct zt_radio_param));
05759    r.radpar = ZT_RADPAR_REMMODE;
05760    r.data = ZT_RADPAR_REM_RBI1;
05761    /* if setparam ioctl fails, its probably not a pciradio card */
05762    if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
05763    {
05764       rbi_out_parallel(myrpt,data);
05765       return;
05766    }
05767    r.radpar = ZT_RADPAR_REMCOMMAND;
05768    memcpy(&r.data,data,5);
05769    if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
05770    {
05771       ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->rxchannel->name);
05772       return;
05773    }
05774 }
05775 
05776 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, 
05777    unsigned char *rxbuf, int rxmaxbytes, int asciiflag)
05778 {
05779    int i,j,index,oldmode,olddata;
05780    struct zt_radio_param prm;
05781    char c;
05782 
05783    if(debug){
05784       printf("String output was: ");
05785       for(i = 0; i < txbytes; i++)
05786          printf("%02X ", (unsigned char ) txbuf[i]);
05787       printf("\n");
05788    }
05789    if (myrpt->iofd > 0)  /* if to do out a serial port */
05790    {
05791       if (rxmaxbytes && rxbuf) tcflush(myrpt->iofd,TCIFLUSH);     
05792       if (write(myrpt->iofd,txbuf,txbytes) != txbytes) return -1;
05793       if ((!rxmaxbytes) || (rxbuf == NULL)) return(0);
05794       memset(rxbuf,0,rxmaxbytes);
05795       for(i = 0; i < rxmaxbytes; i++)
05796       {
05797          j = read(myrpt->iofd,&c,1);
05798          if (j < 1) return(i);
05799          rxbuf[i] = c;
05800          if (asciiflag & 1)
05801          {
05802             rxbuf[i + 1] = 0;
05803             if (c == '\r') break;
05804          }
05805       }              
05806    if(debug){
05807       printf("String returned was: ");
05808       for(j = 0; j < i; j++)
05809          printf("%02X ", (unsigned char ) rxbuf[j]);
05810       printf("\n");
05811    }
05812       return(i);
05813    }
05814    
05815    prm.radpar = ZT_RADPAR_UIOMODE;
05816    if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_GETPARAM,&prm) == -1) return -1;
05817    oldmode = prm.data;
05818    prm.radpar = ZT_RADPAR_UIODATA;
05819    if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_GETPARAM,&prm) == -1) return -1;
05820    olddata = prm.data;
05821         prm.radpar = ZT_RADPAR_REMMODE;
05822         if (asciiflag & 1)  prm.data = ZT_RADPAR_REM_SERIAL_ASCII;
05823         else prm.data = ZT_RADPAR_REM_SERIAL;
05824    if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
05825    if (asciiflag & 2)
05826    {
05827       i = ZT_ONHOOK;
05828       if (ioctl(myrpt->rxchannel->fds[0],ZT_HOOK,&i) == -1) return -1;
05829       usleep(100000);
05830    }
05831         prm.radpar = ZT_RADPAR_REMCOMMAND;
05832         prm.data = rxmaxbytes;
05833         memcpy(prm.buf,txbuf,txbytes);
05834         prm.index = txbytes;
05835    if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
05836         if (rxbuf)
05837         {
05838                 *rxbuf = 0;
05839                 memcpy(rxbuf,prm.buf,prm.index);
05840         }
05841    index = prm.index;
05842         prm.radpar = ZT_RADPAR_REMMODE;
05843         prm.data = ZT_RADPAR_REM_NONE;
05844    if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
05845    if (asciiflag & 2)
05846    {
05847       i = ZT_OFFHOOK;
05848       if (ioctl(myrpt->rxchannel->fds[0],ZT_HOOK,&i) == -1) return -1;
05849    }
05850    prm.radpar = ZT_RADPAR_UIOMODE;
05851    prm.data = oldmode;
05852    if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
05853    prm.radpar = ZT_RADPAR_UIODATA;
05854    prm.data = olddata;
05855    if (ioctl(myrpt->rxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
05856         return(index);
05857 }
05858 
05859 static int civ_cmd(struct rpt *myrpt,unsigned char *cmd, int cmdlen)
05860 {
05861 unsigned char rxbuf[100];
05862 int   i,rv ;
05863 
05864    rv = serial_remote_io(myrpt,cmd,cmdlen,rxbuf,cmdlen + 6,0);
05865    if (rv == -1) return(-1);
05866    if (rv != (cmdlen + 6)) return(1);
05867    for(i = 0; i < 6; i++)
05868       if (rxbuf[i] != cmd[i]) return(1);
05869    if (rxbuf[cmdlen] != 0xfe) return(1);
05870    if (rxbuf[cmdlen + 1] != 0xfe) return(1);
05871    if (rxbuf[cmdlen + 4] != 0xfb) return(1);
05872    if (rxbuf[cmdlen + 5] != 0xfd) return(1);
05873    return(0);
05874 }
05875 
05876 static int sendkenwood(struct rpt *myrpt,char *txstr, char *rxstr)
05877 {
05878 int   i;
05879 
05880    if (debug) printf("Send to kenwood: %s\n",txstr);
05881    i = serial_remote_io(myrpt, (unsigned char *)txstr, strlen(txstr), 
05882       (unsigned char *)rxstr,RAD_SERIAL_BUFLEN - 1,3);
05883    if (i < 0) return -1;
05884    if ((i > 0) && (rxstr[i - 1] == '\r'))
05885       rxstr[i-- - 1] = 0;
05886    if (debug) printf("Got from kenwood: %s\n",rxstr);
05887    return(i);
05888 }
05889 
05890 /* take a PL frequency and turn it into a code */
05891 static int kenwood_pltocode(char *str)
05892 {
05893 int i;
05894 char *s;
05895 
05896    s = strchr(str,'.');
05897    i = 0;
05898    if (s) i = atoi(s + 1);
05899    i += atoi(str) * 10;
05900    switch(i)
05901    {
05902        case 670:
05903       return 1;
05904        case 719:
05905       return 3;
05906        case 744:
05907       return 4;
05908        case 770:
05909       return 5;
05910        case 797:
05911       return 6;
05912        case 825:
05913       return 7;
05914        case 854:
05915       return 8;
05916        case 885:
05917       return 9;
05918        case 915:
05919       return 10;
05920        case 948:
05921       return 11;
05922        case 974:
05923       return 12;
05924        case 1000:
05925       return 13;
05926        case 1035:
05927       return 14;
05928        case 1072:
05929       return 15;
05930        case 1109:
05931       return 16;
05932        case 1148:
05933       return 17;
05934        case 1188:
05935       return 18;
05936        case 1230:
05937       return 19;
05938        case 1273:
05939       return 20;
05940        case 1318:
05941       return 21;
05942        case 1365:
05943       return 22;
05944        case 1413:
05945       return 23;
05946        case 1462:
05947       return 24;
05948        case 1514:
05949       return 25;
05950        case 1567:
05951       return 26;
05952        case 1622:
05953       return 27;
05954        case 1679:
05955       return 28;
05956        case 1738:
05957       return 29;
05958        case 1799:
05959       return 30;
05960        case 1862:
05961       return 31;
05962        case 1928:
05963       return 32;
05964        case 2035:
05965       return 33;
05966        case 2107:
05967       return 34;
05968        case 2181:
05969       return 35;
05970        case 2257:
05971       return 36;
05972        case 2336:
05973       return 37;
05974        case 2418:
05975       return 38;
05976        case 2503:
05977       return 39;
05978    }
05979    return -1;
05980 }
05981 
05982 static int sendrxkenwood(struct rpt *myrpt, char *txstr, char *rxstr, 
05983    char *cmpstr)
05984 {
05985 int   i,j;
05986 
05987    for(i = 0;i < KENWOOD_RETRIES;i++)
05988    {
05989       j = sendkenwood(myrpt,txstr,rxstr);
05990       if (j < 0) return(j);
05991       if (j == 0) continue;
05992       if (!strncmp(rxstr,cmpstr,strlen(cmpstr))) return(0);
05993    }
05994    return(-1);
05995 }     
05996 
05997 static int setkenwood(struct rpt *myrpt)
05998 {
05999 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
06000 char mhz[MAXREMSTR],offset[20],band,decimals[MAXREMSTR],band1,band2;
06001    
06002 int offsets[] = {0,2,1};
06003 int powers[] = {2,1,0};
06004 
06005    if (sendrxkenwood(myrpt,"VMC 0,0\r",rxstr,"VMC") < 0) return -1;
06006    split_freq(mhz, decimals, myrpt->freq);
06007    if (atoi(mhz) > 400)
06008    {
06009       band = '6';
06010       band1 = '1';
06011       band2 = '5';
06012       strcpy(offset,"005000000");
06013    }
06014    else
06015    {
06016       band = '2';
06017       band1 = '0';
06018       band2 = '2';
06019       strcpy(offset,"000600000");
06020    }
06021    strcpy(freq,"000000");
06022    strncpy(freq,decimals,strlen(decimals));
06023    sprintf(txstr,"VW %c,%05d%s,0,%d,0,%d,%d,,%02d,,%02d,%s\r",
06024       band,atoi(mhz),freq,offsets[(int)myrpt->offset],
06025       (myrpt->txplon != 0),(myrpt->rxplon != 0),
06026       kenwood_pltocode(myrpt->txpl),kenwood_pltocode(myrpt->rxpl),
06027       offset);
06028    if (sendrxkenwood(myrpt,txstr,rxstr,"VW") < 0) return -1;
06029    sprintf(txstr,"RBN %c\r",band2);
06030    if (sendrxkenwood(myrpt,txstr,rxstr,"RBN") < 0) return -1;
06031    sprintf(txstr,"PC %c,%d\r",band1,powers[(int)myrpt->powerlevel]);
06032    if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
06033    return 0;
06034 }
06035 
06036 static int setrbi(struct rpt *myrpt)
06037 {
06038 char tmp[MAXREMSTR] = "",*s;
06039 unsigned char rbicmd[5];
06040 int   band,txoffset = 0,txpower = 0,rxpl;
06041 
06042    /* must be a remote system */
06043    if (!myrpt->remote) return(0);
06044    /* must have rbi hardware */
06045    if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
06046    if (setrbi_check(myrpt) == -1) return(-1);
06047    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
06048    s = strchr(tmp,'.');
06049    /* if no decimal, is invalid */
06050    
06051    if (s == NULL){
06052       if(debug)
06053          printf("@@@@ Frequency needs a decimal\n");
06054       return -1;
06055    }
06056    
06057    *s++ = 0;
06058    if (strlen(tmp) < 2){
06059       if(debug)
06060          printf("@@@@ Bad MHz digits: %s\n", tmp);
06061       return -1;
06062    }
06063     
06064    if (strlen(s) < 3){
06065       if(debug)
06066          printf("@@@@ Bad KHz digits: %s\n", s);
06067       return -1;
06068    }
06069 
06070    if ((s[2] != '0') && (s[2] != '5')){
06071       if(debug)
06072          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
06073       return -1;
06074    }
06075     
06076    band = rbi_mhztoband(tmp);
06077    if (band == -1){
06078       if(debug)
06079          printf("@@@@ Bad Band: %s\n", tmp);
06080       return -1;
06081    }
06082    
06083    rxpl = rbi_pltocode(myrpt->rxpl);
06084    
06085    if (rxpl == -1){
06086       if(debug)
06087          printf("@@@@ Bad TX PL: %s\n", myrpt->rxpl);
06088       return -1;
06089    }
06090 
06091    
06092    switch(myrpt->offset)
06093    {
06094        case REM_MINUS:
06095       txoffset = 0;
06096       break;
06097        case REM_PLUS:
06098       txoffset = 0x10;
06099       break;
06100        case REM_SIMPLEX:
06101       txoffset = 0x20;
06102       break;
06103    }
06104    switch(myrpt->powerlevel)
06105    {
06106        case REM_LOWPWR:
06107       txpower = 0;
06108       break;
06109        case REM_MEDPWR:
06110       txpower = 0x20;
06111       break;
06112        case REM_HIPWR:
06113       txpower = 0x10;
06114       break;
06115    }
06116    rbicmd[0] = 0;
06117    rbicmd[1] = band | txpower | 0xc0;
06118    rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
06119    if (s[2] == '5') rbicmd[2] |= 0x40;
06120    rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
06121    rbicmd[4] = rxpl;
06122    if (myrpt->txplon) rbicmd[4] |= 0x40;
06123    if (myrpt->rxplon) rbicmd[4] |= 0x80;
06124    rbi_out(myrpt,rbicmd);
06125    return 0;
06126 }
06127 
06128 static int setrbi_check(struct rpt *myrpt)
06129 {
06130 char tmp[MAXREMSTR] = "",*s;
06131 int   band,txpl;
06132 
06133    /* must be a remote system */
06134    if (!myrpt->remote) return(0);
06135    /* must have rbi hardware */
06136    if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
06137    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
06138    s = strchr(tmp,'.');
06139    /* if no decimal, is invalid */
06140    
06141    if (s == NULL){
06142       if(debug)
06143          printf("@@@@ Frequency needs a decimal\n");
06144       return -1;
06145    }
06146    
06147    *s++ = 0;
06148    if (strlen(tmp) < 2){
06149       if(debug)
06150          printf("@@@@ Bad MHz digits: %s\n", tmp);
06151       return -1;
06152    }
06153     
06154    if (strlen(s) < 3){
06155       if(debug)
06156          printf("@@@@ Bad KHz digits: %s\n", s);
06157       return -1;
06158    }
06159 
06160    if ((s[2] != '0') && (s[2] != '5')){
06161       if(debug)
06162          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
06163       return -1;
06164    }
06165     
06166    band = rbi_mhztoband(tmp);
06167    if (band == -1){
06168       if(debug)
06169          printf("@@@@ Bad Band: %s\n", tmp);
06170       return -1;
06171    }
06172    
06173    txpl = rbi_pltocode(myrpt->txpl);
06174    
06175    if (txpl == -1){
06176       if(debug)
06177          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
06178       return -1;
06179    }
06180    return 0;
06181 }
06182 
06183 static int check_freq_kenwood(int m, int d, int *defmode)
06184 {
06185    int dflmd = REM_MODE_FM;
06186 
06187    if (m == 144){ /* 2 meters */
06188       if(d < 10100)
06189          return -1;
06190    }
06191    else if((m >= 145) && (m < 148)){
06192       ;
06193    }
06194    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
06195       ;
06196    }
06197    else
06198       return -1;
06199    
06200    if(defmode)
06201       *defmode = dflmd; 
06202 
06203 
06204    return 0;
06205 }
06206 
06207 
06208 /* Check for valid rbi frequency */
06209 /* Hard coded limits now, configurable later, maybe? */
06210 
06211 static int check_freq_rbi(int m, int d, int *defmode)
06212 {
06213    int dflmd = REM_MODE_FM;
06214 
06215    if(m == 50){ /* 6 meters */
06216       if(d < 10100)
06217          return -1;
06218    }
06219    else if((m >= 51) && ( m < 54)){
06220                 ;
06221    }
06222    else if(m == 144){ /* 2 meters */
06223       if(d < 10100)
06224          return -1;
06225    }
06226    else if((m >= 145) && (m < 148)){
06227       ;
06228    }
06229    else if((m >= 222) && (m < 225)){ /* 1.25 meters */
06230       ;
06231    }
06232    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
06233       ;
06234    }
06235    else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
06236       ;
06237    }
06238    else
06239       return -1;
06240    
06241    if(defmode)
06242       *defmode = dflmd; 
06243 
06244 
06245    return 0;
06246 }
06247 
06248 /*
06249  * Convert decimals of frequency to int
06250  */
06251 
06252 static int decimals2int(char *fraction)
06253 {
06254    int i;
06255    char len = strlen(fraction);
06256    int multiplier = 100000;
06257    int res = 0;
06258 
06259    if(!len)
06260       return 0;
06261    for( i = 0 ; i < len ; i++, multiplier /= 10)
06262       res += (fraction[i] - '0') * multiplier;
06263    return res;
06264 }
06265 
06266 
06267 /*
06268 * Split frequency into mhz and decimals
06269 */
06270  
06271 static int split_freq(char *mhz, char *decimals, char *freq)
06272 {
06273    char freq_copy[MAXREMSTR];
06274    char *decp;
06275 
06276    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
06277    if(decp){
06278       *decp++ = 0;
06279       strncpy(mhz, freq_copy, MAXREMSTR);
06280       strcpy(decimals, "00000");
06281       strncpy(decimals, decp, strlen(decp));
06282       decimals[5] = 0;
06283       return 0;
06284    }
06285    else
06286       return -1;
06287 
06288 }
06289    
06290 /*
06291 * Split ctcss frequency into hertz and decimal
06292 */
06293  
06294 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
06295 {
06296    char freq_copy[MAXREMSTR];
06297    char *decp;
06298 
06299    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
06300    if(decp){
06301       *decp++ = 0;
06302       strncpy(hertz, freq_copy, MAXREMSTR);
06303       strncpy(decimal, decp, strlen(decp));
06304       decimal[strlen(decp)] = '\0';
06305       return 0;
06306    }
06307    else
06308       return -1;
06309 }
06310 
06311 
06312 
06313 /*
06314 * FT-897 I/O handlers
06315 */
06316 
06317 /* Check to see that the frequency is valid */
06318 /* Hard coded limits now, configurable later, maybe? */
06319 
06320 
06321 static int check_freq_ft897(int m, int d, int *defmode)
06322 {
06323    int dflmd = REM_MODE_FM;
06324 
06325    if(m == 1){ /* 160 meters */
06326       dflmd =  REM_MODE_LSB; 
06327       if(d < 80000)
06328          return -1;
06329    }
06330    else if(m == 3){ /* 80 meters */
06331       dflmd = REM_MODE_LSB;
06332       if(d < 50000)
06333          return -1;
06334    }
06335    else if(m == 7){ /* 40 meters */
06336       dflmd = REM_MODE_LSB;
06337       if(d > 30000)
06338          return -1;
06339    }
06340    else if(m == 14){ /* 20 meters */
06341       dflmd = REM_MODE_USB;
06342       if(d > 35000)
06343          return -1;
06344    }
06345    else if(m == 18){ /* 17 meters */
06346       dflmd = REM_MODE_USB;
06347       if((d < 6800) || (d > 16800))
06348          return -1;
06349    }
06350    else if(m == 21){ /* 15 meters */
06351       dflmd = REM_MODE_USB;
06352       if((d < 20000) || (d > 45000))
06353          return -1;
06354    }
06355    else if(m == 24){ /* 12 meters */
06356       dflmd = REM_MODE_USB;
06357       if((d < 89000) || (d > 99000))
06358          return -1;
06359    }
06360    else if(m == 28){ /* 10 meters */
06361       dflmd = REM_MODE_USB;
06362    }
06363    else if(m == 29){ 
06364       if(d >= 51000)
06365          dflmd = REM_MODE_FM;
06366       else
06367          dflmd = REM_MODE_USB;
06368       if(d > 70000)
06369          return -1;
06370    }
06371    else if(m == 50){ /* 6 meters */
06372       if(d >= 30000)
06373          dflmd = REM_MODE_FM;
06374       else
06375          dflmd = REM_MODE_USB;
06376 
06377    }
06378    else if((m >= 51) && ( m < 54)){
06379       dflmd = REM_MODE_FM;
06380    }
06381    else if(m == 144){ /* 2 meters */
06382       if(d >= 30000)
06383          dflmd = REM_MODE_FM;
06384       else
06385          dflmd = REM_MODE_USB;
06386    }
06387    else if((m >= 145) && (m < 148)){
06388       dflmd = REM_MODE_FM;
06389    }
06390    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
06391       if(m  < 438)
06392          dflmd = REM_MODE_USB;
06393       else
06394          dflmd = REM_MODE_FM;
06395       ;
06396    }
06397    else
06398       return -1;
06399 
06400    if(defmode)
06401       *defmode = dflmd;
06402 
06403    return 0;
06404 }
06405 
06406 /*
06407 * Set a new frequency for the FT897
06408 */
06409 
06410 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
06411 {
06412    unsigned char cmdstr[5];
06413    int fd,m,d;
06414    char mhz[MAXREMSTR];
06415    char decimals[MAXREMSTR];
06416 
06417    fd = 0;
06418    if(debug) 
06419       printf("New frequency: %s\n",newfreq);
06420 
06421    if(split_freq(mhz, decimals, newfreq))
06422       return -1; 
06423 
06424    m = atoi(mhz);
06425    d = atoi(decimals);
06426 
06427    /* The FT-897 likes packed BCD frequencies */
06428 
06429    cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10);        /* 100MHz 10Mhz */
06430    cmdstr[1] = ((m % 10) << 4) + (d / 10000);         /* 1MHz 100KHz */
06431    cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100);  /* 10KHz 1KHz */
06432    cmdstr[3] = (((d % 100)/10) << 4) + (d % 10);         /* 100Hz 10Hz */
06433    cmdstr[4] = 0x01;                /* command */
06434 
06435    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06436 
06437 }
06438 
06439 /* ft-897 simple commands */
06440 
06441 static int simple_command_ft897(struct rpt *myrpt, char command)
06442 {
06443    unsigned char cmdstr[5];
06444    
06445    memset(cmdstr, 0, 5);
06446 
06447    cmdstr[4] = command; 
06448 
06449    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06450 
06451 }
06452 
06453 /* ft-897 offset */
06454 
06455 static int set_offset_ft897(struct rpt *myrpt, char offset)
06456 {
06457    unsigned char cmdstr[5];
06458    
06459    memset(cmdstr, 0, 5);
06460 
06461    switch(offset){
06462       case  REM_SIMPLEX:
06463          cmdstr[0] = 0x89;
06464          break;
06465 
06466       case  REM_MINUS:
06467          cmdstr[0] = 0x09;
06468          break;
06469       
06470       case  REM_PLUS:
06471          cmdstr[0] = 0x49;
06472          break;   
06473 
06474       default:
06475          return -1;
06476    }
06477 
06478    cmdstr[4] = 0x09; 
06479 
06480    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06481 }
06482 
06483 /* ft-897 mode */
06484 
06485 static int set_mode_ft897(struct rpt *myrpt, char newmode)
06486 {
06487    unsigned char cmdstr[5];
06488    
06489    memset(cmdstr, 0, 5);
06490    
06491    switch(newmode){
06492       case  REM_MODE_FM:
06493          cmdstr[0] = 0x08;
06494          break;
06495 
06496       case  REM_MODE_USB:
06497          cmdstr[0] = 0x01;
06498          break;
06499 
06500       case  REM_MODE_LSB:
06501          cmdstr[0] = 0x00;
06502          break;
06503 
06504       case  REM_MODE_AM:
06505          cmdstr[0] = 0x04;
06506          break;
06507       
06508       default:
06509          return -1;
06510    }
06511    cmdstr[4] = 0x07; 
06512 
06513    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06514 }
06515 
06516 /* Set tone encode and decode modes */
06517 
06518 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
06519 {
06520    unsigned char cmdstr[5];
06521    
06522    memset(cmdstr, 0, 5);
06523    
06524    if(rxplon && txplon)
06525       cmdstr[0] = 0x2A; /* Encode and Decode */
06526    else if (!rxplon && txplon)
06527       cmdstr[0] = 0x4A; /* Encode only */
06528    else if (rxplon && !txplon)
06529       cmdstr[0] = 0x3A; /* Encode only */
06530    else
06531       cmdstr[0] = 0x8A; /* OFF */
06532 
06533    cmdstr[4] = 0x0A; 
06534 
06535    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06536 }
06537 
06538 
06539 /* Set transmit and receive ctcss tone frequencies */
06540 
06541 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
06542 {
06543    unsigned char cmdstr[5];
06544    char hertz[MAXREMSTR],decimal[MAXREMSTR];
06545    int h,d; 
06546 
06547    memset(cmdstr, 0, 5);
06548 
06549    if(split_ctcss_freq(hertz, decimal, txtone))
06550       return -1; 
06551 
06552    h = atoi(hertz);
06553    d = atoi(decimal);
06554    
06555    cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
06556    cmdstr[1] = ((h % 10) << 4) + (d % 10);
06557    
06558    if(rxtone){
06559    
06560       if(split_ctcss_freq(hertz, decimal, rxtone))
06561          return -1; 
06562 
06563       h = atoi(hertz);
06564       d = atoi(decimal);
06565    
06566       cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
06567       cmdstr[3] = ((h % 10) << 4) + (d % 10);
06568    }
06569    cmdstr[4] = 0x0B; 
06570 
06571    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06572 }  
06573 
06574 
06575 
06576 static int set_ft897(struct rpt *myrpt)
06577 {
06578    int res;
06579    
06580    if(debug)
06581       printf("@@@@ lock on\n");
06582 
06583    res = simple_command_ft897(myrpt, 0x00);  /* LOCK on */  
06584 
06585    if(debug)
06586       printf("@@@@ ptt off\n");
06587 
06588    if(!res)
06589       res = simple_command_ft897(myrpt, 0x88);     /* PTT off */
06590 
06591    if(debug)
06592       printf("Modulation mode\n");
06593 
06594    if(!res)
06595       res = set_mode_ft897(myrpt, myrpt->remmode);    /* Modulation mode */
06596 
06597    if(debug)
06598       printf("Split off\n");
06599 
06600    if(!res)
06601       simple_command_ft897(myrpt, 0x82);        /* Split off */
06602 
06603    if(debug)
06604       printf("Frequency\n");
06605 
06606    if(!res)
06607       res = set_freq_ft897(myrpt, myrpt->freq);    /* Frequency */
06608    if((myrpt->remmode == REM_MODE_FM)){
06609       if(debug)
06610          printf("Offset\n");
06611       if(!res)
06612          res = set_offset_ft897(myrpt, myrpt->offset);   /* Offset if FM */
06613       if((!res)&&(myrpt->rxplon || myrpt->txplon)){
06614          if(debug)
06615             printf("CTCSS tone freqs.\n");
06616          res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
06617       }
06618       if(!res){
06619          if(debug)
06620             printf("CTCSS mode\n");
06621          res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
06622       }
06623    }
06624    if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
06625       if(debug)
06626          printf("Clarifier off\n");
06627       simple_command_ft897(myrpt, 0x85);        /* Clarifier off if LSB or USB */
06628    }
06629    return res;
06630 }
06631 
06632 static int closerem_ft897(struct rpt *myrpt)
06633 {
06634    simple_command_ft897(myrpt, 0x88); /* PTT off */
06635    return 0;
06636 }  
06637 
06638 /*
06639 * Bump frequency up or down by a small amount 
06640 * Return 0 if the new frequnecy is valid, or -1 if invalid
06641 * Interval is in Hz, resolution is 10Hz 
06642 */
06643 
06644 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
06645 {
06646    int m,d;
06647    char mhz[MAXREMSTR], decimals[MAXREMSTR];
06648 
06649    if(debug)
06650       printf("Before bump: %s\n", myrpt->freq);
06651 
06652    if(split_freq(mhz, decimals, myrpt->freq))
06653       return -1;
06654    
06655    m = atoi(mhz);
06656    d = atoi(decimals);
06657 
06658    d += (interval / 10); /* 10Hz resolution */
06659    if(d < 0){
06660       m--;
06661       d += 100000;
06662    }
06663    else if(d >= 100000){
06664       m++;
06665       d -= 100000;
06666    }
06667 
06668    if(check_freq_ft897(m, d, NULL)){
06669       if(debug)
06670          printf("Bump freq invalid\n");
06671       return -1;
06672    }
06673 
06674    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
06675 
06676    if(debug)
06677       printf("After bump: %s\n", myrpt->freq);
06678 
06679    return set_freq_ft897(myrpt, myrpt->freq);   
06680 }
06681 
06682 
06683 
06684 /*
06685 * IC-706 I/O handlers
06686 */
06687 
06688 /* Check to see that the frequency is valid */
06689 /* Hard coded limits now, configurable later, maybe? */
06690 
06691 
06692 static int check_freq_ic706(int m, int d, int *defmode)
06693 {
06694    int dflmd = REM_MODE_FM;
06695 
06696    if(m == 1){ /* 160 meters */
06697       dflmd =  REM_MODE_LSB; 
06698       if(d < 80000)
06699          return -1;
06700    }
06701    else if(m == 3){ /* 80 meters */
06702       dflmd = REM_MODE_LSB;
06703       if(d < 50000)
06704          return -1;
06705    }
06706    else if(m == 7){ /* 40 meters */
06707       dflmd = REM_MODE_LSB;
06708       if(d > 30000)
06709          return -1;
06710    }
06711    else if(m == 14){ /* 20 meters */
06712       dflmd = REM_MODE_USB;
06713       if(d > 35000)
06714          return -1;
06715    }
06716    else if(m == 18){ /* 17 meters */
06717       dflmd = REM_MODE_USB;
06718       if((d < 6800) || (d > 16800))
06719          return -1;
06720    }
06721    else if(m == 21){ /* 15 meters */
06722       dflmd = REM_MODE_USB;
06723       if((d < 20000) || (d > 45000))
06724          return -1;
06725    }
06726    else if(m == 24){ /* 12 meters */
06727       dflmd = REM_MODE_USB;
06728       if((d < 89000) || (d > 99000))
06729          return -1;
06730    }
06731    else if(m == 28){ /* 10 meters */
06732       dflmd = REM_MODE_USB;
06733    }
06734    else if(m == 29){ 
06735       if(d >= 51000)
06736          dflmd = REM_MODE_FM;
06737       else
06738          dflmd = REM_MODE_USB;
06739       if(d > 70000)
06740          return -1;
06741    }
06742    else if(m == 50){ /* 6 meters */
06743       if(d >= 30000)
06744          dflmd = REM_MODE_FM;
06745       else
06746          dflmd = REM_MODE_USB;
06747 
06748    }
06749    else if((m >= 51) && ( m < 54)){
06750       dflmd = REM_MODE_FM;
06751    }
06752    else if(m == 144){ /* 2 meters */
06753       if(d >= 30000)
06754          dflmd = REM_MODE_FM;
06755       else
06756          dflmd = REM_MODE_USB;
06757    }
06758    else if((m >= 145) && (m < 148)){
06759       dflmd = REM_MODE_FM;
06760    }
06761    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
06762       if(m  < 438)
06763          dflmd = REM_MODE_USB;
06764       else
06765          dflmd = REM_MODE_FM;
06766       ;
06767    }
06768    else
06769       return -1;
06770 
06771    if(defmode)
06772       *defmode = dflmd;
06773 
06774    return 0;
06775 }
06776 
06777 /* take a PL frequency and turn it into a code */
06778 static int ic706_pltocode(char *str)
06779 {
06780 int i;
06781 char *s;
06782 
06783    s = strchr(str,'.');
06784    i = 0;
06785    if (s) i = atoi(s + 1);
06786    i += atoi(str) * 10;
06787    switch(i)
06788    {
06789        case 670:
06790       return 0;
06791        case 693:
06792       return 1;
06793        case 719:
06794       return 2;
06795        case 744:
06796       return 3;
06797        case 770:
06798       return 4;
06799        case 797:
06800       return 5;
06801        case 825:
06802       return 6;
06803        case 854:
06804       return 7;
06805        case 885:
06806       return 8;
06807        case 915:
06808       return 9;
06809        case 948:
06810       return 10;
06811        case 974:
06812       return 11;
06813        case 1000:
06814       return 12;
06815        case 1035:
06816       return 13;
06817        case 1072:
06818       return 14;
06819        case 1109:
06820       return 15;
06821        case 1148:
06822       return 16;
06823        case 1188:
06824       return 17;
06825        case 1230:
06826       return 18;
06827        case 1273:
06828       return 19;
06829        case 1318:
06830       return 20;
06831        case 1365:
06832       return 21;
06833        case 1413:
06834       return 22;
06835        case 1462:
06836       return 23;
06837        case 1514:
06838       return 24;
06839        case 1567:
06840       return 25;
06841        case 1598:
06842       return 26;
06843        case 1622:
06844       return 27;
06845        case 1655:
06846       return 28;     
06847        case 1679:
06848       return 29;
06849        case 1713:
06850       return 30;
06851        case 1738:
06852       return 31;
06853        case 1773:
06854       return 32;
06855        case 1799:
06856       return 33;
06857             case 1835:
06858       return 34;
06859        case 1862:
06860       return 35;
06861        case 1899:
06862       return 36;
06863        case 1928:
06864       return 37;
06865        case 1966:
06866       return 38;
06867        case 1995:
06868       return 39;
06869        case 2035:
06870       return 40;
06871        case 2065:
06872       return 41;
06873        case 2107:
06874       return 42;
06875        case 2181:
06876       return 43;
06877        case 2257:
06878       return 44;
06879        case 2291:
06880       return 45;
06881        case 2336:
06882       return 46;
06883        case 2418:
06884       return 47;
06885        case 2503:
06886       return 48;
06887        case 2541:
06888       return 49;
06889    }
06890    return -1;
06891 }
06892 
06893 /* ic-706 simple commands */
06894 
06895 static int simple_command_ic706(struct rpt *myrpt, char command, char subcommand)
06896 {
06897    unsigned char cmdstr[10];
06898    
06899    cmdstr[0] = cmdstr[1] = 0xfe;
06900    cmdstr[2] = myrpt->p.civaddr;
06901    cmdstr[3] = 0xe0;
06902    cmdstr[4] = command;
06903    cmdstr[5] = subcommand;
06904    cmdstr[6] = 0xfd;
06905 
06906    return(civ_cmd(myrpt,cmdstr,7));
06907 }
06908 
06909 /*
06910 * Set a new frequency for the ic706
06911 */
06912 
06913 static int set_freq_ic706(struct rpt *myrpt, char *newfreq)
06914 {
06915    unsigned char cmdstr[20];
06916    char mhz[MAXREMSTR], decimals[MAXREMSTR];
06917    int fd,m,d;
06918 
06919    fd = 0;
06920    if(debug) 
06921       printf("New frequency: %s\n",newfreq);
06922 
06923    if(split_freq(mhz, decimals, newfreq))
06924       return -1; 
06925 
06926    m = atoi(mhz);
06927    d = atoi(decimals);
06928 
06929    /* The ic-706 likes packed BCD frequencies */
06930 
06931    cmdstr[0] = cmdstr[1] = 0xfe;
06932    cmdstr[2] = myrpt->p.civaddr;
06933    cmdstr[3] = 0xe0;
06934    cmdstr[4] = 5;
06935    cmdstr[5] = ((d % 10) << 4);
06936    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
06937    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
06938    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
06939    cmdstr[9] = (m / 100);
06940    cmdstr[10] = 0xfd;
06941 
06942    return(civ_cmd(myrpt,cmdstr,11));
06943 }
06944 
06945 /* ic-706 offset */
06946 
06947 static int set_offset_ic706(struct rpt *myrpt, char offset)
06948 {
06949    unsigned char c;
06950 
06951    switch(offset){
06952       case  REM_SIMPLEX:
06953          c = 0x10;
06954          break;
06955 
06956       case  REM_MINUS:
06957          c = 0x11;
06958          break;
06959       
06960       case  REM_PLUS:
06961          c = 0x12;
06962          break;   
06963 
06964       default:
06965          return -1;
06966    }
06967 
06968    return simple_command_ic706(myrpt,0x0f,c);
06969 
06970 }
06971 
06972 /* ic-706 mode */
06973 
06974 static int set_mode_ic706(struct rpt *myrpt, char newmode)
06975 {
06976    unsigned char c;
06977    
06978    switch(newmode){
06979       case  REM_MODE_FM:
06980          c = 5;
06981          break;
06982 
06983       case  REM_MODE_USB:
06984          c = 1;
06985          break;
06986 
06987       case  REM_MODE_LSB:
06988          c = 0;
06989          break;
06990 
06991       case  REM_MODE_AM:
06992          c = 2;
06993          break;
06994       
06995       default:
06996          return -1;
06997    }
06998    return simple_command_ic706(myrpt,6,c);
06999 }
07000 
07001 /* Set tone encode and decode modes */
07002 
07003 static int set_ctcss_mode_ic706(struct rpt *myrpt, char txplon, char rxplon)
07004 {
07005    unsigned char cmdstr[10];
07006    int rv;
07007 
07008    cmdstr[0] = cmdstr[1] = 0xfe;
07009    cmdstr[2] = myrpt->p.civaddr;
07010    cmdstr[3] = 0xe0;
07011    cmdstr[4] = 0x16;
07012    cmdstr[5] = 0x42;
07013    cmdstr[6] = (txplon != 0);
07014    cmdstr[7] = 0xfd;
07015 
07016    rv = civ_cmd(myrpt,cmdstr,8);
07017    if (rv) return(-1);
07018 
07019    cmdstr[0] = cmdstr[1] = 0xfe;
07020    cmdstr[2] = myrpt->p.civaddr;
07021    cmdstr[3] = 0xe0;
07022    cmdstr[4] = 0x16;
07023    cmdstr[5] = 0x43;
07024    cmdstr[6] = (rxplon != 0);
07025    cmdstr[7] = 0xfd;
07026 
07027    return(civ_cmd(myrpt,cmdstr,8));
07028 }
07029 
07030 #if 0
07031 /* Set transmit and receive ctcss tone frequencies */
07032 
07033 static int set_ctcss_freq_ic706(struct rpt *myrpt, char *txtone, char *rxtone)
07034 {
07035    unsigned char cmdstr[10];
07036    char hertz[MAXREMSTR],decimal[MAXREMSTR];
07037    int h,d,rv;
07038 
07039    memset(cmdstr, 0, 5);
07040 
07041    if(split_ctcss_freq(hertz, decimal, txtone))
07042       return -1; 
07043 
07044    h = atoi(hertz);
07045    d = atoi(decimal);
07046    
07047    cmdstr[0] = cmdstr[1] = 0xfe;
07048    cmdstr[2] = myrpt->p.civaddr;
07049    cmdstr[3] = 0xe0;
07050    cmdstr[4] = 0x1b;
07051    cmdstr[5] = 0;
07052    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
07053    cmdstr[7] = ((h % 10) << 4) + (d % 10);
07054    cmdstr[8] = 0xfd;
07055 
07056    rv = civ_cmd(myrpt,cmdstr,9);
07057    if (rv) return(-1);
07058 
07059    if (!rxtone) return(0);
07060 
07061    if(split_ctcss_freq(hertz, decimal, rxtone))
07062       return -1; 
07063 
07064    h = atoi(hertz);
07065    d = atoi(decimal);
07066 
07067    cmdstr[0] = cmdstr[1] = 0xfe;
07068    cmdstr[2] = myrpt->p.civaddr;
07069    cmdstr[3] = 0xe0;
07070    cmdstr[4] = 0x1b;
07071    cmdstr[5] = 1;
07072    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
07073    cmdstr[7] = ((h % 10) << 4) + (d % 10);
07074    cmdstr[8] = 0xfd;
07075    return(civ_cmd(myrpt,cmdstr,9));
07076 }  
07077 #endif
07078 
07079 static int vfo_ic706(struct rpt *myrpt)
07080 {
07081    unsigned char cmdstr[10];
07082    
07083    cmdstr[0] = cmdstr[1] = 0xfe;
07084    cmdstr[2] = myrpt->p.civaddr;
07085    cmdstr[3] = 0xe0;
07086    cmdstr[4] = 7;
07087    cmdstr[5] = 0xfd;
07088 
07089    return(civ_cmd(myrpt,cmdstr,6));
07090 }
07091 
07092 static int mem2vfo_ic706(struct rpt *myrpt)
07093 {
07094    unsigned char cmdstr[10];
07095    
07096    cmdstr[0] = cmdstr[1] = 0xfe;
07097    cmdstr[2] = myrpt->p.civaddr;
07098    cmdstr[3] = 0xe0;
07099    cmdstr[4] = 0x0a;
07100    cmdstr[5] = 0xfd;
07101 
07102    return(civ_cmd(myrpt,cmdstr,6));
07103 }
07104 
07105 static int select_mem_ic706(struct rpt *myrpt, int slot)
07106 {
07107    unsigned char cmdstr[10];
07108    
07109    cmdstr[0] = cmdstr[1] = 0xfe;
07110    cmdstr[2] = myrpt->p.civaddr;
07111    cmdstr[3] = 0xe0;
07112    cmdstr[4] = 8;
07113    cmdstr[5] = 0;
07114    cmdstr[6] = ((slot / 10) << 4) + (slot % 10);
07115    cmdstr[7] = 0xfd;
07116 
07117    return(civ_cmd(myrpt,cmdstr,8));
07118 }
07119 
07120 static int set_ic706(struct rpt *myrpt)
07121 {
07122    int res = 0,i;
07123    
07124    if(debug)
07125       printf("Set to VFO A\n");
07126 
07127    if (!res)
07128       res = simple_command_ic706(myrpt,7,0);
07129 
07130 
07131    if((myrpt->remmode == REM_MODE_FM))
07132    {
07133       i = ic706_pltocode(myrpt->rxpl);
07134       if (i == -1) return -1;
07135       if(debug)
07136          printf("Select memory number\n");
07137       if (!res)
07138          res = select_mem_ic706(myrpt,i + IC706_PL_MEMORY_OFFSET);
07139       if(debug)
07140          printf("Transfer memory to VFO\n");
07141       if (!res)
07142          res = mem2vfo_ic706(myrpt);
07143    }
07144       
07145    if(debug)
07146       printf("Set to VFO\n");
07147 
07148    if (!res)
07149       res = vfo_ic706(myrpt);
07150 
07151    if(debug)
07152       printf("Modulation mode\n");
07153 
07154    if (!res)
07155       res = set_mode_ic706(myrpt, myrpt->remmode);    /* Modulation mode */
07156 
07157    if(debug)
07158       printf("Split off\n");
07159 
07160    if(!res)
07161       simple_command_ic706(myrpt, 0x82,0);         /* Split off */
07162 
07163    if(debug)
07164       printf("Frequency\n");
07165 
07166    if(!res)
07167       res = set_freq_ic706(myrpt, myrpt->freq);    /* Frequency */
07168    if((myrpt->remmode == REM_MODE_FM)){
07169       if(debug)
07170          printf("Offset\n");
07171       if(!res)
07172          res = set_offset_ic706(myrpt, myrpt->offset);   /* Offset if FM */
07173       if(!res){
07174          if(debug)
07175             printf("CTCSS mode\n");
07176          res = set_ctcss_mode_ic706(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
07177       }
07178    }
07179    return res;
07180 }
07181 
07182 /*
07183 * Bump frequency up or down by a small amount 
07184 * Return 0 if the new frequnecy is valid, or -1 if invalid
07185 * Interval is in Hz, resolution is 10Hz 
07186 */
07187 
07188 static int multimode_bump_freq_ic706(struct rpt *myrpt, int interval)
07189 {
07190    int m,d;
07191    char mhz[MAXREMSTR], decimals[MAXREMSTR];
07192    unsigned char cmdstr[20];
07193 
07194    if(debug)
07195       printf("Before bump: %s\n", myrpt->freq);
07196 
07197    if(split_freq(mhz, decimals, myrpt->freq))
07198       return -1;
07199    
07200    m = atoi(mhz);
07201    d = atoi(decimals);
07202 
07203    d += (interval / 10); /* 10Hz resolution */
07204    if(d < 0){
07205       m--;
07206       d += 100000;
07207    }
07208    else if(d >= 100000){
07209       m++;
07210       d -= 100000;
07211    }
07212 
07213    if(check_freq_ic706(m, d, NULL)){
07214       if(debug)
07215          printf("Bump freq invalid\n");
07216       return -1;
07217    }
07218 
07219    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
07220 
07221    if(debug)
07222       printf("After bump: %s\n", myrpt->freq);
07223 
07224    /* The ic-706 likes packed BCD frequencies */
07225 
07226    cmdstr[0] = cmdstr[1] = 0xfe;
07227    cmdstr[2] = myrpt->p.civaddr;
07228    cmdstr[3] = 0xe0;
07229    cmdstr[4] = 0;
07230    cmdstr[5] = ((d % 10) << 4);
07231    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
07232    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
07233    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
07234    cmdstr[9] = (m / 100);
07235    cmdstr[10] = 0xfd;
07236 
07237    return(serial_remote_io(myrpt,cmdstr,11,NULL,0,0));
07238 }
07239 
07240 
07241 
07242 /*
07243 * Dispatch to correct I/O handler 
07244 */
07245 
07246 static int setrem(struct rpt *myrpt)
07247 {
07248 char  str[300];
07249 char  *offsets[] = {"MINUS","SIMPLEX","PLUS"};
07250 char  *powerlevels[] = {"LOW","MEDIUM","HIGH"};
07251 char  *modes[] = {"FM","USB","LSB","AM"};
07252 int   res = -1;
07253 
07254    if (myrpt->p.archivedir)
07255    {
07256       sprintf(str,"FREQ,%s,%s,%s,%s,%s,%s,%d,%d",myrpt->freq,
07257          modes[(int)myrpt->remmode],
07258          myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
07259          powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
07260          myrpt->rxplon);
07261       donodelog(myrpt,str);
07262    }
07263    if(!strcmp(myrpt->remote, remote_rig_ft897))
07264    {
07265       rpt_telemetry(myrpt,SETREMOTE,NULL);
07266       res = 0;
07267    }
07268    if(!strcmp(myrpt->remote, remote_rig_ic706))
07269    {
07270       rpt_telemetry(myrpt,SETREMOTE,NULL);
07271       res = 0;
07272    }
07273    else if(!strcmp(myrpt->remote, remote_rig_rbi))
07274    {
07275       res = setrbi_check(myrpt);
07276       if (!res)
07277       {
07278          rpt_telemetry(myrpt,SETREMOTE,NULL);
07279          res = 0;
07280       }
07281    }
07282    else if(!strcmp(myrpt->remote, remote_rig_kenwood)) {
07283       rpt_telemetry(myrpt,SETREMOTE,NULL);
07284       res = 0;
07285    }
07286    else
07287       res = 0;
07288 
07289    if (res < 0) ast_log(LOG_ERROR,"Unable to send remote command on node %s\n",myrpt->name);
07290 
07291    return res;
07292 }
07293 
07294 static int closerem(struct rpt *myrpt)
07295 {
07296    if(!strcmp(myrpt->remote, remote_rig_ft897))
07297       return closerem_ft897(myrpt);
07298    else
07299       return 0;
07300 }
07301 
07302 /*
07303 * Dispatch to correct RX frequency checker
07304 */
07305 
07306 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
07307 {
07308    if(!strcmp(myrpt->remote, remote_rig_ft897))
07309       return check_freq_ft897(m, d, defmode);
07310    else if(!strcmp(myrpt->remote, remote_rig_ic706))
07311       return check_freq_ic706(m, d, defmode);
07312    else if(!strcmp(myrpt->remote, remote_rig_rbi))
07313       return check_freq_rbi(m, d, defmode);
07314    else if(!strcmp(myrpt->remote, remote_rig_kenwood))
07315       return check_freq_kenwood(m, d, defmode);
07316    else
07317       return -1;
07318 }
07319 
07320 /*
07321  * Check TX frequency before transmitting
07322  */
07323 
07324 static char check_tx_freq(struct rpt *myrpt)
07325 {
07326    int i;
07327    int radio_mhz, radio_decimals, ulimit_mhz, ulimit_decimals, llimit_mhz, llimit_decimals;
07328    char radio_mhz_char[MAXREMSTR];
07329    char radio_decimals_char[MAXREMSTR];
07330    char limit_mhz_char[MAXREMSTR];
07331    char limit_decimals_char[MAXREMSTR];
07332    char limits[256];
07333    char *limit_ranges[40];
07334    struct ast_variable *limitlist;
07335    
07336 
07337    /* Must have user logged in and tx_limits defined */
07338 
07339    if(!myrpt->p.txlimitsstanzaname || !myrpt->loginuser[0] || !myrpt->loginlevel[0]){
07340       if(debug > 3){
07341          ast_log(LOG_NOTICE, "No tx band table defined, or no user logged in\n");
07342       }
07343       return 1; /* Assume it's ok otherwise */
07344    }
07345 
07346    /* Retrieve the band table for the loginlevel */
07347    limitlist = ast_variable_browse(myrpt->cfg, myrpt->p.txlimitsstanzaname);
07348 
07349    if(!limitlist){
07350       ast_log(LOG_WARNING, "No entries in %s band table stanza\n", myrpt->p.txlimitsstanzaname);
07351       return 0;
07352    }
07353 
07354    split_freq(radio_mhz_char, radio_decimals_char, myrpt->freq);
07355    radio_mhz = atoi(radio_mhz_char);
07356    radio_decimals = decimals2int(radio_decimals_char);
07357 
07358 
07359    if(debug > 3){
07360       ast_log(LOG_NOTICE, "Login User = %s, login level = %s\n", myrpt->loginuser, myrpt->loginlevel);
07361    }
07362 
07363    /* Find our entry */
07364 
07365    for(;limitlist; limitlist=limitlist->next){
07366       if(!strcmp(limitlist->name, myrpt->loginlevel))
07367          break;
07368    }
07369 
07370    if(!limitlist){
07371       ast_log(LOG_WARNING, "Can't find %s entry in band table stanza %s\n", myrpt->loginlevel, myrpt->p.txlimitsstanzaname);
07372       return 0;
07373    }
07374    
07375    if(debug > 3){
07376       ast_log(LOG_NOTICE, "Auth %s = %s\n", limitlist->name, limitlist->value);
07377    }
07378 
07379    /* Parse the limits */
07380 
07381    strncpy(limits, limitlist->value, 256);
07382    limits[255] = 0;
07383    finddelim(limits, limit_ranges, 40);
07384    for(i = 0; i < 40 && limit_ranges[i] ; i++){
07385       char range[40];
07386       char *r,*s;
07387       strncpy(range, limit_ranges[i], 40);
07388       range[39] = 0;
07389                 if(debug > 3){
07390          ast_log(LOG_NOTICE, "Checking to see if %s is within limits of %s\n", myrpt->freq, range);
07391                 }        
07392    
07393       r = strchr(range, '-');
07394       if(!r){
07395          ast_log(LOG_WARNING, "Malformed range in %s tx band table entry\n", limitlist->name);
07396          return 0;
07397       }
07398       *r++ = 0;
07399       s = eatwhite(range);
07400       r = eatwhite(r);
07401       split_freq(limit_mhz_char, limit_decimals_char, s);
07402       llimit_mhz = atoi(limit_mhz_char);
07403       llimit_decimals = decimals2int(limit_decimals_char);
07404       split_freq(limit_mhz_char, limit_decimals_char, r);
07405       ulimit_mhz = atoi(limit_mhz_char);
07406       ulimit_decimals = decimals2int(limit_decimals_char);
07407          
07408       if((radio_mhz >= llimit_mhz) && (radio_mhz <= ulimit_mhz)){
07409          if(radio_mhz == llimit_mhz){ /* CASE 1: TX freq is in llimit mhz portion of band */
07410             if(radio_decimals >= llimit_decimals){ /* Cannot be below llimit decimals */
07411                if(llimit_mhz == ulimit_mhz){ /* If bandwidth < 1Mhz, check ulimit decimals */
07412                   if(radio_decimals <= ulimit_decimals){
07413                      return 1;
07414                   }
07415                   else{
07416                      if(debug > 3)
07417                         ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 1\n");
07418                      return 0;
07419                   }
07420                }
07421                else{
07422                   return 1;
07423                }
07424             }
07425             else{ /* Is below llimit decimals */
07426                if(debug > 3)
07427                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 2\n");
07428                return 0;
07429             }
07430          }
07431          else if(radio_mhz == ulimit_mhz){ /* CASE 2: TX freq not in llimit mhz portion of band */
07432             if(radio_decimals <= ulimit_decimals){
07433                return 1;
07434             }
07435             else{ /* Is above ulimit decimals */
07436                if(debug > 3)
07437                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 3\n");
07438                return 0;
07439             }
07440          }
07441          else /* CASE 3: TX freq within a multi-Mhz band and ok */
07442             return 1; 
07443       }
07444    }
07445    if(debug > 3) /* No match found in TX band table */
07446       ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 4\n");
07447    return 0;
07448 }
07449 
07450 
07451 /*
07452 * Dispatch to correct frequency bumping function
07453 */
07454 
07455 static int multimode_bump_freq(struct rpt *myrpt, int interval)
07456 {
07457    if(!strcmp(myrpt->remote, remote_rig_ft897))
07458       return multimode_bump_freq_ft897(myrpt, interval);
07459    else if(!strcmp(myrpt->remote, remote_rig_ic706))
07460       return multimode_bump_freq_ic706(myrpt, interval);
07461    else
07462       return -1;
07463 }
07464 
07465 
07466 /*
07467 * Queue announcment that scan has been stopped 
07468 */
07469 
07470 static void stop_scan(struct rpt *myrpt)
07471 {
07472    myrpt->hfscanstop = 1;
07473    rpt_telemetry(myrpt,SCAN,0);
07474 }
07475 
07476 /*
07477 * This is called periodically when in scan mode
07478 */
07479 
07480 
07481 static int service_scan(struct rpt *myrpt)
07482 {
07483    int res, interval;
07484    char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
07485 
07486    switch(myrpt->hfscanmode){
07487 
07488       case HF_SCAN_DOWN_SLOW:
07489          interval = -10; /* 100Hz /sec */
07490          break;
07491 
07492       case HF_SCAN_DOWN_QUICK:
07493          interval = -50; /* 500Hz /sec */
07494          break;
07495 
07496       case HF_SCAN_DOWN_FAST:
07497          interval = -200; /* 2KHz /sec */
07498          break;
07499 
07500       case HF_SCAN_UP_SLOW:
07501          interval = 10; /* 100Hz /sec */
07502          break;
07503 
07504       case HF_SCAN_UP_QUICK:
07505          interval = 50; /* 500 Hz/sec */
07506          break;
07507 
07508       case HF_SCAN_UP_FAST:
07509          interval = 200; /* 2KHz /sec */
07510          break;
07511 
07512       default:
07513          myrpt->hfscanmode = 0; /* Huh? */
07514          return -1;
07515    }
07516 
07517    res = split_freq(mhz, decimals, myrpt->freq);
07518       
07519    if(!res){
07520       k100 =decimals[0];
07521       k10 = decimals[1];
07522       res = multimode_bump_freq(myrpt, interval);
07523    }
07524 
07525    if(!res)
07526       res = split_freq(mhz, decimals, myrpt->freq);
07527 
07528 
07529    if(res){
07530       myrpt->hfscanmode = 0;
07531       myrpt->hfscanstatus = -2;
07532       return -1;
07533    }
07534 
07535    /* Announce 10KHz boundaries */
07536    if(k10 != decimals[1]){
07537       int myhund = (interval < 0) ? k100 : decimals[0];
07538       int myten = (interval < 0) ? k10 : decimals[1];
07539       myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
07540    } else myrpt->hfscanstatus = 0;
07541    return res;
07542 
07543 }
07544 
07545 /*
07546  * Retrieve a memory channel
07547  * Return 0 if sucessful,
07548  * -1 if channel not found,
07549  *  1 if parse error
07550  */
07551 
07552 static int retreive_memory(struct rpt *myrpt, char *memory)
07553 {
07554    char tmp[30], *s, *s1, *val;
07555 
07556    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, memory);
07557    if (!val){
07558       return -1;
07559    }        
07560    strncpy(tmp,val,sizeof(tmp) - 1);
07561    tmp[sizeof(tmp)-1] = 0;
07562 
07563    s = strchr(tmp,',');
07564    if (!s)
07565       return 1; 
07566    *s++ = 0;
07567    s1 = strchr(s,',');
07568    if (!s1)
07569       return 1;
07570    *s1++ = 0;
07571    strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
07572    strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
07573    strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
07574    myrpt->remmode = REM_MODE_FM;
07575    myrpt->offset = REM_SIMPLEX;
07576    myrpt->powerlevel = REM_MEDPWR;
07577    myrpt->txplon = myrpt->rxplon = 0;
07578    while(*s1){
07579       switch(*s1++){
07580          case 'A':
07581          case 'a':
07582             strcpy(myrpt->rxpl, "100.0");
07583             strcpy(myrpt->txpl, "100.0");
07584             myrpt->remmode = REM_MODE_AM; 
07585             break;
07586          case 'B':
07587          case 'b':
07588             strcpy(myrpt->rxpl, "100.0");
07589             strcpy(myrpt->txpl, "100.0");
07590             myrpt->remmode = REM_MODE_LSB;
07591             break;
07592          case 'F':
07593             myrpt->remmode = REM_MODE_FM;
07594             break;
07595          case 'L':
07596          case 'l':
07597             myrpt->powerlevel = REM_LOWPWR;
07598             break;               
07599          case 'H':
07600          case 'h':
07601             myrpt->powerlevel = REM_HIPWR;
07602             break;
07603                
07604          case 'M':
07605          case 'm':
07606             myrpt->powerlevel = REM_MEDPWR;
07607             break;
07608                   
07609          case '-':
07610             myrpt->offset = REM_MINUS;
07611             break;
07612                   
07613          case '+':
07614             myrpt->offset = REM_PLUS;
07615             break;
07616                   
07617          case 'S':
07618          case 's':
07619             myrpt->offset = REM_SIMPLEX;
07620             break;
07621                   
07622          case 'T':
07623          case 't':
07624             myrpt->txplon = 1;
07625             break;
07626                   
07627          case 'R':
07628          case 'r':
07629             myrpt->rxplon = 1;
07630             break;
07631 
07632          case 'U':
07633          case 'u':
07634             strcpy(myrpt->rxpl, "100.0");
07635             strcpy(myrpt->txpl, "100.0");
07636             myrpt->remmode = REM_MODE_USB;
07637             break;
07638          default:
07639             return 1;
07640       }
07641    }
07642    return 0;
07643 }
07644 
07645 
07646 
07647 /*
07648 * Remote base function
07649 */
07650 
07651 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
07652 {
07653    char *s,*s1,*s2;
07654    int i,j,p,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode;
07655    char multimode = 0;
07656    char oc,*cp,*cp1,*cp2;
07657    char tmp[20], freq[20] = "", savestr[20] = "";
07658    char mhz[MAXREMSTR], decimals[MAXREMSTR];
07659 
07660    if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
07661       return DC_ERROR;
07662       
07663    p = myatoi(param);
07664 
07665    if ((p != 99) && (p != 5) && (p != 140) && myrpt->p.authlevel && 
07666       (!myrpt->loginlevel[0])) return DC_ERROR;
07667    multimode = multimode_capable(myrpt);
07668 
07669    switch(p){
07670 
07671       case 1:  /* retrieve memory */
07672          if(strlen(digitbuf) < 2) /* needs 2 digits */
07673             break;
07674          
07675          for(i = 0 ; i < 2 ; i++){
07676             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
07677                return DC_ERROR;
07678          }
07679        
07680          r = retreive_memory(myrpt, digitbuf);
07681          if (r < 0){
07682             rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
07683             return DC_COMPLETE;
07684          }
07685          if (r > 0){
07686             return DC_ERROR;
07687          }
07688          if (setrem(myrpt) == -1) return DC_ERROR;
07689          return DC_COMPLETE;  
07690          
07691       case 2:  /* set freq and offset */
07692       
07693          
07694             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
07695             if(digitbuf[i] == '*'){
07696                j++;
07697                continue;
07698             }
07699             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
07700                goto invalid_freq;
07701             else{
07702                if(j == 0)
07703                   l++; /* # of digits before first * */
07704                if(j == 1)
07705                   k++; /* # of digits after first * */
07706             }
07707          }
07708       
07709          i = strlen(digitbuf) - 1;
07710          if(multimode){
07711             if((j > 2) || (l > 3) || (k > 6))
07712                goto invalid_freq; /* &^@#! */
07713          }
07714          else{
07715             if((j > 2) || (l > 4) || (k > 3))
07716                goto invalid_freq; /* &^@#! */
07717          }
07718 
07719          /* Wait for M+*K+* */
07720 
07721          if(j < 2)
07722             break; /* Not yet */
07723 
07724          /* We have a frequency */
07725 
07726          strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
07727          
07728          s = tmp;
07729          s1 = strsep(&s, "*"); /* Pick off MHz */
07730          s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
07731          ls2 = strlen(s2); 
07732          
07733          switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
07734             case 1:
07735                ht = 0;
07736                k = 100 * atoi(s2);
07737                break;
07738             
07739             case 2:
07740                ht = 0;
07741                k = 10 * atoi(s2);
07742                break;
07743                
07744             case 3:
07745                if(!multimode){
07746                   if((s2[2] != '0')&&(s2[2] != '5'))
07747                      goto invalid_freq;
07748                }
07749                ht = 0;
07750                k = atoi(s2);
07751                   break;
07752             case 4:
07753                k = atoi(s2)/10;
07754                ht = 10 * (atoi(s2+(ls2-1)));
07755                break;
07756 
07757             case 5:
07758                k = atoi(s2)/100;
07759                ht = (atoi(s2+(ls2-2)));
07760                break;
07761                
07762             default:
07763                goto invalid_freq;
07764          }
07765 
07766          /* Check frequency for validity and establish a default mode */
07767          
07768          snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
07769 
07770          if(debug)
07771             printf("New frequency: %s\n", freq);      
07772    
07773          split_freq(mhz, decimals, freq);
07774          m = atoi(mhz);
07775          d = atoi(decimals);
07776 
07777                         if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
07778                                 goto invalid_freq;
07779 
07780 
07781          if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
07782             break; /* Not yet */
07783 
07784 
07785          offset = REM_SIMPLEX; /* Assume simplex */
07786 
07787          if(defmode == REM_MODE_FM){
07788             oc = *s; /* Pick off offset */
07789          
07790             if (oc){
07791                switch(oc){
07792                   case '1':
07793                      offset = REM_MINUS;
07794                      break;
07795                   
07796                   case '2':
07797                      offset = REM_SIMPLEX;
07798                   break;
07799                   
07800                   case '3':
07801                      offset = REM_PLUS;
07802                      break;
07803                   
07804                   default:
07805                      goto invalid_freq;
07806                } 
07807             } 
07808          }  
07809          offsave = myrpt->offset;
07810          modesave = myrpt->remmode;
07811          strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
07812          strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
07813          myrpt->offset = offset;
07814          myrpt->remmode = defmode;
07815 
07816          if (setrem(myrpt) == -1){
07817             myrpt->offset = offsave;
07818             myrpt->remmode = modesave;
07819             strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
07820             goto invalid_freq;
07821          }
07822 
07823          return DC_COMPLETE;
07824 
07825 invalid_freq:
07826          rpt_telemetry(myrpt,INVFREQ,NULL);
07827          return DC_ERROR; 
07828       
07829       case 3: /* set rx PL tone */
07830             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
07831             if(digitbuf[i] == '*'){
07832                j++;
07833                continue;
07834             }
07835             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
07836                return DC_ERROR;
07837             else{
07838                if(j)
07839                   l++;
07840                else
07841                   k++;
07842             }
07843          }
07844          if((j > 1) || (k > 3) || (l > 1))
07845             return DC_ERROR; /* &$@^! */
07846          i = strlen(digitbuf) - 1;
07847          if((j != 1) || (k < 2)|| (l != 1))
07848             break; /* Not yet */
07849          if(debug)
07850             printf("PL digits entered %s\n", digitbuf);
07851             
07852          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
07853          /* see if we have at least 1 */
07854          s = strchr(tmp,'*');
07855          if(s)
07856             *s = '.';
07857          strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
07858          strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
07859          if(!strcmp(myrpt->remote, remote_rig_rbi))
07860          {
07861             strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
07862          }
07863          if (setrem(myrpt) == -1){
07864             strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
07865             return DC_ERROR;
07866          }
07867       
07868       
07869          return DC_COMPLETE;
07870       
07871       case 4: /* set tx PL tone */
07872          /* cant set tx tone on RBI (rx tone does both) */
07873          if(!strcmp(myrpt->remote, remote_rig_rbi))
07874             return DC_ERROR;
07875          if(!strcmp(myrpt->remote, remote_rig_ic706))
07876             return DC_ERROR;
07877             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
07878             if(digitbuf[i] == '*'){
07879                j++;
07880                continue;
07881             }
07882             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
07883                return DC_ERROR;
07884             else{
07885                if(j)
07886                   l++;
07887                else
07888                   k++;
07889             }
07890          }
07891          if((j > 1) || (k > 3) || (l > 1))
07892             return DC_ERROR; /* &$@^! */
07893          i = strlen(digitbuf) - 1;
07894          if((j != 1) || (k < 2)|| (l != 1))
07895             break; /* Not yet */
07896          if(debug)
07897             printf("PL digits entered %s\n", digitbuf);
07898             
07899          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
07900          /* see if we have at least 1 */
07901          s = strchr(tmp,'*');
07902          if(s)
07903             *s = '.';
07904          strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1);
07905          strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
07906          
07907          if (setrem(myrpt) == -1){
07908             strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
07909             return DC_ERROR;
07910          }
07911       
07912       
07913          return DC_COMPLETE;
07914       
07915 
07916       case 6: /* MODE (FM,USB,LSB,AM) */
07917          if(strlen(digitbuf) < 1)
07918             break;
07919 
07920          if(!multimode)
07921             return DC_ERROR; /* Multimode radios only */
07922 
07923          switch(*digitbuf){
07924             case '1':
07925                split_freq(mhz, decimals, myrpt->freq); 
07926                m=atoi(mhz);
07927                if(m < 29) /* No FM allowed below 29MHz! */
07928                   return DC_ERROR;
07929                myrpt->remmode = REM_MODE_FM;
07930                
07931                rpt_telemetry(myrpt,REMMODE,NULL);
07932                break;
07933 
07934             case '2':
07935                myrpt->remmode = REM_MODE_USB;
07936                rpt_telemetry(myrpt,REMMODE,NULL);
07937                break;   
07938 
07939             case '3':
07940                myrpt->remmode = REM_MODE_LSB;
07941                rpt_telemetry(myrpt,REMMODE,NULL);
07942                break;
07943             
07944             case '4':
07945                myrpt->remmode = REM_MODE_AM;
07946                rpt_telemetry(myrpt,REMMODE,NULL);
07947                break;
07948       
07949             default:
07950                return DC_ERROR;
07951          }
07952 
07953          if(setrem(myrpt))
07954             return DC_ERROR;
07955          return DC_COMPLETEQUIET;
07956       case 99:
07957          /* cant log in when logged in */
07958          if (myrpt->loginlevel[0]) 
07959             return DC_ERROR;
07960          *myrpt->loginuser = 0;
07961          myrpt->loginlevel[0] = 0;
07962          cp = strdup(param);
07963          cp1 = strchr(cp,',');
07964          ast_mutex_lock(&myrpt->lock);
07965          if (cp1) 
07966          {
07967             *cp1 = 0;
07968             cp2 = strchr(cp1 + 1,',');
07969             if (cp2) 
07970             {
07971                *cp2 = 0;
07972                strncpy(myrpt->loginlevel,cp2 + 1,
07973                   sizeof(myrpt->loginlevel) - 1);
07974             }
07975             strncpy(myrpt->loginuser,cp1 + 1,sizeof(myrpt->loginuser));
07976             ast_mutex_unlock(&myrpt->lock);
07977             if (myrpt->p.archivedir)
07978             {
07979                char str[100];
07980 
07981                sprintf(str,"LOGIN,%s,%s",
07982                    myrpt->loginuser,myrpt->loginlevel);
07983                donodelog(myrpt,str);
07984             }
07985             if (debug) 
07986                printf("loginuser %s level %s\n",myrpt->loginuser,myrpt->loginlevel);
07987             rpt_telemetry(myrpt,REMLOGIN,NULL);
07988          }
07989          free(cp);
07990          return DC_COMPLETEQUIET;
07991       case 100: /* RX PL Off */
07992          myrpt->rxplon = 0;
07993          setrem(myrpt);
07994          rpt_telemetry(myrpt,REMXXX,(void *)p);
07995          return DC_COMPLETEQUIET;
07996       case 101: /* RX PL On */
07997          myrpt->rxplon = 1;
07998          setrem(myrpt);
07999          rpt_telemetry(myrpt,REMXXX,(void *)p);
08000          return DC_COMPLETEQUIET;
08001       case 102: /* TX PL Off */
08002          myrpt->txplon = 0;
08003          setrem(myrpt);
08004          rpt_telemetry(myrpt,REMXXX,(void *)p);
08005          return DC_COMPLETEQUIET;
08006       case 103: /* TX PL On */
08007          myrpt->txplon = 1;
08008          setrem(myrpt);
08009          rpt_telemetry(myrpt,REMXXX,(void *)p);
08010          return DC_COMPLETEQUIET;
08011       case 104: /* Low Power */
08012          if(!strcmp(myrpt->remote, remote_rig_ic706))
08013             return DC_ERROR;
08014          myrpt->powerlevel = REM_LOWPWR;
08015          setrem(myrpt);
08016          rpt_telemetry(myrpt,REMXXX,(void *)p);
08017          return DC_COMPLETEQUIET;
08018       case 105: /* Medium Power */
08019          if(!strcmp(myrpt->remote, remote_rig_ic706))
08020             return DC_ERROR;
08021          myrpt->powerlevel = REM_MEDPWR;
08022          setrem(myrpt);
08023          rpt_telemetry(myrpt,REMXXX,(void *)p);
08024          return DC_COMPLETEQUIET;
08025       case 106: /* Hi Power */
08026          if(!strcmp(myrpt->remote, remote_rig_ic706))
08027             return DC_ERROR;
08028          myrpt->powerlevel = REM_HIPWR;
08029          setrem(myrpt);
08030          rpt_telemetry(myrpt,REMXXX,(void *)p);
08031          return DC_COMPLETEQUIET;
08032       case 107: /* Bump down 20Hz */
08033          multimode_bump_freq(myrpt, -20);
08034          return DC_COMPLETE;
08035       case 108: /* Bump down 100Hz */
08036          multimode_bump_freq(myrpt, -100);
08037          return DC_COMPLETE;
08038       case 109: /* Bump down 500Hz */
08039          multimode_bump_freq(myrpt, -500);
08040          return DC_COMPLETE;
08041       case 110: /* Bump up 20Hz */
08042          multimode_bump_freq(myrpt, 20);
08043          return DC_COMPLETE;
08044       case 111: /* Bump up 100Hz */
08045          multimode_bump_freq(myrpt, 100);
08046          return DC_COMPLETE;
08047       case 112: /* Bump up 500Hz */
08048          multimode_bump_freq(myrpt, 500);
08049          return DC_COMPLETE;
08050       case 113: /* Scan down slow */
08051          myrpt->scantimer = REM_SCANTIME;
08052          myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
08053          rpt_telemetry(myrpt,REMXXX,(void *)p);
08054          return DC_COMPLETEQUIET;
08055       case 114: /* Scan down quick */
08056          myrpt->scantimer = REM_SCANTIME;
08057          myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
08058          rpt_telemetry(myrpt,REMXXX,(void *)p);
08059          return DC_COMPLETEQUIET;
08060       case 115: /* Scan down fast */
08061          myrpt->scantimer = REM_SCANTIME;
08062          myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
08063          rpt_telemetry(myrpt,REMXXX,(void *)p);
08064          return DC_COMPLETEQUIET;
08065       case 116: /* Scan up slow */
08066          myrpt->scantimer = REM_SCANTIME;
08067          myrpt->hfscanmode = HF_SCAN_UP_SLOW;
08068          rpt_telemetry(myrpt,REMXXX,(void *)p);
08069          return DC_COMPLETEQUIET;
08070       case 117: /* Scan up quick */
08071          myrpt->scantimer = REM_SCANTIME;
08072          myrpt->hfscanmode = HF_SCAN_UP_QUICK;
08073          rpt_telemetry(myrpt,REMXXX,(void *)p);
08074          return DC_COMPLETEQUIET;
08075       case 118: /* Scan up fast */
08076          myrpt->scantimer = REM_SCANTIME;
08077          myrpt->hfscanmode = HF_SCAN_UP_FAST;
08078          rpt_telemetry(myrpt,REMXXX,(void *)p);
08079          return DC_COMPLETEQUIET;
08080       case 119: /* Tune Request */
08081          /* if not currently going, and valid to do */
08082          if((!myrpt->tunerequest) && 
08083              ((!strcmp(myrpt->remote, remote_rig_ft897) || 
08084             !strcmp(myrpt->remote, remote_rig_ic706)) )) { 
08085             myrpt->remotetx = 0;
08086             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
08087             myrpt->tunerequest = 1;
08088             rpt_telemetry(myrpt,TUNE,NULL);
08089             return DC_COMPLETEQUIET;
08090          }
08091          return DC_ERROR;        
08092       case 5: /* Long Status */
08093          rpt_telemetry(myrpt,REMLONGSTATUS,NULL);
08094          return DC_COMPLETEQUIET;
08095       case 140: /* Short Status */
08096          rpt_telemetry(myrpt,REMSHORTSTATUS,NULL);
08097          return DC_COMPLETEQUIET;
08098       case 200:
08099       case 201:
08100       case 202:
08101       case 203:
08102       case 204:
08103       case 205:
08104       case 206:
08105       case 207:
08106       case 208:
08107       case 209:
08108       case 210:
08109       case 211:
08110       case 212:
08111       case 213:
08112       case 214:
08113       case 215:
08114          do_dtmf_local(myrpt,remdtmfstr[p - 200]);
08115          return DC_COMPLETEQUIET;
08116       default:
08117          break;
08118    }
08119    return DC_INDETERMINATE;
08120 }
08121 
08122 
08123 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode)
08124 {
08125 time_t   now;
08126 int   ret,res = 0,src;
08127 
08128    time(&myrpt->last_activity_time);
08129    /* Stop scan mode if in scan mode */
08130    if(myrpt->hfscanmode){
08131       stop_scan(myrpt);
08132       return 0;
08133    }
08134 
08135    time(&now);
08136    /* if timed-out */
08137    if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
08138    {
08139       myrpt->dtmfidx = -1;
08140       myrpt->dtmfbuf[0] = 0;
08141       myrpt->dtmf_time_rem = 0;
08142    }
08143    /* if decode not active */
08144    if (myrpt->dtmfidx == -1)
08145    {
08146       /* if not lead-in digit, dont worry */
08147       if (c != myrpt->p.funcchar)
08148       {
08149          if (!myrpt->p.propagate_dtmf)
08150          {
08151             rpt_mutex_lock(&myrpt->lock);
08152             do_dtmf_local(myrpt,c);
08153             rpt_mutex_unlock(&myrpt->lock);
08154          }
08155          return 0;
08156       }
08157       myrpt->dtmfidx = 0;
08158       myrpt->dtmfbuf[0] = 0;
08159       myrpt->dtmf_time_rem = now;
08160       return 0;
08161    }
08162    /* if too many in buffer, start over */
08163    if (myrpt->dtmfidx >= MAXDTMF)
08164    {
08165       myrpt->dtmfidx = 0;
08166       myrpt->dtmfbuf[0] = 0;
08167       myrpt->dtmf_time_rem = now;
08168    }
08169    if (c == myrpt->p.funcchar)
08170    {
08171       /* if star at beginning, or 2 together, erase buffer */
08172       if ((myrpt->dtmfidx < 1) || 
08173          (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
08174       {
08175          myrpt->dtmfidx = 0;
08176          myrpt->dtmfbuf[0] = 0;
08177          myrpt->dtmf_time_rem = now;
08178          return 0;
08179       }
08180    }
08181    myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
08182    myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
08183    myrpt->dtmf_time_rem = now;
08184    
08185    
08186    src = SOURCE_RMT;
08187    if (phonemode > 1) src = SOURCE_DPHONE;
08188    else if (phonemode) src = SOURCE_PHONE;
08189    ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
08190    
08191    switch(ret){
08192    
08193       case DC_INDETERMINATE:
08194          res = 0;
08195          break;
08196             
08197       case DC_DOKEY:
08198          if (keyed) *keyed = 1;
08199          res = 0;
08200          break;
08201             
08202       case DC_REQ_FLUSH:
08203          myrpt->dtmfidx = 0;
08204          myrpt->dtmfbuf[0] = 0;
08205          res = 0;
08206          break;
08207             
08208             
08209       case DC_COMPLETE:
08210          res = 1;
08211       case DC_COMPLETEQUIET:
08212          myrpt->totalexecdcommands++;
08213          myrpt->dailyexecdcommands++;
08214          strncpy(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF-1);
08215          myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
08216          myrpt->dtmfbuf[0] = 0;
08217          myrpt->dtmfidx = -1;
08218          myrpt->dtmf_time_rem = 0;
08219          break;
08220             
08221       case DC_ERROR:
08222       default:
08223          myrpt->dtmfbuf[0] = 0;
08224          myrpt->dtmfidx = -1;
08225          myrpt->dtmf_time_rem = 0;
08226          res = 0;
08227          break;
08228    }
08229 
08230    return res;
08231 }
08232 
08233 static int handle_remote_data(struct rpt *myrpt, char *str)
08234 {
08235 char  tmp[300],cmd[300],dest[300],src[300],c;
08236 int   seq,res;
08237 
08238    /* put string in our buffer */
08239    strncpy(tmp,str,sizeof(tmp) - 1);
08240    if (!strcmp(tmp,discstr)) return 0;
08241    if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
08242    {
08243       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
08244       return 0;
08245    }
08246    if (strcmp(cmd,"D"))
08247    {
08248       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
08249       return 0;
08250    }
08251    /* if not for me, ignore */
08252    if (strcmp(dest,myrpt->name)) return 0;
08253    if (myrpt->p.archivedir)
08254    {
08255       char str[100];
08256 
08257       sprintf(str,"DTMF,%c",c);
08258       donodelog(myrpt,str);
08259    }
08260    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
08261    if (!c) return(0);
08262    res = handle_remote_dtmf_digit(myrpt,c, NULL, 0);
08263    if (res != 1)
08264       return res;
08265    rpt_telemetry(myrpt,COMPLETE,NULL);
08266    return 0;
08267 }
08268 
08269 static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode)
08270 {
08271 int   res;
08272 
08273 
08274    if (keyed && *keyed && (c == myrpt->p.endchar))
08275    {
08276       *keyed = 0;
08277       return DC_INDETERMINATE;
08278    }
08279 
08280    if (myrpt->p.archivedir)
08281    {
08282       char str[100];
08283 
08284       sprintf(str,"DTMF(P),%c",c);
08285       donodelog(myrpt,str);
08286    }
08287    res = handle_remote_dtmf_digit(myrpt,c,keyed, phonemode);
08288    if (res != 1)
08289       return res;
08290    rpt_telemetry(myrpt,COMPLETE,NULL);
08291    return 0;
08292 }
08293 
08294 static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
08295 {
08296    char *val, *s, *s1, *s2, *tele;
08297    char tmp[300], deststr[300] = "";
08298 
08299    val = node_lookup(myrpt,l->name);
08300    if (!val)
08301    {
08302       fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
08303       return -1;
08304    }
08305 
08306    rpt_mutex_lock(&myrpt->lock);
08307    /* remove from queue */
08308    remque((struct qelem *) l);
08309    rpt_mutex_unlock(&myrpt->lock);
08310    strncpy(tmp,val,sizeof(tmp) - 1);
08311    s = tmp;
08312    s1 = strsep(&s,",");
08313    s2 = strsep(&s,",");
08314    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
08315    tele = strchr(deststr, '/');
08316    if (!tele) {
08317       fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
08318       return -1;
08319    }
08320    *tele++ = 0;
08321    l->elaptime = 0;
08322    l->connecttime = 0;
08323    l->thisconnected = 0;
08324    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
08325    if (l->chan){
08326       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
08327       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
08328       l->chan->whentohangup = 0;
08329       l->chan->appl = "Apprpt";
08330       l->chan->data = "(Remote Rx)";
08331       if (option_verbose > 2)
08332          ast_verbose(VERBOSE_PREFIX_3 "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
08333             deststr, tele, l->chan->name);
08334       if(l->chan->cid.cid_num)
08335          free(l->chan->cid.cid_num);
08336       l->chan->cid.cid_num = strdup(myrpt->name);
08337                 ast_call(l->chan,tele,999); 
08338 
08339    }
08340    else 
08341    {
08342       if (option_verbose > 2)
08343          ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
08344             deststr,tele,l->chan->name);
08345       return -1;
08346    }
08347    rpt_mutex_lock(&myrpt->lock);
08348    /* put back in queue */
08349    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
08350    rpt_mutex_unlock(&myrpt->lock);
08351    ast_log(LOG_NOTICE,"Reconnect Attempt to %s in process\n",l->name);
08352    return 0;
08353 }
08354 
08355 /* 0 return=continue, 1 return = break, -1 return = error */
08356 static void local_dtmf_helper(struct rpt *myrpt,char c)
08357 {
08358 int   res;
08359 pthread_attr_t attr;
08360 char  cmd[MAXDTMF+1] = "";
08361 
08362    if (myrpt->p.archivedir)
08363    {
08364       char str[100];
08365 
08366       sprintf(str,"DTMF,MAIN,%c",c);
08367       donodelog(myrpt,str);
08368    }
08369    if (c == myrpt->p.endchar)
08370    {
08371    /* if in simple mode, kill autopatch */
08372       if (myrpt->p.simple && myrpt->callmode)
08373       {
08374          rpt_mutex_lock(&myrpt->lock);
08375          myrpt->callmode = 0;
08376          rpt_mutex_unlock(&myrpt->lock);
08377          rpt_telemetry(myrpt,TERM,NULL);
08378          return;
08379       }
08380       rpt_mutex_lock(&myrpt->lock);
08381       myrpt->stopgen = 1;
08382       if (myrpt->cmdnode[0])
08383       {
08384          myrpt->cmdnode[0] = 0;
08385          myrpt->dtmfidx = -1;
08386          myrpt->dtmfbuf[0] = 0;
08387          rpt_mutex_unlock(&myrpt->lock);
08388          rpt_telemetry(myrpt,COMPLETE,NULL);
08389       } 
08390       else
08391                 {
08392                         rpt_mutex_unlock(&myrpt->lock);
08393                         if (myrpt->p.propagate_phonedtmf)
08394                                do_dtmf_phone(myrpt,NULL,c);
08395                 }
08396       return;
08397    }
08398    rpt_mutex_lock(&myrpt->lock);
08399    if (myrpt->cmdnode[0])
08400    {
08401       rpt_mutex_unlock(&myrpt->lock);
08402       send_link_dtmf(myrpt,c);
08403       return;
08404    }
08405    if (!myrpt->p.simple)
08406    {
08407       if (c == myrpt->p.funcchar)
08408       {
08409          myrpt->dtmfidx = 0;
08410          myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
08411          rpt_mutex_unlock(&myrpt->lock);
08412          time(&myrpt->dtmf_time);
08413          return;
08414       } 
08415       else if ((c != myrpt->p.endchar) && (myrpt->dtmfidx >= 0))
08416       {
08417          time(&myrpt->dtmf_time);
08418          
08419          if (myrpt->dtmfidx < MAXDTMF)
08420          {
08421             myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
08422             myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
08423             
08424             strncpy(cmd, myrpt->dtmfbuf, sizeof(cmd) - 1);
08425             
08426             rpt_mutex_unlock(&myrpt->lock);
08427             res = collect_function_digits(myrpt, cmd, SOURCE_RPT, NULL);
08428             rpt_mutex_lock(&myrpt->lock);
08429             switch(res){
08430                 case DC_INDETERMINATE:
08431                break;
08432                 case DC_REQ_FLUSH:
08433                myrpt->dtmfidx = 0;
08434                myrpt->dtmfbuf[0] = 0;
08435                break;
08436                 case DC_COMPLETE:
08437                 case DC_COMPLETEQUIET:
08438                myrpt->totalexecdcommands++;
08439                myrpt->dailyexecdcommands++;
08440                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
08441                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
08442                myrpt->dtmfbuf[0] = 0;
08443                myrpt->dtmfidx = -1;
08444                myrpt->dtmf_time = 0;
08445                break;
08446 
08447                 case DC_ERROR:
08448                 default:
08449                myrpt->dtmfbuf[0] = 0;
08450                myrpt->dtmfidx = -1;
08451                myrpt->dtmf_time = 0;
08452                break;
08453             }
08454             if(res != DC_INDETERMINATE) {
08455                rpt_mutex_unlock(&myrpt->lock);
08456                return;
08457             }
08458          } 
08459       }
08460    }
08461    else /* if simple */
08462    {
08463       if ((!myrpt->callmode) && (c == myrpt->p.funcchar))
08464       {
08465          myrpt->callmode = 1;
08466          myrpt->patchnoct = 0;
08467          myrpt->patchquiet = 0;
08468          myrpt->patchfarenddisconnect = 0;
08469          myrpt->patchdialtime = 0;
08470          strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
08471          myrpt->cidx = 0;
08472          myrpt->exten[myrpt->cidx] = 0;
08473          rpt_mutex_unlock(&myrpt->lock);
08474               pthread_attr_init(&attr);
08475               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
08476          ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
08477          return;
08478       }
08479    }
08480    if (myrpt->callmode == 1)
08481    {
08482       myrpt->exten[myrpt->cidx++] = c;
08483       myrpt->exten[myrpt->cidx] = 0;
08484       /* if this exists */
08485       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
08486       {
08487          myrpt->callmode = 2;
08488          rpt_mutex_unlock(&myrpt->lock);
08489          if(!myrpt->patchquiet)
08490             rpt_telemetry(myrpt,PROC,NULL); 
08491          return;
08492       }
08493       /* if can continue, do so */
08494       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
08495       {
08496          /* call has failed, inform user */
08497          myrpt->callmode = 4;
08498       }
08499       rpt_mutex_unlock(&myrpt->lock);
08500       return;
08501    }
08502    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
08503    {
08504       myrpt->mydtmf = c;
08505    }
08506    rpt_mutex_unlock(&myrpt->lock);
08507    if ((myrpt->dtmfidx < 0) && myrpt->p.propagate_phonedtmf)
08508       do_dtmf_phone(myrpt,NULL,c);
08509    return;
08510 }
08511 
08512 
08513 /* place an ID event in the telemetry queue */
08514 
08515 static void queue_id(struct rpt *myrpt)
08516 {
08517    if(myrpt->p.idtime){ /* ID time must be non-zero */
08518       myrpt->mustid = myrpt->tailid = 0;
08519       myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
08520       rpt_mutex_unlock(&myrpt->lock);
08521       rpt_telemetry(myrpt,ID,NULL);
08522       rpt_mutex_lock(&myrpt->lock);
08523    }
08524 }
08525 
08526 /* Scheduler */
08527 /* must be called locked */
08528 
08529 static void do_scheduler(struct rpt *myrpt)
08530 {
08531    int i,res;
08532    struct tm tmnow;
08533    struct ast_variable *skedlist;
08534    char *strs[5],*vp,*val,value[100];
08535 
08536    memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
08537    
08538    if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
08539       ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
08540 
08541    /* Try to get close to a 1 second resolution */
08542    
08543    if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
08544       return;
08545 
08546    rpt_localtime(&myrpt->curtv.tv_sec, &tmnow);
08547 
08548    /* If midnight, then reset all daily statistics */
08549    
08550    if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
08551       myrpt->dailykeyups = 0;
08552       myrpt->dailytxtime = 0;
08553       myrpt->dailykerchunks = 0;
08554       myrpt->dailyexecdcommands = 0;
08555    }
08556 
08557    if(tmnow.tm_sec != 0)
08558       return;
08559 
08560    /* Code below only executes once per minute */
08561 
08562 
08563    /* Don't schedule if remote */
08564 
08565         if (myrpt->remote)
08566                 return;
08567 
08568    /* Don't schedule if disabled */
08569 
08570         if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable){
08571       if(debug > 6)
08572          ast_log(LOG_NOTICE, "Scheduler disabled\n");
08573       return;
08574    }
08575 
08576    if(!myrpt->p.skedstanzaname){ /* No stanza means we do nothing */
08577       if(debug > 6)
08578          ast_log(LOG_NOTICE,"No stanza for scheduler in rpt.conf\n");
08579       return;
08580    }
08581 
08582         /* get pointer to linked list of scheduler entries */
08583         skedlist = ast_variable_browse(myrpt->cfg, myrpt->p.skedstanzaname);
08584 
08585    if(debug > 6){
08586       ast_log(LOG_NOTICE, "Time now: %02d:%02d %02d %02d %02d\n",
08587          tmnow.tm_hour,tmnow.tm_min,tmnow.tm_mday,tmnow.tm_mon + 1, tmnow.tm_wday); 
08588    }
08589    /* walk the list */
08590    for(; skedlist; skedlist = skedlist->next){
08591       if(debug > 6)
08592          ast_log(LOG_NOTICE, "Scheduler entry %s = %s being considered\n",skedlist->name, skedlist->value);
08593       strncpy(value,skedlist->value,99);
08594       value[99] = 0;
08595       /* point to the substrings for minute, hour, dom, month, and dow */
08596       for( i = 0, vp = value ; i < 5; i++){
08597          if(!*vp)
08598             break;
08599          while((*vp == ' ') || (*vp == 0x09)) /* get rid of any leading white space */
08600             vp++;
08601          strs[i] = vp; /* save pointer to beginning of substring */
08602          while((*vp != ' ') && (*vp != 0x09) && (*vp != 0)) /* skip over substring */
08603             vp++;
08604          if(*vp)
08605             *vp++ = 0; /* mark end of substring */
08606       }
08607       if(debug > 6)
08608          ast_log(LOG_NOTICE, "i = %d, min = %s, hour = %s, mday=%s, mon=%s, wday=%s\n",i,
08609             strs[0], strs[1], strs[2], strs[3], strs[4]); 
08610       if(i == 5){
08611          if((*strs[0] != '*')&&(atoi(strs[0]) != tmnow.tm_min))
08612             continue;
08613          if((*strs[1] != '*')&&(atoi(strs[1]) != tmnow.tm_hour))
08614             continue;
08615          if((*strs[2] != '*')&&(atoi(strs[2]) != tmnow.tm_mday))
08616             continue;
08617          if((*strs[3] != '*')&&(atoi(strs[3]) != tmnow.tm_mon + 1))
08618             continue;
08619          if(atoi(strs[4]) == 7)
08620             strs[4] = "0";
08621          if((*strs[4] != '*')&&(atoi(strs[4]) != tmnow.tm_wday))
08622             continue;
08623          if(debug)
08624             ast_log(LOG_NOTICE, "Executing scheduler entry %s = %s\n", skedlist->name, skedlist->value);
08625          if(atoi(skedlist->name) == 0)
08626             return; /* Zero is reserved for the startup macro */
08627          val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, skedlist->name);
08628          if (!val){
08629             ast_log(LOG_WARNING,"Scheduler could not find macro %s\n",skedlist->name);
08630             return; /* Macro not found */
08631          }
08632          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)){
08633             ast_log(LOG_WARNING, "Scheduler could not execute macro %s: Macro buffer full\n",
08634                skedlist->name);
08635             return; /* Macro buffer full */
08636          }
08637          myrpt->macrotimer = MACROTIME;
08638          strncat(myrpt->macrobuf,val,MAXMACRO - 1);
08639       }
08640       else{
08641          ast_log(LOG_WARNING,"Malformed scheduler entry in rpt.conf: %s = %s\n",
08642             skedlist->name, skedlist->value);
08643       }
08644    }
08645 
08646 }
08647 
08648 
08649 /* single thread with one file (request) to dial */
08650 static void *rpt(void *this)
08651 {
08652 struct   rpt *myrpt = (struct rpt *)this;
08653 char *tele,*idtalkover,c;
08654 int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued;
08655 int tailmessagequeued,ctqueued,dtmfed;
08656 struct ast_channel *who;
08657 ZT_CONFINFO ci;  /* conference info */
08658 time_t   t;
08659 struct rpt_link *l,*m;
08660 struct rpt_tele *telem;
08661 char tmpstr[300],lstr[MAXLINKLIST];
08662 
08663 
08664    if (myrpt->p.archivedir) mkdir(myrpt->p.archivedir,0600);
08665    sprintf(tmpstr,"%s/%s",myrpt->p.archivedir,myrpt->name);
08666    mkdir(tmpstr,0600);
08667    rpt_mutex_lock(&myrpt->lock);
08668 
08669    telem = myrpt->tele.next;
08670    while(telem != &myrpt->tele)
08671    {
08672       ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
08673       telem = telem->next;
08674    }
08675    rpt_mutex_unlock(&myrpt->lock);
08676    /* find our index, and load the vars initially */
08677    for(i = 0; i < nrpts; i++)
08678    {
08679       if (&rpt_vars[i] == myrpt)
08680       {
08681          load_rpt_vars(i,0);
08682          break;
08683       }
08684    }
08685    rpt_mutex_lock(&myrpt->lock);
08686    strncpy(tmpstr,myrpt->rxchanname,sizeof(tmpstr) - 1);
08687    tele = strchr(tmpstr,'/');
08688    if (!tele)
08689    {
08690       fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
08691       rpt_mutex_unlock(&myrpt->lock);
08692       myrpt->rpt_thread = AST_PTHREADT_STOP;
08693       pthread_exit(NULL);
08694    }
08695    *tele++ = 0;
08696    myrpt->rxchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
08697    if (myrpt->rxchannel)
08698    {
08699       if (myrpt->rxchannel->_state == AST_STATE_BUSY)
08700       {
08701          fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
08702          rpt_mutex_unlock(&myrpt->lock);
08703          ast_hangup(myrpt->rxchannel);
08704          myrpt->rpt_thread = AST_PTHREADT_STOP;
08705          pthread_exit(NULL);
08706       }
08707       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
08708       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
08709       myrpt->rxchannel->whentohangup = 0;
08710       myrpt->rxchannel->appl = "Apprpt";
08711       myrpt->rxchannel->data = "(Repeater Rx)";
08712       if (option_verbose > 2)
08713          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
08714             tmpstr,tele,myrpt->rxchannel->name);
08715       ast_call(myrpt->rxchannel,tele,999);
08716       if (myrpt->rxchannel->_state != AST_STATE_UP)
08717       {
08718          rpt_mutex_unlock(&myrpt->lock);
08719          ast_hangup(myrpt->rxchannel);
08720          myrpt->rpt_thread = AST_PTHREADT_STOP;
08721          pthread_exit(NULL);
08722       }
08723    }
08724    else
08725    {
08726       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
08727       rpt_mutex_unlock(&myrpt->lock);
08728       myrpt->rpt_thread = AST_PTHREADT_STOP;
08729       pthread_exit(NULL);
08730    }
08731    if (myrpt->txchanname)
08732    {
08733       strncpy(tmpstr,myrpt->txchanname,sizeof(tmpstr) - 1);
08734       tele = strchr(tmpstr,'/');
08735       if (!tele)
08736       {
08737          fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
08738          rpt_mutex_unlock(&myrpt->lock);
08739          ast_hangup(myrpt->rxchannel);
08740          myrpt->rpt_thread = AST_PTHREADT_STOP;
08741          pthread_exit(NULL);
08742       }
08743       *tele++ = 0;
08744       myrpt->txchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
08745       if (myrpt->txchannel)
08746       {
08747          if (myrpt->txchannel->_state == AST_STATE_BUSY)
08748          {
08749             fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
08750             rpt_mutex_unlock(&myrpt->lock);
08751             ast_hangup(myrpt->txchannel);
08752             ast_hangup(myrpt->rxchannel);
08753             myrpt->rpt_thread = AST_PTHREADT_STOP;
08754             pthread_exit(NULL);
08755          }        
08756          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
08757          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
08758          myrpt->txchannel->whentohangup = 0;
08759          myrpt->txchannel->appl = "Apprpt";
08760          myrpt->txchannel->data = "(Repeater Tx)";
08761          if (option_verbose > 2)
08762             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
08763                tmpstr,tele,myrpt->txchannel->name);
08764          ast_call(myrpt->txchannel,tele,999);
08765          if (myrpt->rxchannel->_state != AST_STATE_UP)
08766          {
08767             rpt_mutex_unlock(&myrpt->lock);
08768             ast_hangup(myrpt->rxchannel);
08769             ast_hangup(myrpt->txchannel);
08770             myrpt->rpt_thread = AST_PTHREADT_STOP;
08771             pthread_exit(NULL);
08772          }
08773       }
08774       else
08775       {
08776          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
08777          rpt_mutex_unlock(&myrpt->lock);
08778          ast_hangup(myrpt->rxchannel);
08779          myrpt->rpt_thread = AST_PTHREADT_STOP;
08780          pthread_exit(NULL);
08781       }
08782    }
08783    else
08784    {
08785       myrpt->txchannel = myrpt->rxchannel;
08786    }
08787    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
08788    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
08789    /* allocate a pseudo-channel thru asterisk */
08790    myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
08791    if (!myrpt->pchannel)
08792    {
08793       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
08794       rpt_mutex_unlock(&myrpt->lock);
08795       if (myrpt->txchannel != myrpt->rxchannel) 
08796          ast_hangup(myrpt->txchannel);
08797       ast_hangup(myrpt->rxchannel);
08798       myrpt->rpt_thread = AST_PTHREADT_STOP;
08799       pthread_exit(NULL);
08800    }
08801    /* allocate a pseudo-channel thru asterisk */
08802    myrpt->monchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
08803    if (!myrpt->monchannel)
08804    {
08805       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
08806       rpt_mutex_unlock(&myrpt->lock);
08807       if (myrpt->txchannel != myrpt->rxchannel) 
08808          ast_hangup(myrpt->txchannel);
08809       ast_hangup(myrpt->rxchannel);
08810       myrpt->rpt_thread = AST_PTHREADT_STOP;
08811       pthread_exit(NULL);
08812    }
08813    ast_set_read_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
08814    ast_set_write_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
08815    /* make a conference for the tx */
08816    ci.chan = 0;
08817    ci.confno = -1; /* make a new conf */
08818    ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
08819    /* first put the channel on the conference in proper mode */
08820    if (ioctl(myrpt->txchannel->fds[0],ZT_SETCONF,&ci) == -1)
08821    {
08822       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
08823       rpt_mutex_unlock(&myrpt->lock);
08824       ast_hangup(myrpt->pchannel);
08825       ast_hangup(myrpt->monchannel);
08826       if (myrpt->txchannel != myrpt->rxchannel) 
08827          ast_hangup(myrpt->txchannel);
08828       ast_hangup(myrpt->rxchannel);
08829       myrpt->rpt_thread = AST_PTHREADT_STOP;
08830       pthread_exit(NULL);
08831    }
08832    /* save tx conference number */
08833    myrpt->txconf = ci.confno;
08834    /* make a conference for the pseudo */
08835    ci.chan = 0;
08836    ci.confno = -1; /* make a new conf */
08837    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON :
08838       (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
08839    /* first put the channel on the conference in announce mode */
08840    if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
08841    {
08842       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
08843       rpt_mutex_unlock(&myrpt->lock);
08844       ast_hangup(myrpt->pchannel);
08845       ast_hangup(myrpt->monchannel);
08846       if (myrpt->txchannel != myrpt->rxchannel) 
08847          ast_hangup(myrpt->txchannel);
08848       ast_hangup(myrpt->rxchannel);
08849       myrpt->rpt_thread = AST_PTHREADT_STOP;
08850       pthread_exit(NULL);
08851    }
08852    /* save pseudo channel conference number */
08853    myrpt->conf = ci.confno;
08854    /* make a conference for the pseudo */
08855    ci.chan = 0;
08856    if (strstr(myrpt->txchannel->name,"pseudo") == NULL)
08857    {
08858       /* get tx channel's port number */
08859       if (ioctl(myrpt->txchannel->fds[0],ZT_CHANNO,&ci.confno) == -1)
08860       {
08861          ast_log(LOG_WARNING, "Unable to set tx channel's chan number\n");
08862          rpt_mutex_unlock(&myrpt->lock);
08863          ast_hangup(myrpt->pchannel);
08864          ast_hangup(myrpt->monchannel);
08865          if (myrpt->txchannel != myrpt->rxchannel) 
08866             ast_hangup(myrpt->txchannel);
08867          ast_hangup(myrpt->rxchannel);
08868          myrpt->rpt_thread = AST_PTHREADT_STOP;
08869          pthread_exit(NULL);
08870       }
08871       ci.confmode = ZT_CONF_MONITORTX;
08872    }
08873    else
08874    {
08875       ci.confno = myrpt->txconf;
08876       ci.confmode = ZT_CONF_CONFANNMON;
08877    }
08878    /* first put the channel on the conference in announce mode */
08879    if (ioctl(myrpt->monchannel->fds[0],ZT_SETCONF,&ci) == -1)
08880    {
08881       ast_log(LOG_WARNING, "Unable to set conference mode for monitor\n");
08882       rpt_mutex_unlock(&myrpt->lock);
08883       ast_hangup(myrpt->pchannel);
08884       ast_hangup(myrpt->monchannel);
08885       if (myrpt->txchannel != myrpt->rxchannel) 
08886          ast_hangup(myrpt->txchannel);
08887       ast_hangup(myrpt->rxchannel);
08888       myrpt->rpt_thread = AST_PTHREADT_STOP;
08889       pthread_exit(NULL);
08890    }
08891    /* allocate a pseudo-channel thru asterisk */
08892    myrpt->txpchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
08893    if (!myrpt->txpchannel)
08894    {
08895       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
08896       rpt_mutex_unlock(&myrpt->lock);
08897       ast_hangup(myrpt->pchannel);
08898       ast_hangup(myrpt->monchannel);
08899       if (myrpt->txchannel != myrpt->rxchannel) 
08900          ast_hangup(myrpt->txchannel);
08901       ast_hangup(myrpt->rxchannel);
08902       myrpt->rpt_thread = AST_PTHREADT_STOP;
08903       pthread_exit(NULL);
08904    }
08905    /* make a conference for the tx */
08906    ci.chan = 0;
08907    ci.confno = myrpt->txconf;
08908    ci.confmode = ZT_CONF_CONF | ZT_CONF_TALKER ;
08909    /* first put the channel on the conference in proper mode */
08910    if (ioctl(myrpt->txpchannel->fds[0],ZT_SETCONF,&ci) == -1)
08911    {
08912       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
08913       rpt_mutex_unlock(&myrpt->lock);
08914       ast_hangup(myrpt->txpchannel);
08915       ast_hangup(myrpt->monchannel);
08916       if (myrpt->txchannel != myrpt->rxchannel) 
08917          ast_hangup(myrpt->txchannel);
08918       ast_hangup(myrpt->rxchannel);
08919       myrpt->rpt_thread = AST_PTHREADT_STOP;
08920       pthread_exit(NULL);
08921    }
08922    /* Now, the idea here is to copy from the physical rx channel buffer
08923       into the pseudo tx buffer, and from the pseudo rx buffer into the 
08924       tx channel buffer */
08925    myrpt->links.next = &myrpt->links;
08926    myrpt->links.prev = &myrpt->links;
08927    myrpt->tailtimer = 0;
08928    myrpt->totimer = 0;
08929    myrpt->tmsgtimer = myrpt->p.tailmessagetime;
08930    myrpt->idtimer = myrpt->p.politeid;
08931    myrpt->mustid = myrpt->tailid = 0;
08932    myrpt->callmode = 0;
08933    myrpt->tounkeyed = 0;
08934    myrpt->tonotify = 0;
08935    myrpt->retxtimer = 0;
08936    myrpt->rerxtimer = 0;
08937    myrpt->skedtimer = 0;
08938    myrpt->tailevent = 0;
08939    lasttx = 0;
08940    myrpt->keyed = 0;
08941    idtalkover = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
08942    myrpt->dtmfidx = -1;
08943    myrpt->dtmfbuf[0] = 0;
08944    myrpt->rem_dtmfidx = -1;
08945    myrpt->rem_dtmfbuf[0] = 0;
08946    myrpt->dtmf_time = 0;
08947    myrpt->rem_dtmf_time = 0;
08948    myrpt->disgorgetime = 0;
08949    myrpt->lastnodewhichkeyedusup[0] = '\0';
08950    myrpt->dailytxtime = 0;
08951    myrpt->totaltxtime = 0;
08952    myrpt->dailykeyups = 0;
08953    myrpt->totalkeyups = 0;
08954    myrpt->dailykerchunks = 0;
08955    myrpt->totalkerchunks = 0;
08956    myrpt->dailyexecdcommands = 0;
08957    myrpt->totalexecdcommands = 0;
08958    myrpt->timeouts = 0;
08959    myrpt->exten[0] = '\0';
08960    myrpt->lastdtmfcommand[0] = '\0';
08961    if (myrpt->p.startupmacro)
08962    {
08963       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
08964    }
08965    rpt_mutex_unlock(&myrpt->lock);
08966    val = 1;
08967    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
08968    val = 1;
08969    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
08970    if (myrpt->p.archivedir) donodelog(myrpt,"STARTUP");
08971    dtmfed = 0;
08972    while (ms >= 0)
08973    {
08974       struct ast_frame *f,*f1,*f2;
08975       struct ast_channel *cs[300],*cs1[300];
08976       int totx=0,elap=0,n,x,toexit=0;
08977 
08978       /* DEBUG Dump */
08979       if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){
08980          struct rpt_link *zl;
08981          struct rpt_tele *zt;
08982 
08983          myrpt->disgorgetime = 0;
08984          ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n");
08985          ast_log(LOG_NOTICE,"totx = %d\n",totx);
08986          ast_log(LOG_NOTICE,"remrx = %d\n",remrx);
08987          ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx);
08988          ast_log(LOG_NOTICE,"elap = %d\n",elap);
08989          ast_log(LOG_NOTICE,"toexit = %d\n",toexit);
08990 
08991          ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed);
08992          ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx);
08993          ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode);
08994          ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
08995          ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed);
08996          ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify);
08997          ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
08998          ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
08999          ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
09000          ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
09001 
09002          zl = myrpt->links.next;
09003                   while(zl != &myrpt->links){
09004             ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",zl->name);
09005             ast_log(LOG_NOTICE,"        link->lasttx %d\n",zl->lasttx);
09006             ast_log(LOG_NOTICE,"        link->lastrx %d\n",zl->lastrx);
09007             ast_log(LOG_NOTICE,"        link->connected %d\n",zl->connected);
09008             ast_log(LOG_NOTICE,"        link->hasconnected %d\n",zl->hasconnected);
09009             ast_log(LOG_NOTICE,"        link->outbound %d\n",zl->outbound);
09010             ast_log(LOG_NOTICE,"        link->disced %d\n",zl->disced);
09011             ast_log(LOG_NOTICE,"        link->killme %d\n",zl->killme);
09012             ast_log(LOG_NOTICE,"        link->disctime %ld\n",zl->disctime);
09013             ast_log(LOG_NOTICE,"        link->retrytimer %ld\n",zl->retrytimer);
09014             ast_log(LOG_NOTICE,"        link->retries = %d\n",zl->retries);
09015             ast_log(LOG_NOTICE,"        link->reconnects = %d\n",zl->reconnects);
09016                            zl = zl->next;
09017                   }
09018                                                                                                                                
09019          zt = myrpt->tele.next;
09020          if(zt != &myrpt->tele)
09021             ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n");
09022                   while(zt != &myrpt->tele){
09023             ast_log(LOG_NOTICE,"        Telemetry mode: %d\n",zt->mode);
09024                            zt = zt->next;
09025                   }
09026          ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n");
09027 
09028       }  
09029 
09030 
09031       if (myrpt->reload)
09032       {
09033          struct rpt_tele *telem;
09034 
09035          rpt_mutex_lock(&myrpt->lock);
09036          telem = myrpt->tele.next;
09037          while(telem != &myrpt->tele)
09038          {
09039             ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
09040             telem = telem->next;
09041          }
09042          myrpt->reload = 0;
09043          rpt_mutex_unlock(&myrpt->lock);
09044          usleep(10000);
09045          /* find our index, and load the vars */
09046          for(i = 0; i < nrpts; i++)
09047          {
09048             if (&rpt_vars[i] == myrpt)
09049             {
09050                load_rpt_vars(i,0);
09051                break;
09052             }
09053          }
09054       }
09055 
09056       rpt_mutex_lock(&myrpt->lock);
09057       if (ast_check_hangup(myrpt->rxchannel)) break;
09058       if (ast_check_hangup(myrpt->txchannel)) break;
09059       if (ast_check_hangup(myrpt->pchannel)) break;
09060       if (ast_check_hangup(myrpt->monchannel)) break;
09061       if (ast_check_hangup(myrpt->txpchannel)) break;
09062 
09063       /* Set local tx with keyed */
09064       myrpt->localtx = myrpt->keyed;
09065       /* If someone's connected, and they're transmitting from their end to us, set remrx true */
09066       l = myrpt->links.next;
09067       remrx = 0;
09068       while(l != &myrpt->links)
09069       {
09070          if (l->lastrx){
09071             remrx = 1;
09072             if(l->name[0] != '0') /* Ignore '0' nodes */
09073                strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
09074          }
09075          l = l->next;
09076       }
09077       /* Create a "must_id" flag for the cleanup ID */      
09078       if(myrpt->p.idtime) /* ID time must be non-zero */
09079          myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
09080       /* Build a fresh totx from myrpt->keyed and autopatch activated */
09081       totx = myrpt->callmode;
09082       /* If full duplex, add local tx to totx */
09083       if (myrpt->p.duplex > 1) 
09084       {
09085          totx = totx || myrpt->localtx;
09086       }
09087       /* Traverse the telemetry list to see what's queued */
09088       identqueued = 0;
09089       othertelemqueued = 0;
09090       tailmessagequeued = 0;
09091       ctqueued = 0;
09092       telem = myrpt->tele.next;
09093       while(telem != &myrpt->tele)
09094       {
09095          if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
09096             identqueued = 1; /* Identification telemetry */
09097          }
09098          else if(telem->mode == TAILMSG)
09099          {
09100             tailmessagequeued = 1; /* Tail message telemetry */
09101          }
09102          else
09103          {
09104             if ((telem->mode != UNKEY) && (telem->mode != LINKUNKEY))
09105                othertelemqueued = 1;  /* Other telemetry */
09106             else
09107                ctqueued = 1; /* Courtesy tone telemetry */
09108          }
09109          telem = telem->next;
09110       }
09111    
09112       /* Add in any "other" telemetry, unless specified otherwise */
09113       if (!myrpt->p.notelemtx) totx = totx || othertelemqueued;
09114       /* Update external (to links) transmitter PTT state with everything but ID, CT, and tailmessage telemetry */
09115       myrpt->exttx = totx;
09116       totx = totx || myrpt->dtmf_local_timer;
09117       /* If half or 3/4 duplex, add localtx to external link tx */
09118       if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
09119       /* Add in ID telemetry to local transmitter */
09120       totx = totx || remrx;
09121       /* If 3/4 or full duplex, add in ident and CT telemetry */
09122       if (myrpt->p.duplex > 0)
09123          totx = totx || identqueued || ctqueued;
09124       /* If full duplex, add local dtmf stuff active */
09125       if (myrpt->p.duplex > 1) 
09126       {
09127          totx = totx || (myrpt->dtmfidx > -1) ||
09128             myrpt->cmdnode[0];
09129       }
09130       /* Reset time out timer variables if there is no activity */
09131       if (!totx) 
09132       {
09133          myrpt->totimer = myrpt->p.totime;
09134          myrpt->tounkeyed = 0;
09135          myrpt->tonotify = 0;
09136       }
09137       else{
09138          myrpt->tailtimer = myrpt->p.s[myrpt->p.sysstate_cur].alternatetail ?
09139             myrpt->p.althangtime : /* Initialize tail timer */
09140             myrpt->p.hangtime;
09141       }
09142       /* Disable the local transmitter if we are timed out */
09143       totx = totx && myrpt->totimer;
09144       /* if timed-out and not said already, say it */
09145       if ((!myrpt->totimer) && (!myrpt->tonotify))
09146       {
09147          myrpt->tonotify = 1;
09148          myrpt->timeouts++;
09149          rpt_mutex_unlock(&myrpt->lock);
09150          rpt_telemetry(myrpt,TIMEOUT,NULL);
09151          rpt_mutex_lock(&myrpt->lock);
09152       }
09153 
09154       /* If unkey and re-key, reset time out timer */
09155       if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
09156       {
09157          myrpt->tounkeyed = 1;
09158       }
09159       if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
09160       {
09161          myrpt->totimer = myrpt->p.totime;
09162          myrpt->tounkeyed = 0;
09163          myrpt->tonotify = 0;
09164          rpt_mutex_unlock(&myrpt->lock);
09165          continue;
09166       }
09167       /* if timed-out and in circuit busy after call */
09168       if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
09169       {
09170          myrpt->callmode = 0;
09171       }
09172       /* get rid of tail if timed out */
09173       if (!myrpt->totimer) myrpt->tailtimer = 0;
09174       /* if not timed-out, add in tail */
09175       if (myrpt->totimer) totx = totx || myrpt->tailtimer;
09176       /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
09177       /* If tail message, kill the message if someone keys up over it */ 
09178       if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
09179          int hasid = 0,hastalkover = 0;
09180 
09181          telem = myrpt->tele.next;
09182          while(telem != &myrpt->tele){
09183             if(telem->mode == ID){
09184                if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
09185                hasid = 1;
09186             }
09187             if(telem->mode == TAILMSG){
09188                                         if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
09189                                 }
09190             if (telem->mode == IDTALKOVER) hastalkover = 1;
09191             telem = telem->next;
09192          }
09193          rpt_mutex_unlock(&myrpt->lock);
09194          if (hasid && (!hastalkover)) rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
09195          rpt_mutex_lock(&myrpt->lock);
09196       }
09197       /* Try to be polite */
09198       /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
09199       /* If within 30 seconds of the time to ID, try do it in the tail */
09200       /* else if at ID time limit, do it right over the top of them */
09201       /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
09202       if(myrpt->mustid && (!myrpt->idtimer))
09203          queue_id(myrpt);
09204 
09205       if ((myrpt->p.idtime && totx && (!myrpt->exttx) &&
09206           (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) /* ID time must be non-zero */ 
09207          {
09208             myrpt->tailid = 1;
09209          }
09210 
09211       /* If tail timer expires, then check for tail messages */
09212 
09213       if(myrpt->tailevent){
09214          myrpt->tailevent = 0;
09215          if(myrpt->tailid){
09216             totx = 1;
09217             queue_id(myrpt);
09218          }
09219          else if ((myrpt->p.tailmessages[0]) &&
09220             (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
09221                totx = 1;
09222                myrpt->tmsgtimer = myrpt->p.tailmessagetime; 
09223                rpt_mutex_unlock(&myrpt->lock);
09224                rpt_telemetry(myrpt, TAILMSG, NULL);
09225                rpt_mutex_lock(&myrpt->lock);
09226          }  
09227       }
09228 
09229       /* Main TX control */
09230 
09231       /* let telemetry transmit anyway (regardless of timeout) */
09232       if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
09233       if (totx && (!lasttx))
09234       {
09235          char mydate[100],myfname[100];
09236          time_t myt;
09237 
09238          if (myrpt->monstream) ast_closestream(myrpt->monstream);
09239          if (myrpt->p.archivedir)
09240          {
09241             long blocksleft;
09242 
09243             time(&myt);
09244             strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
09245                localtime(&myt));
09246             sprintf(myfname,"%s/%s/%s",myrpt->p.archivedir,
09247                myrpt->name,mydate);
09248             myrpt->monstream = ast_writefile(myfname,"wav49",
09249                "app_rpt Air Archive",O_CREAT | O_APPEND,0,0600);
09250             if (myrpt->p.monminblocks)
09251             {
09252                blocksleft = diskavail(myrpt);
09253                if (blocksleft >= myrpt->p.monminblocks)
09254                   donodelog(myrpt,"TXKEY,MAIN");
09255             } else donodelog(myrpt,"TXKEY,MAIN");
09256          }
09257          lasttx = 1;
09258          myrpt->dailykeyups++;
09259          myrpt->totalkeyups++;
09260          rpt_mutex_unlock(&myrpt->lock);
09261          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
09262          rpt_mutex_lock(&myrpt->lock);
09263       }
09264       totx = totx && !myrpt->p.s[myrpt->p.sysstate_cur].txdisable;
09265       if ((!totx) && lasttx)
09266       {
09267          if (myrpt->monstream) ast_closestream(myrpt->monstream);
09268          myrpt->monstream = NULL;
09269 
09270          lasttx = 0;
09271          rpt_mutex_unlock(&myrpt->lock);
09272          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
09273          rpt_mutex_lock(&myrpt->lock);
09274          donodelog(myrpt,"TXUNKEY,MAIN");
09275       }
09276       time(&t);
09277       /* if DTMF timeout */
09278       if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t))
09279       {
09280          myrpt->dtmfidx = -1;
09281          myrpt->dtmfbuf[0] = 0;
09282       }        
09283       /* if remote DTMF timeout */
09284       if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
09285       {
09286          myrpt->rem_dtmfidx = -1;
09287          myrpt->rem_dtmfbuf[0] = 0;
09288       }  
09289 
09290       /* Reconnect */
09291    
09292       l = myrpt->links.next;
09293       while(l != &myrpt->links)
09294       {
09295          if (l->killme)
09296          {
09297             /* remove from queue */
09298             remque((struct qelem *) l);
09299             if (!strcmp(myrpt->cmdnode,l->name))
09300                myrpt->cmdnode[0] = 0;
09301             rpt_mutex_unlock(&myrpt->lock);
09302             /* hang-up on call to device */
09303             if (l->chan) ast_hangup(l->chan);
09304             ast_hangup(l->pchan);
09305             free(l);
09306             rpt_mutex_lock(&myrpt->lock);
09307             /* re-start link traversal */
09308             l = myrpt->links.next;
09309             continue;
09310          }
09311          l = l->next;
09312       }
09313       n = 0;
09314       cs[n++] = myrpt->rxchannel;
09315       cs[n++] = myrpt->pchannel;
09316       cs[n++] = myrpt->monchannel;
09317       cs[n++] = myrpt->txpchannel;
09318       if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
09319       l = myrpt->links.next;
09320       while(l != &myrpt->links)
09321       {
09322          if ((!l->killme) && (!l->disctime) && l->chan)
09323          {
09324             cs[n++] = l->chan;
09325             cs[n++] = l->pchan;
09326          }
09327          l = l->next;
09328       }
09329       rpt_mutex_unlock(&myrpt->lock);
09330       ms = MSWAIT;
09331       for(x = 0; x < n; x++)
09332       {
09333          int s = -(-x - myrpt->scram - 1) % n;
09334          cs1[x] = cs[s];
09335       }
09336       myrpt->scram++;
09337       who = ast_waitfor_n(cs1,n,&ms);
09338       if (who == NULL) ms = 0;
09339       elap = MSWAIT - ms;
09340       rpt_mutex_lock(&myrpt->lock);
09341       l = myrpt->links.next;
09342       while(l != &myrpt->links)
09343       {
09344          if (l->linklisttimer)
09345          {
09346             l->linklisttimer -= elap;
09347             if (l->linklisttimer < 0) l->linklisttimer = 0;
09348          }
09349          if ((!l->linklisttimer) && (l->name[0] != '0') && (!l->isremote))
09350          {
09351             struct   ast_frame lf;
09352 
09353             memset(&lf,0,sizeof(lf));
09354             lf.frametype = AST_FRAME_TEXT;
09355             lf.subclass = 0;
09356             lf.offset = 0;
09357             lf.mallocd = 0;
09358             lf.samples = 0;
09359             l->linklisttimer = LINKLISTTIME;
09360             strcpy(lstr,"L ");
09361             __mklinklist(myrpt,l,lstr + 2);
09362             if (l->chan)
09363             {
09364                lf.datalen = strlen(lstr) + 1;
09365                lf.data = lstr;
09366                ast_write(l->chan,&lf);
09367                if (debug > 6) ast_log(LOG_NOTICE,
09368                   "@@@@ node %s sent node string %s to node %s\n",
09369                      myrpt->name,lstr,l->name);
09370             }
09371          }
09372 #ifndef  OLDKEY
09373          if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
09374          {
09375             l->retxtimer = 0;
09376             if (l->chan && l->phonemode == 0) 
09377             {
09378                if (l->lasttx)
09379                   ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
09380                else
09381                   ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
09382             }
09383          }
09384          if ((l->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 5))
09385          {
09386             if (debug == 7) printf("@@@@ rx un-key\n");
09387             l->lastrx = 0;
09388             l->rerxtimer = 0;
09389             if(myrpt->p.duplex) 
09390                rpt_telemetry(myrpt,LINKUNKEY,l);
09391             if (myrpt->p.archivedir)
09392             {
09393                char str[100];
09394 
09395                l->lastrx1 = 0;
09396                sprintf(str,"RXUNKEY(T),%s",l->name);
09397                donodelog(myrpt,str);
09398             }
09399          }
09400 #endif
09401          if (l->disctime) /* Disconnect timer active on a channel ? */
09402          {
09403             l->disctime -= elap;
09404             if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
09405                l->disctime = 0; /* Yep */
09406          }
09407 
09408          if (l->retrytimer)
09409          {
09410             l->retrytimer -= elap;
09411             if (l->retrytimer < 0) l->retrytimer = 0;
09412          }
09413 
09414          /* Tally connect time */
09415          l->connecttime += elap;
09416 
09417          /* ignore non-timing channels */
09418          if (l->elaptime < 0)
09419          {
09420             l = l->next;
09421             continue;
09422          }
09423          l->elaptime += elap;
09424          /* if connection has taken too long */
09425          if ((l->elaptime > MAXCONNECTTIME) && 
09426             ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
09427          {
09428             l->elaptime = 0;
09429             rpt_mutex_unlock(&myrpt->lock);
09430             if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
09431             rpt_mutex_lock(&myrpt->lock);
09432             break;
09433          }
09434          if ((!l->chan) && (!l->retrytimer) && l->outbound && 
09435             (l->retries++ < l->max_retries) && (l->hasconnected))
09436          {
09437             if (l->chan) ast_hangup(l->chan);
09438             l->chan = 0;
09439             rpt_mutex_unlock(&myrpt->lock);
09440             if ((l->name[0] != '0') && (!l->isremote))
09441             {
09442                if (attempt_reconnect(myrpt,l) == -1)
09443                {
09444                   l->retrytimer = RETRY_TIMER_MS;
09445                } 
09446             }
09447             else 
09448             {
09449                l->retrytimer = l->max_retries + 1;
09450             }
09451 
09452             rpt_mutex_lock(&myrpt->lock);
09453             break;
09454          }
09455          if ((!l->chan) && (!l->retrytimer) && l->outbound &&
09456             (l->retries >= l->max_retries))
09457          {
09458             /* remove from queue */
09459             remque((struct qelem *) l);
09460             if (!strcmp(myrpt->cmdnode,l->name))
09461                myrpt->cmdnode[0] = 0;
09462             rpt_mutex_unlock(&myrpt->lock);
09463             if (l->name[0] != '0')
09464             {
09465                if (!l->hasconnected)
09466                   rpt_telemetry(myrpt,CONNFAIL,l);
09467                else rpt_telemetry(myrpt,REMDISC,l);
09468             }
09469             if (myrpt->p.archivedir)
09470             {
09471                char str[100];
09472 
09473                if (!l->hasconnected)
09474                   sprintf(str,"LINKFAIL,%s",l->name);
09475                else
09476                   sprintf(str,"LINKDISC,%s",l->name);
09477                donodelog(myrpt,str);
09478             }
09479             /* hang-up on call to device */
09480             ast_hangup(l->pchan);
09481             free(l);
09482                                 rpt_mutex_lock(&myrpt->lock);
09483             break;
09484          }
09485                         if ((!l->chan) && (!l->disctime) && (!l->outbound))
09486                         {
09487                                 /* remove from queue */
09488                                 remque((struct qelem *) l);
09489                                 if (!strcmp(myrpt->cmdnode,l->name))
09490                                         myrpt->cmdnode[0] = 0;
09491                                 rpt_mutex_unlock(&myrpt->lock);
09492             if (l->name[0] != '0') 
09493             {
09494                                    rpt_telemetry(myrpt,REMDISC,l);
09495             }
09496             if (myrpt->p.archivedir)
09497             {
09498                char str[100];
09499 
09500                sprintf(str,"LINKDISC,%s",l->name);
09501                donodelog(myrpt,str);
09502             }
09503                                 /* hang-up on call to device */
09504                                 ast_hangup(l->pchan);
09505                                 free(l);
09506                                 rpt_mutex_lock(&myrpt->lock);
09507                                 break;
09508                         }
09509          l = l->next;
09510       }
09511       if(totx){
09512          myrpt->dailytxtime += elap;
09513          myrpt->totaltxtime += elap;
09514       }
09515       i = myrpt->tailtimer;
09516       if (myrpt->tailtimer) myrpt->tailtimer -= elap;
09517       if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
09518       if((i) && (myrpt->tailtimer == 0))
09519          myrpt->tailevent = 1;
09520       if ((!myrpt->p.s[myrpt->p.sysstate_cur].totdisable) && myrpt->totimer) myrpt->totimer -= elap;
09521       if (myrpt->totimer < 0) myrpt->totimer = 0;
09522       if (myrpt->idtimer) myrpt->idtimer -= elap;
09523       if (myrpt->idtimer < 0) myrpt->idtimer = 0;
09524       if (myrpt->tmsgtimer) myrpt->tmsgtimer -= elap;
09525       if (myrpt->tmsgtimer < 0) myrpt->tmsgtimer = 0;
09526       /* do macro timers */
09527       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
09528       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
09529       /* do local dtmf timer */
09530       if (myrpt->dtmf_local_timer)
09531       {
09532          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
09533          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
09534       }
09535       do_dtmf_local(myrpt,0);
09536       /* Execute scheduler appx. every 2 tenths of a second */
09537       if (myrpt->skedtimer <= 0){
09538          myrpt->skedtimer = 200;
09539          do_scheduler(myrpt);
09540       }
09541       else
09542          myrpt->skedtimer -=elap;
09543       if (!ms) 
09544       {
09545          rpt_mutex_unlock(&myrpt->lock);
09546          continue;
09547       }
09548       c = myrpt->macrobuf[0];
09549       time(&t);
09550       if (c && (!myrpt->macrotimer) && 
09551          starttime && (t > (starttime + START_DELAY)))
09552       {
09553          myrpt->macrotimer = MACROTIME;
09554          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
09555          if ((c == 'p') || (c == 'P'))
09556             myrpt->macrotimer = MACROPTIME;
09557          rpt_mutex_unlock(&myrpt->lock);
09558          if (myrpt->p.archivedir)
09559          {
09560             char str[100];
09561 
09562             sprintf(str,"DTMF(M),MAIN,%c",c);
09563             donodelog(myrpt,str);
09564          }
09565          local_dtmf_helper(myrpt,c);
09566       } else rpt_mutex_unlock(&myrpt->lock);
09567       if (who == myrpt->rxchannel) /* if it was a read from rx */
09568       {
09569          int ismuted;
09570 
09571          f = ast_read(myrpt->rxchannel);
09572          if (!f)
09573          {
09574             if (debug) printf("@@@@ rpt:Hung Up\n");
09575             break;
09576          }
09577          if (f->frametype == AST_FRAME_VOICE)
09578          {
09579 #ifdef   _MDC_DECODE_H_
09580             unsigned char ubuf[2560];
09581             short *sp;
09582             int n;
09583 #endif
09584 
09585             if ((!myrpt->localtx) && (!myrpt->p.linktolink)) {
09586                memset(f->data,0,f->datalen);
09587             }
09588 
09589 #ifdef   _MDC_DECODE_H_
09590             sp = (short *) f->data;
09591             /* convert block to unsigned char */
09592             for(n = 0; n < f->datalen / 2; n++)
09593             {
09594                ubuf[n] = (*sp++ >> 8) + 128;
09595             }
09596             n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
09597             if (n == 1)
09598             {
09599                   unsigned char op,arg;
09600                   unsigned short unitID;
09601 
09602                   mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
09603                   if (debug > 2)
09604                   {
09605                      ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
09606                      ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
09607                         op & 255,arg & 255,unitID);
09608                   }
09609                   if ((op == 1) && (arg == 0))
09610                   {
09611                      myrpt->lastunit = unitID;
09612                   }
09613             }
09614             if ((debug > 2) && (i == 2))
09615             {
09616                unsigned char op,arg,ex1,ex2,ex3,ex4;
09617                unsigned short unitID;
09618 
09619                mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
09620                   &ex1,&ex2,&ex3,&ex4);
09621                ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
09622                ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
09623                   op & 255,arg & 255,unitID);
09624                ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
09625                   ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
09626             }
09627 #endif
09628 #ifdef   __RPT_NOTCH
09629             /* apply inbound filters, if any */
09630             rpt_filter(myrpt,f->data,f->datalen / 2);
09631 #endif
09632             if (ioctl(myrpt->rxchannel->fds[0], ZT_GETCONFMUTE, &ismuted) == -1)
09633             {
09634                ismuted = 0;
09635             }
09636             if (dtmfed) ismuted = 1;
09637             dtmfed = 0;
09638             if (ismuted)
09639             {
09640                memset(f->data,0,f->datalen);
09641                if (myrpt->lastf1)
09642                   memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
09643                if (myrpt->lastf2)
09644                   memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
09645             } 
09646             if (f) f2 = ast_frdup(f);
09647             else f2 = NULL;
09648             f1 = myrpt->lastf2;
09649             myrpt->lastf2 = myrpt->lastf1;
09650             myrpt->lastf1 = f2;
09651             if (ismuted)
09652             {
09653                if (myrpt->lastf1)
09654                   memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
09655                if (myrpt->lastf2)
09656                   memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
09657             }
09658             if (f1)
09659             {
09660                ast_write(myrpt->pchannel,f1);
09661                ast_frfree(f1);
09662             }
09663          }
09664 #ifndef  OLD_ASTERISK
09665          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
09666          {
09667             if (myrpt->lastf1)
09668                memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
09669             if (myrpt->lastf2)
09670                memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
09671             dtmfed = 1;
09672          }
09673 #endif
09674          else if (f->frametype == AST_FRAME_DTMF)
09675          {
09676             c = (char) f->subclass; /* get DTMF char */
09677             ast_frfree(f);
09678             if (myrpt->lastf1)
09679                memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
09680             if (myrpt->lastf2)
09681                memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
09682             dtmfed = 1;
09683             if (!myrpt->keyed) continue;
09684             c = func_xlat(myrpt,c,&myrpt->p.inxlat);
09685             if (c) local_dtmf_helper(myrpt,c);
09686             continue;
09687          }                 
09688          else if (f->frametype == AST_FRAME_CONTROL)
09689          {
09690             if (f->subclass == AST_CONTROL_HANGUP)
09691             {
09692                if (debug) printf("@@@@ rpt:Hung Up\n");
09693                ast_frfree(f);
09694                break;
09695             }
09696             /* if RX key */
09697             if (f->subclass == AST_CONTROL_RADIO_KEY)
09698             {
09699                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink)) 
09700                {
09701                   if (debug == 7) printf("@@@@ rx key\n");
09702                   myrpt->keyed = 1;
09703                }
09704                if (myrpt->p.archivedir)
09705                {
09706                   donodelog(myrpt,"RXKEY,MAIN");
09707                }
09708             }
09709             /* if RX un-key */
09710             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
09711             {
09712                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
09713                {
09714                   if (debug == 7) printf("@@@@ rx un-key\n");
09715                   if(myrpt->p.duplex && myrpt->keyed) {
09716                      rpt_telemetry(myrpt,UNKEY,NULL);
09717                   }
09718                }
09719                myrpt->keyed = 0;
09720                if (myrpt->p.archivedir)
09721                {
09722                   donodelog(myrpt,"RXUNKEY,MAIN");
09723                }
09724             }
09725          }
09726          ast_frfree(f);
09727          continue;
09728       }
09729       if (who == myrpt->pchannel) /* if it was a read from pseudo */
09730       {
09731          f = ast_read(myrpt->pchannel);
09732          if (!f)
09733          {
09734             if (debug) printf("@@@@ rpt:Hung Up\n");
09735             break;
09736          }
09737          if (f->frametype == AST_FRAME_VOICE)
09738          {
09739             ast_write(myrpt->txpchannel,f);
09740          }
09741          if (f->frametype == AST_FRAME_CONTROL)
09742          {
09743             if (f->subclass == AST_CONTROL_HANGUP)
09744             {
09745                if (debug) printf("@@@@ rpt:Hung Up\n");
09746                ast_frfree(f);
09747                break;
09748             }
09749          }
09750          ast_frfree(f);
09751          continue;
09752       }
09753       if (who == myrpt->txchannel) /* if it was a read from tx */
09754       {
09755          f = ast_read(myrpt->txchannel);
09756          if (!f)
09757          {
09758             if (debug) printf("@@@@ rpt:Hung Up\n");
09759             break;
09760          }
09761          if (f->frametype == AST_FRAME_CONTROL)
09762          {
09763             if (f->subclass == AST_CONTROL_HANGUP)
09764             {
09765                if (debug) printf("@@@@ rpt:Hung Up\n");
09766                ast_frfree(f);
09767                break;
09768             }
09769          }
09770          ast_frfree(f);
09771          continue;
09772       }
09773       toexit = 0;
09774       rpt_mutex_lock(&myrpt->lock);
09775       l = myrpt->links.next;
09776       while(l != &myrpt->links)
09777       {
09778          if (l->disctime)
09779          {
09780             l = l->next;
09781             continue;
09782          }
09783          if (who == l->chan) /* if it was a read from rx */
09784          {
09785             int remnomute;
09786 
09787             remrx = 0;
09788             /* see if any other links are receiving */
09789             m = myrpt->links.next;
09790             while(m != &myrpt->links)
09791             {
09792                /* if not us, count it */
09793                if ((m != l) && (m->lastrx)) remrx = 1;
09794                m = m->next;
09795             }
09796             rpt_mutex_unlock(&myrpt->lock);
09797             remnomute = myrpt->localtx && 
09798                 (!(myrpt->cmdnode[0] || 
09799                (myrpt->dtmfidx > -1)));
09800             totx = (((l->isremote) ? (remnomute) : 
09801                myrpt->exttx) || remrx) && l->mode;
09802             if (l->phonemode == 0 && l->chan && (l->lasttx != totx))
09803             {
09804                if (totx)
09805                {
09806                   ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
09807                }
09808                else
09809                {
09810                   ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
09811                }
09812                if (myrpt->p.archivedir)
09813                {
09814                   char str[100];
09815 
09816                   if (totx)
09817                      sprintf(str,"TXKEY,%s",l->name);
09818                   else
09819                      sprintf(str,"TXUNKEY,%s",l->name);
09820                   donodelog(myrpt,str);
09821                }
09822             }
09823             l->lasttx = totx;
09824             f = ast_read(l->chan);
09825             if (!f)
09826             {
09827                rpt_mutex_lock(&myrpt->lock);
09828                __kickshort(myrpt);
09829                rpt_mutex_unlock(&myrpt->lock);
09830                if ((!l->disced) && (!l->outbound))
09831                {
09832                   if ((l->name[0] == '0') || l->isremote)
09833                      l->disctime = 1;
09834                   else
09835                      l->disctime = DISC_TIME;
09836                   rpt_mutex_lock(&myrpt->lock);
09837                   ast_hangup(l->chan);
09838                   l->chan = 0;
09839                   break;
09840                }
09841 
09842                if (l->retrytimer) 
09843                {
09844                   ast_hangup(l->chan);
09845                   l->chan = 0;
09846                   rpt_mutex_lock(&myrpt->lock);
09847                   break; 
09848                }
09849                if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
09850                {
09851                   rpt_mutex_lock(&myrpt->lock);
09852                   if (l->chan) ast_hangup(l->chan);
09853                   l->chan = 0;
09854                   l->hasconnected = 1;
09855                   l->retrytimer = RETRY_TIMER_MS;
09856                   l->elaptime = 0;
09857                   l->connecttime = 0;
09858                   l->thisconnected = 0;
09859                   break;
09860                }
09861                rpt_mutex_lock(&myrpt->lock);
09862                /* remove from queue */
09863                remque((struct qelem *) l);
09864                if (!strcmp(myrpt->cmdnode,l->name))
09865                   myrpt->cmdnode[0] = 0;
09866                __kickshort(myrpt);
09867                rpt_mutex_unlock(&myrpt->lock);
09868                if (!l->hasconnected)
09869                   rpt_telemetry(myrpt,CONNFAIL,l);
09870                else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
09871                if (myrpt->p.archivedir)
09872                {
09873                   char str[100];
09874 
09875                   if (!l->hasconnected)
09876                      sprintf(str,"LINKFAIL,%s",l->name);
09877                   else
09878                      sprintf(str,"LINKDISC,%s",l->name);
09879                   donodelog(myrpt,str);
09880                }
09881                if (l->lastf1) ast_frfree(l->lastf1);
09882                l->lastf1 = NULL;
09883                if (l->lastf2) ast_frfree(l->lastf2);
09884                l->lastf2 = NULL;
09885                /* hang-up on call to device */
09886                ast_hangup(l->chan);
09887                ast_hangup(l->pchan);
09888                free(l);
09889                rpt_mutex_lock(&myrpt->lock);
09890                break;
09891             }
09892             if (f->frametype == AST_FRAME_VOICE)
09893             {
09894                int ismuted;
09895 
09896                if (l->phonemode)
09897                {
09898                   if (ioctl(l->chan->fds[0], ZT_GETCONFMUTE, &ismuted) == -1)
09899                   {
09900                      ismuted = 0;
09901                   }
09902                   /* if not receiving, zero-out audio */
09903                   ismuted |= (!l->lastrx);
09904                   if (l->dtmfed && l->phonemode) ismuted = 1;
09905                   l->dtmfed = 0;
09906                   if (ismuted)
09907                   {
09908                      memset(f->data,0,f->datalen);
09909                      if (l->lastf1)
09910                         memset(l->lastf1->data,0,l->lastf1->datalen);
09911                      if (l->lastf2)
09912                         memset(l->lastf2->data,0,l->lastf2->datalen);
09913                   } 
09914                   if (f) f2 = ast_frdup(f);
09915                   else f2 = NULL;
09916                   f1 = l->lastf2;
09917                   l->lastf2 = l->lastf1;
09918                   l->lastf1 = f2;
09919                   if (ismuted)
09920                   {
09921                      if (l->lastf1)
09922                         memset(l->lastf1->data,0,l->lastf1->datalen);
09923                      if (l->lastf2)
09924                         memset(l->lastf2->data,0,l->lastf2->datalen);
09925                   }
09926                   if (f1)
09927                   {
09928                      ast_write(l->pchan,f1);
09929                      ast_frfree(f1);
09930                   }
09931                }
09932                else
09933                {
09934                   if (!l->lastrx)
09935                      memset(f->data,0,f->datalen);
09936                   ast_write(l->pchan,f);
09937                }
09938             }
09939 #ifndef  OLD_ASTERISK
09940             else if (f->frametype == AST_FRAME_DTMF_BEGIN)
09941             {
09942                if (l->lastf1)
09943                   memset(l->lastf1->data,0,l->lastf1->datalen);
09944                if (l->lastf2)
09945                   memset(l->lastf2->data,0,l->lastf2->datalen);
09946                l->dtmfed = 1;
09947             }
09948 #endif
09949 
09950             if (f->frametype == AST_FRAME_TEXT)
09951             {
09952                handle_link_data(myrpt,l,f->data);
09953             }
09954             if (f->frametype == AST_FRAME_DTMF)
09955             {
09956                if (l->lastf1)
09957                   memset(l->lastf1->data,0,l->lastf1->datalen);
09958                if (l->lastf2)
09959                   memset(l->lastf2->data,0,l->lastf2->datalen);
09960                l->dtmfed = 1;
09961                handle_link_phone_dtmf(myrpt,l,f->subclass);
09962             }
09963             if (f->frametype == AST_FRAME_CONTROL)
09964             {
09965                if (f->subclass == AST_CONTROL_ANSWER)
09966                {
09967                   char lconnected = l->connected;
09968 
09969                   __kickshort(myrpt);
09970                   l->connected = 1;
09971                   l->hasconnected = 1;
09972                   l->thisconnected = 1;
09973                   l->elaptime = -1;
09974                   if (!l->isremote) l->retries = 0;
09975                   if (!lconnected) 
09976                   {
09977                      rpt_telemetry(myrpt,CONNECTED,l);
09978                      if (myrpt->p.archivedir)
09979                      {
09980                         char str[100];
09981 
09982                         if (l->mode)
09983                            sprintf(str,"LINKTRX,%s",l->name);
09984                         else
09985                            sprintf(str,"LINKMONITOR,%s",l->name);
09986                         donodelog(myrpt,str);
09987                      }
09988                   }     
09989                   else
09990                      l->reconnects++;
09991                }
09992                /* if RX key */
09993                if (f->subclass == AST_CONTROL_RADIO_KEY)
09994                {
09995                   if (debug == 7 ) printf("@@@@ rx key\n");
09996                   l->lastrx = 1;
09997                   l->rerxtimer = 0;
09998                   if (myrpt->p.archivedir && (!l->lastrx1))
09999                   {
10000                      char str[100];
10001 
10002                      l->lastrx1 = 1;
10003                      sprintf(str,"RXKEY,%s",l->name);
10004                      donodelog(myrpt,str);
10005                   }
10006                }
10007                /* if RX un-key */
10008                if (f->subclass == AST_CONTROL_RADIO_UNKEY)
10009                {
10010                   if (debug == 7) printf("@@@@ rx un-key\n");
10011                   l->lastrx = 0;
10012                   l->rerxtimer = 0;
10013                   if(myrpt->p.duplex) 
10014                      rpt_telemetry(myrpt,LINKUNKEY,l);
10015                   if (myrpt->p.archivedir && (l->lastrx1))
10016                   {
10017                      char str[100];
10018 
10019                      l->lastrx1 = 0;
10020                      sprintf(str,"RXUNKEY,%s",l->name);
10021                      donodelog(myrpt,str);
10022                   }
10023                }
10024                if (f->subclass == AST_CONTROL_HANGUP)
10025                {
10026                   ast_frfree(f);
10027                   rpt_mutex_lock(&myrpt->lock);
10028                   __kickshort(myrpt);
10029                   rpt_mutex_unlock(&myrpt->lock);
10030                   if ((!l->outbound) && (!l->disced))
10031                   {
10032                      if ((l->name[0] == '0') || l->isremote)
10033                         l->disctime = 1;
10034                      else
10035                         l->disctime = DISC_TIME;
10036                      rpt_mutex_lock(&myrpt->lock);
10037                      ast_hangup(l->chan);
10038                      l->chan = 0;
10039                      break;
10040                   }
10041                   if (l->retrytimer) 
10042                   {
10043                      if (l->chan) ast_hangup(l->chan);
10044                      l->chan = 0;
10045                      rpt_mutex_lock(&myrpt->lock);
10046                      break;
10047                   }
10048                   if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
10049                   {
10050                      rpt_mutex_lock(&myrpt->lock);
10051                      if (l->chan) ast_hangup(l->chan);
10052                      l->chan = 0;
10053                      l->hasconnected = 1;
10054                      l->elaptime = 0;
10055                      l->retrytimer = RETRY_TIMER_MS;
10056                      l->connecttime = 0;
10057                      l->thisconnected = 0;
10058                      break;
10059                   }
10060                   rpt_mutex_lock(&myrpt->lock);
10061                   /* remove from queue */
10062                   remque((struct qelem *) l);
10063                   if (!strcmp(myrpt->cmdnode,l->name))
10064                      myrpt->cmdnode[0] = 0;
10065                   __kickshort(myrpt);
10066                   rpt_mutex_unlock(&myrpt->lock);
10067                   if (!l->hasconnected)
10068                      rpt_telemetry(myrpt,CONNFAIL,l);
10069                   else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
10070                   if (myrpt->p.archivedir)
10071                   {
10072                      char str[100];
10073 
10074                      if (!l->hasconnected)
10075                         sprintf(str,"LINKFAIL,%s",l->name);
10076                      else
10077                         sprintf(str,"LINKDISC,%s",l->name);
10078                      donodelog(myrpt,str);
10079                   }
10080                   if (l->lastf1) ast_frfree(l->lastf1);
10081                   l->lastf1 = NULL;
10082                   if (l->lastf2) ast_frfree(l->lastf2);
10083                   l->lastf2 = NULL;
10084                   /* hang-up on call to device */
10085                   ast_hangup(l->chan);
10086                   ast_hangup(l->pchan);
10087                   free(l);
10088                   rpt_mutex_lock(&myrpt->lock);
10089                   break;
10090                }
10091             }
10092             ast_frfree(f);
10093             rpt_mutex_lock(&myrpt->lock);
10094             break;
10095          }
10096          if (who == l->pchan) 
10097          {
10098             rpt_mutex_unlock(&myrpt->lock);
10099             f = ast_read(l->pchan);
10100             if (!f)
10101             {
10102                if (debug) printf("@@@@ rpt:Hung Up\n");
10103                toexit = 1;
10104                rpt_mutex_lock(&myrpt->lock);
10105                break;
10106             }
10107             if (f->frametype == AST_FRAME_VOICE)
10108             {
10109                if (l->chan) ast_write(l->chan,f);
10110             }
10111             if (f->frametype == AST_FRAME_CONTROL)
10112             {
10113                if (f->subclass == AST_CONTROL_HANGUP)
10114                {
10115                   if (debug) printf("@@@@ rpt:Hung Up\n");
10116                   ast_frfree(f);
10117                   toexit = 1;
10118                   rpt_mutex_lock(&myrpt->lock);
10119                   break;
10120                }
10121             }
10122             ast_frfree(f);
10123             rpt_mutex_lock(&myrpt->lock);
10124             break;
10125          }
10126          l = l->next;
10127       }
10128       rpt_mutex_unlock(&myrpt->lock);
10129       if (toexit) break;
10130       if (who == myrpt->monchannel) 
10131       {
10132          f = ast_read(myrpt->monchannel);
10133          if (!f)
10134          {
10135             if (debug) printf("@@@@ rpt:Hung Up\n");
10136             break;
10137          }
10138          if (f->frametype == AST_FRAME_VOICE)
10139          {
10140             if (myrpt->monstream) 
10141                ast_writestream(myrpt->monstream,f);
10142          }
10143          if (f->frametype == AST_FRAME_CONTROL)
10144          {
10145             if (f->subclass == AST_CONTROL_HANGUP)
10146             {
10147                if (debug) printf("@@@@ rpt:Hung Up\n");
10148                ast_frfree(f);
10149                break;
10150             }
10151          }
10152          ast_frfree(f);
10153          continue;
10154       }
10155       if (who == myrpt->txpchannel) /* if it was a read from remote tx */
10156       {
10157          f = ast_read(myrpt->txpchannel);
10158          if (!f)
10159          {
10160             if (debug) printf("@@@@ rpt:Hung Up\n");
10161             break;
10162          }
10163          if (f->frametype == AST_FRAME_CONTROL)
10164          {
10165             if (f->subclass == AST_CONTROL_HANGUP)
10166             {
10167                if (debug) printf("@@@@ rpt:Hung Up\n");
10168                ast_frfree(f);
10169                break;
10170             }
10171          }
10172          ast_frfree(f);
10173          continue;
10174       }
10175    }
10176    usleep(100000);
10177    ast_hangup(myrpt->pchannel);
10178    ast_hangup(myrpt->monchannel);
10179    ast_hangup(myrpt->txpchannel);
10180    if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
10181    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
10182    myrpt->lastf1 = NULL;
10183    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
10184    myrpt->lastf2 = NULL;
10185    ast_hangup(myrpt->rxchannel);
10186    rpt_mutex_lock(&myrpt->lock);
10187    l = myrpt->links.next;
10188    while(l != &myrpt->links)
10189    {
10190       struct rpt_link *ll = l;
10191       /* remove from queue */
10192       remque((struct qelem *) l);
10193       /* hang-up on call to device */
10194       if (l->chan) ast_hangup(l->chan);
10195       ast_hangup(l->pchan);
10196       l = l->next;
10197       free(ll);
10198    }
10199    rpt_mutex_unlock(&myrpt->lock);
10200    if (debug) printf("@@@@ rpt:Hung up channel\n");
10201    myrpt->rpt_thread = AST_PTHREADT_STOP;
10202    pthread_exit(NULL); 
10203    return NULL;
10204 }
10205 
10206    
10207 static void *rpt_master(void *ignore)
10208 {
10209 int   i,n;
10210 pthread_attr_t attr;
10211 struct ast_config *cfg;
10212 char *this,*val;
10213 
10214    /* init nodelog queue */
10215    nodelog.next = nodelog.prev = &nodelog;
10216    /* go thru all the specified repeaters */
10217    this = NULL;
10218    n = 0;
10219    rpt_vars[n].cfg = ast_config_load("rpt.conf");
10220    cfg = rpt_vars[n].cfg;
10221    if (!cfg) {
10222       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
10223       pthread_exit(NULL);
10224    }
10225    while((this = ast_category_browse(cfg,this)) != NULL)
10226    {
10227       for(i = 0 ; i < strlen(this) ; i++){
10228          if((this[i] < '0') || (this[i] > '9'))
10229             break;
10230       }
10231       if(i != strlen(this)) continue; /* Not a node defn */
10232       memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
10233       rpt_vars[n].name = strdup(this);
10234       val = (char *) ast_variable_retrieve(cfg,this,"rxchannel");
10235       if (val) rpt_vars[n].rxchanname = strdup(val);
10236       val = (char *) ast_variable_retrieve(cfg,this,"txchannel");
10237       if (val) rpt_vars[n].txchanname = strdup(val);
10238       val = (char *) ast_variable_retrieve(cfg,this,"remote");
10239       if (val) rpt_vars[n].remote = strdup(val);
10240       ast_mutex_init(&rpt_vars[n].lock);
10241       ast_mutex_init(&rpt_vars[n].remlock);
10242       rpt_vars[n].tele.next = &rpt_vars[n].tele;
10243       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
10244       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
10245       rpt_vars[n].tailmessagen = 0;
10246 #ifdef   _MDC_DECODE_H_
10247       rpt_vars[n].mdc = mdc_decoder_new(8000);
10248 #endif
10249       n++;
10250    }
10251    nrpts = n;
10252    ast_config_destroy(cfg);
10253 
10254    /* start em all */
10255    for(i = 0; i < n; i++)
10256    {
10257       load_rpt_vars(i,1);
10258 
10259       /* if is a remote, dont start one for it */
10260       if (rpt_vars[i].remote)
10261       {
10262          if(retreive_memory(&rpt_vars[i],"init")){ /* Try to retreive initial memory channel */
10263             strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
10264             strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
10265 
10266             strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
10267             rpt_vars[i].remmode = REM_MODE_FM;
10268             rpt_vars[i].offset = REM_SIMPLEX;
10269             rpt_vars[i].powerlevel = REM_MEDPWR;
10270          }
10271          continue;
10272       }
10273       if (!rpt_vars[i].p.ident)
10274       {
10275          ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
10276          ast_config_destroy(cfg);
10277          pthread_exit(NULL);
10278       }
10279            pthread_attr_init(&attr);
10280            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10281       ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
10282    }
10283    usleep(500000);
10284    time(&starttime);
10285    for(;;)
10286    {
10287       /* Now monitor each thread, and restart it if necessary */
10288       for(i = 0; i < n; i++)
10289       { 
10290          int rv;
10291          if (rpt_vars[i].remote) continue;
10292          if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP) 
10293             rv = -1;
10294          else
10295             rv = pthread_kill(rpt_vars[i].rpt_thread,0);
10296          if (rv)
10297          {
10298             if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15)
10299             {
10300                if(rpt_vars[i].threadrestarts >= 5)
10301                {
10302                   ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n");
10303                   exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
10304                }
10305                else
10306                {
10307                   ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name);
10308                   rpt_vars[i].threadrestarts++;
10309                }
10310             }
10311             else
10312                rpt_vars[i].threadrestarts = 0;
10313 
10314             rpt_vars[i].lastthreadrestarttime = time(NULL);
10315                  pthread_attr_init(&attr);
10316                  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10317             ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
10318             ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
10319          }
10320 
10321       }
10322       for(;;)
10323       {
10324          struct nodelog *nodep;
10325          char *space,datestr[100],fname[300];
10326          int fd;
10327 
10328          ast_mutex_lock(&nodeloglock);
10329          nodep = nodelog.next;
10330          if(nodep == &nodelog) /* if nothing in queue */
10331          {
10332             ast_mutex_unlock(&nodeloglock);
10333             break;
10334          }
10335          remque((struct qelem *)nodep);
10336          ast_mutex_unlock(&nodeloglock);
10337          space = strchr(nodep->str,' ');
10338          if (!space) 
10339          {
10340             free(nodep);
10341             continue;
10342          }
10343          *space = 0;
10344          strftime(datestr,sizeof(datestr) - 1,"%Y%m%d",
10345             localtime(&nodep->timestamp));
10346          sprintf(fname,"%s/%s/%s.txt",nodep->archivedir,
10347             nodep->str,datestr);
10348          fd = open(fname,O_WRONLY | O_CREAT | O_APPEND,0600);
10349          if (fd == -1)
10350          {
10351             ast_log(LOG_ERROR,"Cannot open node log file %s for write",space + 1);
10352             free(nodep);
10353             continue;
10354          }
10355          if (write(fd,space + 1,strlen(space + 1)) !=
10356             strlen(space + 1))
10357          {
10358             ast_log(LOG_ERROR,"Cannot write node log file %s for write",space + 1);
10359             free(nodep);
10360             continue;
10361          }
10362          close(fd);
10363          free(nodep);
10364       }
10365       usleep(2000000);
10366    }
10367    ast_config_destroy(cfg);
10368    pthread_exit(NULL);
10369 }
10370 
10371 static int rpt_exec(struct ast_channel *chan, void *data)
10372 {
10373    int res=-1,i,rem_totx,rem_rx,remkeyed,n,phone_mode = 0;
10374    int iskenwood_pci4,authtold,authreq,setting,notremming,reming;
10375    int ismuted,dtmfed;
10376 #ifdef   OLD_ASTERISK
10377    struct localuser *u;
10378 #endif
10379    char tmp[256], keyed = 0,keyed1 = 0;
10380    char *options,*stringp,*tele,c;
10381    struct   rpt *myrpt;
10382    struct ast_frame *f,*f1,*f2;
10383    struct ast_channel *who;
10384    struct ast_channel *cs[20];
10385    struct   rpt_link *l;
10386    ZT_CONFINFO ci;  /* conference info */
10387    ZT_PARAMS par;
10388    int ms,elap,nullfd;
10389    time_t t,last_timeout_warning;
10390    struct   zt_radio_param z;
10391    struct rpt_tele *telem;
10392 
10393    nullfd = open("/dev/null",O_RDWR);
10394    if (ast_strlen_zero(data)) {
10395       ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
10396       return -1;
10397    }
10398    strncpy(tmp, (char *)data, sizeof(tmp)-1);
10399    time(&t);
10400    /* if time has externally shifted negative, screw it */
10401    if (t < starttime) t = starttime + START_DELAY;
10402    if ((!starttime) || (t < (starttime + START_DELAY)))
10403    {
10404       ast_log(LOG_NOTICE,"Node %s rejecting call: too soon!\n",tmp);
10405       ast_safe_sleep(chan,3000);
10406       return -1;
10407    }
10408    stringp=tmp;
10409    strsep(&stringp, "|");
10410    options = stringp;
10411    myrpt = NULL;
10412    /* see if we can find our specified one */
10413    for(i = 0; i < nrpts; i++)
10414    {
10415       /* if name matches, assign it and exit loop */
10416       if (!strcmp(tmp,rpt_vars[i].name))
10417       {
10418          myrpt = &rpt_vars[i];
10419          break;
10420       }
10421    }
10422    if (myrpt == NULL)
10423    {
10424       ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
10425       return -1;
10426    }
10427    
10428    if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable){ /* Do not allow incoming connections if disabled */
10429       ast_log(LOG_NOTICE, "Connect attempt to node %s  with tx disabled", myrpt->name);
10430       return -1;
10431    }
10432 
10433    /* if not phone access, must be an IAX connection */
10434    if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R')))
10435    {
10436       int val;
10437 
10438       phone_mode = 1;
10439       if (*options == 'D') phone_mode = 2;
10440       ast_set_callerid(chan,"0","app_rpt user","0");
10441       val = 1;
10442       ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
10443    }
10444    else
10445    {
10446       if (strncmp(chan->name,"IAX2",4))
10447       {
10448          ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
10449          return -1;
10450       }
10451    }
10452    if (options && (*options == 'R'))
10453    {
10454 
10455       /* Parts of this section taken from app_parkandannounce */
10456       char *return_context;
10457       int l, m, lot, timeout = 0;
10458       char tmp[256],*template;
10459       char *working, *context, *exten, *priority;
10460       char *s,*orig_s;
10461 
10462 
10463       rpt_mutex_lock(&myrpt->lock);
10464       m = myrpt->callmode;
10465       rpt_mutex_unlock(&myrpt->lock);
10466 
10467       if ((!myrpt->p.nobusyout) && m)
10468       {
10469          if (chan->_state != AST_STATE_UP)
10470          {
10471             ast_indicate(chan,AST_CONTROL_BUSY);
10472          }
10473          while(ast_safe_sleep(chan,10000) != -1);
10474          return -1;
10475       }
10476 
10477       if (chan->_state != AST_STATE_UP)
10478       {
10479          ast_answer(chan);
10480       }
10481 
10482       l=strlen(options)+2;
10483       orig_s=malloc(l);
10484       if(!orig_s) {
10485          ast_log(LOG_WARNING, "Out of memory\n");
10486          return -1;
10487       }
10488       s=orig_s;
10489       strncpy(s,options,l);
10490 
10491       template=strsep(&s,"|");
10492       if(!template) {
10493          ast_log(LOG_WARNING, "An announce template must be defined\n");
10494          free(orig_s);
10495          return -1;
10496       } 
10497   
10498       if(s) {
10499          timeout = atoi(strsep(&s, "|"));
10500          timeout *= 1000;
10501       }
10502    
10503       return_context = s;
10504   
10505       if(return_context != NULL) {
10506          /* set the return context. Code borrowed from the Goto builtin */
10507     
10508          working = return_context;
10509          context = strsep(&working, "|");
10510          exten = strsep(&working, "|");
10511          if(!exten) {
10512             /* Only a priority in this one */
10513             priority = context;
10514             exten = NULL;
10515             context = NULL;
10516          } else {
10517             priority = strsep(&working, "|");
10518             if(!priority) {
10519                /* Only an extension and priority in this one */
10520                priority = exten;
10521                exten = context;
10522                context = NULL;
10523          }
10524       }
10525       if(atoi(priority) < 0) {
10526          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
10527          free(orig_s);
10528          return -1;
10529       }
10530       /* At this point we have a priority and maybe an extension and a context */
10531       chan->priority = atoi(priority);
10532 #ifdef OLD_ASTERISK
10533       if(exten && strcasecmp(exten, "BYEXTENSION"))
10534 #else
10535       if(exten)
10536 #endif
10537          strncpy(chan->exten, exten, sizeof(chan->exten)-1);
10538       if(context)
10539          strncpy(chan->context, context, sizeof(chan->context)-1);
10540       } else {  /* increment the priority by default*/
10541          chan->priority++;
10542       }
10543 
10544       if(option_verbose > 2) {
10545          ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
10546          if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
10547             ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
10548          }
10549       }
10550   
10551       /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
10552       before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
10553 
10554       ast_masq_park_call(chan, NULL, timeout, &lot);
10555 
10556       if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
10557 
10558       snprintf(tmp,sizeof(tmp) - 1,"%d,%s",lot,template + 1);
10559 
10560       rpt_telemetry(myrpt,REV_PATCH,tmp);
10561 
10562       free(orig_s);
10563 
10564       return 0;
10565 
10566    }
10567 
10568    if (!options)
10569    {
10570                 struct ast_hostent ahp;
10571                 struct hostent *hp;
10572       struct in_addr ia;
10573       char hisip[100],nodeip[100],*val, *s, *s1, *s2, *b,*b1;
10574 
10575       /* look at callerid to see what node this comes from */
10576       if (!chan->cid.cid_num) /* if doesn't have caller id */
10577       {
10578          ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
10579          return -1;
10580       }
10581 
10582       /* get his IP from IAX2 module */
10583       memset(hisip,0,sizeof(hisip));
10584       pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
10585       if (!hisip[0])
10586       {
10587          ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
10588          return -1;
10589       }
10590       
10591       ast_callerid_parse(chan->cid.cid_num,&b,&b1);
10592       ast_shrink_phone_number(b1);
10593       if (!strcmp(myrpt->name,b1))
10594       {
10595          ast_log(LOG_WARNING, "Trying to link to self!!\n");
10596          return -1;
10597       }
10598 
10599       if (*b1 < '1')
10600       {
10601          ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n",b1);
10602          return -1;
10603       }
10604 
10605 
10606       /* look for his reported node string */
10607       val = node_lookup(myrpt,b1);
10608       if (!val)
10609       {
10610          ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
10611          return -1;
10612       }
10613       strncpy(tmp,val,sizeof(tmp) - 1);
10614       s = tmp;
10615       s1 = strsep(&s,",");
10616       s2 = strsep(&s,",");
10617       if (!s2)
10618       {
10619          ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n",b1);
10620          return -1;
10621       }
10622                 if (strcmp(s2,"NONE")) {
10623          hp = ast_gethostbyname(s2, &ahp);
10624          if (!hp)
10625          {
10626             ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s2);
10627             return -1;
10628          }
10629          memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
10630 #ifdef   OLD_ASTERISK
10631          ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
10632 #else
10633          strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
10634 #endif
10635          if (strcmp(hisip,nodeip))
10636          {
10637             char *s3 = strchr(s1,'@');
10638             if (s3) s1 = s3 + 1;
10639             s3 = strchr(s1,'/');
10640             if (s3) *s3 = 0;
10641             hp = ast_gethostbyname(s1, &ahp);
10642             if (!hp)
10643             {
10644                ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s1);
10645                return -1;
10646             }
10647             memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
10648 #ifdef   OLD_ASTERISK
10649             ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
10650 #else
10651             strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
10652 #endif
10653             if (strcmp(hisip,nodeip))
10654             {
10655                ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip);
10656                return -1;
10657             }
10658          }
10659       }
10660    }
10661 
10662    /* if is not a remote */
10663    if (!myrpt->remote)
10664    {
10665 
10666       char *b,*b1;
10667       int reconnects = 0;
10668 
10669       /* look at callerid to see what node this comes from */
10670       if (!chan->cid.cid_num) /* if doesn't have caller id */
10671       {
10672          ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
10673          return -1;
10674       }
10675 
10676       ast_callerid_parse(chan->cid.cid_num,&b,&b1);
10677       ast_shrink_phone_number(b1);
10678       if (!strcmp(myrpt->name,b1))
10679       {
10680          ast_log(LOG_WARNING, "Trying to link to self!!\n");
10681          return -1;
10682       }
10683       rpt_mutex_lock(&myrpt->lock);
10684       l = myrpt->links.next;
10685       /* try to find this one in queue */
10686       while(l != &myrpt->links)
10687       {
10688          if (l->name[0] == '0') 
10689          {
10690             l = l->next;
10691             continue;
10692          }
10693          /* if found matching string */
10694          if (!strcmp(l->name,b1)) break;
10695          l = l->next;
10696       }
10697       /* if found */
10698       if (l != &myrpt->links) 
10699       {
10700          l->killme = 1;
10701          l->retries = l->max_retries + 1;
10702          l->disced = 2;
10703          reconnects = l->reconnects;
10704          reconnects++;
10705                         rpt_mutex_unlock(&myrpt->lock);
10706          usleep(500000);   
10707       } else 
10708          rpt_mutex_unlock(&myrpt->lock);
10709       /* establish call in tranceive mode */
10710       l = malloc(sizeof(struct rpt_link));
10711       if (!l)
10712       {
10713          ast_log(LOG_WARNING, "Unable to malloc\n");
10714          pthread_exit(NULL);
10715       }
10716       /* zero the silly thing */
10717       memset((char *)l,0,sizeof(struct rpt_link));
10718       l->mode = 1;
10719       strncpy(l->name,b1,MAXNODESTR - 1);
10720       l->isremote = 0;
10721       l->chan = chan;
10722       l->connected = 1;
10723       l->thisconnected = 1;
10724       l->hasconnected = 1;
10725       l->reconnects = reconnects;
10726       l->phonemode = phone_mode;
10727       l->lastf1 = NULL;
10728       l->lastf2 = NULL;
10729       l->dtmfed = 0;
10730       ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
10731       ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
10732       /* allocate a pseudo-channel thru asterisk */
10733       l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
10734       if (!l->pchan)
10735       {
10736          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10737          pthread_exit(NULL);
10738       }
10739       ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
10740       ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
10741       /* make a conference for the tx */
10742       ci.chan = 0;
10743       ci.confno = myrpt->conf;
10744       ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
10745       /* first put the channel on the conference in proper mode */
10746       if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
10747       {
10748          ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10749          pthread_exit(NULL);
10750       }
10751       rpt_mutex_lock(&myrpt->lock);
10752       if (phone_mode > 1) l->lastrx = 1;
10753       l->max_retries = MAX_RETRIES;
10754       /* insert at end of queue */
10755       insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
10756       __kickshort(myrpt);
10757       rpt_mutex_unlock(&myrpt->lock);
10758       if (chan->_state != AST_STATE_UP) {
10759          ast_answer(chan);
10760       }
10761       if (myrpt->p.archivedir)
10762       {
10763          char str[100];
10764 
10765          if (l->phonemode)
10766             sprintf(str,"LINK(P),%s",l->name);
10767          else
10768             sprintf(str,"LINK,%s",l->name);
10769          donodelog(myrpt,str);
10770       }
10771       return AST_PBX_KEEPALIVE;
10772    }
10773    /* well, then it is a remote */
10774    rpt_mutex_lock(&myrpt->lock);
10775    /* if remote, error if anyone else already linked */
10776    if (myrpt->remoteon)
10777    {
10778       rpt_mutex_unlock(&myrpt->lock);
10779       usleep(500000);
10780       if (myrpt->remoteon)
10781       {
10782          ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
10783          return -1;
10784       }     
10785       rpt_mutex_lock(&myrpt->lock);
10786    }
10787    if ((!strcmp(myrpt->remote, remote_rig_rbi)) &&
10788      (ioperm(myrpt->p.iobase,1,1) == -1))
10789    {
10790       rpt_mutex_unlock(&myrpt->lock);
10791       ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
10792       return -1;
10793    }
10794    myrpt->remoteon = 1;
10795 #ifdef   OLD_ASTERISK
10796    LOCAL_USER_ADD(u);
10797 #endif
10798    rpt_mutex_unlock(&myrpt->lock);
10799    /* find our index, and load the vars initially */
10800    for(i = 0; i < nrpts; i++)
10801    {
10802       if (&rpt_vars[i] == myrpt)
10803       {
10804          load_rpt_vars(i,0);
10805          break;
10806       }
10807    }
10808    rpt_mutex_lock(&myrpt->lock);
10809    tele = strchr(myrpt->rxchanname,'/');
10810    if (!tele)
10811    {
10812       fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
10813       rpt_mutex_unlock(&myrpt->lock);
10814       pthread_exit(NULL);
10815    }
10816    *tele++ = 0;
10817    myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele,NULL);
10818    if (myrpt->rxchannel)
10819    {
10820       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10821       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10822       myrpt->rxchannel->whentohangup = 0;
10823       myrpt->rxchannel->appl = "Apprpt";
10824       myrpt->rxchannel->data = "(Link Rx)";
10825       if (option_verbose > 2)
10826          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
10827             myrpt->rxchanname,tele,myrpt->rxchannel->name);
10828       rpt_mutex_unlock(&myrpt->lock);
10829       ast_call(myrpt->rxchannel,tele,999);
10830       rpt_mutex_lock(&myrpt->lock);
10831    }
10832    else
10833    {
10834       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
10835       rpt_mutex_unlock(&myrpt->lock);
10836       pthread_exit(NULL);
10837    }
10838    *--tele = '/';
10839    if (myrpt->txchanname)
10840    {
10841       tele = strchr(myrpt->txchanname,'/');
10842       if (!tele)
10843       {
10844          fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
10845          rpt_mutex_unlock(&myrpt->lock);
10846          ast_hangup(myrpt->rxchannel);
10847          pthread_exit(NULL);
10848       }
10849       *tele++ = 0;
10850       myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele,NULL);
10851       if (myrpt->txchannel)
10852       {
10853          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
10854          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
10855          myrpt->txchannel->whentohangup = 0;
10856          myrpt->txchannel->appl = "Apprpt";
10857          myrpt->txchannel->data = "(Link Tx)";
10858          if (option_verbose > 2)
10859             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
10860                myrpt->txchanname,tele,myrpt->txchannel->name);
10861          rpt_mutex_unlock(&myrpt->lock);
10862          ast_call(myrpt->txchannel,tele,999);
10863          rpt_mutex_lock(&myrpt->lock);
10864       }
10865       else
10866       {
10867          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
10868          rpt_mutex_unlock(&myrpt->lock);
10869          ast_hangup(myrpt->rxchannel);
10870          pthread_exit(NULL);
10871       }
10872       *--tele = '/';
10873    }
10874    else
10875    {
10876       myrpt->txchannel = myrpt->rxchannel;
10877    }
10878    /* allocate a pseudo-channel thru asterisk */
10879    myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
10880    if (!myrpt->pchannel)
10881    {
10882       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10883       rpt_mutex_unlock(&myrpt->lock);
10884       if (myrpt->txchannel != myrpt->rxchannel) 
10885          ast_hangup(myrpt->txchannel);
10886       ast_hangup(myrpt->rxchannel);
10887       pthread_exit(NULL);
10888    }
10889    ast_set_read_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
10890    ast_set_write_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
10891    /* make a conference for the pseudo */
10892    ci.chan = 0;
10893    ci.confno = -1; /* make a new conf */
10894    ci.confmode = ZT_CONF_CONFANNMON ;
10895    /* first put the channel on the conference in announce/monitor mode */
10896    if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
10897    {
10898       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10899       rpt_mutex_unlock(&myrpt->lock);
10900       ast_hangup(myrpt->pchannel);
10901       if (myrpt->txchannel != myrpt->rxchannel) 
10902          ast_hangup(myrpt->txchannel);
10903       ast_hangup(myrpt->rxchannel);
10904       pthread_exit(NULL);
10905    }
10906    /* if serial io port, open it */
10907    myrpt->iofd = -1;
10908    if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt->p.ioport)) == -1))
10909    {
10910       rpt_mutex_unlock(&myrpt->lock);
10911       ast_hangup(myrpt->pchannel);
10912       if (myrpt->txchannel != myrpt->rxchannel) 
10913          ast_hangup(myrpt->txchannel);
10914       ast_hangup(myrpt->rxchannel);
10915       pthread_exit(NULL);
10916    }
10917    iskenwood_pci4 = 0;
10918    memset(&z,0,sizeof(z));
10919    if (myrpt->iofd < 1)
10920    {
10921       z.radpar = ZT_RADPAR_REMMODE;
10922       z.data = ZT_RADPAR_REM_NONE;
10923       res = ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z);
10924       /* if PCIRADIO and kenwood selected */
10925       if ((!res) && (!strcmp(myrpt->remote,remote_rig_kenwood)))
10926       {
10927          z.radpar = ZT_RADPAR_UIOMODE;
10928          z.data = 1;
10929          if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
10930          {
10931             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
10932             return -1;
10933          }
10934          z.radpar = ZT_RADPAR_UIODATA;
10935          z.data = 3;
10936          if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
10937          {
10938             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
10939             return -1;
10940          }
10941          i = ZT_OFFHOOK;
10942          if (ioctl(myrpt->txchannel->fds[0],ZT_HOOK,&i) == -1)
10943          {
10944             ast_log(LOG_ERROR,"Cannot set hook\n");
10945             return -1;
10946          }
10947          iskenwood_pci4 = 1;
10948       }
10949    }
10950    i = ZT_ONHOOK;
10951    ioctl(myrpt->txchannel->fds[0],ZT_HOOK,&i);
10952    /* if PCIRADIO and Yaesu ft897/ICOM IC-706 selected */
10953    if ((myrpt->iofd < 1) && (!res) &&
10954       (!strcmp(myrpt->remote,remote_rig_ft897) ||
10955          (!strcmp(myrpt->remote,remote_rig_ic706))))
10956    {
10957       z.radpar = ZT_RADPAR_UIOMODE;
10958       z.data = 1;
10959       if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
10960       {
10961          ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
10962          return -1;
10963       }
10964       z.radpar = ZT_RADPAR_UIODATA;
10965       z.data = 3;
10966       if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
10967       {
10968          ast_log(LOG_ERROR,"Cannot set UIODATA\n");
10969          return -1;
10970       }
10971    }
10972    /* save pseudo channel conference number */
10973    myrpt->conf = myrpt->txconf = ci.confno;
10974    myrpt->remoterx = 0;
10975    myrpt->remotetx = 0;
10976    myrpt->retxtimer = 0;
10977    myrpt->rerxtimer = 0;
10978    myrpt->remoteon = 1;
10979    myrpt->dtmfidx = -1;
10980    myrpt->dtmfbuf[0] = 0;
10981    myrpt->dtmf_time_rem = 0;
10982    myrpt->hfscanmode = 0;
10983    myrpt->hfscanstatus = 0;
10984    if (myrpt->p.startupmacro)
10985    {
10986       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
10987    }
10988    time(&myrpt->start_time);
10989    myrpt->last_activity_time = myrpt->start_time;
10990    last_timeout_warning = 0;
10991    myrpt->reload = 0;
10992    myrpt->tele.next = &myrpt->tele;
10993    myrpt->tele.prev = &myrpt->tele;
10994    rpt_mutex_unlock(&myrpt->lock);
10995    ast_set_write_format(chan, AST_FORMAT_SLINEAR);
10996    ast_set_read_format(chan, AST_FORMAT_SLINEAR);
10997    rem_rx = 0;
10998    remkeyed = 0;
10999    /* if we are on 2w loop and are a remote, turn EC on */
11000    if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
11001    {
11002       i = 128;
11003       ioctl(myrpt->rxchannel->fds[0],ZT_ECHOCANCEL,&i);
11004    }
11005    if (chan->_state != AST_STATE_UP) {
11006       ast_answer(chan);
11007    }
11008 
11009    if (ioctl(myrpt->rxchannel->fds[0],ZT_GET_PARAMS,&par) != -1)
11010    {
11011       if (par.rxisoffhook)
11012       {
11013          ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11014          myrpt->remoterx = 1;
11015          remkeyed = 1;
11016       }
11017    }
11018    if (myrpt->p.archivedir)
11019    {
11020       char mycmd[100],mydate[100],*b,*b1;
11021       time_t myt;
11022       long blocksleft;
11023 
11024 
11025       mkdir(myrpt->p.archivedir,0600);
11026       sprintf(mycmd,"%s/%s",myrpt->p.archivedir,myrpt->name);
11027       mkdir(mycmd,0600);
11028       time(&myt);
11029       strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
11030          localtime(&myt));
11031       sprintf(mycmd,"mixmonitor start %s %s/%s/%s.wav49 a",chan->name,
11032          myrpt->p.archivedir,myrpt->name,mydate);
11033       if (myrpt->p.monminblocks)
11034       {
11035          blocksleft = diskavail(myrpt);
11036          if (myrpt->p.remotetimeout)
11037          {
11038             blocksleft -= (myrpt->p.remotetimeout *
11039                MONITOR_DISK_BLOCKS_PER_MINUTE) / 60;
11040          }
11041          if (blocksleft >= myrpt->p.monminblocks)
11042             ast_cli_command(nullfd,mycmd);
11043       } else ast_cli_command(nullfd,mycmd);
11044       /* look at callerid to see what node this comes from */
11045       if (!chan->cid.cid_num) /* if doesn't have caller id */
11046       {
11047          b1 = "0";
11048       } else {
11049          ast_callerid_parse(chan->cid.cid_num,&b,&b1);
11050          ast_shrink_phone_number(b1);
11051       }
11052       sprintf(mycmd,"CONNECT,%s",b1);
11053       donodelog(myrpt,mycmd);
11054    }
11055    myrpt->loginuser[0] = 0;
11056    myrpt->loginlevel[0] = 0;
11057    myrpt->authtelltimer = 0;
11058    myrpt->authtimer = 0;
11059    authtold = 0;
11060    authreq = 0;
11061    if (myrpt->p.authlevel > 1) authreq = 1;
11062    setrem(myrpt); 
11063    n = 0;
11064    dtmfed = 0;
11065    cs[n++] = chan;
11066    cs[n++] = myrpt->rxchannel;
11067    cs[n++] = myrpt->pchannel;
11068    if (myrpt->rxchannel != myrpt->txchannel)
11069       cs[n++] = myrpt->txchannel;
11070    /* start un-locked */
11071    for(;;) 
11072    {
11073       if (ast_check_hangup(chan)) break;
11074       if (ast_check_hangup(myrpt->rxchannel)) break;
11075       notremming = 0;
11076       setting = 0;
11077       reming = 0;
11078       telem = myrpt->tele.next;
11079       while(telem != &myrpt->tele)
11080       {
11081          if (telem->mode == SETREMOTE) setting = 1;
11082          if ((telem->mode == SETREMOTE) ||
11083              (telem->mode == SCAN) ||
11084             (telem->mode == TUNE))  reming = 1;
11085          else notremming = 1;
11086          telem = telem->next;
11087       }
11088       if (myrpt->reload)
11089       {
11090          myrpt->reload = 0;
11091          /* find our index, and load the vars */
11092          for(i = 0; i < nrpts; i++)
11093          {
11094             if (&rpt_vars[i] == myrpt)
11095             {
11096                load_rpt_vars(i,0);
11097                break;
11098             }
11099          }
11100       }
11101       time(&t);
11102       if (myrpt->p.remotetimeout)
11103       { 
11104          time_t r;
11105 
11106          r = (t - myrpt->start_time);
11107          if (r >= myrpt->p.remotetimeout)
11108          {
11109             sayfile(chan,"rpt/node");
11110             ast_say_character_str(chan,myrpt->name,NULL,chan->language);
11111             sayfile(chan,"rpt/timeout");
11112             ast_safe_sleep(chan,1000);
11113             break;
11114          }
11115          if ((myrpt->p.remotetimeoutwarning) && 
11116              (r >= (myrpt->p.remotetimeout -
11117             myrpt->p.remotetimeoutwarning)) &&
11118                 (r <= (myrpt->p.remotetimeout - 
11119                   myrpt->p.remotetimeoutwarningfreq)))
11120          {
11121             if (myrpt->p.remotetimeoutwarningfreq)
11122             {
11123                 if ((t - last_timeout_warning) >=
11124                myrpt->p.remotetimeoutwarningfreq)
11125                 {
11126                time(&last_timeout_warning);
11127                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
11128                 }
11129             }
11130             else
11131             {
11132                 if (!last_timeout_warning)
11133                 {
11134                time(&last_timeout_warning);
11135                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
11136                 }
11137             }
11138          }
11139       }
11140       if (myrpt->p.remoteinacttimeout && myrpt->last_activity_time)
11141       { 
11142          time_t r;
11143 
11144          r = (t - myrpt->last_activity_time);
11145          if (r >= myrpt->p.remoteinacttimeout)
11146          {
11147             sayfile(chan,"rpt/node");
11148             ast_say_character_str(chan,myrpt->name,NULL,chan->language);
11149             sayfile(chan,"rpt/timeout");
11150             ast_safe_sleep(chan,1000);
11151             break;
11152          }
11153          if ((myrpt->p.remotetimeoutwarning) && 
11154              (r >= (myrpt->p.remoteinacttimeout -
11155             myrpt->p.remotetimeoutwarning)) &&
11156                 (r <= (myrpt->p.remoteinacttimeout - 
11157                   myrpt->p.remotetimeoutwarningfreq)))
11158          {
11159             if (myrpt->p.remotetimeoutwarningfreq)
11160             {
11161                 if ((t - last_timeout_warning) >=
11162                myrpt->p.remotetimeoutwarningfreq)
11163                 {
11164                time(&last_timeout_warning);
11165                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
11166                 }
11167             }
11168             else
11169             {
11170                 if (!last_timeout_warning)
11171                 {
11172                time(&last_timeout_warning);
11173                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
11174                 }
11175             }
11176          }
11177       }
11178       ms = MSWAIT;
11179       who = ast_waitfor_n(cs,n,&ms);
11180       if (who == NULL) ms = 0;
11181       elap = MSWAIT - ms;
11182       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
11183       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
11184       if (!ms) continue;
11185       /* do local dtmf timer */
11186       if (myrpt->dtmf_local_timer)
11187       {
11188          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
11189          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
11190       }
11191       rpt_mutex_lock(&myrpt->lock);
11192       do_dtmf_local(myrpt,0);
11193       rpt_mutex_unlock(&myrpt->lock);
11194       rem_totx =  myrpt->dtmf_local_timer && (!phone_mode);
11195       rem_totx |= keyed && (!myrpt->tunerequest);
11196       rem_rx = (remkeyed && (!setting)) || (myrpt->tele.next != &myrpt->tele);
11197       if(!strcmp(myrpt->remote, remote_rig_ic706))
11198          rem_totx |= myrpt->tunerequest;
11199       if (keyed && (!keyed1))
11200       {
11201          keyed1 = 1;
11202       }
11203 
11204       if (!keyed && (keyed1))
11205       {
11206          time_t myt;
11207 
11208          keyed1 = 0;
11209          time(&myt);
11210          /* if login necessary, and not too soon */
11211          if ((myrpt->p.authlevel) && 
11212              (!myrpt->loginlevel[0]) &&
11213             (myt > (t + 3)))
11214          {
11215             authreq = 1;
11216             authtold = 0;
11217             myrpt->authtelltimer = AUTHTELLTIME - AUTHTXTIME;
11218          }
11219       }
11220 
11221 
11222       if (rem_rx && (!myrpt->remoterx))
11223       {
11224          myrpt->remoterx = 1;
11225          ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11226       }
11227       if ((!rem_rx) && (myrpt->remoterx))
11228       {
11229          myrpt->remoterx = 0;
11230          ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
11231       }
11232       /* if auth requested, and not authed yet */
11233       if (authreq && (!myrpt->loginlevel[0]))
11234       {
11235          if ((!authtold) && ((myrpt->authtelltimer += elap)
11236              >= AUTHTELLTIME))
11237          {
11238             authtold = 1;
11239             rpt_telemetry(myrpt,LOGINREQ,NULL);
11240          }
11241          if ((myrpt->authtimer += elap) >= AUTHLOGOUTTIME)
11242          {
11243             break; /* if not logged in, hang up after a time */
11244          }
11245       }
11246 #ifndef  OLDKEY
11247       if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
11248       {
11249          myrpt->retxtimer = 0;
11250          if ((myrpt->remoterx) && (!myrpt->remotetx))
11251             ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11252          else
11253             ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
11254       }
11255 
11256       if ((myrpt->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 2))
11257       {
11258          keyed = 0;
11259          myrpt->rerxtimer = 0;
11260       }
11261 #endif
11262       if (rem_totx && (!myrpt->remotetx))
11263       {
11264          /* if not authed, and needed, dont transmit */
11265          if ((!myrpt->p.authlevel) || myrpt->loginlevel[0])
11266          {
11267             myrpt->remotetx = 1;
11268             if((myrpt->remtxfreqok = check_tx_freq(myrpt)))
11269             {
11270                time(&myrpt->last_activity_time);
11271                if (iskenwood_pci4)
11272                {
11273                   z.radpar = ZT_RADPAR_UIODATA;
11274                   z.data = 1;
11275                   if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11276                   {
11277                      ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11278                      return -1;
11279                   }
11280                }
11281                else
11282                {
11283                   ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
11284                }
11285                if (myrpt->p.archivedir) donodelog(myrpt,"TXKEY");
11286             }
11287          }
11288       }
11289       if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
11290       {
11291          myrpt->remotetx = 0;
11292          if(!myrpt->remtxfreqok){
11293             rpt_telemetry(myrpt,UNAUTHTX,NULL);
11294          }
11295          if (iskenwood_pci4)
11296          {
11297             z.radpar = ZT_RADPAR_UIODATA;
11298             z.data = 3;
11299             if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11300             {
11301                ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11302                return -1;
11303             }
11304          }
11305          else
11306          {
11307             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
11308          }
11309          if (myrpt->p.archivedir) donodelog(myrpt,"TXUNKEY");
11310       }
11311       if (myrpt->hfscanmode){
11312          myrpt->scantimer -= elap;
11313          if(myrpt->scantimer <= 0){
11314             if (!reming)
11315             {
11316                myrpt->scantimer = REM_SCANTIME;
11317                rpt_telemetry(myrpt,SCAN,0);
11318             } else myrpt->scantimer = 1;
11319          }
11320       }
11321       rpt_mutex_lock(&myrpt->lock);
11322       c = myrpt->macrobuf[0];
11323       if (c && (!myrpt->macrotimer))
11324       {
11325          myrpt->macrotimer = MACROTIME;
11326          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
11327          if ((c == 'p') || (c == 'P'))
11328             myrpt->macrotimer = MACROPTIME;
11329          rpt_mutex_unlock(&myrpt->lock);
11330          if (myrpt->p.archivedir)
11331          {
11332             char str[100];
11333                sprintf(str,"DTMF(M),%c",c);
11334             donodelog(myrpt,str);
11335          }
11336          if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
11337          continue;
11338       } else rpt_mutex_unlock(&myrpt->lock);
11339       if (who == chan) /* if it was a read from incomming */
11340       {
11341          f = ast_read(chan);
11342          if (!f)
11343          {
11344             if (debug) printf("@@@@ link:Hung Up\n");
11345             break;
11346          }
11347          if (f->frametype == AST_FRAME_VOICE)
11348          {
11349             if (ioctl(chan->fds[0], ZT_GETCONFMUTE, &ismuted) == -1)
11350             {
11351                ismuted = 0;
11352             }
11353             /* if not transmitting, zero-out audio */
11354             ismuted |= (!myrpt->remotetx);
11355             if (dtmfed && phone_mode) ismuted = 1;
11356             dtmfed = 0;
11357             if (ismuted)
11358             {
11359                memset(f->data,0,f->datalen);
11360                if (myrpt->lastf1)
11361                   memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11362                if (myrpt->lastf2)
11363                   memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11364             } 
11365             if (f) f2 = ast_frdup(f);
11366             else f2 = NULL;
11367             f1 = myrpt->lastf2;
11368             myrpt->lastf2 = myrpt->lastf1;
11369             myrpt->lastf1 = f2;
11370             if (ismuted)
11371             {
11372                if (myrpt->lastf1)
11373                   memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11374                if (myrpt->lastf2)
11375                   memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11376             }
11377             if (f1)
11378             {
11379                if (phone_mode)
11380                   ast_write(myrpt->txchannel,f1);
11381                else
11382                   ast_write(myrpt->txchannel,f);
11383                ast_frfree(f1);
11384             }
11385          }
11386 #ifndef  OLD_ASTERISK
11387          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
11388          {
11389             if (myrpt->lastf1)
11390                memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11391             if (myrpt->lastf2)
11392                memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11393             dtmfed = 1;
11394          }
11395 #endif
11396          if (f->frametype == AST_FRAME_DTMF)
11397          {
11398             if (myrpt->lastf1)
11399                memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11400             if (myrpt->lastf2)
11401                memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11402             dtmfed = 1;
11403             if (handle_remote_phone_dtmf(myrpt,f->subclass,&keyed,phone_mode) == -1)
11404             {
11405                if (debug) printf("@@@@ rpt:Hung Up\n");
11406                ast_frfree(f);
11407                break;
11408             }
11409          }
11410          if (f->frametype == AST_FRAME_TEXT)
11411          {
11412             if (handle_remote_data(myrpt,f->data) == -1)
11413             {
11414                if (debug) printf("@@@@ rpt:Hung Up\n");
11415                ast_frfree(f);
11416                break;
11417             }
11418          }
11419          if (f->frametype == AST_FRAME_CONTROL)
11420          {
11421             if (f->subclass == AST_CONTROL_HANGUP)
11422             {
11423                if (debug) printf("@@@@ rpt:Hung Up\n");
11424                ast_frfree(f);
11425                break;
11426             }
11427             /* if RX key */
11428             if (f->subclass == AST_CONTROL_RADIO_KEY)
11429             {
11430                if (debug == 7) printf("@@@@ rx key\n");
11431                keyed = 1;
11432                myrpt->rerxtimer = 0;
11433             }
11434             /* if RX un-key */
11435             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
11436             {
11437                myrpt->rerxtimer = 0;
11438                if (debug == 7) printf("@@@@ rx un-key\n");
11439                keyed = 0;
11440             }
11441          }
11442          ast_frfree(f);
11443          continue;
11444       }
11445       if (who == myrpt->rxchannel) /* if it was a read from radio */
11446       {
11447          f = ast_read(myrpt->rxchannel);
11448          if (!f)
11449          {
11450             if (debug) printf("@@@@ link:Hung Up\n");
11451             break;
11452          }
11453          if (f->frametype == AST_FRAME_VOICE)
11454          {
11455             int myreming = 0;
11456 
11457             if(!strcmp(myrpt->remote, remote_rig_kenwood))
11458                myreming = reming;
11459 
11460             if (myreming || (!remkeyed) ||
11461             ((myrpt->remote) && (myrpt->remotetx)) ||
11462               ((myrpt->remmode != REM_MODE_FM) &&
11463                 notremming))
11464                memset(f->data,0,f->datalen); 
11465              ast_write(myrpt->pchannel,f);
11466          }
11467          else if (f->frametype == AST_FRAME_CONTROL)
11468          {
11469             if (f->subclass == AST_CONTROL_HANGUP)
11470             {
11471                if (debug) printf("@@@@ rpt:Hung Up\n");
11472                ast_frfree(f);
11473                break;
11474             }
11475             /* if RX key */
11476             if (f->subclass == AST_CONTROL_RADIO_KEY)
11477             {
11478                if (debug == 7) printf("@@@@ remote rx key\n");
11479                if (!myrpt->remotetx)
11480                {
11481                   remkeyed = 1;
11482                }
11483             }
11484             /* if RX un-key */
11485             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
11486             {
11487                if (debug == 7) printf("@@@@ remote rx un-key\n");
11488                if (!myrpt->remotetx) 
11489                {
11490                   remkeyed = 0;
11491                }
11492             }
11493          }
11494          ast_frfree(f);
11495          continue;
11496       }
11497       if (who == myrpt->pchannel) /* if is remote mix output */
11498       {
11499          f = ast_read(myrpt->pchannel);
11500          if (!f)
11501          {
11502             if (debug) printf("@@@@ link:Hung Up\n");
11503             break;
11504          }
11505          if (f->frametype == AST_FRAME_VOICE)
11506          {
11507             ast_write(chan,f);
11508          }
11509          if (f->frametype == AST_FRAME_CONTROL)
11510          {
11511             if (f->subclass == AST_CONTROL_HANGUP)
11512             {
11513                if (debug) printf("@@@@ rpt:Hung Up\n");
11514                ast_frfree(f);
11515                break;
11516             }
11517          }
11518          ast_frfree(f);
11519          continue;
11520       }
11521       if ((myrpt->rxchannel != myrpt->txchannel) && 
11522          (who == myrpt->txchannel)) /* do this cuz you have to */
11523       {
11524          f = ast_read(myrpt->txchannel);
11525          if (!f)
11526          {
11527             if (debug) printf("@@@@ link:Hung Up\n");
11528             break;
11529          }
11530          if (f->frametype == AST_FRAME_CONTROL)
11531          {
11532             if (f->subclass == AST_CONTROL_HANGUP)
11533             {
11534                if (debug) printf("@@@@ rpt:Hung Up\n");
11535                ast_frfree(f);
11536                break;
11537             }
11538          }
11539          ast_frfree(f);
11540          continue;
11541       }
11542    }
11543    if (myrpt->p.archivedir)
11544    {
11545       char mycmd[100],*b,*b1;
11546 
11547       /* look at callerid to see what node this comes from */
11548       if (!chan->cid.cid_num) /* if doesn't have caller id */
11549       {
11550          b1 = "0";
11551       } else {
11552          ast_callerid_parse(chan->cid.cid_num,&b,&b1);
11553          ast_shrink_phone_number(b1);
11554       }
11555       sprintf(mycmd,"DISCONNECT,%s",b1);
11556       donodelog(myrpt,mycmd);
11557    }
11558    /* wait for telem to be done */
11559    while(myrpt->tele.next != &myrpt->tele) usleep(100000);
11560    sprintf(tmp,"mixmonitor stop %s",chan->name);
11561    ast_cli_command(nullfd,tmp);
11562    close(nullfd);
11563    rpt_mutex_lock(&myrpt->lock);
11564    myrpt->hfscanmode = 0;
11565    myrpt->hfscanstatus = 0;
11566    myrpt->remoteon = 0;
11567    rpt_mutex_unlock(&myrpt->lock);
11568    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
11569    myrpt->lastf1 = NULL;
11570    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
11571    myrpt->lastf2 = NULL;
11572    if (iskenwood_pci4)
11573    {
11574       z.radpar = ZT_RADPAR_UIOMODE;
11575       z.data = 3;
11576       if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11577       {
11578          ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11579          return -1;
11580       }
11581       z.radpar = ZT_RADPAR_UIODATA;
11582       z.data = 3;
11583       if (ioctl(myrpt->txchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11584       {
11585          ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11586          return -1;
11587       }
11588       i = ZT_OFFHOOK;
11589       if (ioctl(myrpt->txchannel->fds[0],ZT_HOOK,&i) == -1)
11590       {
11591          ast_log(LOG_ERROR,"Cannot set hook\n");
11592          return -1;
11593       }
11594    }
11595    if (myrpt->iofd) close(myrpt->iofd);
11596    myrpt->iofd = -1;
11597    ast_hangup(myrpt->pchannel);
11598    if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
11599    ast_hangup(myrpt->rxchannel);
11600    closerem(myrpt);
11601 #ifdef   OLD_ASTERISK
11602    LOCAL_USER_REMOVE(u);
11603 #endif
11604    return res;
11605 }
11606 
11607 #ifdef   OLD_ASTERISK
11608 int unload_module()
11609 #else
11610 static int unload_module(void)
11611 #endif
11612 {
11613    int i;
11614 
11615 #ifdef   OLD_ASTERISK
11616    STANDARD_HANGUP_LOCALUSERS;
11617 #endif
11618    for(i = 0; i < nrpts; i++) {
11619       if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
11620                 ast_mutex_destroy(&rpt_vars[i].lock);
11621                 ast_mutex_destroy(&rpt_vars[i].remlock);
11622    }
11623    i = ast_unregister_application(app);
11624 
11625    /* Unregister cli extensions */
11626    ast_cli_unregister(&cli_debug);
11627    ast_cli_unregister(&cli_dump);
11628    ast_cli_unregister(&cli_stats);
11629    ast_cli_unregister(&cli_lstats);
11630    ast_cli_unregister(&cli_nodes);
11631    ast_cli_unregister(&cli_reload);
11632    ast_cli_unregister(&cli_restart);
11633    ast_cli_unregister(&cli_fun);
11634 
11635    return i;
11636 }
11637 
11638 #ifdef   OLD_ASTERISK
11639 int load_module()
11640 #else
11641 static int load_module(void)
11642 #endif
11643 {
11644    ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
11645 
11646    /* Register cli extensions */
11647    ast_cli_register(&cli_debug);
11648    ast_cli_register(&cli_dump);
11649    ast_cli_register(&cli_stats);
11650    ast_cli_register(&cli_lstats);
11651    ast_cli_register(&cli_nodes);
11652    ast_cli_register(&cli_reload);
11653    ast_cli_register(&cli_restart);
11654    ast_cli_register(&cli_fun);
11655 
11656    return ast_register_application(app, rpt_exec, synopsis, descrip);
11657 }
11658 
11659 #ifdef   OLD_ASTERISK
11660 char *description()
11661 {
11662    return tdesc;
11663 }
11664 int usecount(void)
11665 {
11666    int res;
11667    STANDARD_USECOUNT(res);
11668    return res;
11669 }
11670 
11671 char *key()
11672 {
11673    return ASTERISK_GPL_KEY;
11674 }
11675 #endif
11676 
11677 #ifdef   OLD_ASTERISK
11678 int reload()
11679 #else
11680 static int reload(void)
11681 #endif
11682 {
11683 int   n;
11684 
11685    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
11686    return(0);
11687 }
11688 
11689 #ifndef  OLD_ASTERISK
11690 /* STD_MOD(MOD_1, reload, NULL, NULL); */
11691 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application",
11692       .load = load_module,
11693       .unload = unload_module,
11694       .reload = reload,
11695           );
11696 
11697 #endif
11698 

Generated on Wed Aug 15 01:24:14 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.3