Mon Mar 31 07:37:55 2008

Asterisk developer's documentation


app_rpt.c

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

Generated on Mon Mar 31 07:37:55 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1