Tue Nov 4 13:20:13 2008

Asterisk developer's documentation


app_rpt.c

Go to the documentation of this file.
00001 /* #define OLD_ASTERISK */
00002 #define  OLDKEY
00003 /*
00004  * Asterisk -- An open source telephony toolkit.
00005  *
00006  * Copyright (C) 2002-2007, Jim Dixon, WB6NIL
00007  *
00008  * Jim Dixon, WB6NIL <jim@lambdatel.com>
00009  * Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
00010  *
00011  * See http://www.asterisk.org for more information about
00012  * the Asterisk project. Please do not directly contact
00013  * any of the maintainers of this project for assistance;
00014  * the project provides a web site, mailing lists and IRC
00015  * channels for your use.
00016  *
00017  * This program is free software, distributed under the terms of
00018  * the GNU General Public License Version 2. See the LICENSE file
00019  * at the top of the source tree.
00020  */
00021 /*! \file
00022  *
00023  * \brief Radio Repeater / Remote Base program 
00024  *  version 0.73 09/04/07
00025  * 
00026  * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
00027  *
00028  * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
00029  * 
00030  * See http://www.zapatatelephony.org/app_rpt.html
00031  *
00032  *
00033  * Repeater / Remote Functions:
00034  * "Simple" Mode:  * - autopatch access, # - autopatch hangup
00035  * Normal mode:
00036  * See the function list in rpt.conf (autopatchup, autopatchdn)
00037  * autopatchup can optionally take comma delimited setting=value pairs:
00038  *  
00039  *
00040  * context=string    :  Override default context with "string"
00041  * dialtime=ms       :  Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
00042  * farenddisconnect=1      :  Automatically disconnect when called party hangs up
00043  * noct=1         :  Don't send repeater courtesy tone during autopatch calls
00044  * quiet=1        :  Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
00045  *
00046  *
00047  * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
00048  *
00049  *  To send an asterisk (*) while dialing or talking on phone,
00050  *  use the autopatch acess code.
00051  *
00052  *
00053  * status cmds:
00054  *
00055  *  1 - Force ID
00056  *  2 - Give Time of Day
00057  *  3 - Give software Version
00058  *
00059  * cop (control operator) cmds:
00060  *
00061  *  1 - System warm boot
00062  *  2 - System enable
00063  *  3 - System disable
00064  *  4 - Test Tone On/Off
00065  *  5 - Dump System Variables on Console (debug)
00066  *  6 - PTT (phone mode only)
00067  *  7 - Time out timer enable
00068  *  8 - Time out timer disable
00069  *  9 - Autopatch enable
00070  *  10 - Autopatch disable
00071  *  11 - Link enable
00072  *  12 - Link disable
00073  *  13 - Query System State
00074  *  14 - Change System State
00075  *  15 - Scheduler Enable
00076  *  16 - Scheduler Disable
00077  *  17 - User functions (time, id, etc) enable
00078  *  18 - User functions (time, id, etc) disable
00079  *  19 - Select alternate hang timer
00080  *  20 - Select standard hang timer 
00081  *
00082  * ilink cmds:
00083  *
00084  *  1 - Disconnect specified link
00085  *  2 - Connect specified link -- monitor only
00086  *  3 - Connect specified link -- tranceive
00087  *  4 - Enter command mode on specified link
00088  *  5 - System status
00089  *  6 - Disconnect all links
00090  *  11 - Disconnect a previously permanently connected link
00091  *  12 - Permanently connect specified link -- monitor only
00092  *  13 - Permanently connect specified link -- tranceive
00093  *  15 - Full system status (all nodes)
00094  *  16 - Reconnect links disconnected with "disconnect all links"
00095  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
00096  *
00097  * remote cmds:
00098  *
00099  *  1 - Recall Memory MM  (*000-*099) (Gets memory from rpt.conf)
00100  *  2 - Set VFO MMMMM*KKK*O   (Mhz digits, Khz digits, Offset)
00101  *  3 - Set Rx PL Tone HHH*D*
00102  *  4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
00103  *  5 - Link Status (long)
00104  *  6 - Set operating mode M (FM, USB, LSB, AM, etc)
00105  *  100 - RX PL off (Default)
00106  *  101 - RX PL On
00107  *  102 - TX PL Off (Default)
00108  *  103 - TX PL On
00109  *  104 - Low Power
00110  *  105 - Med Power
00111  *  106 - Hi Power
00112  *  107 - Bump Down 20 Hz
00113  *  108 - Bump Down 100 Hz
00114  *  109 - Bump Down 500 Hz
00115  *  110 - Bump Up 20 Hz
00116  *  111 - Bump Up 100 Hz
00117  *  112 - Bump Up 500 Hz
00118  *  113 - Scan Down Slow
00119  *  114 - Scan Down Medium
00120  *  115 - Scan Down Fast
00121  *  116 - Scan Up Slow
00122  *  117 - Scan Up Medium
00123  *  118 - Scan Up Fast
00124  *  119 - Transmit allowing auto-tune
00125  *  140 - Link Status (brief)
00126  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
00127  *
00128  *
00129  * 'duplex' modes:  (defaults to duplex=2)
00130  *
00131  * 0 - Only remote links key Tx and no main repeat audio.
00132  * 1 - Everything other then main Rx keys Tx, no main repeat audio.
00133  * 2 - Normal mode
00134  * 3 - Normal except no main repeat audio.
00135  * 4 - Normal except no main repeat audio during autopatch only
00136  *
00137 */
00138 
00139 /*** MODULEINFO
00140    <depend>zaptel</depend>
00141    <depend>tonezone</depend>
00142    <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: 107472 $")
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 #include <sys/io.h>
00277 #include <sys/vfs.h>
00278 #include <math.h>
00279 #ifdef OLD_ASTERISK
00280 #include <linux/zaptel.h>
00281 #include <tonezone.h>
00282 #else
00283 #include <zaptel/zaptel.h>
00284 #include <zaptel/tonezone.h>
00285 #endif
00286 #include <netinet/in.h>
00287 #include <arpa/inet.h>
00288 
00289 #include "asterisk/utils.h"
00290 #include "asterisk/lock.h"
00291 #include "asterisk/file.h"
00292 #include "asterisk/logger.h"
00293 #include "asterisk/channel.h"
00294 #include "asterisk/callerid.h"
00295 #include "asterisk/pbx.h"
00296 #include "asterisk/module.h"
00297 #include "asterisk/translate.h"
00298 #include "asterisk/features.h"
00299 #include "asterisk/options.h"
00300 #include "asterisk/cli.h"
00301 #include "asterisk/config.h"
00302 #include "asterisk/say.h"
00303 #include "asterisk/localtime.h"
00304 #include "asterisk/cdr.h"
00305 #include "asterisk/options.h"
00306 #include <termios.h>
00307 
00308 /* Start a tone-list going */
00309 int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
00310 /*! Stop the tones from playing */
00311 void ast_playtones_stop(struct ast_channel *chan);
00312 
00313 static  char *tdesc = "Radio Repeater / Remote Base  version 0.73  09/04/2007";
00314 
00315 static char *app = "Rpt";
00316 
00317 static char *synopsis = "Radio Repeater/Remote Base Control System";
00318 
00319 static char *descrip = 
00320 "  Rpt(nodename[|options]):  Radio Remote Link or Remote Base Link Endpoint Process.\n"
00321 "\n"
00322 "    Not specifying an option puts it in normal endpoint mode (where source\n"
00323 "    IP and nodename are verified).\n"
00324 "\n"
00325 "    Options are as follows:\n"
00326 "\n"
00327 "        X - Normal endpoint mode WITHOUT security check. Only specify\n"
00328 "            this if you have checked security already (like with an IAX2\n"
00329 "            user/password or something).\n"
00330 "\n"
00331 "        Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
00332 "            Reverse Autopatch. Caller is put on hold, and announcement (as\n"
00333 "            specified by the 'announce-string') is played on radio system.\n"
00334 "            Users of radio system can access autopatch, dial specified\n"
00335 "            code, and pick up call. Announce-string is list of names of\n"
00336 "            recordings, or \"PARKED\" to substitute code for un-parking,\n"
00337 "            or \"NODE\" to substitute node number.\n"
00338 "\n"
00339 "        P - Phone Control mode. This allows a regular phone user to have\n"
00340 "            full control and audio access to the radio system. For the\n"
00341 "            user to have DTMF control, the 'phone_functions' parameter\n"
00342 "            must be specified for the node in 'rpt.conf'. An additional\n"
00343 "            function (cop,6) must be listed so that PTT control is available.\n"
00344 "\n"
00345 "        D - Dumb Phone Control mode. This allows a regular phone user to\n"
00346 "            have full control and audio access to the radio system. In this\n"
00347 "            mode, the PTT is activated for the entire length of the call.\n"
00348 "            For the user to have DTMF control (not generally recomended in\n"
00349 "            this mode), the 'dphone_functions' parameter must be specified\n"
00350 "            for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
00351 "            available to the phone user.\n"
00352 "\n";
00353 
00354 static int debug = 0;  /* Set this >0 for extra debug output */
00355 static int nrpts = 0;
00356 
00357 static char remdtmfstr[] = "0123456789*#ABCD";
00358 
00359 enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
00360 
00361 int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
00362 
00363 #define NRPTSTAT 7
00364 
00365 struct rpt_chan_stat
00366 {
00367    struct timeval last;
00368    long long total;
00369    unsigned long count;
00370    unsigned long largest;
00371    struct timeval largest_time;
00372 };
00373 
00374 char *discstr = "!!DISCONNECT!!";
00375 static char *remote_rig_ft897="ft897";
00376 static char *remote_rig_rbi="rbi";
00377 static char *remote_rig_kenwood="kenwood";
00378 static char *remote_rig_ic706="ic706";
00379 
00380 #ifdef   OLD_ASTERISK
00381 STANDARD_LOCAL_USER;
00382 LOCAL_USER_DECL;
00383 #endif
00384 
00385 #define  MSWAIT 200
00386 #define  HANGTIME 5000
00387 #define  TOTIME 180000
00388 #define  IDTIME 300000
00389 #define  MAXRPTS 20
00390 #define MAX_STAT_LINKS 32
00391 #define POLITEID 30000
00392 #define FUNCTDELAY 1500
00393 
00394 #define  MAXXLAT 20
00395 #define  MAXXLATTIME 3
00396 
00397 #define MAX_SYSSTATES 10
00398 
00399 struct rpt_xlat
00400 {
00401 char  funccharseq[MAXXLAT];
00402 char  endcharseq[MAXXLAT];
00403 char  passchars[MAXXLAT];
00404 int   funcindex;
00405 int   endindex;
00406 time_t   lastone;
00407 } ;
00408 
00409 static time_t  starttime = 0;
00410 
00411 static  pthread_t rpt_master_thread;
00412 
00413 struct rpt;
00414 
00415 struct rpt_link
00416 {
00417    struct rpt_link *next;
00418    struct rpt_link *prev;
00419    char  mode;       /* 1 if in tx mode */
00420    char  isremote;
00421    char  phonemode;
00422    char  name[MAXNODESTR]; /* identifier (routing) string */
00423    char  lasttx;
00424    char  lastrx;
00425    char  lastrx1;
00426    char  connected;
00427    char  hasconnected;
00428    char  perma;
00429    char  thisconnected;
00430    char  outbound;
00431    char  disced;
00432    char  killme;
00433    long  elaptime;
00434    long  disctime;
00435    long  retrytimer;
00436    long  retxtimer;
00437    long  rerxtimer;
00438    int   retries;
00439    int   max_retries;
00440    int   reconnects;
00441    long long connecttime;
00442    struct ast_channel *chan;  
00443    struct ast_channel *pchan; 
00444    char  linklist[MAXLINKLIST];
00445    time_t   linklistreceived;
00446    long  linklisttimer;
00447    int   dtmfed;
00448    int linkunkeytocttimer;
00449    struct   ast_frame *lastf1,*lastf2;
00450    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00451 } ;
00452 
00453 struct rpt_lstat
00454 {
00455    struct   rpt_lstat *next;
00456    struct   rpt_lstat *prev;
00457    char  peer[MAXPEERSTR];
00458    char  name[MAXNODESTR];
00459    char  mode;
00460    char  outbound;
00461    char  reconnects;
00462    char  thisconnected;
00463    long long   connecttime;
00464    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00465 } ;
00466 
00467 struct rpt_tele
00468 {
00469    struct rpt_tele *next;
00470    struct rpt_tele *prev;
00471    struct rpt *rpt;
00472    struct ast_channel *chan;
00473    int   mode;
00474    struct rpt_link mylink;
00475    char param[TELEPARAMSIZE];
00476    int   submode;
00477    pthread_t threadid;
00478 } ;
00479 
00480 struct function_table_tag
00481 {
00482    char action[ACTIONSIZE];
00483    int (*function)(struct rpt *myrpt, char *param, char *digitbuf, 
00484       int command_source, struct rpt_link *mylink);
00485 } ;
00486 
00487 /* Used to store the morse code patterns */
00488 
00489 struct morse_bits
00490 {       
00491    int len;
00492    int ddcomb;
00493 } ;
00494 
00495 struct telem_defaults
00496 {
00497    char name[20];
00498    char value[80];
00499 } ;
00500 
00501 
00502 struct sysstate
00503 {
00504    char txdisable;
00505    char totdisable;
00506    char linkfundisable;
00507    char autopatchdisable;
00508    char schedulerdisable;
00509    char userfundisable;
00510    char alternatetail;
00511 };
00512 
00513 static struct rpt
00514 {
00515    ast_mutex_t lock;
00516    ast_mutex_t remlock;
00517    struct ast_config *cfg;
00518    char reload;
00519 
00520    char *name;
00521    char *rxchanname;
00522    char *txchanname;
00523    char *remote;
00524    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00525    unsigned int scram;
00526 
00527    struct {
00528       char *ourcontext;
00529       char *ourcallerid;
00530       char *acctcode;
00531       char *ident;
00532       char *tonezone;
00533       char simple;
00534       char *functions;
00535       char *link_functions;
00536       char *phone_functions;
00537       char *dphone_functions;
00538       char *nodes;
00539       char *extnodes;
00540       char *extnodefile;
00541       int hangtime;
00542       int althangtime;
00543       int totime;
00544       int idtime;
00545       int tailmessagetime;
00546       int tailsquashedtime;
00547       int duplex;
00548       int politeid;
00549       char *tailmessages[500];
00550       int tailmessagemax;
00551       char  *memory;
00552       char  *macro;
00553       char  *startupmacro;
00554       int iobase;
00555       char *ioport;
00556       char funcchar;
00557       char endchar;
00558       char nobusyout;
00559       char notelemtx;
00560       char propagate_dtmf;
00561       char propagate_phonedtmf;
00562       char linktolink;
00563       unsigned char civaddr;
00564       struct rpt_xlat inxlat;
00565       struct rpt_xlat outxlat;
00566       char *archivedir;
00567       int authlevel;
00568       char *csstanzaname;
00569       char *skedstanzaname;
00570       char *txlimitsstanzaname;
00571       long monminblocks;
00572       int remoteinacttimeout;
00573       int remotetimeout;
00574       int remotetimeoutwarning;
00575       int remotetimeoutwarningfreq;
00576       int sysstate_cur;
00577       struct sysstate s[MAX_SYSSTATES];
00578    } p;
00579    struct rpt_link links;
00580    int unkeytocttimer;
00581    char keyed;
00582    char exttx;
00583    char localtx;
00584    char remoterx;
00585    char remotetx;
00586    char remoteon;
00587    char remtxfreqok;
00588    char tounkeyed;
00589    char tonotify;
00590    char dtmfbuf[MAXDTMF];
00591    char macrobuf[MAXMACRO];
00592    char rem_dtmfbuf[MAXDTMF];
00593    char lastdtmfcommand[MAXDTMF];
00594    char cmdnode[50];
00595    struct ast_channel *rxchannel,*txchannel, *monchannel;
00596    struct ast_channel *pchannel,*txpchannel, *zaprxchannel, *zaptxchannel;
00597    struct ast_frame *lastf1,*lastf2;
00598    struct rpt_tele tele;
00599    struct timeval lasttv,curtv;
00600    pthread_t rpt_call_thread,rpt_thread;
00601    time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
00602    int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
00603    int mustid,tailid;
00604    int tailevent;
00605    int telemrefcount;
00606    int dtmfidx,rem_dtmfidx;
00607    int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
00608    int totalexecdcommands, dailyexecdcommands;
00609    long  retxtimer;
00610    long  rerxtimer;
00611    long long totaltxtime;
00612    char mydtmf;
00613    char exten[AST_MAX_EXTENSION];
00614    char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
00615    char offset;
00616    char powerlevel;
00617    char txplon;
00618    char rxplon;
00619    char remmode;
00620    char tunerequest;
00621    char hfscanmode;
00622    int hfscanstatus;
00623    char hfscanstop;
00624    char lastlinknode[MAXNODESTR];
00625    char savednodes[MAXNODESTR];
00626    int stopgen;
00627    char patchfarenddisconnect;
00628    char patchnoct;
00629    char patchquiet;
00630    char patchcontext[MAXPATCHCONTEXT];
00631    int patchdialtime;
00632    int macro_longest;
00633    int phone_longestfunc;
00634    int dphone_longestfunc;
00635    int link_longestfunc;
00636    int longestfunc;
00637    int longestnode;
00638    int threadrestarts;     
00639    int tailmessagen;
00640    time_t disgorgetime;
00641    time_t lastthreadrestarttime;
00642    long  macrotimer;
00643    char  lastnodewhichkeyedusup[MAXNODESTR];
00644    int   dtmf_local_timer;
00645    char  dtmf_local_str[100];
00646    struct ast_filestream *monstream;
00647    char  loginuser[50];
00648    char  loginlevel[10];
00649    long  authtelltimer;
00650    long  authtimer;
00651    int iofd;
00652    time_t start_time,last_activity_time;
00653 #ifdef   __RPT_NOTCH
00654    struct rptfilter
00655    {
00656       char  desc[100];
00657       float x0;
00658       float x1;
00659       float x2;
00660       float y0;
00661       float y1;
00662       float y2;
00663       float gain;
00664       float const0;
00665       float const1;
00666       float const2;
00667    } filters[MAXFILTERS];
00668 #endif
00669 #ifdef   _MDC_DECODE_H_
00670    mdc_decoder_t *mdc;
00671    unsigned short lastunit;
00672 #endif
00673 } rpt_vars[MAXRPTS]; 
00674 
00675 struct nodelog {
00676 struct nodelog *next;
00677 struct nodelog *prev;
00678 time_t   timestamp;
00679 char archivedir[MAXNODESTR];
00680 char str[MAXNODESTR * 2];
00681 } nodelog;
00682 
00683 static int service_scan(struct rpt *myrpt);
00684 static int set_mode_ft897(struct rpt *myrpt, char newmode);
00685 static int set_mode_ic706(struct rpt *myrpt, char newmode);
00686 static int simple_command_ft897(struct rpt *myrpt, char command);
00687 static int setrem(struct rpt *myrpt);
00688 
00689 AST_MUTEX_DEFINE_STATIC(nodeloglock);
00690 
00691 AST_MUTEX_DEFINE_STATIC(nodelookuplock);
00692 
00693 #ifdef   APP_RPT_LOCK_DEBUG
00694 
00695 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
00696 
00697 #define  MAXLOCKTHREAD 100
00698 
00699 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
00700 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
00701 
00702 struct lockthread
00703 {
00704    pthread_t id;
00705    int lockcount;
00706    int lastlock;
00707    int lastunlock;
00708 } lockthreads[MAXLOCKTHREAD];
00709 
00710 
00711 struct by_lightning
00712 {
00713    int line;
00714    struct timeval tv;
00715    struct rpt *rpt;
00716    struct lockthread lockthread;
00717 } lock_ring[32];
00718 
00719 int lock_ring_index = 0;
00720 
00721 AST_MUTEX_DEFINE_STATIC(locklock);
00722 
00723 static struct lockthread *get_lockthread(pthread_t id)
00724 {
00725 int   i;
00726 
00727    for(i = 0; i < MAXLOCKTHREAD; i++)
00728    {
00729       if (lockthreads[i].id == id) return(&lockthreads[i]);
00730    }
00731    return(NULL);
00732 }
00733 
00734 static struct lockthread *put_lockthread(pthread_t id)
00735 {
00736 int   i;
00737 
00738    for(i = 0; i < MAXLOCKTHREAD; i++)
00739    {
00740       if (lockthreads[i].id == id)
00741          return(&lockthreads[i]);
00742    }
00743    for(i = 0; i < MAXLOCKTHREAD; i++)
00744    {
00745       if (!lockthreads[i].id)
00746       {
00747          lockthreads[i].lockcount = 0;
00748          lockthreads[i].lastlock = 0;
00749          lockthreads[i].lastunlock = 0;
00750          lockthreads[i].id = id;
00751          return(&lockthreads[i]);
00752       }
00753    }
00754    return(NULL);
00755 }
00756 
00757 
00758 static void rpt_mutex_spew(void)
00759 {
00760    struct by_lightning lock_ring_copy[32];
00761    int lock_ring_index_copy;
00762    int i,j;
00763    long long diff;
00764    char a[100];
00765    struct timeval lasttv;
00766 
00767    ast_mutex_lock(&locklock);
00768    memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
00769    lock_ring_index_copy = lock_ring_index;
00770    ast_mutex_unlock(&locklock);
00771 
00772    lasttv.tv_sec = lasttv.tv_usec = 0;
00773    for(i = 0 ; i < 32 ; i++)
00774    {
00775       j = (i + lock_ring_index_copy) % 32;
00776       strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
00777          localtime(&lock_ring_copy[j].tv.tv_sec));
00778       diff = 0;
00779       if(lasttv.tv_sec)
00780       {
00781          diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
00782             * 1000000;
00783          diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
00784       }
00785       lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
00786       lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
00787       if (!lock_ring_copy[j].tv.tv_sec) continue;
00788       if (lock_ring_copy[j].line < 0)
00789       {
00790          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00791             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);
00792       }
00793       else
00794       {
00795          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00796             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);
00797       }
00798    }
00799 }
00800 
00801 
00802 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
00803 {
00804 struct lockthread *t;
00805 pthread_t id;
00806 
00807    id = pthread_self();
00808    ast_mutex_lock(&locklock);
00809    t = put_lockthread(id);
00810    if (!t)
00811    {
00812       ast_mutex_unlock(&locklock);
00813       return;
00814    }
00815    if (t->lockcount)
00816    {
00817       int lastline = t->lastlock;
00818       ast_mutex_unlock(&locklock);
00819       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);
00820       rpt_mutex_spew();
00821       return;
00822    }
00823    t->lastlock = line;
00824    t->lockcount = 1;
00825    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
00826    lock_ring[lock_ring_index].rpt = myrpt;
00827    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
00828    lock_ring[lock_ring_index++].line = line;
00829    if(lock_ring_index == 32)
00830       lock_ring_index = 0;
00831    ast_mutex_unlock(&locklock);
00832    ast_mutex_lock(lockp);
00833 }
00834 
00835 
00836 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
00837 {
00838 struct lockthread *t;
00839 pthread_t id;
00840 
00841    id = pthread_self();
00842    ast_mutex_lock(&locklock);
00843    t = put_lockthread(id);
00844    if (!t)
00845    {
00846       ast_mutex_unlock(&locklock);
00847       return;
00848    }
00849    if (!t->lockcount)
00850    {
00851       int lastline = t->lastunlock;
00852       ast_mutex_unlock(&locklock);
00853       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);
00854       rpt_mutex_spew();
00855       return;
00856    }
00857    t->lastunlock = line;
00858    t->lockcount = 0;
00859    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
00860    lock_ring[lock_ring_index].rpt = myrpt;
00861    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
00862    lock_ring[lock_ring_index++].line = -line;
00863    if(lock_ring_index == 32)
00864       lock_ring_index = 0;
00865    ast_mutex_unlock(&locklock);
00866    ast_mutex_unlock(lockp);
00867 }
00868 
00869 #else  /* APP_RPT_LOCK_DEBUG */
00870 
00871 #define rpt_mutex_lock(x) ast_mutex_lock(x)
00872 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
00873 
00874 #endif  /* APP_RPT_LOCK_DEBUG */
00875 
00876 /*
00877 * Return 1 if rig is multimode capable
00878 */
00879 
00880 static int multimode_capable(struct rpt *myrpt)
00881 {
00882    if(!strcmp(myrpt->remote, remote_rig_ft897))
00883       return 1;
00884    if(!strcmp(myrpt->remote, remote_rig_ic706))
00885       return 1;
00886    return 0;
00887 }  
00888 
00889 /*
00890 * CLI extensions
00891 */
00892 
00893 /* Debug mode */
00894 static int rpt_do_debug(int fd, int argc, char *argv[]);
00895 static int rpt_do_dump(int fd, int argc, char *argv[]);
00896 static int rpt_do_stats(int fd, int argc, char *argv[]);
00897 static int rpt_do_lstats(int fd, int argc, char *argv[]);
00898 static int rpt_do_nodes(int fd, int argc, char *argv[]);
00899 static int rpt_do_reload(int fd, int argc, char *argv[]);
00900 static int rpt_do_restart(int fd, int argc, char *argv[]);
00901 static int rpt_do_fun(int fd, int argc, char *argv[]);
00902 
00903 static char debug_usage[] =
00904 "Usage: rpt debug level {0-7}\n"
00905 "       Enables debug messages in app_rpt\n";
00906 
00907 static char dump_usage[] =
00908 "Usage: rpt dump <nodename>\n"
00909 "       Dumps struct debug info to log\n";
00910 
00911 static char dump_stats[] =
00912 "Usage: rpt stats <nodename>\n"
00913 "       Dumps node statistics to console\n";
00914 
00915 static char dump_lstats[] =
00916 "Usage: rpt lstats <nodename>\n"
00917 "       Dumps link statistics to console\n";
00918 
00919 static char dump_nodes[] =
00920 "Usage: rpt nodes <nodename>\n"
00921 "       Dumps a list of directly and indirectly connected nodes to the console\n";
00922 
00923 static char reload_usage[] =
00924 "Usage: rpt reload\n"
00925 "       Reloads app_rpt running config parameters\n";
00926 
00927 static char restart_usage[] =
00928 "Usage: rpt restart\n"
00929 "       Restarts app_rpt\n";
00930 
00931 static char fun_usage[] =
00932 "Usage: rpt fun <nodename> <command>\n"
00933 "       Send a DTMF function to a node\n";
00934 
00935 
00936 static struct ast_cli_entry  cli_debug =
00937         { { "rpt", "debug", "level" }, rpt_do_debug, 
00938       "Enable app_rpt debugging", debug_usage };
00939 
00940 static struct ast_cli_entry  cli_dump =
00941         { { "rpt", "dump" }, rpt_do_dump,
00942       "Dump app_rpt structs for debugging", dump_usage };
00943 
00944 static struct ast_cli_entry  cli_stats =
00945         { { "rpt", "stats" }, rpt_do_stats,
00946       "Dump node statistics", dump_stats };
00947 
00948 static struct ast_cli_entry  cli_nodes =
00949         { { "rpt", "nodes" }, rpt_do_nodes,
00950       "Dump node list", dump_nodes };
00951 
00952 static struct ast_cli_entry  cli_lstats =
00953         { { "rpt", "lstats" }, rpt_do_lstats,
00954       "Dump link statistics", dump_lstats };
00955 
00956 static struct ast_cli_entry  cli_reload =
00957         { { "rpt", "reload" }, rpt_do_reload,
00958       "Reload app_rpt config", reload_usage };
00959 
00960 static struct ast_cli_entry  cli_restart =
00961         { { "rpt", "restart" }, rpt_do_restart,
00962       "Restart app_rpt", restart_usage };
00963 
00964 static struct ast_cli_entry  cli_fun =
00965         { { "rpt", "fun" }, rpt_do_fun,
00966       "Execute a DTMF function", fun_usage };
00967 
00968 /*
00969 * Telemetry defaults
00970 */
00971 
00972 
00973 static struct telem_defaults tele_defs[] = {
00974    {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
00975    {"ct2","|t(660,880,150,3072)"},
00976    {"ct3","|t(440,0,150,3072)"},
00977    {"ct4","|t(550,0,150,3072)"},
00978    {"ct5","|t(660,0,150,3072)"},
00979    {"ct6","|t(880,0,150,3072)"},
00980    {"ct7","|t(660,440,150,3072)"},
00981    {"ct8","|t(700,1100,150,3072)"},
00982    {"remotemon","|t(1600,0,75,2048)"},
00983    {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
00984    {"cmdmode","|t(900,904,200,2048)"},
00985    {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
00986 } ;
00987 
00988 /*
00989 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
00990 */
00991 
00992 static int setrbi(struct rpt *myrpt);
00993 static int set_ft897(struct rpt *myrpt);
00994 static int set_ic706(struct rpt *myrpt);
00995 static int setkenwood(struct rpt *myrpt);
00996 static int setrbi_check(struct rpt *myrpt);
00997 
00998 
00999 
01000 /*
01001 * Define function protos for function table here
01002 */
01003 
01004 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01005 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01006 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01007 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01008 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01009 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01010 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01011 /*
01012 * Function table
01013 */
01014 
01015 static struct function_table_tag function_table[] = {
01016    {"cop", function_cop},
01017    {"autopatchup", function_autopatchup},
01018    {"autopatchdn", function_autopatchdn},
01019    {"ilink", function_ilink},
01020    {"status", function_status},
01021    {"remote", function_remote},
01022    {"macro", function_macro}
01023 } ;
01024 
01025 static long diskavail(struct rpt *myrpt)
01026 {
01027 struct   statfs statfsbuf;
01028 
01029    if (!myrpt->p.archivedir) return(0);
01030    if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
01031    {
01032       ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
01033          myrpt->p.archivedir,myrpt->name);
01034       return(-1);
01035    }
01036    return(statfsbuf.f_bavail);
01037 }
01038 
01039 static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
01040 {
01041 struct        rpt_link *l;
01042 
01043        l = myrpt->links.next;
01044        /* go thru all the links */
01045        while(l != &myrpt->links)
01046        {
01047                if (!l->phonemode)
01048                {
01049                        l = l->next;
01050                        continue;
01051                }
01052                /* dont send to self */
01053                if (mylink && (l == mylink))
01054                {
01055                        l = l->next;
01056                        continue;
01057                }
01058                if (l->chan) ast_senddigit(l->chan,c);
01059                l = l->next;
01060        }
01061        return;
01062 }
01063 
01064 /* node logging function */
01065 static void donodelog(struct rpt *myrpt,char *str)
01066 {
01067 struct nodelog *nodep;
01068 char  datestr[100];
01069 
01070    if (!myrpt->p.archivedir) return;
01071    nodep = (struct nodelog *)malloc(sizeof(struct nodelog));
01072    if (nodep == NULL)
01073    {
01074       ast_log(LOG_ERROR,"Cannot get memory for node log");
01075       return;
01076    }
01077    time(&nodep->timestamp);
01078    strncpy(nodep->archivedir,myrpt->p.archivedir,
01079       sizeof(nodep->archivedir) - 1);
01080    strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
01081       localtime(&nodep->timestamp));
01082    snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
01083       myrpt->name,datestr,str);
01084    ast_mutex_lock(&nodeloglock);
01085    insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
01086    ast_mutex_unlock(&nodeloglock);
01087 }
01088 
01089 /* must be called locked */
01090 static void do_dtmf_local(struct rpt *myrpt, char c)
01091 {
01092 int   i;
01093 char  digit;
01094 static const char* dtmf_tones[] = {
01095    "!941+1336/200,!0/200", /* 0 */
01096    "!697+1209/200,!0/200", /* 1 */
01097    "!697+1336/200,!0/200", /* 2 */
01098    "!697+1477/200,!0/200", /* 3 */
01099    "!770+1209/200,!0/200", /* 4 */
01100    "!770+1336/200,!0/200", /* 5 */
01101    "!770+1477/200,!0/200", /* 6 */
01102    "!852+1209/200,!0/200", /* 7 */
01103    "!852+1336/200,!0/200", /* 8 */
01104    "!852+1477/200,!0/200", /* 9 */
01105    "!697+1633/200,!0/200", /* A */
01106    "!770+1633/200,!0/200", /* B */
01107    "!852+1633/200,!0/200", /* C */
01108    "!941+1633/200,!0/200", /* D */
01109    "!941+1209/200,!0/200", /* * */
01110    "!941+1477/200,!0/200" };  /* # */
01111 
01112 
01113    if (c)
01114    {
01115       snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
01116       if (!myrpt->dtmf_local_timer) 
01117           myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
01118    }
01119    /* if at timeout */
01120    if (myrpt->dtmf_local_timer == 1)
01121    {
01122       /* if anything in the string */
01123       if (myrpt->dtmf_local_str[0])
01124       {
01125          digit = myrpt->dtmf_local_str[0];
01126          myrpt->dtmf_local_str[0] = 0;
01127          for(i = 1; myrpt->dtmf_local_str[i]; i++)
01128          {
01129             myrpt->dtmf_local_str[i - 1] =
01130                myrpt->dtmf_local_str[i];
01131          }
01132          myrpt->dtmf_local_str[i - 1] = 0;
01133          myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
01134          rpt_mutex_unlock(&myrpt->lock);
01135          if (digit >= '0' && digit <='9')
01136             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
01137          else if (digit >= 'A' && digit <= 'D')
01138             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
01139          else if (digit == '*')
01140             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
01141          else if (digit == '#')
01142             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
01143          else {
01144             /* not handled */
01145             ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name);
01146          }
01147          rpt_mutex_lock(&myrpt->lock);
01148       }
01149       else
01150       {
01151          myrpt->dtmf_local_timer = 0;
01152       }
01153    }
01154 }
01155 
01156 static int openserial(char *fname)
01157 {
01158    struct termios mode;
01159    int fd;
01160 
01161    fd = open(fname,O_RDWR);
01162    if (fd == -1)
01163    {
01164       ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
01165       return -1;
01166    }
01167    memset(&mode, 0, sizeof(mode));
01168    if (tcgetattr(fd, &mode)) {
01169       ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
01170       return -1;
01171    }
01172 #ifndef SOLARIS
01173    cfmakeraw(&mode);
01174 #else
01175         mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
01176                         |INLCR|IGNCR|ICRNL|IXON);
01177         mode.c_oflag &= ~OPOST;
01178         mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
01179         mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
01180         mode.c_cflag |= CS8;
01181    mode.c_cc[TIME] = 3;
01182    mode.c_cc[MAX] = 1;
01183 #endif
01184 
01185    cfsetispeed(&mode, B9600);
01186    cfsetospeed(&mode, B9600);
01187    if (tcsetattr(fd, TCSANOW, &mode)) 
01188       ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
01189    return(fd); 
01190 }
01191 
01192 static void mdc1200_notify(struct rpt *myrpt,char *fromnode, unsigned int unit)
01193 {
01194    if (!fromnode)
01195    {
01196       ast_verbose("Got MDC-1200 ID %04X from local system (%s)\n",
01197          unit,myrpt->name);
01198    }
01199    else
01200    {
01201       ast_verbose("Got MDC-1200 ID %04X from node %s (%s)\n",
01202          unit,fromnode,myrpt->name);
01203    }
01204 }
01205 
01206 #ifdef   _MDC_DECODE_H_
01207 
01208 static void mdc1200_send(struct rpt *myrpt, unsigned int unit)
01209 {
01210 struct rpt_link *l;
01211 struct   ast_frame wf;
01212 char  str[200];
01213 
01214 
01215    sprintf(str,"I %s %04X",myrpt->name,unit);
01216 
01217    wf.frametype = AST_FRAME_TEXT;
01218    wf.subclass = 0;
01219    wf.offset = 0;
01220    wf.mallocd = 0;
01221    wf.datalen = strlen(str) + 1;
01222    wf.samples = 0;
01223 
01224 
01225    l = myrpt->links.next;
01226    /* otherwise, send it to all of em */
01227    while(l != &myrpt->links)
01228    {
01229       if (l->name[0] == '0') 
01230       {
01231          l = l->next;
01232          continue;
01233       }
01234       wf.data = str;
01235       if (l->chan) ast_write(l->chan,&wf); 
01236       l = l->next;
01237    }
01238    return;
01239 }
01240 
01241 #endif
01242 
01243 static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
01244 {
01245 time_t   now;
01246 int   gotone;
01247 
01248    time(&now);
01249    gotone = 0;
01250    /* if too much time, reset the skate machine */
01251    if ((now - xlat->lastone) > MAXXLATTIME)
01252    {
01253       xlat->funcindex = xlat->endindex = 0;
01254    }
01255    if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
01256    {
01257       time(&xlat->lastone);
01258       gotone = 1;
01259       if (!xlat->funccharseq[xlat->funcindex])
01260       {
01261          xlat->funcindex = xlat->endindex = 0;
01262          return(myrpt->p.funcchar);
01263       }
01264    } else xlat->funcindex = 0;
01265    if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
01266    {
01267       time(&xlat->lastone);
01268       gotone = 1;
01269       if (!xlat->endcharseq[xlat->endindex])
01270       {
01271          xlat->funcindex = xlat->endindex = 0;
01272          return(myrpt->p.endchar);
01273       }
01274    } else xlat->endindex = 0;
01275    /* if in middle of decode seq, send nothing back */
01276    if (gotone) return(0);
01277    /* if no pass chars specified, return em all */
01278    if (!xlat->passchars[0]) return(c);
01279    /* if a "pass char", pass it */
01280    if (strchr(xlat->passchars,c)) return(c);
01281    return(0);
01282 }
01283 
01284 /*
01285  * Return a pointer to the first non-whitespace character
01286  */
01287 
01288 static char *eatwhite(char *s)
01289 {
01290    while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
01291       if(!*s)
01292          break;
01293       s++;
01294    }
01295    return s;
01296 }
01297 
01298 /*
01299 * Break up a delimited string into a table of substrings
01300 *
01301 * str - delimited string ( will be modified )
01302 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
01303 * limit- maximum number of substrings to process
01304 */
01305    
01306 
01307 
01308 static int finddelim(char *str, char *strp[], int limit)
01309 {
01310 int     i,l,inquo;
01311 
01312         inquo = 0;
01313         i = 0;
01314         strp[i++] = str;
01315         if (!*str)
01316            {
01317                 strp[0] = 0;
01318                 return(0);
01319            }
01320         for(l = 0; *str && (l < limit) ; str++)
01321            {
01322                 if (*str == QUOTECHR)
01323                    {
01324                         if (inquo)
01325                            {
01326                                 *str = 0;
01327                                 inquo = 0;
01328                            }
01329                         else
01330                            {
01331                                 strp[i - 1] = str + 1;
01332                                 inquo = 1;
01333                            }
01334       }
01335                 if ((*str == DELIMCHR) && (!inquo))
01336                 {
01337                         *str = 0;
01338          l++;
01339                         strp[i++] = str + 1;
01340                 }
01341            }
01342         strp[i] = 0;
01343         return(i);
01344 
01345 }
01346 
01347 /* must be called locked */
01348 static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
01349 {
01350 struct rpt_link *l;
01351 char mode;
01352 int   i,spos;
01353 
01354    buf[0] = 0; /* clear output buffer */
01355    /* go thru all links */
01356    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01357    {
01358       /* if is not a real link, ignore it */
01359       if (l->name[0] == '0') continue;
01360       /* dont count our stuff */
01361       if (l == mylink) continue;
01362       if (mylink && (!strcmp(l->name,mylink->name))) continue;
01363       /* figure out mode to report */
01364       mode = 'T'; /* use Tranceive by default */
01365       if (!l->mode) mode = 'R'; /* indicate RX for our mode */
01366       if (!l->thisconnected)  mode = 'C'; /* indicate connecting */
01367       spos = strlen(buf); /* current buf size (b4 we add our stuff) */
01368       if (spos)
01369       {
01370          strcat(buf,",");
01371          spos++;
01372       }
01373       /* add nodes into buffer */
01374       if (l->linklist[0])
01375       {
01376          snprintf(buf + spos,MAXLINKLIST - spos,
01377             "%c%s,%s",mode,l->name,l->linklist);
01378       }
01379       else /* if no nodes, add this node into buffer */
01380       {
01381          snprintf(buf + spos,MAXLINKLIST - spos,
01382             "%c%s",mode,l->name);
01383       }
01384       /* if we are in tranceive mode, let all modes stand */
01385       if (mode == 'T') continue;
01386       /* downgrade everyone on this node if appropriate */
01387       for(i = spos; buf[i]; i++)
01388       {
01389          if (buf[i] == 'T') buf[i] = mode;
01390          if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
01391       }
01392    }
01393    return;
01394 }
01395 
01396 /* must be called locked */
01397 static void __kickshort(struct rpt *myrpt)
01398 {
01399 struct rpt_link *l;
01400 
01401    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01402    {
01403       /* if is not a real link, ignore it */
01404       if (l->name[0] == '0') continue;
01405       l->linklisttimer = LINKLISTSHORTTIME;
01406    }
01407    return;
01408 }
01409 
01410 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
01411 {
01412 
01413 char *val;
01414 int longestnode,j;
01415 struct stat mystat;
01416 static time_t last = 0;
01417 static struct ast_config *ourcfg = NULL;
01418 struct ast_variable *vp;
01419 
01420    /* try to look it up locally first */
01421    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
01422    if (val) return(val);
01423    ast_mutex_lock(&nodelookuplock);
01424    /* if file does not exist */
01425    if (stat(myrpt->p.extnodefile,&mystat) == -1)
01426    {
01427       if (ourcfg) ast_config_destroy(ourcfg);
01428       ourcfg = NULL;
01429       ast_mutex_unlock(&nodelookuplock);
01430       return(NULL);
01431    }
01432    /* if we need to reload */
01433    if (mystat.st_mtime > last)
01434    {
01435       if (ourcfg) ast_config_destroy(ourcfg);
01436       ourcfg = ast_config_load(myrpt->p.extnodefile);
01437       /* if file not there, just bail */
01438       if (!ourcfg)
01439       {
01440          ast_mutex_unlock(&nodelookuplock);
01441          return(NULL);
01442       }
01443       /* reset "last" time */
01444       last = mystat.st_mtime;
01445 
01446       /* determine longest node length again */    
01447       longestnode = 0;
01448       vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
01449       while(vp){
01450          j = strlen(vp->name);
01451          if (j > longestnode)
01452             longestnode = j;
01453          vp = vp->next;
01454       }
01455 
01456       vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
01457       while(vp){
01458          j = strlen(vp->name);
01459          if (j > longestnode)
01460             longestnode = j;
01461          vp = vp->next;
01462       }
01463 
01464       myrpt->longestnode = longestnode;
01465    }
01466    val = NULL;
01467    if (ourcfg)
01468       val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
01469    ast_mutex_unlock(&nodelookuplock);
01470    return(val);
01471 }
01472 
01473 /*
01474 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
01475 * If param is passed in non-null, then it will be set to the first character past the match
01476 */
01477 
01478 static int matchkeyword(char *string, char **param, char *keywords[])
01479 {
01480 int   i,ls;
01481    for( i = 0 ; keywords[i] ; i++){
01482       ls = strlen(keywords[i]);
01483       if(!ls){
01484          *param = NULL;
01485          return 0;
01486       }
01487       if(!strncmp(string, keywords[i], ls)){
01488          if(param)
01489             *param = string + ls;
01490          return i + 1; 
01491       }
01492    }
01493    param = NULL;
01494    return 0;
01495 }
01496 
01497 /*
01498 * Skip characters in string which are in charlist, and return a pointer to the
01499 * first non-matching character
01500 */
01501 
01502 static char *skipchars(char *string, char *charlist)
01503 {
01504 int i;   
01505    while(*string){
01506       for(i = 0; charlist[i] ; i++){
01507          if(*string == charlist[i]){
01508             string++;
01509             break;
01510          }
01511       }
01512       if(!charlist[i])
01513          return string;
01514    }
01515    return string;
01516 }  
01517                
01518 
01519 
01520 static int myatoi(char *str)
01521 {
01522 int   ret;
01523 
01524    if (str == NULL) return -1;
01525    /* leave this %i alone, non-base-10 input is useful here */
01526    if (sscanf(str,"%i",&ret) != 1) return -1;
01527    return ret;
01528 }
01529 
01530 static int mycompar(const void *a, const void *b)
01531 {
01532 char  **x = (char **) a;
01533 char  **y = (char **) b;
01534 int   xoff,yoff;
01535 
01536    if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
01537    if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
01538    return(strcmp((*x) + xoff,(*y) + yoff));
01539 }
01540 
01541 #ifdef   __RPT_NOTCH
01542 
01543 /* rpt filter routine */
01544 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
01545 {
01546 int   i,j;
01547 struct   rptfilter *f;
01548 
01549    for(i = 0; i < len; i++)
01550    {
01551       for(j = 0; j < MAXFILTERS; j++)
01552       {
01553          f = &myrpt->filters[j];
01554          if (!*f->desc) continue;
01555          f->x0 = f->x1; f->x1 = f->x2;
01556               f->x2 = ((float)buf[i]) / f->gain;
01557               f->y0 = f->y1; f->y1 = f->y2;
01558               f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
01559                            + (f->const1 * f->y0) + (f->const2 * f->y1);
01560          buf[i] = (short)f->y2;
01561       }
01562    }
01563 }
01564 
01565 #endif
01566 
01567 
01568 /*
01569  Get the time for the machine's time zone
01570  Note: Asterisk requires a copy of localtime
01571  in the /etc directory for this to work properly.
01572  If /etc/localtime is not present, you will get
01573  GMT time! This is especially important on systems
01574  running embedded linux distributions as they don't usually
01575  have support for locales. 
01576 
01577  If OLD_ASTERISK is defined, then the older localtime_r
01578  function will be used. The /etc/localtime file is not
01579  required in this case. This provides backward compatibility
01580  with Asterisk 1.2 systems.
01581 
01582 */
01583 
01584 static void rpt_localtime( time_t * t, struct tm *lt)
01585 {
01586 #ifdef OLD_ASTERISK
01587    localtime_r(t, lt);
01588 #else
01589    ast_localtime(t, lt, NULL);
01590 #endif
01591 }
01592 
01593 /* Retrieve an int from a config file */
01594                                                                                 
01595 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
01596 {
01597         char *var;
01598         int ret;
01599    char include_zero = 0;
01600 
01601    if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
01602       min = -min;
01603       include_zero = 1;
01604    }           
01605                                                                      
01606         var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
01607         if(var){
01608                 ret = myatoi(var);
01609       if(include_zero && !ret)
01610          return 0;
01611                 if(ret < min)
01612                         ret = min;
01613                 if(ret > max)
01614                         ret = max;
01615         }
01616         else
01617                 ret = defl;
01618         return ret;
01619 }
01620 
01621 
01622 static void load_rpt_vars(int n,int init)
01623 {
01624 char *this,*val;
01625 int   i,j,longestnode;
01626 struct ast_variable *vp;
01627 struct ast_config *cfg;
01628 char *strs[100];
01629 char s1[256];
01630 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
01631             "ufena","ufdis","atena","atdis",NULL};
01632 
01633    if (option_verbose > 2)
01634       ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
01635          (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
01636    ast_mutex_lock(&rpt_vars[n].lock);
01637    if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
01638    cfg = ast_config_load("rpt.conf");
01639    if (!cfg) {
01640       ast_mutex_unlock(&rpt_vars[n].lock);
01641       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
01642       pthread_exit(NULL);
01643    }
01644    rpt_vars[n].cfg = cfg; 
01645    this = rpt_vars[n].name;
01646    memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
01647    if (init)
01648    {
01649       /* clear all the fields in the structure after 'p' */
01650       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));
01651       rpt_vars[n].tele.next = &rpt_vars[n].tele;
01652       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
01653       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
01654       rpt_vars[n].tailmessagen = 0;
01655    }
01656 #ifdef   __RPT_NOTCH
01657    /* zot out filters stuff */
01658    memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
01659 #endif
01660    val = (char *) ast_variable_retrieve(cfg,this,"context");
01661    if (val) rpt_vars[n].p.ourcontext = val;
01662    else rpt_vars[n].p.ourcontext = this;
01663    val = (char *) ast_variable_retrieve(cfg,this,"callerid");
01664    if (val) rpt_vars[n].p.ourcallerid = val;
01665    val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
01666    if (val) rpt_vars[n].p.acctcode = val;
01667    val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
01668    if (val) rpt_vars[n].p.ident = val;
01669    val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
01670    if (val) rpt_vars[n].p.hangtime = atoi(val);
01671       else rpt_vars[n].p.hangtime = HANGTIME;
01672    val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
01673    if (val) rpt_vars[n].p.althangtime = atoi(val);
01674       else rpt_vars[n].p.althangtime = HANGTIME;
01675    val = (char *) ast_variable_retrieve(cfg,this,"totime");
01676    if (val) rpt_vars[n].p.totime = atoi(val);
01677       else rpt_vars[n].p.totime = TOTIME;
01678    rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);    
01679    rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);     
01680    rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
01681    rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME);   /* Enforce a min max including zero */
01682    rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
01683    val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
01684    if (val) rpt_vars[n].p.tonezone = val;
01685    rpt_vars[n].p.tailmessages[0] = 0;
01686    rpt_vars[n].p.tailmessagemax = 0;
01687    val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
01688    if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
01689    val = (char *) ast_variable_retrieve(cfg,this,"memory");
01690    if (!val) val = MEMORY;
01691    rpt_vars[n].p.memory = val;
01692    val = (char *) ast_variable_retrieve(cfg,this,"macro");
01693    if (!val) val = MACRO;
01694    rpt_vars[n].p.macro = val;
01695    val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
01696    if (val) rpt_vars[n].p.startupmacro = val;
01697    val = (char *) ast_variable_retrieve(cfg,this,"iobase");
01698    /* do not use atoi() here, we need to be able to have
01699       the input specified in hex or decimal so we use
01700       sscanf with a %i */
01701    if ((!val) || (sscanf(val,"%i",&rpt_vars[n].p.iobase) != 1))
01702    rpt_vars[n].p.iobase = DEFAULT_IOBASE;
01703    val = (char *) ast_variable_retrieve(cfg,this,"ioport");
01704    rpt_vars[n].p.ioport = val;
01705    val = (char *) ast_variable_retrieve(cfg,this,"functions");
01706    if (!val)
01707       {
01708          val = FUNCTIONS;
01709          rpt_vars[n].p.simple = 1;
01710       } 
01711    rpt_vars[n].p.functions = val;
01712    val =  (char *) ast_variable_retrieve(cfg,this,"link_functions");
01713    if (val) rpt_vars[n].p.link_functions = val;
01714    else 
01715       rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
01716    val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
01717    if (val) rpt_vars[n].p.phone_functions = val;
01718    val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
01719    if (val) rpt_vars[n].p.dphone_functions = val;
01720    val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
01721    if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
01722       rpt_vars[n].p.funcchar = *val;      
01723    val = (char *) ast_variable_retrieve(cfg,this,"endchar");
01724    if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
01725       rpt_vars[n].p.endchar = *val;    
01726    val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
01727    if (val) rpt_vars[n].p.nobusyout = ast_true(val);
01728    val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
01729    if (val) rpt_vars[n].p.notelemtx = ast_true(val);
01730    val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
01731    if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
01732    val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
01733    if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
01734    val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
01735    if (val) rpt_vars[n].p.linktolink = ast_true(val);
01736    val = (char *) ast_variable_retrieve(cfg,this,"nodes");
01737    if (!val) val = NODES;
01738    rpt_vars[n].p.nodes = val;
01739    val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
01740    if (!val) val = EXTNODES;
01741    rpt_vars[n].p.extnodes = val;
01742    val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
01743    if (!val) val = EXTNODEFILE;
01744    rpt_vars[n].p.extnodefile = val;
01745    val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
01746    if (val) rpt_vars[n].p.archivedir = val;
01747    val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
01748    if (val) rpt_vars[n].p.authlevel = atoi(val); 
01749    else rpt_vars[n].p.authlevel = 0;
01750    val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
01751    if (val) rpt_vars[n].p.monminblocks = atol(val); 
01752    else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
01753    val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
01754    if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); 
01755    else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
01756    val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
01757    if (val) rpt_vars[n].p.civaddr = atoi(val); 
01758    else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
01759    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
01760    if (val) rpt_vars[n].p.remotetimeout = atoi(val); 
01761    else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
01762    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
01763    if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); 
01764    else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
01765    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
01766    if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); 
01767    else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
01768 #ifdef   __RPT_NOTCH
01769    val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
01770    if (val) {
01771       i = finddelim(val,strs,MAXFILTERS * 2);
01772       i &= ~1; /* force an even number, rounded down */
01773       if (i >= 2) for(j = 0; j < i; j += 2)
01774       {
01775          rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
01776            &rpt_vars[n].filters[j >> 1].gain,
01777              &rpt_vars[n].filters[j >> 1].const0,
01778             &rpt_vars[n].filters[j >> 1].const1,
01779                 &rpt_vars[n].filters[j >> 1].const2);
01780          sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
01781             strs[j],strs[j + 1]);
01782       }
01783 
01784    }
01785 #endif
01786    val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
01787    if (val) {
01788       memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
01789       i = finddelim(val,strs,3);
01790       if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
01791       if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
01792       if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
01793    }
01794    val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
01795    if (val) {
01796       memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
01797       i = finddelim(val,strs,3);
01798       if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
01799       if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
01800       if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
01801    }
01802    /* retreive the stanza name for the control states if there is one */
01803    val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
01804    rpt_vars[n].p.csstanzaname = val;
01805       
01806    /* retreive the stanza name for the scheduler if there is one */
01807    val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
01808    rpt_vars[n].p.skedstanzaname = val;
01809 
01810    /* retreive the stanza name for the txlimits */
01811    val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
01812    rpt_vars[n].p.txlimitsstanzaname = val;
01813 
01814    longestnode = 0;
01815 
01816    vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
01817       
01818    while(vp){
01819       j = strlen(vp->name);
01820       if (j > longestnode)
01821          longestnode = j;
01822       vp = vp->next;
01823    }
01824 
01825    rpt_vars[n].longestnode = longestnode;
01826       
01827    /*
01828    * For this repeater, Determine the length of the longest function 
01829    */
01830    rpt_vars[n].longestfunc = 0;
01831    vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
01832    while(vp){
01833       j = strlen(vp->name);
01834       if (j > rpt_vars[n].longestfunc)
01835          rpt_vars[n].longestfunc = j;
01836       vp = vp->next;
01837    }
01838    /*
01839    * For this repeater, Determine the length of the longest function 
01840    */
01841    rpt_vars[n].link_longestfunc = 0;
01842    vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
01843    while(vp){
01844       j = strlen(vp->name);
01845       if (j > rpt_vars[n].link_longestfunc)
01846          rpt_vars[n].link_longestfunc = j;
01847       vp = vp->next;
01848    }
01849    rpt_vars[n].phone_longestfunc = 0;
01850    if (rpt_vars[n].p.phone_functions)
01851    {
01852       vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
01853       while(vp){
01854          j = strlen(vp->name);
01855          if (j > rpt_vars[n].phone_longestfunc)
01856             rpt_vars[n].phone_longestfunc = j;
01857          vp = vp->next;
01858       }
01859    }
01860    rpt_vars[n].dphone_longestfunc = 0;
01861    if (rpt_vars[n].p.dphone_functions)
01862    {
01863       vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
01864       while(vp){
01865          j = strlen(vp->name);
01866          if (j > rpt_vars[n].dphone_longestfunc)
01867             rpt_vars[n].dphone_longestfunc = j;
01868          vp = vp->next;
01869       }
01870    }
01871    rpt_vars[n].macro_longest = 1;
01872    vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
01873    while(vp){
01874       j = strlen(vp->name);
01875       if (j > rpt_vars[n].macro_longest)
01876          rpt_vars[n].macro_longest = j;
01877       vp = vp->next;
01878    }
01879    
01880    /* Browse for control states */
01881    if(rpt_vars[n].p.csstanzaname)
01882       vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
01883    else
01884       vp = NULL;
01885    for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
01886       int k,nukw,statenum;
01887       statenum=atoi(vp->name);
01888       strncpy(s1, vp->value, 255);
01889       s1[255] = 0;
01890       nukw  = finddelim(s1,strs,32);
01891       
01892       for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */  
01893          for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
01894             if(!strcmp(strs[k],cs_keywords[j])){
01895                switch(j){
01896                   case 0: /* rptena */
01897                      rpt_vars[n].p.s[statenum].txdisable = 0;
01898                      break;
01899                   case 1: /* rptdis */
01900                      rpt_vars[n].p.s[statenum].txdisable = 1;
01901                      break;
01902          
01903                   case 2: /* apena */
01904                      rpt_vars[n].p.s[statenum].autopatchdisable = 0;
01905                      break;
01906 
01907                   case 3: /* apdis */
01908                      rpt_vars[n].p.s[statenum].autopatchdisable = 1;
01909                      break;
01910 
01911                   case 4: /* lnkena */
01912                      rpt_vars[n].p.s[statenum].linkfundisable = 0;
01913                      break;
01914    
01915                   case 5: /* lnkdis */
01916                      rpt_vars[n].p.s[statenum].linkfundisable = 1;
01917                      break;
01918 
01919                   case 6: /* totena */
01920                      rpt_vars[n].p.s[statenum].totdisable = 0;
01921                      break;
01922                
01923                   case 7: /* totdis */
01924                      rpt_vars[n].p.s[statenum].totdisable = 1;
01925                      break;
01926 
01927                   case 8: /* skena */
01928                      rpt_vars[n].p.s[statenum].schedulerdisable = 0;
01929                      break;
01930 
01931                   case 9: /* skdis */
01932                      rpt_vars[n].p.s[statenum].schedulerdisable = 1;
01933                      break;
01934 
01935                   case 10: /* ufena */
01936                      rpt_vars[n].p.s[statenum].userfundisable = 0;
01937                      break;
01938 
01939                   case 11: /* ufdis */
01940                      rpt_vars[n].p.s[statenum].userfundisable = 1;
01941                      break;
01942 
01943                   case 12: /* atena */
01944                      rpt_vars[n].p.s[statenum].alternatetail = 1;
01945                      break;
01946 
01947                   case 13: /* atdis */
01948                      rpt_vars[n].p.s[statenum].alternatetail = 0;
01949                      break;
01950          
01951                   default:
01952                      ast_log(LOG_WARNING,
01953                         "Unhandled control state keyword %s", cs_keywords[i]);
01954                      break;
01955                }
01956             }
01957          }
01958       }
01959       vp = vp->next;
01960    }
01961    ast_mutex_unlock(&rpt_vars[n].lock);
01962 }
01963 
01964 /*
01965 * Enable or disable debug output at a given level at the console
01966 */
01967                                                                                                                                  
01968 static int rpt_do_debug(int fd, int argc, char *argv[])
01969 {
01970    int newlevel;
01971 
01972         if (argc != 4)
01973                 return RESULT_SHOWUSAGE;
01974         newlevel = myatoi(argv[3]);
01975         if((newlevel < 0) || (newlevel > 7))
01976                 return RESULT_SHOWUSAGE;
01977         if(newlevel)
01978                 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
01979         else
01980                 ast_cli(fd, "app_rpt Debugging disabled\n");
01981 
01982         debug = newlevel;                                                                                                                          
01983         return RESULT_SUCCESS;
01984 }
01985 
01986 /*
01987 * Dump rpt struct debugging onto console
01988 */
01989                                                                                                                                  
01990 static int rpt_do_dump(int fd, int argc, char *argv[])
01991 {
01992    int i;
01993 
01994         if (argc != 3)
01995                 return RESULT_SHOWUSAGE;
01996 
01997    for(i = 0; i < nrpts; i++)
01998    {
01999       if (!strcmp(argv[2],rpt_vars[i].name))
02000       {
02001          rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
02002               ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
02003               return RESULT_SUCCESS;
02004       }
02005    }
02006    return RESULT_FAILURE;
02007 }
02008 
02009 /*
02010 * Dump statistics onto console
02011 */
02012 
02013 static int rpt_do_stats(int fd, int argc, char *argv[])
02014 {
02015    int i,j;
02016    int dailytxtime, dailykerchunks;
02017    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
02018    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
02019    long long totaltxtime;
02020    struct   rpt_link *l;
02021    char *listoflinks[MAX_STAT_LINKS];  
02022    char *lastnodewhichkeyedusup, *lastdtmfcommand;
02023    char *tot_state, *ider_state, *patch_state;
02024    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
02025    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
02026    struct rpt *myrpt;
02027 
02028    static char *not_applicable = "N/A";
02029 
02030    if(argc != 3)
02031       return RESULT_SHOWUSAGE;
02032 
02033    for(i = 0 ; i < MAX_STAT_LINKS; i++)
02034       listoflinks[i] = NULL;
02035 
02036    tot_state = ider_state = 
02037    patch_state = reverse_patch_state = 
02038    input_signal = called_number = 
02039    lastdtmfcommand = not_applicable;
02040 
02041    for(i = 0; i < nrpts; i++)
02042    {
02043       if (!strcmp(argv[2],rpt_vars[i].name)){
02044          /* Make a copy of all stat variables while locked */
02045          myrpt = &rpt_vars[i];
02046          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02047 
02048          dailytxtime = myrpt->dailytxtime;
02049          totaltxtime = myrpt->totaltxtime;
02050          dailykeyups = myrpt->dailykeyups;
02051          totalkeyups = myrpt->totalkeyups;
02052          dailykerchunks = myrpt->dailykerchunks;
02053          totalkerchunks = myrpt->totalkerchunks;
02054          dailyexecdcommands = myrpt->dailyexecdcommands;
02055          totalexecdcommands = myrpt->totalexecdcommands;
02056          timeouts = myrpt->timeouts;
02057 
02058          /* Traverse the list of connected nodes */
02059          reverse_patch_state = "DOWN";
02060          j = 0;
02061          l = myrpt->links.next;
02062          while(l && (l != &myrpt->links)){
02063             if (l->name[0] == '0'){ /* Skip '0' nodes */
02064                reverse_patch_state = "UP";
02065                l = l->next;
02066                continue;
02067             }
02068             listoflinks[j] = ast_strdupa(l->name);
02069             if(listoflinks[j])
02070                j++;
02071             l = l->next;
02072          }
02073 
02074          lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);       
02075          if((!lastnodewhichkeyedusup) || (!strlen(lastnodewhichkeyedusup)))
02076             lastnodewhichkeyedusup = not_applicable;
02077 
02078          if(myrpt->keyed)
02079             input_signal = "YES";
02080          else
02081             input_signal = "NO";
02082 
02083          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
02084             sys_ena = "DISABLED";
02085          else
02086             sys_ena = "ENABLED";
02087 
02088          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
02089             tot_ena = "DISABLED";
02090          else
02091             tot_ena = "ENABLED";
02092 
02093          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
02094             link_ena = "DISABLED";
02095          else
02096             link_ena = "ENABLED";
02097 
02098          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
02099             patch_ena = "DISABLED";
02100          else
02101             patch_ena = "ENABLED";
02102 
02103          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
02104             sch_ena = "DISABLED";
02105          else
02106             sch_ena = "ENABLED";
02107 
02108          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
02109             user_funs = "DISABLED";
02110          else
02111             user_funs = "ENABLED";
02112 
02113          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
02114             tail_type = "ALTERNATE";
02115          else
02116             tail_type = "STANDARD";
02117 
02118          if(!myrpt->totimer)
02119             tot_state = "TIMED OUT!";
02120          else if(myrpt->totimer != myrpt->p.totime)
02121             tot_state = "ARMED";
02122          else
02123             tot_state = "RESET";
02124 
02125          if(myrpt->tailid)
02126             ider_state = "QUEUED IN TAIL";
02127          else if(myrpt->mustid)
02128             ider_state = "QUEUED FOR CLEANUP";
02129          else
02130             ider_state = "CLEAN";
02131 
02132          switch(myrpt->callmode){
02133             case 1:
02134                patch_state = "DIALING";
02135                break;
02136             case 2:
02137                patch_state = "CONNECTING";
02138                break;
02139             case 3:
02140                patch_state = "UP";
02141                break;
02142 
02143             case 4:
02144                patch_state = "CALL FAILED";
02145                break;
02146 
02147             default:
02148                patch_state = "DOWN";
02149          }
02150 
02151          if(strlen(myrpt->exten)){
02152             called_number = ast_strdupa(myrpt->exten);
02153             if(!called_number)
02154                called_number = not_applicable;
02155          }
02156 
02157          if(strlen(myrpt->lastdtmfcommand)){
02158             lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
02159             if(!lastdtmfcommand)
02160                lastdtmfcommand = not_applicable;
02161          }
02162 
02163          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02164 
02165          ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
02166          ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
02167          ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
02168          ast_cli(fd, "System...........................................: %s\n", sys_ena);
02169          ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
02170          ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
02171          ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
02172          ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
02173          ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
02174          ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
02175          ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
02176          ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
02177          ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
02178          ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
02179          ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
02180          ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
02181          ast_cli(fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
02182          hours = dailytxtime/3600000;
02183          dailytxtime %= 3600000;
02184          minutes = dailytxtime/60000;
02185          dailytxtime %= 60000;
02186          seconds = dailytxtime/1000;
02187          dailytxtime %= 1000;
02188 
02189          ast_cli(fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
02190             hours, minutes, seconds, dailytxtime);
02191 
02192          hours = (int) totaltxtime/3600000;
02193          totaltxtime %= 3600000;
02194          minutes = (int) totaltxtime/60000;
02195          totaltxtime %= 60000;
02196          seconds = (int)  totaltxtime/1000;
02197          totaltxtime %= 1000;
02198 
02199          ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
02200              hours, minutes, seconds, (int) totaltxtime);
02201          ast_cli(fd, "Nodes currently connected to us..................: ");
02202          for(j = 0 ;; j++){
02203             if(!listoflinks[j]){
02204                if(!j){
02205                   ast_cli(fd,"<NONE>");
02206                }
02207                break;
02208             }
02209             ast_cli(fd, "%s", listoflinks[j]);
02210             if(j % 4 == 3){
02211                ast_cli(fd, "\n");
02212                ast_cli(fd, "                                                 : ");
02213             }
02214             else{
02215                if(listoflinks[j + 1])
02216                   ast_cli(fd, ", ");
02217             }
02218          }
02219          ast_cli(fd,"\n");
02220 
02221          ast_cli(fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
02222          ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
02223          ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
02224          ast_cli(fd, "Autopatch called number..........................: %s\n", called_number);
02225          ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
02226          ast_cli(fd, "User linking commands............................: %s\n", link_ena);
02227          ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
02228               return RESULT_SUCCESS;
02229       }
02230    }
02231    return RESULT_FAILURE;
02232 }
02233 
02234 /*
02235 * Link stats function
02236 */
02237 
02238 static int rpt_do_lstats(int fd, int argc, char *argv[])
02239 {
02240    int i,j;
02241    char *connstate;
02242    struct rpt *myrpt;
02243    struct rpt_link *l;
02244    struct rpt_lstat *s,*t;
02245    struct rpt_lstat s_head;
02246    if(argc != 3)
02247       return RESULT_SHOWUSAGE;
02248 
02249    s = NULL;
02250    s_head.next = &s_head;
02251    s_head.prev = &s_head;
02252 
02253    for(i = 0; i < nrpts; i++)
02254    {
02255       if (!strcmp(argv[2],rpt_vars[i].name)){
02256          /* Make a copy of all stat variables while locked */
02257          myrpt = &rpt_vars[i];
02258          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02259          /* Traverse the list of connected nodes */
02260          j = 0;
02261          l = myrpt->links.next;
02262          while(l && (l != &myrpt->links)){
02263             if (l->name[0] == '0'){ /* Skip '0' nodes */
02264                l = l->next;
02265                continue;
02266             }
02267             if((s = (struct rpt_lstat *) malloc(sizeof(struct rpt_lstat))) == NULL){
02268                ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
02269                rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02270                return RESULT_FAILURE;
02271             }
02272             memset(s, 0, sizeof(struct rpt_lstat));
02273             strncpy(s->name, l->name, MAXREMSTR - 1);
02274             if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
02275             else strcpy(s->peer,"(none)");
02276             s->mode = l->mode;
02277             s->outbound = l->outbound;
02278             s->reconnects = l->reconnects;
02279             s->connecttime = l->connecttime;
02280             s->thisconnected = l->thisconnected;
02281             memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
02282             insque((struct qelem *) s, (struct qelem *) s_head.next);
02283             memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
02284             l = l->next;
02285          }
02286          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02287          ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME        CONNECT STATE\n");
02288          ast_cli(fd, "----      ----                ----------  ---------  ------------        -------------\n");
02289 
02290          for(s = s_head.next; s != &s_head; s = s->next){
02291             int hours, minutes, seconds;
02292             long long connecttime = s->connecttime;
02293             char conntime[21];
02294             hours = (int) connecttime/3600000;
02295             connecttime %= 3600000;
02296             minutes = (int) connecttime/60000;
02297             connecttime %= 60000;
02298             seconds = (int)  connecttime/1000;
02299             connecttime %= 1000;
02300             snprintf(conntime, 20, "%02d:%02d:%02d.%d",
02301                hours, minutes, seconds, (int) connecttime);
02302             conntime[20] = 0;
02303             if(s->thisconnected)
02304                connstate  = "ESTABLISHED";
02305             else
02306                connstate = "CONNECTING";
02307             ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
02308                s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
02309          }  
02310          /* destroy our local link queue */
02311          s = s_head.next;
02312          while(s != &s_head){
02313             t = s;
02314             s = s->next;
02315             remque((struct qelem *)t);
02316             free(t);
02317          }        
02318          return RESULT_SUCCESS;
02319       }
02320    }
02321    return RESULT_FAILURE;
02322 }
02323 
02324 /*
02325 * List all nodes connected, directly or indirectly
02326 */
02327 
02328 static int rpt_do_nodes(int fd, int argc, char *argv[])
02329 {
02330    int i,j;
02331    char ns;
02332    char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
02333    struct rpt *myrpt;
02334    if(argc != 3)
02335       return RESULT_SHOWUSAGE;
02336 
02337    for(i = 0; i < nrpts; i++)
02338    {
02339       if (!strcmp(argv[2],rpt_vars[i].name)){
02340          /* Make a copy of all stat variables while locked */
02341          myrpt = &rpt_vars[i];
02342          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02343          __mklinklist(myrpt,NULL,lbuf);
02344          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02345          /* parse em */
02346          ns = finddelim(lbuf,strs,MAXLINKLIST);
02347          /* sort em */
02348          if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
02349          ast_cli(fd,"\n");
02350          ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
02351          for(j = 0 ;; j++){
02352             if(!strs[j]){
02353                if(!j){
02354                   ast_cli(fd,"<NONE>");
02355                }
02356                break;
02357             }
02358             ast_cli(fd, "%s", strs[j]);
02359             if(j % 8 == 7){
02360                ast_cli(fd, "\n");
02361             }
02362             else{
02363                if(strs[j + 1])
02364                   ast_cli(fd, ", ");
02365             }
02366          }
02367          ast_cli(fd,"\n\n");
02368          return RESULT_SUCCESS;
02369       }
02370    }
02371    return RESULT_FAILURE;
02372 }
02373 
02374 /*
02375 * reload vars 
02376 */
02377 
02378 static int rpt_do_reload(int fd, int argc, char *argv[])
02379 {
02380 int   n;
02381 
02382         if (argc > 2) return RESULT_SHOWUSAGE;
02383 
02384    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
02385 
02386    return RESULT_FAILURE;
02387 }
02388 
02389 /*
02390 * restart app_rpt
02391 */
02392                                                                                                                                  
02393 static int rpt_do_restart(int fd, int argc, char *argv[])
02394 {
02395 int   i;
02396 
02397         if (argc > 2) return RESULT_SHOWUSAGE;
02398    for(i = 0; i < nrpts; i++)
02399    {
02400       if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
02401    }
02402    return RESULT_FAILURE;
02403 }
02404 
02405 
02406 /*
02407 * send an app_rpt DTMF function from the CLI
02408 */
02409                                                                                                                                  
02410 static int rpt_do_fun(int fd, int argc, char *argv[])
02411 {
02412    int   i,busy=0;
02413 
02414         if (argc != 4) return RESULT_SHOWUSAGE;
02415 
02416    for(i = 0; i < nrpts; i++){
02417       if(!strcmp(argv[2], rpt_vars[i].name)){
02418          struct rpt *myrpt = &rpt_vars[i];
02419          rpt_mutex_lock(&myrpt->lock);
02420          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
02421             rpt_mutex_unlock(&myrpt->lock);
02422             busy=1;
02423          }
02424          if(!busy){
02425             myrpt->macrotimer = MACROTIME;
02426             strncat(myrpt->macrobuf, argv[3], MAXMACRO - strlen(myrpt->macrobuf) - 1);
02427          }
02428          rpt_mutex_unlock(&myrpt->lock);
02429       }
02430    }
02431    if(busy){
02432       ast_cli(fd, "Function decoder busy");
02433    }
02434    return RESULT_FAILURE;
02435 }
02436 
02437 
02438 
02439 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
02440 {
02441    int res;
02442 
02443         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
02444                 return res;
02445                                                                                                                                             
02446         while(chan->generatordata) {
02447       if (ast_safe_sleep(chan,1)) return -1;
02448    }
02449 
02450         return 0;
02451 }
02452 
02453 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
02454 {
02455    return play_tone_pair(chan, freq, 0, duration, amplitude);
02456 }
02457 
02458 static int play_silence(struct ast_channel *chan, int duration)
02459 {
02460    return play_tone_pair(chan, 0, 0, duration, 0);
02461 }
02462 
02463 
02464 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
02465 {
02466 
02467 static struct morse_bits mbits[] = {
02468       {0, 0}, /* SPACE */
02469       {0, 0}, 
02470       {6, 18},/* " */
02471       {0, 0},
02472       {7, 72},/* $ */
02473       {0, 0},
02474       {0, 0},
02475       {6, 30},/* ' */
02476       {5, 13},/* ( */
02477       {6, 29},/* ) */
02478       {0, 0},
02479       {5, 10},/* + */
02480       {6, 51},/* , */
02481       {6, 33},/* - */
02482       {6, 42},/* . */
02483       {5, 9}, /* / */
02484       {5, 31},/* 0 */
02485       {5, 30},/* 1 */
02486       {5, 28},/* 2 */
02487       {5, 24},/* 3 */
02488       {5, 16},/* 4 */
02489       {5, 0}, /* 5 */
02490       {5, 1}, /* 6 */
02491       {5, 3}, /* 7 */
02492       {5, 7}, /* 8 */
02493       {5, 15},/* 9 */
02494       {6, 7}, /* : */
02495       {6, 21},/* ; */
02496       {0, 0},
02497       {5, 33},/* = */
02498       {0, 0},
02499       {6, 12},/* ? */
02500       {0, 0},
02501          {2, 2}, /* A */
02502       {4, 1}, /* B */
02503       {4, 5}, /* C */
02504       {3, 1}, /* D */
02505       {1, 0}, /* E */
02506       {4, 4}, /* F */
02507       {3, 3}, /* G */
02508       {4, 0}, /* H */
02509       {2, 0}, /* I */
02510       {4, 14},/* J */
02511       {3, 5}, /* K */
02512       {4, 2}, /* L */
02513       {2, 3}, /* M */
02514       {2, 1}, /* N */
02515       {3, 7}, /* O */
02516       {4, 6}, /* P */
02517       {4, 11},/* Q */
02518       {3, 2}, /* R */
02519       {3, 0}, /* S */
02520       {1, 1}, /* T */
02521       {3, 4}, /* U */
02522       {4, 8}, /* V */
02523       {3, 6}, /* W */
02524       {4, 9}, /* X */
02525       {4, 13},/* Y */
02526       {4, 3}  /* Z */
02527    };
02528 
02529 
02530    int dottime;
02531    int dashtime;
02532    int intralettertime;
02533    int interlettertime;
02534    int interwordtime;
02535    int len, ddcomb;
02536    int res;
02537    int c;
02538    int i;
02539    int flags;
02540          
02541    res = 0;
02542    
02543    /* Approximate the dot time from the speed arg. */
02544    
02545    dottime = 900/speed;
02546    
02547    /* Establish timing releationships */
02548    
02549    dashtime = 3 * dottime;
02550    intralettertime = dottime;
02551    interlettertime = dottime * 4 ;
02552    interwordtime = dottime * 7;
02553    
02554    for(;(*string) && (!res); string++){
02555    
02556       c = *string;
02557       
02558       /* Convert lower case to upper case */
02559       
02560       if((c >= 'a') && (c <= 'z'))
02561          c -= 0x20;
02562       
02563       /* Can't deal with any char code greater than Z, skip it */
02564       
02565       if(c  > 'Z')
02566          continue;
02567       
02568       /* If space char, wait the inter word time */
02569                
02570       if(c == ' '){
02571          if(!res)
02572             res = play_silence(chan, interwordtime);
02573          continue;
02574       }
02575       
02576       /* Subtract out control char offset to match our table */
02577       
02578       c -= 0x20;
02579       
02580       /* Get the character data */
02581       
02582       len = mbits[c].len;
02583       ddcomb = mbits[c].ddcomb;
02584       
02585       /* Send the character */
02586       
02587       for(; len ; len--){
02588          if(!res)
02589             res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
02590          if(!res)
02591             res = play_silence(chan, intralettertime);
02592          ddcomb >>= 1;
02593       }
02594       
02595       /* Wait the interletter time */
02596       
02597       if(!res)
02598          res = play_silence(chan, interlettertime - intralettertime);
02599    }
02600    
02601    /* Wait for all the frames to be sent */
02602    
02603    if (!res) 
02604       res = ast_waitstream(chan, "");
02605    ast_stopstream(chan);
02606    
02607    /*
02608    * Wait for the zaptel driver to physically write the tone blocks to the hardware
02609    */
02610 
02611    for(i = 0; i < 20 ; i++){
02612       flags =  ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT; 
02613       res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
02614       if(flags & ZT_IOMUX_WRITEEMPTY)
02615          break;
02616       if( ast_safe_sleep(chan, 50)){
02617          res = -1;
02618          break;
02619       }
02620    }
02621 
02622    
02623    return res;
02624 }
02625 
02626 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
02627 {
02628    char *stringp;
02629    char *tonesubset;
02630    int f1,f2;
02631    int duration;
02632    int amplitude;
02633    int res;
02634    int i;
02635    int flags;
02636    
02637    res = 0;
02638    
02639    stringp = ast_strdupa(tonestring);
02640 
02641    for(;tonestring;){
02642       tonesubset = strsep(&stringp,")");
02643       if(!tonesubset)
02644          break;
02645       if(sscanf(tonesubset,"(%d,%d,%d,%d", &f1, &f2, &duration, &amplitude) != 4)
02646          break;
02647       res = play_tone_pair(chan, f1, f2, duration, amplitude);
02648       if(res)
02649          break;
02650    }
02651    if(!res)
02652       res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
02653    
02654    if (!res) 
02655       res = ast_waitstream(chan, "");
02656    ast_stopstream(chan);
02657 
02658    /*
02659    * Wait for the zaptel driver to physically write the tone blocks to the hardware
02660    */
02661 
02662    for(i = 0; i < 20 ; i++){
02663       flags =  ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT; 
02664       res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
02665       if(flags & ZT_IOMUX_WRITEEMPTY)
02666          break;
02667       if( ast_safe_sleep(chan, 50)){
02668          res = -1;
02669          break;
02670       }
02671    }
02672       
02673    return res;
02674       
02675 }
02676 
02677 static int sayfile(struct ast_channel *mychannel,char *fname)
02678 {
02679 int   res;
02680 
02681    res = ast_streamfile(mychannel, fname, mychannel->language);
02682    if (!res) 
02683       res = ast_waitstream(mychannel, "");
02684    else
02685        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02686    ast_stopstream(mychannel);
02687    return res;
02688 }
02689 
02690 static int saycharstr(struct ast_channel *mychannel,char *str)
02691 {
02692 int   res;
02693 
02694    res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
02695    if (!res) 
02696       res = ast_waitstream(mychannel, "");
02697    else
02698        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02699    ast_stopstream(mychannel);
02700    return res;
02701 }
02702 
02703 static int saynum(struct ast_channel *mychannel, int num)
02704 {
02705    int res;
02706    res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
02707    if(!res)
02708       res = ast_waitstream(mychannel, "");
02709    else
02710       ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02711    ast_stopstream(mychannel);
02712    return res;
02713 }
02714 
02715 
02716 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
02717 {
02718    int res;
02719    char c;
02720    
02721    static int morsespeed;
02722    static int morsefreq;
02723    static int morseampl;
02724    static int morseidfreq = 0;
02725    static int morseidampl;
02726    static char mcat[] = MORSE;
02727    
02728    res = 0;
02729    
02730    if(!morseidfreq){ /* Get the morse parameters if not already loaded */
02731       morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
02732          morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
02733          morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
02734       morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
02735       morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330); 
02736    }
02737    
02738    /* Is it a file, or a tone sequence? */
02739          
02740    if(entry[0] == '|'){
02741       c = entry[1];
02742       if((c >= 'a')&&(c <= 'z'))
02743          c -= 0x20;
02744    
02745       switch(c){
02746          case 'I': /* Morse ID */
02747             res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
02748             break;
02749          
02750          case 'M': /* Morse Message */
02751             res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
02752             break;
02753          
02754          case 'T': /* Tone sequence */
02755             res = send_tone_telemetry(chan, entry + 2);
02756             break;
02757          default:
02758             res = -1;
02759       }
02760    }
02761    else
02762       res = sayfile(chan, entry); /* File */
02763    return res;
02764 }
02765 
02766 /*
02767 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
02768 *
02769 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
02770 */
02771 
02772 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
02773 {
02774    
02775    int res;
02776    int i;
02777    char *entry;
02778    char *telemetry;
02779    char *telemetry_save;
02780 
02781    res = 0;
02782    telemetry_save = NULL;
02783    entry = NULL;
02784    
02785    /* Retrieve the section name for telemetry from the node section */
02786    telemetry = (char *) ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
02787    if(telemetry ){
02788       telemetry_save = ast_strdupa(telemetry);
02789       if(!telemetry_save){
02790          ast_log(LOG_WARNING,"ast_strdupa() failed in telem_lookup()\n");
02791          return res;
02792       }
02793       entry = (char *) ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
02794    }
02795    
02796    /* Try to look up the telemetry name */   
02797 
02798    if(!entry){
02799       /* Telemetry name wasn't found in the config file, use the default */
02800       for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
02801          if(!strcasecmp(tele_defs[i].name, name))
02802             entry = tele_defs[i].value;
02803       }
02804    }
02805    if(entry){  
02806       if(strlen(entry))
02807          telem_any(myrpt,chan, entry);
02808    }
02809    else{
02810       res = -1;
02811    }
02812    return res;
02813 }
02814 
02815 /*
02816 * Retrieve a wait interval
02817 */
02818 
02819 static int get_wait_interval(struct rpt *myrpt, int type)
02820 {
02821         int interval;
02822         char *wait_times;
02823         char *wait_times_save;
02824                                                                                                                   
02825         wait_times_save = NULL;
02826         wait_times = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
02827                                                                                                                   
02828         if(wait_times){
02829                 wait_times_save = ast_strdupa(wait_times);
02830                 if(!wait_times_save){
02831                         ast_log(LOG_WARNING, "Out of memory in wait_interval()\n");
02832                         wait_times = NULL;
02833                 }
02834         }
02835                                                                                                                   
02836         switch(type){
02837                 case DLY_TELEM:
02838                         if(wait_times)
02839                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
02840                         else
02841                                 interval = 1000;
02842                         break;
02843                                                                                                                   
02844                 case DLY_ID:
02845                         if(wait_times)
02846                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
02847                         else
02848                                 interval = 500;
02849                         break;
02850                                                                                                                   
02851                 case DLY_UNKEY:
02852                         if(wait_times)
02853                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",500,5000,1000);
02854                         else
02855                                 interval = 1000;
02856                         break;
02857                                                                                                                   
02858                 case DLY_LINKUNKEY:
02859                         if(wait_times)
02860                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "linkunkeywait",500,5000,1000);
02861                         else
02862                                 interval = 1000;
02863                         break;
02864                                                                                                                   
02865                 case DLY_CALLTERM:
02866                         if(wait_times)
02867                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
02868                         else
02869                                 interval = 1500;
02870                         break;
02871                                                                                                                   
02872                 case DLY_COMP:
02873                         if(wait_times)
02874                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "compwait",500,5000,200);
02875                         else
02876                                 interval = 200;
02877                         break;
02878                                                                                                                   
02879                 default:
02880                         return 0;
02881         }
02882    return interval;
02883 }                                                                                                                  
02884 
02885 
02886 /*
02887 * Wait a configurable interval of time 
02888 */
02889 
02890 
02891 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
02892 {
02893    int interval;
02894    interval = get_wait_interval(myrpt, type);
02895    if(debug)
02896       ast_log(LOG_NOTICE," Delay interval = %d\n", interval);
02897    if(interval)
02898       ast_safe_sleep(chan,interval);
02899    if(debug)
02900       ast_log(LOG_NOTICE,"Delay complete\n");
02901    return;
02902 }
02903 
02904 static int split_freq(char *mhz, char *decimals, char *freq);
02905 
02906 static void *rpt_tele_thread(void *this)
02907 {
02908 ZT_CONFINFO ci;  /* conference info */
02909 int   res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
02910 struct   rpt_tele *mytele = (struct rpt_tele *)this;
02911 struct  rpt_tele *tlist;
02912 struct   rpt *myrpt;
02913 struct   rpt_link *l,*l1,linkbase;
02914 struct   ast_channel *mychannel;
02915 int vmajor, vminor, m;
02916 char *p,*ct,*ct_copy,*ident, *nodename,*cp;
02917 time_t t;
02918 struct tm localtm;
02919 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
02920 int   i,ns,rbimode;
02921 char mhz[MAXREMSTR];
02922 char decimals[MAXREMSTR];
02923 struct zt_params par;
02924 
02925 
02926    /* get a pointer to myrpt */
02927    myrpt = mytele->rpt;
02928 
02929    /* Snag copies of a few key myrpt variables */
02930    rpt_mutex_lock(&myrpt->lock);
02931    nodename = ast_strdupa(myrpt->name);
02932    if (myrpt->p.ident) ident = ast_strdupa(myrpt->p.ident);
02933    else ident = "";
02934    rpt_mutex_unlock(&myrpt->lock);
02935    
02936    /* allocate a pseudo-channel thru asterisk */
02937    mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
02938    if (!mychannel)
02939    {
02940       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
02941       rpt_mutex_lock(&myrpt->lock);
02942       remque((struct qelem *)mytele);
02943       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
02944       rpt_mutex_unlock(&myrpt->lock);
02945       free(mytele);     
02946       pthread_exit(NULL);
02947    }
02948 #ifdef   AST_CDR_FLAG_POST_DISABLED
02949    ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
02950 #endif
02951    rpt_mutex_lock(&myrpt->lock);
02952    mytele->chan = mychannel;
02953    rpt_mutex_unlock(&myrpt->lock);
02954    /* make a conference for the tx */
02955    ci.chan = 0;
02956    /* If there's an ID queued, or tail message queued, */
02957    /* only connect the ID audio to the local tx conference so */
02958    /* linked systems can't hear it */
02959    ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
02960       (mytele->mode == TAILMSG) || (mytele->mode == LINKUNKEY)) || (mytele->mode == TIMEOUT) ?
02961          myrpt->txconf : myrpt->conf);
02962    ci.confmode = ZT_CONF_CONFANN;
02963    /* first put the channel on the conference in announce mode */
02964    if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
02965    {
02966       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02967       rpt_mutex_lock(&myrpt->lock);
02968       remque((struct qelem *)mytele);
02969       rpt_mutex_unlock(&myrpt->lock);
02970       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
02971       free(mytele);     
02972       ast_hangup(mychannel);
02973       pthread_exit(NULL);
02974    }
02975    ast_stopstream(mychannel);
02976    switch(mytele->mode)
02977    {
02978        case ID:
02979        case ID1:
02980       /* wait a bit */
02981       wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
02982       res = telem_any(myrpt,mychannel, ident); 
02983       imdone=1;   
02984       break;
02985       
02986        case TAILMSG:
02987       res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language); 
02988       break;
02989       
02990        case IDTALKOVER:
02991          p = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
02992          if(p)
02993          res = telem_any(myrpt,mychannel, p); 
02994       imdone=1;   
02995          break;
02996             
02997        case PROC:
02998       /* wait a little bit longer */
02999       wait_interval(myrpt, DLY_TELEM, mychannel);
03000       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
03001       if(res < 0){ /* Then default message */
03002          res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
03003       }
03004       break;
03005        case TERM:
03006       /* wait a little bit longer */
03007       wait_interval(myrpt, DLY_CALLTERM, mychannel);
03008       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
03009       if(res < 0){ /* Then default message */
03010          res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
03011       }
03012       break;
03013        case COMPLETE:
03014       /* wait a little bit */
03015       wait_interval(myrpt, DLY_TELEM, mychannel);
03016       res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03017       break;
03018        case MACRO_NOTFOUND:
03019       /* wait a little bit */
03020       wait_interval(myrpt, DLY_TELEM, mychannel);
03021       res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
03022       break;
03023        case MACRO_BUSY:
03024       /* wait a little bit */
03025       wait_interval(myrpt, DLY_TELEM, mychannel);
03026       res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
03027       break;
03028        case UNKEY:
03029       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
03030          imdone = 1;
03031          break;
03032       }
03033          
03034       /*
03035       * Reset the Unkey to CT timer
03036       */
03037 
03038       x = get_wait_interval(myrpt, DLY_UNKEY);
03039       rpt_mutex_lock(&myrpt->lock);
03040       myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
03041       rpt_mutex_unlock(&myrpt->lock);
03042 
03043       /*
03044       * If there's one already queued, don't do another
03045       */
03046 
03047       tlist = myrpt->tele.next;
03048       unkeys_queued = 0;
03049                 if (tlist != &myrpt->tele)
03050                 {
03051                         rpt_mutex_lock(&myrpt->lock);
03052                         while(tlist != &myrpt->tele){
03053                                 if (tlist->mode == UNKEY) unkeys_queued++;
03054                                 tlist = tlist->next;
03055                         }
03056                         rpt_mutex_unlock(&myrpt->lock);
03057       }
03058       if( unkeys_queued > 1){
03059          imdone = 1;
03060          break;
03061       }
03062 
03063       /* Wait for the telemetry timer to expire */
03064       /* Periodically check the timer since it can be re-initialized above */
03065       while(myrpt->unkeytocttimer)
03066       {
03067          int ctint;
03068          if(myrpt->unkeytocttimer > 100)
03069             ctint = 100;
03070          else
03071             ctint = myrpt->unkeytocttimer;
03072          ast_safe_sleep(mychannel, ctint);
03073          rpt_mutex_lock(&myrpt->lock);
03074          if(myrpt->unkeytocttimer < ctint)
03075             myrpt->unkeytocttimer = 0;
03076          else
03077             myrpt->unkeytocttimer -= ctint;
03078          rpt_mutex_unlock(&myrpt->lock);
03079       }
03080    
03081       /*
03082       * Now, the carrier on the rptr rx should be gone. 
03083       * If it re-appeared, then forget about sending the CT
03084       */
03085       if(myrpt->keyed){
03086          imdone = 1;
03087          break;
03088       }
03089       
03090       rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
03091       myrpt->dailykerchunks++;
03092       myrpt->totalkerchunks++;
03093       rpt_mutex_unlock(&myrpt->lock);
03094    
03095       haslink = 0;
03096       hastx = 0;
03097       hasremote = 0;    
03098       l = myrpt->links.next;
03099       if (l != &myrpt->links)
03100       {
03101          rpt_mutex_lock(&myrpt->lock);
03102          while(l != &myrpt->links)
03103          {
03104             if (l->name[0] == '0')
03105             {
03106                l = l->next;
03107                continue;
03108             }
03109             haslink = 1;
03110             if (l->mode) {
03111                hastx++;
03112                if (l->isremote) hasremote++;
03113             }
03114             l = l->next;
03115          }
03116          rpt_mutex_unlock(&myrpt->lock);
03117       }
03118       if (haslink)
03119       {
03120 
03121          res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
03122          if(res)
03123             ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
03124          
03125       
03126          /* if in remote cmd mode, indicate it */
03127          if (myrpt->cmdnode[0])
03128          {
03129             ast_safe_sleep(mychannel,200);
03130             res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
03131             if(res)
03132                ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
03133             ast_stopstream(mychannel);
03134          }
03135       }
03136       else if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
03137          ct_copy = ast_strdupa(ct);
03138          res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
03139          if(res)
03140             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
03141       }  
03142       if (hasremote && (!myrpt->cmdnode[0]))
03143       {
03144          /* set for all to hear */
03145          ci.chan = 0;
03146          ci.confno = myrpt->conf;
03147          ci.confmode = ZT_CONF_CONFANN;
03148          /* first put the channel on the conference in announce mode */
03149          if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
03150          {
03151             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
03152             rpt_mutex_lock(&myrpt->lock);
03153             remque((struct qelem *)mytele);
03154             rpt_mutex_unlock(&myrpt->lock);
03155             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03156             free(mytele);     
03157             ast_hangup(mychannel);
03158             pthread_exit(NULL);
03159          }
03160          if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
03161             ast_safe_sleep(mychannel,200);
03162             ct_copy = ast_strdupa(ct);
03163             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
03164             if(res)
03165                ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
03166          }  
03167       }
03168 #if   defined(_MDC_DECODE_H_) && defined(MDC_SAY_WHEN_DOING_CT)
03169       if (myrpt->lastunit)
03170       {
03171          char mystr[10];
03172 
03173          ast_safe_sleep(mychannel,200);
03174          /* set for all to hear */
03175          ci.chan = 0;
03176          ci.confno = myrpt->txconf;
03177          ci.confmode = ZT_CONF_CONFANN;
03178          /* first put the channel on the conference in announce mode */
03179          if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
03180          {
03181             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
03182             rpt_mutex_lock(&myrpt->lock);
03183             remque((struct qelem *)mytele);
03184             rpt_mutex_unlock(&myrpt->lock);
03185             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03186             free(mytele);     
03187             ast_hangup(mychannel);
03188             pthread_exit(NULL);
03189          }
03190          sprintf(mystr,"%04x",myrpt->lastunit);
03191          myrpt->lastunit = 0;
03192          ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
03193          break;
03194       }
03195 #endif
03196       imdone = 1;
03197       break;
03198        case LINKUNKEY:
03199       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
03200          imdone = 1;
03201          break;
03202       }
03203          
03204       /*
03205       * Reset the Unkey to CT timer
03206       */
03207 
03208       x = get_wait_interval(myrpt, DLY_LINKUNKEY);
03209       mytele->mylink.linkunkeytocttimer = x; /* Must be protected as it is changed below */
03210 
03211       /*
03212       * If there's one already queued, don't do another
03213       */
03214 
03215       tlist = myrpt->tele.next;
03216       unkeys_queued = 0;
03217                 if (tlist != &myrpt->tele)
03218                 {
03219                         rpt_mutex_lock(&myrpt->lock);
03220                         while(tlist != &myrpt->tele){
03221                                 if (tlist->mode == LINKUNKEY) unkeys_queued++;
03222                                 tlist = tlist->next;
03223                         }
03224                         rpt_mutex_unlock(&myrpt->lock);
03225       }
03226       if( unkeys_queued > 1){
03227          imdone = 1;
03228          break;
03229       }
03230 
03231       /* Wait for the telemetry timer to expire */
03232       /* Periodically check the timer since it can be re-initialized above */
03233       while(mytele->mylink.linkunkeytocttimer)
03234       {
03235          int ctint;
03236          if(mytele->mylink.linkunkeytocttimer > 100)
03237             ctint = 100;
03238          else
03239             ctint = mytele->mylink.linkunkeytocttimer;
03240          ast_safe_sleep(mychannel, ctint);
03241          rpt_mutex_lock(&myrpt->lock);
03242          if(mytele->mylink.linkunkeytocttimer < ctint)
03243             mytele->mylink.linkunkeytocttimer = 0;
03244          else
03245             mytele->mylink.linkunkeytocttimer -= ctint;
03246          rpt_mutex_unlock(&myrpt->lock);
03247       }
03248    
03249       if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "linkunkeyct"))){ /* Unlinked Courtesy Tone */
03250          ct_copy = ast_strdupa(ct);
03251          res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
03252          if(res)
03253             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
03254       }  
03255       imdone = 1;
03256       break;
03257        case REMDISC:
03258       /* wait a little bit */
03259       wait_interval(myrpt, DLY_TELEM, mychannel);
03260       l = myrpt->links.next;
03261       haslink = 0;
03262       /* dont report if a link for this one still on system */
03263       if (l != &myrpt->links)
03264       {
03265          rpt_mutex_lock(&myrpt->lock);
03266          while(l != &myrpt->links)
03267          {
03268             if (l->name[0] == '0')
03269             {
03270                l = l->next;
03271                continue;
03272             }
03273             if (!strcmp(l->name,mytele->mylink.name))
03274             {
03275                haslink = 1;
03276                break;
03277             }
03278             l = l->next;
03279          }
03280          rpt_mutex_unlock(&myrpt->lock);
03281       }
03282       if (haslink)
03283       {
03284          imdone = 1;
03285          break;
03286       }
03287       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03288       if (!res) 
03289          res = ast_waitstream(mychannel, "");
03290       else
03291           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03292       ast_stopstream(mychannel);
03293       ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
03294       res = ast_streamfile(mychannel, ((mytele->mylink.hasconnected) ? 
03295          "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
03296       break;
03297        case REMALREADY:
03298       /* wait a little bit */
03299       wait_interval(myrpt, DLY_TELEM, mychannel);
03300       res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
03301       break;
03302        case REMNOTFOUND:
03303       /* wait a little bit */
03304       wait_interval(myrpt, DLY_TELEM, mychannel);
03305       res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
03306       break;
03307        case REMGO:
03308       /* wait a little bit */
03309       wait_interval(myrpt, DLY_TELEM, mychannel);
03310       res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
03311       break;
03312        case CONNECTED:
03313       /* wait a little bit */
03314       wait_interval(myrpt, DLY_TELEM,  mychannel);
03315       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03316       if (!res) 
03317          res = ast_waitstream(mychannel, "");
03318       else
03319           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03320       ast_stopstream(mychannel);
03321       ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
03322       res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
03323       if (!res) 
03324          res = ast_waitstream(mychannel, "");
03325       else
03326           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03327       ast_stopstream(mychannel);
03328       res = ast_streamfile(mychannel, "digits/2", mychannel->language);
03329       if (!res) 
03330          res = ast_waitstream(mychannel, "");
03331       else
03332           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03333       ast_stopstream(mychannel);
03334       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03335       if (!res) 
03336          res = ast_waitstream(mychannel, "");
03337       else
03338           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03339       ast_stopstream(mychannel);
03340       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03341       imdone = 1;
03342       break;
03343        case CONNFAIL:
03344       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03345       if (!res) 
03346          res = ast_waitstream(mychannel, "");
03347       else
03348           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03349       ast_stopstream(mychannel);
03350       ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
03351       res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
03352       break;
03353        case MEMNOTFOUND:
03354       /* wait a little bit */
03355       wait_interval(myrpt, DLY_TELEM, mychannel);
03356       res = ast_streamfile(mychannel, "rpt/memory_notfound", mychannel->language);
03357       break;
03358        case SETREMOTE:
03359       ast_mutex_lock(&myrpt->remlock);
03360       res = 0;
03361       if(!strcmp(myrpt->remote, remote_rig_ft897))
03362       {
03363          res = set_ft897(myrpt);
03364       }
03365       if(!strcmp(myrpt->remote, remote_rig_ic706))
03366       {
03367          res = set_ic706(myrpt);
03368       }
03369       else if(!strcmp(myrpt->remote, remote_rig_rbi))
03370       {
03371          if (ioperm(myrpt->p.iobase,1,1) == -1)
03372          {
03373             rpt_mutex_unlock(&myrpt->lock);
03374             ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
03375             res = -1;
03376          }
03377          else res = setrbi(myrpt);
03378       }
03379       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 = ZT_FLUSH_EVENT;
03389          if (ioctl(myrpt->zaptxchannel->fds[0],ZT_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],ZT_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 ZT_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 = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
04185       | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
04186    /* first put the channel on the conference */
04187    if (ioctl(mychannel->fds[0],ZT_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 = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
04208       | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
04209    /* first put the channel on the conference */
04210    if (ioctl(genchannel->fds[0],ZT_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],ZT_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],ZT_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) ? ZT_CONF_CONFANNMON :
04350       (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
04351    /* first put the channel on the conference in announce mode */
04352    if (ioctl(myrpt->pchannel->fds[0],ZT_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],ZT_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)) ? ZT_CONF_CONFANNMON :
04405       (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
04406    /* first put the channel on the conference in announce mode */
04407    if (ioctl(myrpt->pchannel->fds[0],ZT_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    ZT_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 = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
04614    /* first put the channel on the conference in proper mode */
04615    if (ioctl(l->pchan->fds[0], ZT_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 zt_radio_param r;
05851 
05852    memset(&r,0,sizeof(struct zt_radio_param));
05853    r.radpar = ZT_RADPAR_REMMODE;
05854    r.data = ZT_RADPAR_REM_RBI1;
05855    /* if setparam ioctl fails, its probably not a pciradio card */
05856    if (ioctl(myrpt->zaprxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
05857    {
05858       rbi_out_parallel(myrpt,data);
05859       return;
05860    }
05861    r.radpar = ZT_RADPAR_REMCOMMAND;
05862    memcpy(&r.data,data,5);
05863    if (ioctl(myrpt->zaprxchannel->fds[0],ZT_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 zt_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 = ZT_RADPAR_UIOMODE;
05913    if (ioctl(myrpt->zaprxchannel->fds[0],ZT_RADIO_GETPARAM,&prm) == -1) return -1;
05914    oldmode = prm.data;
05915    prm.radpar = ZT_RADPAR_UIODATA;
05916    if (ioctl(myrpt->zaprxchannel->fds[0],ZT_RADIO_GETPARAM,&prm) == -1) return -1;
05917    olddata = prm.data;
05918         prm.radpar = ZT_RADPAR_REMMODE;
05919         if (asciiflag & 1)  prm.data = ZT_RADPAR_REM_SERIAL_ASCII;
05920         else prm.data = ZT_RADPAR_REM_SERIAL;
05921    if (ioctl(myrpt->zaprxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
05922    if (asciiflag & 2)
05923    {
05924       i = ZT_ONHOOK;
05925       if (ioctl(myrpt->zaprxchannel->fds[0],ZT_HOOK,&i) == -1) return -1;
05926       usleep(100000);
05927    }
05928         prm.radpar = ZT_RADPAR_REMCOMMAND;
05929         prm.data = rxmaxbytes;
05930         memcpy(prm.buf,txbuf,txbytes);
05931         prm.index = txbytes;
05932    if (ioctl(myrpt->zaprxchannel->fds[0],ZT_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 = ZT_RADPAR_REMMODE;
05940         prm.data = ZT_RADPAR_REM_NONE;
05941    if (ioctl(myrpt->zaprxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
05942    if (asciiflag & 2)
05943    {
05944       i = ZT_OFFHOOK;
05945       if (ioctl(myrpt->zaprxchannel->fds[0],ZT_HOOK,&i) == -1) return -1;
05946    }
05947    prm.radpar = ZT_RADPAR_UIOMODE;
05948    prm.data = oldmode;
05949    if (ioctl(myrpt->zaprxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
05950    prm.radpar = ZT_RADPAR_UIODATA;
05951    prm.data = olddata;
05952    if (ioctl(myrpt->zaprxchannel->fds[0],ZT_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 ZT_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 = ZT_CONF_CONF | ZT_CONF_LISTENER;
08967    /* first put the channel on the conference in proper mode */
08968    if (ioctl(myrpt->zaptxchannel->fds[0],ZT_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)) ? ZT_CONF_CONFANNMON :
08986       (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
08987    /* first put the channel on the conference in announce mode */
08988    if (ioctl(myrpt->pchannel->fds[0],ZT_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],ZT_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 = ZT_CONF_MONITORTX;
09021    }
09022    else
09023    {
09024       ci.confno = myrpt->txconf;
09025       ci.confmode = ZT_CONF_CONFANNMON;
09026    }
09027    /* first put the channel on the conference in announce mode */
09028    if (ioctl(myrpt->monchannel->fds[0],ZT_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 = ZT_CONF_CONF | ZT_CONF_TALKER ;
09061    /* first put the channel on the conference in proper mode */
09062    if (ioctl(myrpt->txpchannel->fds[0],ZT_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], ZT_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], ZT_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       usleep(2000000);
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    ZT_CONFINFO ci;  /* conference info */
10572    ZT_PARAMS par;
10573    int ms,elap,nullfd;
10574    time_t t,last_timeout_warning;
10575    struct   zt_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 = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
10952       /* first put the channel on the conference in proper mode */
10953       if (ioctl(l->pchan->fds[0],ZT_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    if ((!strcmp(myrpt->remote, remote_rig_rbi)) &&
10995      (ioperm(myrpt->p.iobase,1,1) == -1))
10996    {
10997       rpt_mutex_unlock(&myrpt->lock);
10998       ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
10999       return -1;
11000    }
11001    myrpt->remoteon = 1;
11002 #ifdef   OLD_ASTERISK
11003    LOCAL_USER_ADD(u);
11004 #endif
11005    rpt_mutex_unlock(&myrpt->lock);
11006    /* find our index, and load the vars initially */
11007    for(i = 0; i < nrpts; i++)
11008    {
11009       if (&rpt_vars[i] == myrpt)
11010       {
11011          load_rpt_vars(i,0);
11012          break;
11013       }
11014    }
11015    rpt_mutex_lock(&myrpt->lock);
11016    tele = strchr(myrpt->rxchanname,'/');
11017    if (!tele)
11018    {
11019       fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
11020       rpt_mutex_unlock(&myrpt->lock);
11021       pthread_exit(NULL);
11022    }
11023    *tele++ = 0;
11024    myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele,NULL);
11025    myrpt->zaprxchannel = NULL;
11026    if (!strcasecmp(myrpt->rxchanname,"Zap"))
11027       myrpt->zaprxchannel = myrpt->rxchannel;
11028    if (myrpt->rxchannel)
11029    {
11030       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
11031       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
11032 #ifdef   AST_CDR_FLAG_POST_DISABLED
11033       ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11034 #endif
11035       myrpt->rxchannel->whentohangup = 0;
11036       myrpt->rxchannel->appl = "Apprpt";
11037       myrpt->rxchannel->data = "(Link Rx)";
11038       if (option_verbose > 2)
11039          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
11040             myrpt->rxchanname,tele,myrpt->rxchannel->name);
11041       rpt_mutex_unlock(&myrpt->lock);
11042       ast_call(myrpt->rxchannel,tele,999);
11043       rpt_mutex_lock(&myrpt->lock);
11044    }
11045    else
11046    {
11047       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
11048       rpt_mutex_unlock(&myrpt->lock);
11049       pthread_exit(NULL);
11050    }
11051    *--tele = '/';
11052    myrpt->zaptxchannel = NULL;
11053    if (myrpt->txchanname)
11054    {
11055       tele = strchr(myrpt->txchanname,'/');
11056       if (!tele)
11057       {
11058          fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
11059          rpt_mutex_unlock(&myrpt->lock);
11060          ast_hangup(myrpt->rxchannel);
11061          pthread_exit(NULL);
11062       }
11063       *tele++ = 0;
11064       myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele,NULL);
11065       if (!strcasecmp(myrpt->txchanname,"Zap"))
11066          myrpt->zaptxchannel = myrpt->txchannel;
11067       if (myrpt->txchannel)
11068       {
11069          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
11070          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
11071 #ifdef   AST_CDR_FLAG_POST_DISABLED
11072          ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11073 #endif
11074          myrpt->txchannel->whentohangup = 0;
11075          myrpt->txchannel->appl = "Apprpt";
11076          myrpt->txchannel->data = "(Link Tx)";
11077          if (option_verbose > 2)
11078             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
11079                myrpt->txchanname,tele,myrpt->txchannel->name);
11080          rpt_mutex_unlock(&myrpt->lock);
11081          ast_call(myrpt->txchannel,tele,999);
11082          rpt_mutex_lock(&myrpt->lock);
11083       }
11084       else
11085       {
11086          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
11087          rpt_mutex_unlock(&myrpt->lock);
11088          ast_hangup(myrpt->rxchannel);
11089          pthread_exit(NULL);
11090       }
11091       *--tele = '/';
11092    }
11093    else
11094    {
11095       myrpt->txchannel = myrpt->rxchannel;
11096    }
11097    /* allocate a pseudo-channel thru asterisk */
11098    myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
11099    if (!myrpt->pchannel)
11100    {
11101       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11102       rpt_mutex_unlock(&myrpt->lock);
11103       if (myrpt->txchannel != myrpt->rxchannel) 
11104          ast_hangup(myrpt->txchannel);
11105       ast_hangup(myrpt->rxchannel);
11106       pthread_exit(NULL);
11107    }
11108    ast_set_read_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
11109    ast_set_write_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
11110 #ifdef   AST_CDR_FLAG_POST_DISABLED
11111    ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11112 #endif
11113    if (!myrpt->zaprxchannel) myrpt->zaprxchannel = myrpt->pchannel;
11114    if (!myrpt->zaptxchannel) myrpt->zaptxchannel = myrpt->pchannel;
11115    /* make a conference for the pseudo */
11116    ci.chan = 0;
11117    ci.confno = -1; /* make a new conf */
11118    ci.confmode = ZT_CONF_CONFANNMON ;
11119    /* first put the channel on the conference in announce/monitor mode */
11120    if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
11121    {
11122       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
11123       rpt_mutex_unlock(&myrpt->lock);
11124       ast_hangup(myrpt->pchannel);
11125       if (myrpt->txchannel != myrpt->rxchannel) 
11126          ast_hangup(myrpt->txchannel);
11127       ast_hangup(myrpt->rxchannel);
11128       pthread_exit(NULL);
11129    }
11130    /* save pseudo channel conference number */
11131    myrpt->conf = myrpt->txconf = ci.confno;
11132    /* if serial io port, open it */
11133    myrpt->iofd = -1;
11134    if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt->p.ioport)) == -1))
11135    {
11136       rpt_mutex_unlock(&myrpt->lock);
11137       ast_hangup(myrpt->pchannel);
11138       if (myrpt->txchannel != myrpt->rxchannel) 
11139          ast_hangup(myrpt->txchannel);
11140       ast_hangup(myrpt->rxchannel);
11141       pthread_exit(NULL);
11142    }
11143    iskenwood_pci4 = 0;
11144    memset(&z,0,sizeof(z));
11145    if ((myrpt->iofd < 1) && (myrpt->txchannel == myrpt->zaptxchannel))
11146    {
11147       z.radpar = ZT_RADPAR_REMMODE;
11148       z.data = ZT_RADPAR_REM_NONE;
11149       res = ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z);
11150       /* if PCIRADIO and kenwood selected */
11151       if ((!res) && (!strcmp(myrpt->remote,remote_rig_kenwood)))
11152       {
11153          z.radpar = ZT_RADPAR_UIOMODE;
11154          z.data = 1;
11155          if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11156          {
11157             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11158             return -1;
11159          }
11160          z.radpar = ZT_RADPAR_UIODATA;
11161          z.data = 3;
11162          if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11163          {
11164             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11165             return -1;
11166          }
11167          i = ZT_OFFHOOK;
11168          if (ioctl(myrpt->zaptxchannel->fds[0],ZT_HOOK,&i) == -1)
11169          {
11170             ast_log(LOG_ERROR,"Cannot set hook\n");
11171             return -1;
11172          }
11173          iskenwood_pci4 = 1;
11174       }
11175    }
11176    if (myrpt->txchannel == myrpt->zaptxchannel)
11177    {
11178       i = ZT_ONHOOK;
11179       ioctl(myrpt->zaptxchannel->fds[0],ZT_HOOK,&i);
11180       /* if PCIRADIO and Yaesu ft897/ICOM IC-706 selected */
11181       if ((myrpt->iofd < 1) && (!res) &&
11182          (!strcmp(myrpt->remote,remote_rig_ft897) ||
11183             (!strcmp(myrpt->remote,remote_rig_ic706))))
11184       {
11185          z.radpar = ZT_RADPAR_UIOMODE;
11186          z.data = 1;
11187          if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11188          {
11189             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11190             return -1;
11191          }
11192          z.radpar = ZT_RADPAR_UIODATA;
11193          z.data = 3;
11194          if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11195          {
11196             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11197             return -1;
11198          }
11199       }
11200    }
11201    myrpt->remoterx = 0;
11202    myrpt->remotetx = 0;
11203    myrpt->retxtimer = 0;
11204    myrpt->rerxtimer = 0;
11205    myrpt->remoteon = 1;
11206    myrpt->dtmfidx = -1;
11207    myrpt->dtmfbuf[0] = 0;
11208    myrpt->dtmf_time_rem = 0;
11209    myrpt->hfscanmode = 0;
11210    myrpt->hfscanstatus = 0;
11211    if (myrpt->p.startupmacro)
11212    {
11213       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
11214    }
11215    time(&myrpt->start_time);
11216    myrpt->last_activity_time = myrpt->start_time;
11217    last_timeout_warning = 0;
11218    myrpt->reload = 0;
11219    myrpt->tele.next = &myrpt->tele;
11220    myrpt->tele.prev = &myrpt->tele;
11221    rpt_mutex_unlock(&myrpt->lock);
11222    ast_set_write_format(chan, AST_FORMAT_SLINEAR);
11223    ast_set_read_format(chan, AST_FORMAT_SLINEAR);
11224    rem_rx = 0;
11225    remkeyed = 0;
11226    /* if we are on 2w loop and are a remote, turn EC on */
11227    if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
11228    {
11229       i = 128;
11230       ioctl(myrpt->zaprxchannel->fds[0],ZT_ECHOCANCEL,&i);
11231    }
11232    if (chan->_state != AST_STATE_UP) {
11233       ast_answer(chan);
11234    }
11235 
11236    if (myrpt->rxchannel == myrpt->zaprxchannel)
11237    {
11238       if (ioctl(myrpt->zaprxchannel->fds[0],ZT_GET_PARAMS,&par) != -1)
11239       {
11240          if (par.rxisoffhook)
11241          {
11242             ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11243             myrpt->remoterx = 1;
11244             remkeyed = 1;
11245          }
11246       }
11247    }
11248    if (myrpt->p.archivedir)
11249    {
11250       char mycmd[100],mydate[100],*b,*b1;
11251       time_t myt;
11252       long blocksleft;
11253 
11254 
11255       mkdir(myrpt->p.archivedir,0600);
11256       sprintf(mycmd,"%s/%s",myrpt->p.archivedir,myrpt->name);
11257       mkdir(mycmd,0600);
11258       time(&myt);
11259       strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
11260          localtime(&myt));
11261       sprintf(mycmd,"mixmonitor start %s %s/%s/%s.wav49 a",chan->name,
11262          myrpt->p.archivedir,myrpt->name,mydate);
11263       if (myrpt->p.monminblocks)
11264       {
11265          blocksleft = diskavail(myrpt);
11266          if (myrpt->p.remotetimeout)
11267          {
11268             blocksleft -= (myrpt->p.remotetimeout *
11269                MONITOR_DISK_BLOCKS_PER_MINUTE) / 60;
11270          }
11271          if (blocksleft >= myrpt->p.monminblocks)
11272             ast_cli_command(nullfd,mycmd);
11273       } else ast_cli_command(nullfd,mycmd);
11274       /* look at callerid to see what node this comes from */
11275       if (!chan->cid.cid_num) /* if doesn't have caller id */
11276       {
11277          b1 = "0";
11278       } else {
11279          ast_callerid_parse(chan->cid.cid_num,&b,&b1);
11280          ast_shrink_phone_number(b1);
11281       }
11282       sprintf(mycmd,"CONNECT,%s",b1);
11283       donodelog(myrpt,mycmd);
11284    }
11285    myrpt->loginuser[0] = 0;
11286    myrpt->loginlevel[0] = 0;
11287    myrpt->authtelltimer = 0;
11288    myrpt->authtimer = 0;
11289    authtold = 0;
11290    authreq = 0;
11291    if (myrpt->p.authlevel > 1) authreq = 1;
11292    setrem(myrpt); 
11293    n = 0;
11294    dtmfed = 0;
11295    cs[n++] = chan;
11296    cs[n++] = myrpt->rxchannel;
11297    cs[n++] = myrpt->pchannel;
11298    if (myrpt->rxchannel != myrpt->txchannel)
11299       cs[n++] = myrpt->txchannel;
11300    /* start un-locked */
11301    for(;;) 
11302    {
11303       if (ast_check_hangup(chan)) break;
11304       if (ast_check_hangup(myrpt->rxchannel)) break;
11305       notremming = 0;
11306       setting = 0;
11307       reming = 0;
11308       telem = myrpt->tele.next;
11309       while(telem != &myrpt->tele)
11310       {
11311          if (telem->mode == SETREMOTE) setting = 1;
11312          if ((telem->mode == SETREMOTE) ||
11313              (telem->mode == SCAN) ||
11314             (telem->mode == TUNE))  reming = 1;
11315          else notremming = 1;
11316          telem = telem->next;
11317       }
11318       if (myrpt->reload)
11319       {
11320          myrpt->reload = 0;
11321          /* find our index, and load the vars */
11322          for(i = 0; i < nrpts; i++)
11323          {
11324             if (&rpt_vars[i] == myrpt)
11325             {
11326                load_rpt_vars(i,0);
11327                break;
11328             }
11329          }
11330       }
11331       time(&t);
11332       if (myrpt->p.remotetimeout)
11333       { 
11334          time_t r;
11335 
11336          r = (t - myrpt->start_time);
11337          if (r >= myrpt->p.remotetimeout)
11338          {
11339             sayfile(chan,"rpt/node");
11340             ast_say_character_str(chan,myrpt->name,NULL,chan->language);
11341             sayfile(chan,"rpt/timeout");
11342             ast_safe_sleep(chan,1000);
11343             break;
11344          }
11345          if ((myrpt->p.remotetimeoutwarning) && 
11346              (r >= (myrpt->p.remotetimeout -
11347             myrpt->p.remotetimeoutwarning)) &&
11348                 (r <= (myrpt->p.remotetimeout - 
11349                   myrpt->p.remotetimeoutwarningfreq)))
11350          {
11351             if (myrpt->p.remotetimeoutwarningfreq)
11352             {
11353                 if ((t - last_timeout_warning) >=
11354                myrpt->p.remotetimeoutwarningfreq)
11355                 {
11356                time(&last_timeout_warning);
11357                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
11358                 }
11359             }
11360             else
11361             {
11362                 if (!last_timeout_warning)
11363                 {
11364                time(&last_timeout_warning);
11365                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
11366                 }
11367             }
11368          }
11369       }
11370       if (myrpt->p.remoteinacttimeout && myrpt->last_activity_time)
11371       { 
11372          time_t r;
11373 
11374          r = (t - myrpt->last_activity_time);
11375          if (r >= myrpt->p.remoteinacttimeout)
11376          {
11377             sayfile(chan,"rpt/node");
11378             ast_say_character_str(chan,myrpt->name,NULL,chan->language);
11379             sayfile(chan,"rpt/timeout");
11380             ast_safe_sleep(chan,1000);
11381             break;
11382          }
11383          if ((myrpt->p.remotetimeoutwarning) && 
11384              (r >= (myrpt->p.remoteinacttimeout -
11385             myrpt->p.remotetimeoutwarning)) &&
11386                 (r <= (myrpt->p.remoteinacttimeout - 
11387                   myrpt->p.remotetimeoutwarningfreq)))
11388          {
11389             if (myrpt->p.remotetimeoutwarningfreq)
11390             {
11391                 if ((t - last_timeout_warning) >=
11392                myrpt->p.remotetimeoutwarningfreq)
11393                 {
11394                time(&last_timeout_warning);
11395                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
11396                 }
11397             }
11398             else
11399             {
11400                 if (!last_timeout_warning)
11401                 {
11402                time(&last_timeout_warning);
11403                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
11404                 }
11405             }
11406          }
11407       }
11408       ms = MSWAIT;
11409       who = ast_waitfor_n(cs,n,&ms);
11410       if (who == NULL) ms = 0;
11411       elap = MSWAIT - ms;
11412       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
11413       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
11414       if (!ms) continue;
11415       /* do local dtmf timer */
11416       if (myrpt->dtmf_local_timer)
11417       {
11418          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
11419          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
11420       }
11421       rpt_mutex_lock(&myrpt->lock);
11422       do_dtmf_local(myrpt,0);
11423       rpt_mutex_unlock(&myrpt->lock);
11424       rem_totx =  myrpt->dtmf_local_timer && (!phone_mode);
11425       rem_totx |= keyed && (!myrpt->tunerequest);
11426       rem_rx = (remkeyed && (!setting)) || (myrpt->tele.next != &myrpt->tele);
11427       if(!strcmp(myrpt->remote, remote_rig_ic706))
11428          rem_totx |= myrpt->tunerequest;
11429       if (keyed && (!keyed1))
11430       {
11431          keyed1 = 1;
11432       }
11433 
11434       if (!keyed && (keyed1))
11435       {
11436          time_t myt;
11437 
11438          keyed1 = 0;
11439          time(&myt);
11440          /* if login necessary, and not too soon */
11441          if ((myrpt->p.authlevel) && 
11442              (!myrpt->loginlevel[0]) &&
11443             (myt > (t + 3)))
11444          {
11445             authreq = 1;
11446             authtold = 0;
11447             myrpt->authtelltimer = AUTHTELLTIME - AUTHTXTIME;
11448          }
11449       }
11450 
11451 
11452       if (rem_rx && (!myrpt->remoterx))
11453       {
11454          myrpt->remoterx = 1;
11455          ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11456       }
11457       if ((!rem_rx) && (myrpt->remoterx))
11458       {
11459          myrpt->remoterx = 0;
11460          ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
11461       }
11462       /* if auth requested, and not authed yet */
11463       if (authreq && (!myrpt->loginlevel[0]))
11464       {
11465          if ((!authtold) && ((myrpt->authtelltimer += elap)
11466              >= AUTHTELLTIME))
11467          {
11468             authtold = 1;
11469             rpt_telemetry(myrpt,LOGINREQ,NULL);
11470          }
11471          if ((myrpt->authtimer += elap) >= AUTHLOGOUTTIME)
11472          {
11473             break; /* if not logged in, hang up after a time */
11474          }
11475       }
11476 #ifndef  OLDKEY
11477       if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
11478       {
11479          myrpt->retxtimer = 0;
11480          if ((myrpt->remoterx) && (!myrpt->remotetx))
11481             ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11482          else
11483             ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
11484       }
11485 
11486       if ((myrpt->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 2))
11487       {
11488          keyed = 0;
11489          myrpt->rerxtimer = 0;
11490       }
11491 #endif
11492       if (rem_totx && (!myrpt->remotetx))
11493       {
11494          /* if not authed, and needed, dont transmit */
11495          if ((!myrpt->p.authlevel) || myrpt->loginlevel[0])
11496          {
11497             myrpt->remotetx = 1;
11498             if((myrpt->remtxfreqok = check_tx_freq(myrpt)))
11499             {
11500                time(&myrpt->last_activity_time);
11501                if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->zaptxchannel))
11502                {
11503                   z.radpar = ZT_RADPAR_UIODATA;
11504                   z.data = 1;
11505                   if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11506                   {
11507                      ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11508                      return -1;
11509                   }
11510                }
11511                else
11512                {
11513                   ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
11514                }
11515                if (myrpt->p.archivedir) donodelog(myrpt,"TXKEY");
11516             }
11517          }
11518       }
11519       if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
11520       {
11521          myrpt->remotetx = 0;
11522          if(!myrpt->remtxfreqok){
11523             rpt_telemetry(myrpt,UNAUTHTX,NULL);
11524          }
11525          if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->zaptxchannel))
11526          {
11527             z.radpar = ZT_RADPAR_UIODATA;
11528             z.data = 3;
11529             if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11530             {
11531                ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11532                return -1;
11533             }
11534          }
11535          else
11536          {
11537             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
11538          }
11539          if (myrpt->p.archivedir) donodelog(myrpt,"TXUNKEY");
11540       }
11541       if (myrpt->hfscanmode){
11542          myrpt->scantimer -= elap;
11543          if(myrpt->scantimer <= 0){
11544             if (!reming)
11545             {
11546                myrpt->scantimer = REM_SCANTIME;
11547                rpt_telemetry(myrpt,SCAN,0);
11548             } else myrpt->scantimer = 1;
11549          }
11550       }
11551       rpt_mutex_lock(&myrpt->lock);
11552       c = myrpt->macrobuf[0];
11553       if (c && (!myrpt->macrotimer))
11554       {
11555          myrpt->macrotimer = MACROTIME;
11556          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
11557          if ((c == 'p') || (c == 'P'))
11558             myrpt->macrotimer = MACROPTIME;
11559          rpt_mutex_unlock(&myrpt->lock);
11560          if (myrpt->p.archivedir)
11561          {
11562             char str[100];
11563                sprintf(str,"DTMF(M),%c",c);
11564             donodelog(myrpt,str);
11565          }
11566          if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
11567          continue;
11568       } else rpt_mutex_unlock(&myrpt->lock);
11569       if (who == chan) /* if it was a read from incomming */
11570       {
11571          f = ast_read(chan);
11572          if (!f)
11573          {
11574             if (debug) printf("@@@@ link:Hung Up\n");
11575             break;
11576          }
11577          if (f->frametype == AST_FRAME_VOICE)
11578          {
11579             if (ioctl(chan->fds[0], ZT_GETCONFMUTE, &ismuted) == -1)
11580             {
11581                ismuted = 0;
11582             }
11583             /* if not transmitting, zero-out audio */
11584             ismuted |= (!myrpt->remotetx);
11585             if (dtmfed && phone_mode) ismuted = 1;
11586             dtmfed = 0;
11587             if (ismuted)
11588             {
11589                memset(f->data,0,f->datalen);
11590                if (myrpt->lastf1)
11591                   memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11592                if (myrpt->lastf2)
11593                   memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11594             } 
11595             if (f) f2 = ast_frdup(f);
11596             else f2 = NULL;
11597             f1 = myrpt->lastf2;
11598             myrpt->lastf2 = myrpt->lastf1;
11599             myrpt->lastf1 = f2;
11600             if (ismuted)
11601             {
11602                if (myrpt->lastf1)
11603                   memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11604                if (myrpt->lastf2)
11605                   memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11606             }
11607             if (f1)
11608             {
11609                if (phone_mode)
11610                   ast_write(myrpt->txchannel,f1);
11611                else
11612                   ast_write(myrpt->txchannel,f);
11613                ast_frfree(f1);
11614             }
11615          }
11616 #ifndef  OLD_ASTERISK
11617          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
11618          {
11619             if (myrpt->lastf1)
11620                memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11621             if (myrpt->lastf2)
11622                memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11623             dtmfed = 1;
11624          }
11625 #endif
11626          if (f->frametype == AST_FRAME_DTMF)
11627          {
11628             if (myrpt->lastf1)
11629                memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11630             if (myrpt->lastf2)
11631                memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11632             dtmfed = 1;
11633             if (handle_remote_phone_dtmf(myrpt,f->subclass,&keyed,phone_mode) == -1)
11634             {
11635                if (debug) printf("@@@@ rpt:Hung Up\n");
11636                ast_frfree(f);
11637                break;
11638             }
11639          }
11640          if (f->frametype == AST_FRAME_TEXT)
11641          {
11642             if (handle_remote_data(myrpt,f->data) == -1)
11643             {
11644                if (debug) printf("@@@@ rpt:Hung Up\n");
11645                ast_frfree(f);
11646                break;
11647             }
11648          }
11649          if (f->frametype == AST_FRAME_CONTROL)
11650          {
11651             if (f->subclass == AST_CONTROL_HANGUP)
11652             {
11653                if (debug) printf("@@@@ rpt:Hung Up\n");
11654                ast_frfree(f);
11655                break;
11656             }
11657             /* if RX key */
11658             if (f->subclass == AST_CONTROL_RADIO_KEY)
11659             {
11660                if (debug == 7) printf("@@@@ rx key\n");
11661                keyed = 1;
11662                myrpt->rerxtimer = 0;
11663             }
11664             /* if RX un-key */
11665             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
11666             {
11667                myrpt->rerxtimer = 0;
11668                if (debug == 7) printf("@@@@ rx un-key\n");
11669                keyed = 0;
11670             }
11671          }
11672          ast_frfree(f);
11673          continue;
11674       }
11675       if (who == myrpt->rxchannel) /* if it was a read from radio */
11676       {
11677          f = ast_read(myrpt->rxchannel);
11678          if (!f)
11679          {
11680             if (debug) printf("@@@@ link:Hung Up\n");
11681             break;
11682          }
11683          if (f->frametype == AST_FRAME_VOICE)
11684          {
11685             int myreming = 0;
11686 
11687             if(!strcmp(myrpt->remote, remote_rig_kenwood))
11688                myreming = reming;
11689 
11690             if (myreming || (!remkeyed) ||
11691             ((myrpt->remote) && (myrpt->remotetx)) ||
11692               ((myrpt->remmode != REM_MODE_FM) &&
11693                 notremming))
11694                memset(f->data,0,f->datalen); 
11695              ast_write(myrpt->pchannel,f);
11696          }
11697          else if (f->frametype == AST_FRAME_CONTROL)
11698          {
11699             if (f->subclass == AST_CONTROL_HANGUP)
11700             {
11701                if (debug) printf("@@@@ rpt:Hung Up\n");
11702                ast_frfree(f);
11703                break;
11704             }
11705             /* if RX key */
11706             if (f->subclass == AST_CONTROL_RADIO_KEY)
11707             {
11708                if (debug == 7) printf("@@@@ remote rx key\n");
11709                if (!myrpt->remotetx)
11710                {
11711                   remkeyed = 1;
11712                }
11713             }
11714             /* if RX un-key */
11715             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
11716             {
11717                if (debug == 7) printf("@@@@ remote rx un-key\n");
11718                if (!myrpt->remotetx) 
11719                {
11720                   remkeyed = 0;
11721                }
11722             }
11723          }
11724          ast_frfree(f);
11725          continue;
11726       }
11727       if (who == myrpt->pchannel) /* if is remote mix output */
11728       {
11729          f = ast_read(myrpt->pchannel);
11730          if (!f)
11731          {
11732             if (debug) printf("@@@@ link:Hung Up\n");
11733             break;
11734          }
11735          if (f->frametype == AST_FRAME_VOICE)
11736          {
11737             ast_write(chan,f);
11738          }
11739          if (f->frametype == AST_FRAME_CONTROL)
11740          {
11741             if (f->subclass == AST_CONTROL_HANGUP)
11742             {
11743                if (debug) printf("@@@@ rpt:Hung Up\n");
11744                ast_frfree(f);
11745                break;
11746             }
11747          }
11748          ast_frfree(f);
11749          continue;
11750       }
11751       if ((myrpt->rxchannel != myrpt->txchannel) && 
11752          (who == myrpt->txchannel)) /* do this cuz you have to */
11753       {
11754          f = ast_read(myrpt->txchannel);
11755          if (!f)
11756          {
11757             if (debug) printf("@@@@ link:Hung Up\n");
11758             break;
11759          }
11760          if (f->frametype == AST_FRAME_CONTROL)
11761          {
11762             if (f->subclass == AST_CONTROL_HANGUP)
11763             {
11764                if (debug) printf("@@@@ rpt:Hung Up\n");
11765                ast_frfree(f);
11766                break;
11767             }
11768          }
11769          ast_frfree(f);
11770          continue;
11771       }
11772    }
11773    if (myrpt->p.archivedir)
11774    {
11775       char mycmd[100],*b,*b1;
11776 
11777       /* look at callerid to see what node this comes from */
11778       if (!chan->cid.cid_num) /* if doesn't have caller id */
11779       {
11780          b1 = "0";
11781       } else {
11782          ast_callerid_parse(chan->cid.cid_num,&b,&b1);
11783          ast_shrink_phone_number(b1);
11784       }
11785       sprintf(mycmd,"DISCONNECT,%s",b1);
11786       donodelog(myrpt,mycmd);
11787    }
11788    /* wait for telem to be done */
11789    while(myrpt->tele.next != &myrpt->tele) usleep(100000);
11790    sprintf(tmp,"mixmonitor stop %s",chan->name);
11791    ast_cli_command(nullfd,tmp);
11792    close(nullfd);
11793    rpt_mutex_lock(&myrpt->lock);
11794    myrpt->hfscanmode = 0;
11795    myrpt->hfscanstatus = 0;
11796    myrpt->remoteon = 0;
11797    rpt_mutex_unlock(&myrpt->lock);
11798    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
11799    myrpt->lastf1 = NULL;
11800    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
11801    myrpt->lastf2 = NULL;
11802    if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->zaptxchannel))
11803    {
11804       z.radpar = ZT_RADPAR_UIOMODE;
11805       z.data = 3;
11806       if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11807       {
11808          ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11809          return -1;
11810       }
11811       z.radpar = ZT_RADPAR_UIODATA;
11812       z.data = 3;
11813       if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11814       {
11815          ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11816          return -1;
11817       }
11818       i = ZT_OFFHOOK;
11819       if (ioctl(myrpt->zaptxchannel->fds[0],ZT_HOOK,&i) == -1)
11820       {
11821          ast_log(LOG_ERROR,"Cannot set hook\n");
11822          return -1;
11823       }
11824    }
11825    if (myrpt->iofd) close(myrpt->iofd);
11826    myrpt->iofd = -1;
11827    ast_hangup(myrpt->pchannel);
11828    if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
11829    ast_hangup(myrpt->rxchannel);
11830    closerem(myrpt);
11831 #ifdef   OLD_ASTERISK
11832    LOCAL_USER_REMOVE(u);
11833 #endif
11834    return res;
11835 }
11836 
11837 #ifdef   OLD_ASTERISK
11838 int unload_module()
11839 #else
11840 static int unload_module(void)
11841 #endif
11842 {
11843    int i;
11844 
11845 #ifdef   OLD_ASTERISK
11846    STANDARD_HANGUP_LOCALUSERS;
11847 #endif
11848    for(i = 0; i < nrpts; i++) {
11849       if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
11850                 ast_mutex_destroy(&rpt_vars[i].lock);
11851                 ast_mutex_destroy(&rpt_vars[i].remlock);
11852    }
11853    i = ast_unregister_application(app);
11854 
11855    /* Unregister cli extensions */
11856    ast_cli_unregister(&cli_debug);
11857    ast_cli_unregister(&cli_dump);
11858    ast_cli_unregister(&cli_stats);
11859    ast_cli_unregister(&cli_lstats);
11860    ast_cli_unregister(&cli_nodes);
11861    ast_cli_unregister(&cli_reload);
11862    ast_cli_unregister(&cli_restart);
11863    ast_cli_unregister(&cli_fun);
11864 
11865    return i;
11866 }
11867 
11868 #ifdef   OLD_ASTERISK
11869 int load_module()
11870 #else
11871 static int load_module(void)
11872 #endif
11873 {
11874    ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
11875 
11876    /* Register cli extensions */
11877    ast_cli_register(&cli_debug);
11878    ast_cli_register(&cli_dump);
11879    ast_cli_register(&cli_stats);
11880    ast_cli_register(&cli_lstats);
11881    ast_cli_register(&cli_nodes);
11882    ast_cli_register(&cli_reload);
11883    ast_cli_register(&cli_restart);
11884    ast_cli_register(&cli_fun);
11885 
11886    return ast_register_application(app, rpt_exec, synopsis, descrip);
11887 }
11888 
11889 #ifdef   OLD_ASTERISK
11890 char *description()
11891 {
11892    return tdesc;
11893 }
11894 int usecount(void)
11895 {
11896    int res;
11897    STANDARD_USECOUNT(res);
11898    return res;
11899 }
11900 
11901 char *key()
11902 {
11903    return ASTERISK_GPL_KEY;
11904 }
11905 #endif
11906 
11907 #ifdef   OLD_ASTERISK
11908 int reload()
11909 #else
11910 static int reload(void)
11911 #endif
11912 {
11913 int   n;
11914 
11915    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
11916    return(0);
11917 }
11918 
11919 #ifndef  OLD_ASTERISK
11920 /* STD_MOD(MOD_1, reload, NULL, NULL); */
11921 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application",
11922       .load = load_module,
11923       .unload = unload_module,
11924       .reload = reload,
11925           );
11926 
11927 #endif
11928 

Generated on Tue Nov 4 13:20:13 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7