Wed Mar 4 19:57:59 2009

Asterisk developer's documentation


app_rpt.c

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

Generated on Wed Mar 4 19:58:00 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7