Mon Mar 12 2012 21:18:46

Asterisk developer's documentation


app_rpt.c
Go to the documentation of this file.
00001 #define  NEW_ASTERISK
00002 /* #define OLD_ASTERISK */
00003 /*
00004  * Asterisk -- An open source telephony toolkit.
00005  *
00006  * Copyright (C) 2002-2008, 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.115 5/12/08 2055 EDT
00025  * 
00026  * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
00027  *
00028  * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
00029  * \note Steven Henke, W9SH, <w9sh@arrl.net> added a few features here and there.
00030  *
00031  * See http://www.zapatatelephony.org/app_rpt.html
00032  *
00033  *
00034  * Repeater / Remote Functions:
00035  * "Simple" Mode:  * - autopatch access, # - autopatch hangup
00036  * Normal mode:
00037  * See the function list in rpt.conf (autopatchup, autopatchdn)
00038  * autopatchup can optionally take comma delimited setting=value pairs:
00039  *  
00040  *
00041  * context=string    :  Override default context with "string"
00042  * dialtime=ms       :  Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
00043  * farenddisconnect=1      :  Automatically disconnect when called party hangs up
00044  * noct=1         :  Don't send repeater courtesy tone during autopatch calls
00045  * quiet=1        :  Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
00046  *
00047  *
00048  * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
00049  *
00050  *  To send an asterisk (*) while dialing or talking on phone,
00051  *  use the autopatch acess code.
00052  *
00053  *
00054  * status cmds:
00055  *
00056  *  1 - Force ID (global)
00057  *  2 - Give Time of Day (global)
00058  *  3 - Give software Version (global)
00059  *  11 - Force ID (local only)
00060  *  12 - Give Time of Day (local only)
00061  *
00062  * cop (control operator) cmds:
00063  *
00064  *  1 - System warm boot
00065  *  2 - System enable
00066  *  3 - System disable
00067  *  4 - Test Tone On/Off
00068  *  5 - Dump System Variables on Console (debug)
00069  *  6 - PTT (phone mode only)
00070  *  7 - Time out timer enable
00071  *  8 - Time out timer disable
00072  *  9 - Autopatch enable
00073  *  10 - Autopatch disable
00074  *  11 - Link enable
00075  *  12 - Link disable
00076  *  13 - Query System State
00077  *  14 - Change System State
00078  *  15 - Scheduler Enable
00079  *  16 - Scheduler Disable
00080  *  17 - User functions (time, id, etc) enable
00081  *  18 - User functions (time, id, etc) disable
00082  *  19 - Select alternate hang timer
00083  *  20 - Select standard hang timer 
00084  *  21 - Enable Parrot Mode
00085  *  22 - Disable Parrot Mode
00086  *  23 - Birdbath (Current Parrot Cleanup/Flush)
00087  *  24 - Flush all telemetry
00088  *  25 - Query last node un-keyed
00089  *  26 - Query all nodes keyed/unkeyed
00090  *  30 - Recall Memory Setting in Attached Xcvr
00091  *  31 - Channel Selector for Parallel Programmed Xcvr
00092  *  32 - Touchtone pad test: command + Digit string + # to playback all digits pressed
00093  *
00094  * ilink cmds:
00095  *
00096  *  1 - Disconnect specified link
00097  *  2 - Connect specified link -- monitor only
00098  *  3 - Connect specified link -- tranceive
00099  *  4 - Enter command mode on specified link
00100  *  5 - System status
00101  *  6 - Disconnect all links
00102  *  11 - Disconnect a previously permanently connected link
00103  *  12 - Permanently connect specified link -- monitor only
00104  *  13 - Permanently connect specified link -- tranceive
00105  *  15 - Full system status (all nodes)
00106  *  16 - Reconnect links disconnected with "disconnect all links"
00107  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
00108  *
00109  * remote cmds:
00110  *
00111  *  1 - Recall Memory MM  (*000-*099) (Gets memory from rpt.conf)
00112  *  2 - Set VFO MMMMM*KKK*O   (Mhz digits, Khz digits, Offset)
00113  *  3 - Set Rx PL Tone HHH*D*
00114  *  4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
00115  *  5 - Link Status (long)
00116  *  6 - Set operating mode M (FM, USB, LSB, AM, etc)
00117  *  100 - RX PL off (Default)
00118  *  101 - RX PL On
00119  *  102 - TX PL Off (Default)
00120  *  103 - TX PL On
00121  *  104 - Low Power
00122  *  105 - Med Power
00123  *  106 - Hi Power
00124  *  107 - Bump Down 20 Hz
00125  *  108 - Bump Down 100 Hz
00126  *  109 - Bump Down 500 Hz
00127  *  110 - Bump Up 20 Hz
00128  *  111 - Bump Up 100 Hz
00129  *  112 - Bump Up 500 Hz
00130  *  113 - Scan Down Slow
00131  *  114 - Scan Down Medium
00132  *  115 - Scan Down Fast
00133  *  116 - Scan Up Slow
00134  *  117 - Scan Up Medium
00135  *  118 - Scan Up Fast
00136  *  119 - Transmit allowing auto-tune
00137  *  140 - Link Status (brief)
00138  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
00139  *
00140  * playback cmds:
00141  *  specify the name of the file to be played (for example, 25=rpt/foo)
00142  *
00143  *
00144  * 'duplex' modes:  (defaults to duplex=2)
00145  *
00146  * 0 - Only remote links key Tx and no main repeat audio.
00147  * 1 - Everything other then main Rx keys Tx, no main repeat audio.
00148  * 2 - Normal mode
00149  * 3 - Normal except no main repeat audio.
00150  * 4 - Normal except no main repeat audio during autopatch only
00151  *
00152 */
00153 
00154 /*** MODULEINFO
00155    <depend>dahdi</depend>
00156    <depend>tonezone</depend>
00157    <support_level>extended</support_level>
00158  ***/
00159 
00160 /* Un-comment the following to include support for MDC-1200 digital tone
00161    signalling protocol (using KA6SQG's GPL'ed implementation) */
00162 /* #include "mdc_decode.c" */
00163 
00164 /* Un-comment the following to include support for notch filters in the
00165    rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
00166 /* #include "rpt_notch.c" */
00167 
00168 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
00169 
00170 #ifdef OLD_ASTERISK
00171 #define ast_free free
00172 #define ast_malloc malloc
00173 #define ast_strdup strdup
00174 #endif
00175 
00176 
00177 #define  MAXDTMF 32
00178 #define  MAXMACRO 2048
00179 #define  MAXLINKLIST 512
00180 #define  LINKLISTTIME 10000
00181 #define  LINKLISTSHORTTIME 200
00182 #define  LINKPOSTTIME 30000
00183 #define  LINKPOSTSHORTTIME 200
00184 #define  KEYPOSTTIME 30000
00185 #define  KEYPOSTSHORTTIME 200
00186 #define  MACROTIME 100
00187 #define  MACROPTIME 500
00188 #define  DTMF_TIMEOUT 3
00189 #define  KENWOOD_RETRIES 5
00190 #define  TOPKEYN 32
00191 #define  TOPKEYWAIT 3
00192 #define  TOPKEYMAXSTR 30
00193 
00194 #define  AUTHTELLTIME 7000
00195 #define  AUTHTXTIME 1000
00196 #define  AUTHLOGOUTTIME 25000
00197 
00198 #ifdef   __RPT_NOTCH
00199 #define  MAXFILTERS 10
00200 #endif
00201 
00202 #define  DISC_TIME 10000  /* report disc after 10 seconds of no connect */
00203 #define  MAX_RETRIES 5
00204 #define  MAX_RETRIES_PERM 1000000000
00205 
00206 #define  REDUNDANT_TX_TIME 2000
00207 
00208 #define  RETRY_TIMER_MS 5000
00209 
00210 #define  PATCH_DIALPLAN_TIMEOUT 1500
00211 
00212 #ifdef OLD_ASTERISK
00213 #define  START_DELAY 10
00214 #else
00215 #define  START_DELAY 2
00216 #endif
00217 
00218 #define  RPT_LOCKOUT_SECS 10
00219 
00220 #define MAXPEERSTR 31
00221 #define  MAXREMSTR 15
00222 
00223 #define  DELIMCHR ','
00224 #define  QUOTECHR 34
00225 
00226 #define  MONITOR_DISK_BLOCKS_PER_MINUTE 38
00227 
00228 #define  DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000
00229 #define  DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60)
00230 #define  DEFAULT_REMOTE_TIMEOUT (60 * 60)
00231 #define  DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60)
00232 #define  DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30
00233 
00234 #define  NODES "nodes"
00235 #define  EXTNODES "extnodes"
00236 #define MEMORY "memory"
00237 #define MACRO "macro"
00238 #define  FUNCTIONS "functions"
00239 #define TELEMETRY "telemetry"
00240 #define MORSE "morse"
00241 #define  TONEMACRO "tonemacro"
00242 #define  FUNCCHAR '*'
00243 #define  ENDCHAR '#'
00244 #define  EXTNODEFILE "/var/lib/asterisk/rpt_extnodes"
00245 #define  NODENAMES "rpt/nodenames"
00246 #define  PARROTFILE "/tmp/parrot_%s_%u"
00247 
00248 #define  PARROTTIME 1000
00249 
00250 #define  DEFAULT_IOBASE 0x378
00251 
00252 #define  DEFAULT_CIV_ADDR 0x58
00253 
00254 #define  MAXCONNECTTIME 5000
00255 
00256 #define MAXNODESTR 300
00257 
00258 #define MAXNODELEN 16
00259 
00260 #define MAXIDENTLEN 32
00261 
00262 #define MAXPATCHCONTEXT 100
00263 
00264 #define ACTIONSIZE 32
00265 
00266 #define TELEPARAMSIZE 256
00267 
00268 #define REM_SCANTIME 100
00269 
00270 #define  DTMF_LOCAL_TIME 250
00271 #define  DTMF_LOCAL_STARTTIME 500
00272 
00273 #define  IC706_PL_MEMORY_OFFSET 50
00274 
00275 #define  VOX_ON_DEBOUNCE_COUNT 3
00276 #define  VOX_OFF_DEBOUNCE_COUNT 20
00277 #define  VOX_MAX_THRESHOLD 10000.0
00278 #define  VOX_MIN_THRESHOLD 3000.0
00279 #define  VOX_TIMEOUT_MS 5000
00280 #define  VOX_RECOVER_MS 500
00281 #define  SIMPLEX_PATCH_DELAY 25
00282 #define  SIMPLEX_PHONE_DELAY 25
00283 
00284 #define  STATPOST_PROGRAM "/usr/bin/wget,-q,--output-document=/dev/null,--no-check-certificate"
00285 
00286 #define  ALLOW_LOCAL_CHANNELS
00287 
00288 enum {REM_OFF,REM_MONITOR,REM_TX};
00289 
00290 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
00291    CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME, PLAYBACK,
00292    STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
00293    TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS,
00294    MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS,
00295    REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE, TOPKEY,
00296    TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX, PARROT,
00297    STATS_TIME_LOCAL};
00298 
00299 
00300 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
00301 
00302 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
00303 
00304 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY};
00305 
00306 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE, SOURCE_ALT};
00307 
00308 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY, DLY_PARROT};
00309 
00310 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
00311 
00312 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
00313       HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
00314 
00315 #include "asterisk.h"
00316 
00317 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00318 
00319 #include <signal.h>
00320 #include <stdio.h>
00321 #include <stdint.h>
00322 #include <unistd.h>
00323 #include <string.h>
00324 #include <stdlib.h>
00325 #include <search.h>
00326 #include <sys/types.h>
00327 #include <sys/stat.h>
00328 #include <errno.h>
00329 #include <dirent.h>
00330 #include <ctype.h>
00331 #include <sys/stat.h>
00332 #include <sys/time.h>
00333 #include <sys/file.h>
00334 #include <sys/ioctl.h>
00335 #ifdef HAVE_SYS_IO_H
00336 #include <sys/io.h>
00337 #endif
00338 #include <sys/vfs.h>
00339 #include <math.h>
00340 #include <dahdi/user.h>
00341 #include <dahdi/tonezone.h>
00342 #include <netinet/in.h>
00343 #include <arpa/inet.h>
00344 
00345 #include "asterisk/utils.h"
00346 #include "asterisk/lock.h"
00347 #include "asterisk/file.h"
00348 #include "asterisk/logger.h"
00349 #include "asterisk/channel.h"
00350 #include "asterisk/callerid.h"
00351 #include "asterisk/pbx.h"
00352 #include "asterisk/module.h"
00353 #include "asterisk/translate.h"
00354 #include "asterisk/features.h"
00355 #include "asterisk/options.h"
00356 #include "asterisk/cli.h"
00357 #include "asterisk/config.h"
00358 #include "asterisk/say.h"
00359 #include "asterisk/localtime.h"
00360 #include "asterisk/cdr.h"
00361 #include "asterisk/options.h"
00362 #include "asterisk/manager.h"
00363 #include "asterisk/app.h"
00364 
00365 #include <termios.h>
00366 
00367 #ifdef   NEW_ASTERISK
00368 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
00369 #endif
00370 
00371 
00372 /* Start a tone-list going */
00373 int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
00374 /*! Stop the tones from playing */
00375 void ast_playtones_stop(struct ast_channel *chan);
00376 
00377 static  char *tdesc = "Radio Repeater / Remote Base  version 0.115  5/12/2008";
00378 
00379 static char *app = "Rpt";
00380 
00381 static char *synopsis = "Radio Repeater/Remote Base Control System";
00382 
00383 static char *descrip = 
00384 "  Rpt(nodename[|options][|M][|*]):  \n"
00385 "    Radio Remote Link or Remote Base Link Endpoint Process.\n"
00386 "\n"
00387 "    Not specifying an option puts it in normal endpoint mode (where source\n"
00388 "    IP and nodename are verified).\n"
00389 "\n"
00390 "    Options are as follows:\n"
00391 "\n"
00392 "        X - Normal endpoint mode WITHOUT security check. Only specify\n"
00393 "            this if you have checked security already (like with an IAX2\n"
00394 "            user/password or something).\n"
00395 "\n"
00396 "        Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
00397 "            Reverse Autopatch. Caller is put on hold, and announcement (as\n"
00398 "            specified by the 'announce-string') is played on radio system.\n"
00399 "            Users of radio system can access autopatch, dial specified\n"
00400 "            code, and pick up call. Announce-string is list of names of\n"
00401 "            recordings, or \"PARKED\" to substitute code for un-parking,\n"
00402 "            or \"NODE\" to substitute node number.\n"
00403 "\n"
00404 "        P - Phone Control mode. This allows a regular phone user to have\n"
00405 "            full control and audio access to the radio system. For the\n"
00406 "            user to have DTMF control, the 'phone_functions' parameter\n"
00407 "            must be specified for the node in 'rpt.conf'. An additional\n"
00408 "            function (cop,6) must be listed so that PTT control is available.\n"
00409 "\n"
00410 "        D - Dumb Phone Control mode. This allows a regular phone user to\n"
00411 "            have full control and audio access to the radio system. In this\n"
00412 "            mode, the PTT is activated for the entire length of the call.\n"
00413 "            For the user to have DTMF control (not generally recomended in\n"
00414 "            this mode), the 'dphone_functions' parameter must be specified\n"
00415 "            for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
00416 "            available to the phone user.\n"
00417 "\n"
00418 "        S - Simplex Dumb Phone Control mode. This allows a regular phone user\n"
00419 "            audio-only access to the radio system. In this mode, the\n"
00420 "            transmitter is toggled on and off when the phone user presses the\n"
00421 "            funcchar (*) key on the telephone set. In addition, the transmitter\n"
00422 "            will turn off if the endchar (#) key is pressed. When a user first\n"
00423 "            calls in, the transmitter will be off, and the user can listen for\n"
00424 "            radio traffic. When the user wants to transmit, they press the *\n" 
00425 "            key, start talking, then press the * key again or the # key to turn\n"
00426 "            the transmitter off.  No other functions can be executed by the\n"
00427 "            user on the phone when this mode is selected. Note: If your\n"
00428 "            radio system is full-duplex, we recommend using either P or D\n"
00429 "            modes as they provide more flexibility.\n"
00430 "\n"
00431 "        q - Query Status. Sets channel variables and returns + 101 in plan.\n"
00432 "\n"
00433 "        M - Memory Channel Steer as MXX where XX is the memory channel number.\n"
00434 "\n"
00435 "        * - Alt Macro to execute (e.g. *7 for status)\n"
00436 "\n";
00437 ;
00438 
00439 static int debug = 0;  /* Set this >0 for extra debug output */
00440 static int nrpts = 0;
00441 
00442 static const char remdtmfstr[] = "0123456789*#ABCD";
00443 
00444 enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
00445 
00446 int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
00447 
00448 #define NRPTSTAT 7
00449 
00450 struct rpt_chan_stat
00451 {
00452    struct timeval last;
00453    long long total;
00454    unsigned long count;
00455    unsigned long largest;
00456    struct timeval largest_time;
00457 };
00458 
00459 char *discstr = "!!DISCONNECT!!";
00460 char *newkeystr = "!NEWKEY!";
00461 static char *remote_rig_ft897="ft897";
00462 static char *remote_rig_rbi="rbi";
00463 static char *remote_rig_kenwood="kenwood";
00464 static char *remote_rig_tm271="tm271";
00465 static char *remote_rig_ic706="ic706";
00466 static char *remote_rig_rtx150="rtx150";
00467 static char *remote_rig_rtx450="rtx450";
00468 static char *remote_rig_ppp16="ppp16";       // parallel port programmable 16 channels
00469 
00470 #define ISRIG_RTX(x) ((!strcmp(x,remote_rig_rtx150)) || (!strcmp(x,remote_rig_rtx450)))
00471 #define  IS_XPMR(x) (!strncasecmp(x->rxchanname,"rad",3))
00472 
00473 #ifdef   OLD_ASTERISK
00474 STANDARD_LOCAL_USER;
00475 LOCAL_USER_DECL;
00476 #endif
00477 
00478 #define  MSWAIT 200
00479 #define  HANGTIME 5000
00480 #define  TOTIME 180000
00481 #define  IDTIME 300000
00482 #define  MAXRPTS 20
00483 #define MAX_STAT_LINKS 32
00484 #define POLITEID 30000
00485 #define FUNCTDELAY 1500
00486 
00487 #define  MAXXLAT 20
00488 #define  MAXXLATTIME 3
00489 
00490 #define MAX_SYSSTATES 10
00491 
00492 struct vox {
00493    float speech_energy;
00494    float noise_energy;
00495    int   enacount;
00496    char  voxena;
00497    char  lastvox;
00498    int   offdebcnt;
00499    int   ondebcnt;
00500 } ;
00501 
00502 #define  mymax(x,y) ((x > y) ? x : y)
00503 #define  mymin(x,y) ((x < y) ? x : y)
00504 
00505 struct rpt_topkey
00506 {
00507 char  node[TOPKEYMAXSTR];
00508 int   timesince;
00509 int   keyed;
00510 } ;
00511 
00512 struct rpt_xlat
00513 {
00514 char  funccharseq[MAXXLAT];
00515 char  endcharseq[MAXXLAT];
00516 char  passchars[MAXXLAT];
00517 int   funcindex;
00518 int   endindex;
00519 time_t   lastone;
00520 } ;
00521 
00522 static time_t  starttime = 0;
00523 
00524 static  pthread_t rpt_master_thread;
00525 
00526 struct rpt;
00527 
00528 struct rpt_link
00529 {
00530    struct rpt_link *next;
00531    struct rpt_link *prev;
00532    char  mode;       /* 1 if in tx mode */
00533    char  isremote;
00534    char  phonemode;
00535    char  phonevox;      /* vox the phone */
00536    char  name[MAXNODESTR]; /* identifier (routing) string */
00537    char  lasttx;
00538    char  lasttx1;
00539    char  lastrx;
00540    char  lastrealrx;
00541    char  lastrx1;
00542    char  connected;
00543    char  hasconnected;
00544    char  perma;
00545    char  thisconnected;
00546    char  outbound;
00547    char  disced;
00548    char  killme;
00549    long  elaptime;
00550    long  disctime;
00551    long  retrytimer;
00552    long  retxtimer;
00553    long  rerxtimer;
00554    int   retries;
00555    int   max_retries;
00556    int   reconnects;
00557    long long connecttime;
00558    struct ast_channel *chan;  
00559    struct ast_channel *pchan; 
00560    char  linklist[MAXLINKLIST];
00561    time_t   linklistreceived;
00562    long  linklisttimer;
00563    int   dtmfed;
00564    int linkunkeytocttimer;
00565    struct timeval lastlinktv;
00566    struct   ast_frame *lastf1,*lastf2;
00567    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00568    struct vox vox;
00569    char wasvox;
00570    int voxtotimer;
00571    char voxtostate;
00572    char newkey;
00573 #ifdef OLD_ASTERISK
00574         AST_LIST_HEAD(, ast_frame) rxq;
00575 #else
00576    AST_LIST_HEAD_NOLOCK(, ast_frame) rxq;
00577 #endif
00578 } ;
00579 
00580 struct rpt_lstat
00581 {
00582    struct   rpt_lstat *next;
00583    struct   rpt_lstat *prev;
00584    char  peer[MAXPEERSTR];
00585    char  name[MAXNODESTR];
00586    char  mode;
00587    char  outbound;
00588    char  reconnects;
00589    char  thisconnected;
00590    long long   connecttime;
00591    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00592 } ;
00593 
00594 struct rpt_tele
00595 {
00596    struct rpt_tele *next;
00597    struct rpt_tele *prev;
00598    struct rpt *rpt;
00599    struct ast_channel *chan;
00600    int   mode;
00601    struct rpt_link mylink;
00602    char param[TELEPARAMSIZE];
00603    intptr_t submode;
00604    uintptr_t  parrot;
00605    pthread_t threadid;
00606 } ;
00607 
00608 struct function_table_tag
00609 {
00610    char action[ACTIONSIZE];
00611    int (*function)(struct rpt *myrpt, char *param, char *digitbuf, 
00612       int command_source, struct rpt_link *mylink);
00613 } ;
00614 
00615 /* Used to store the morse code patterns */
00616 
00617 struct morse_bits
00618 {       
00619    int len;
00620    int ddcomb;
00621 } ;
00622 
00623 struct telem_defaults
00624 {
00625    char name[20];
00626    char value[80];
00627 } ;
00628 
00629 
00630 struct sysstate
00631 {
00632    char txdisable;
00633    char totdisable;
00634    char linkfundisable;
00635    char autopatchdisable;
00636    char schedulerdisable;
00637    char userfundisable;
00638    char alternatetail;
00639 };
00640 
00641 /* rpt cmd support */
00642 #define CMD_DEPTH 1
00643 #define CMD_STATE_IDLE 0
00644 #define CMD_STATE_BUSY 1
00645 #define CMD_STATE_READY 2
00646 #define CMD_STATE_EXECUTING 3
00647 
00648 struct rpt_cmd_struct
00649 {
00650     int state;
00651     int functionNumber;
00652     char param[MAXDTMF];
00653     char digits[MAXDTMF];
00654     int command_source;
00655 };
00656 
00657 static struct rpt
00658 {
00659    ast_mutex_t lock;
00660    ast_mutex_t remlock;
00661    ast_mutex_t statpost_lock;
00662    struct ast_config *cfg;
00663    char reload;
00664    char xlink;                         // cross link state of a share repeater/remote radio
00665    unsigned int statpost_seqno;
00666 
00667    char *name;
00668    char *rxchanname;
00669    char *txchanname;
00670    char remote;
00671    char *remoterig;
00672    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00673    unsigned int scram;
00674 
00675    struct {
00676       char *ourcontext;
00677       char *ourcallerid;
00678       char *acctcode;
00679       char *ident;
00680       char *tonezone;
00681       char simple;
00682       char *functions;
00683       char *link_functions;
00684       char *phone_functions;
00685       char *dphone_functions;
00686       char *alt_functions;
00687       char *nodes;
00688       char *extnodes;
00689       char *extnodefile;
00690       int hangtime;
00691       int althangtime;
00692       int totime;
00693       int idtime;
00694       int tailmessagetime;
00695       int tailsquashedtime;
00696       int duplex;
00697       int politeid;
00698       char *tailmessages[500];
00699       int tailmessagemax;
00700       char  *memory;
00701       char  *macro;
00702       char  *tonemacro;
00703       char  *startupmacro;
00704       int iobase;
00705       char *ioport;
00706       char funcchar;
00707       char endchar;
00708       char nobusyout;
00709       char notelemtx;
00710       char propagate_dtmf;
00711       char propagate_phonedtmf;
00712       char linktolink;
00713       unsigned char civaddr;
00714       struct rpt_xlat inxlat;
00715       struct rpt_xlat outxlat;
00716       char *archivedir;
00717       int authlevel;
00718       char *csstanzaname;
00719       char *skedstanzaname;
00720       char *txlimitsstanzaname;
00721       long monminblocks;
00722       int remoteinacttimeout;
00723       int remotetimeout;
00724       int remotetimeoutwarning;
00725       int remotetimeoutwarningfreq;
00726       int sysstate_cur;
00727       struct sysstate s[MAX_SYSSTATES];
00728       char parrotmode;
00729       int parrottime;
00730       char *rptnode;
00731       char remote_mars;
00732       int voxtimeout_ms;
00733       int voxrecover_ms;
00734       int simplexpatchdelay;
00735       int simplexphonedelay;
00736       char *statpost_program;
00737       char *statpost_url;
00738    } p;
00739    struct rpt_link links;
00740    int unkeytocttimer;
00741    time_t lastkeyedtime;
00742    time_t lasttxkeyedtime;
00743    char keyed;
00744    char txkeyed;
00745    char exttx;
00746    char localtx;
00747    char remoterx;
00748    char remotetx;
00749    char remoteon;
00750    char remtxfreqok;
00751    char tounkeyed;
00752    char tonotify;
00753    char dtmfbuf[MAXDTMF];
00754    char macrobuf[MAXMACRO];
00755    char rem_dtmfbuf[MAXDTMF];
00756    char lastdtmfcommand[MAXDTMF];
00757    char cmdnode[50];
00758    char nowchan;                 // channel now
00759    char waschan;                 // channel selected initially or by command
00760    char bargechan;                  // barge in channel
00761    char macropatch;              // autopatch via tonemacro state
00762    char parrotstate;
00763    int  parrottimer;
00764    unsigned int parrotcnt;
00765    struct ast_channel *rxchannel,*txchannel, *monchannel, *parrotchannel;
00766    struct ast_channel *pchannel,*txpchannel, *dahdirxchannel, *dahditxchannel;
00767    struct ast_channel *voxchannel;
00768    struct ast_frame *lastf1,*lastf2;
00769    struct rpt_tele tele;
00770    struct timeval lasttv,curtv;
00771    pthread_t rpt_call_thread,rpt_thread;
00772    time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
00773    int calldigittimer;
00774    int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
00775    int mustid,tailid;
00776    int tailevent;
00777    int telemrefcount;
00778    int dtmfidx,rem_dtmfidx;
00779    int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
00780    int totalexecdcommands, dailyexecdcommands;
00781    long  retxtimer;
00782    long  rerxtimer;
00783    long long totaltxtime;
00784    char mydtmf;
00785    char exten[AST_MAX_EXTENSION];
00786    char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
00787    char offset;
00788    char powerlevel;
00789    char txplon;
00790    char rxplon;
00791    char remmode;
00792    char tunerequest;
00793    char hfscanmode;
00794    int hfscanstatus;
00795    char hfscanstop;
00796    char lastlinknode[MAXNODESTR];
00797    char savednodes[MAXNODESTR];
00798    int stopgen;
00799    char patchfarenddisconnect;
00800    char patchnoct;
00801    char patchquiet;
00802    char patchcontext[MAXPATCHCONTEXT];
00803    int patchdialtime;
00804    int macro_longest;
00805    int phone_longestfunc;
00806    int alt_longestfunc;
00807    int dphone_longestfunc;
00808    int link_longestfunc;
00809    int longestfunc;
00810    int longestnode;
00811    int threadrestarts;     
00812    int tailmessagen;
00813    time_t disgorgetime;
00814    time_t lastthreadrestarttime;
00815    long  macrotimer;
00816    char  lastnodewhichkeyedusup[MAXNODESTR];
00817    int   dtmf_local_timer;
00818    char  dtmf_local_str[100];
00819    struct ast_filestream *monstream,*parrotstream;
00820    char  loginuser[50];
00821    char  loginlevel[10];
00822    long  authtelltimer;
00823    long  authtimer;
00824    int iofd;
00825    time_t start_time,last_activity_time;
00826    char  lasttone[32];
00827    struct rpt_tele *active_telem;
00828    struct   rpt_topkey topkey[TOPKEYN];
00829    int topkeystate;
00830    time_t topkeytime;
00831    int topkeylong;
00832    struct vox vox;
00833    char wasvox;
00834    int voxtotimer;
00835    char voxtostate;
00836    int linkposttimer;         
00837    int keyposttimer;       
00838    char newkey;
00839    char inpadtest;
00840 #ifdef OLD_ASTERISK
00841    AST_LIST_HEAD(, ast_frame) txq;
00842 #else
00843    AST_LIST_HEAD_NOLOCK(, ast_frame) txq;
00844 #endif
00845    char txrealkeyed;
00846 #ifdef   __RPT_NOTCH
00847    struct rptfilter
00848    {
00849       char  desc[100];
00850       float x0;
00851       float x1;
00852       float x2;
00853       float y0;
00854       float y1;
00855       float y2;
00856       float gain;
00857       float const0;
00858       float const1;
00859       float const2;
00860    } filters[MAXFILTERS];
00861 #endif
00862 #ifdef   _MDC_DECODE_H_
00863    mdc_decoder_t *mdc;
00864    unsigned short lastunit;
00865 #endif
00866    struct rpt_cmd_struct cmdAction;
00867 } rpt_vars[MAXRPTS]; 
00868 
00869 struct nodelog {
00870 struct nodelog *next;
00871 struct nodelog *prev;
00872 time_t   timestamp;
00873 char archivedir[MAXNODESTR];
00874 char str[MAXNODESTR * 2];
00875 } nodelog;
00876 
00877 static int service_scan(struct rpt *myrpt);
00878 static int set_mode_ft897(struct rpt *myrpt, char newmode);
00879 static int set_mode_ic706(struct rpt *myrpt, char newmode);
00880 static int simple_command_ft897(struct rpt *myrpt, char command);
00881 static int setrem(struct rpt *myrpt);
00882 static int setrtx_check(struct rpt *myrpt);
00883 static int channel_revert(struct rpt *myrpt);
00884 static int channel_steer(struct rpt *myrpt, char *data);
00885 
00886 AST_MUTEX_DEFINE_STATIC(nodeloglock);
00887 
00888 AST_MUTEX_DEFINE_STATIC(nodelookuplock);
00889 
00890 #ifdef   APP_RPT_LOCK_DEBUG
00891 
00892 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
00893 
00894 #define  MAXLOCKTHREAD 100
00895 
00896 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
00897 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
00898 
00899 struct lockthread
00900 {
00901    pthread_t id;
00902    int lockcount;
00903    int lastlock;
00904    int lastunlock;
00905 } lockthreads[MAXLOCKTHREAD];
00906 
00907 
00908 struct by_lightning
00909 {
00910    int line;
00911    struct timeval tv;
00912    struct rpt *rpt;
00913    struct lockthread lockthread;
00914 } lock_ring[32];
00915 
00916 int lock_ring_index = 0;
00917 
00918 AST_MUTEX_DEFINE_STATIC(locklock);
00919 
00920 static struct lockthread *get_lockthread(pthread_t id)
00921 {
00922 int   i;
00923 
00924    for(i = 0; i < MAXLOCKTHREAD; i++)
00925    {
00926       if (lockthreads[i].id == id) return(&lockthreads[i]);
00927    }
00928    return(NULL);
00929 }
00930 
00931 static struct lockthread *put_lockthread(pthread_t id)
00932 {
00933 int   i;
00934 
00935    for(i = 0; i < MAXLOCKTHREAD; i++)
00936    {
00937       if (lockthreads[i].id == id)
00938          return(&lockthreads[i]);
00939    }
00940    for(i = 0; i < MAXLOCKTHREAD; i++)
00941    {
00942       if (!lockthreads[i].id)
00943       {
00944          lockthreads[i].lockcount = 0;
00945          lockthreads[i].lastlock = 0;
00946          lockthreads[i].lastunlock = 0;
00947          lockthreads[i].id = id;
00948          return(&lockthreads[i]);
00949       }
00950    }
00951    return(NULL);
00952 }
00953 
00954 
00955 static void rpt_mutex_spew(void)
00956 {
00957    struct by_lightning lock_ring_copy[32];
00958    int lock_ring_index_copy;
00959    int i,j;
00960    long long diff;
00961    char a[100];
00962    struct timeval lasttv;
00963 
00964    ast_mutex_lock(&locklock);
00965    memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
00966    lock_ring_index_copy = lock_ring_index;
00967    ast_mutex_unlock(&locklock);
00968 
00969    lasttv.tv_sec = lasttv.tv_usec = 0;
00970    for(i = 0 ; i < 32 ; i++)
00971    {
00972       j = (i + lock_ring_index_copy) % 32;
00973       strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
00974          localtime(&lock_ring_copy[j].tv.tv_sec));
00975       diff = 0;
00976       if(lasttv.tv_sec)
00977       {
00978          diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
00979             * 1000000;
00980          diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
00981       }
00982       lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
00983       lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
00984       if (!lock_ring_copy[j].tv.tv_sec) continue;
00985       if (lock_ring_copy[j].line < 0)
00986       {
00987          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00988             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);
00989       }
00990       else
00991       {
00992          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00993             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);
00994       }
00995    }
00996 }
00997 
00998 
00999 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
01000 {
01001 struct lockthread *t;
01002 pthread_t id;
01003 
01004    id = pthread_self();
01005    ast_mutex_lock(&locklock);
01006    t = put_lockthread(id);
01007    if (!t)
01008    {
01009       ast_mutex_unlock(&locklock);
01010       return;
01011    }
01012    if (t->lockcount)
01013    {
01014       int lastline = t->lastlock;
01015       ast_mutex_unlock(&locklock);
01016       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);
01017       rpt_mutex_spew();
01018       return;
01019    }
01020    t->lastlock = line;
01021    t->lockcount = 1;
01022    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
01023    lock_ring[lock_ring_index].rpt = myrpt;
01024    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
01025    lock_ring[lock_ring_index++].line = line;
01026    if(lock_ring_index == 32)
01027       lock_ring_index = 0;
01028    ast_mutex_unlock(&locklock);
01029    ast_mutex_lock(lockp);
01030 }
01031 
01032 
01033 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
01034 {
01035 struct lockthread *t;
01036 pthread_t id;
01037 
01038    id = pthread_self();
01039    ast_mutex_lock(&locklock);
01040    t = put_lockthread(id);
01041    if (!t)
01042    {
01043       ast_mutex_unlock(&locklock);
01044       return;
01045    }
01046    if (!t->lockcount)
01047    {
01048       int lastline = t->lastunlock;
01049       ast_mutex_unlock(&locklock);
01050       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);
01051       rpt_mutex_spew();
01052       return;
01053    }
01054    t->lastunlock = line;
01055    t->lockcount = 0;
01056    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
01057    lock_ring[lock_ring_index].rpt = myrpt;
01058    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
01059    lock_ring[lock_ring_index++].line = -line;
01060    if(lock_ring_index == 32)
01061       lock_ring_index = 0;
01062    ast_mutex_unlock(&locklock);
01063    ast_mutex_unlock(lockp);
01064 }
01065 
01066 #else  /* APP_RPT_LOCK_DEBUG */
01067 
01068 #define rpt_mutex_lock(x) ast_mutex_lock(x)
01069 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
01070 
01071 #endif  /* APP_RPT_LOCK_DEBUG */
01072 
01073 /*
01074 * Return 1 if rig is multimode capable
01075 */
01076 
01077 static int multimode_capable(struct rpt *myrpt)
01078 {
01079    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
01080       return 1;
01081    if(!strcmp(myrpt->remoterig, remote_rig_ic706))
01082       return 1;
01083    return 0;
01084 }  
01085 
01086 static void voxinit_rpt(struct rpt *myrpt,char enable)
01087 {
01088 
01089    myrpt->vox.speech_energy = 0.0;
01090    myrpt->vox.noise_energy = 0.0;
01091    myrpt->vox.enacount = 0;
01092    myrpt->vox.voxena = 0;
01093    if (!enable) myrpt->vox.voxena = -1;
01094    myrpt->vox.lastvox = 0;
01095    myrpt->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
01096    myrpt->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
01097    myrpt->wasvox = 0;
01098    myrpt->voxtotimer = 0;
01099    myrpt->voxtostate = 0;
01100 }
01101 
01102 static void voxinit_link(struct rpt_link *mylink,char enable)
01103 {
01104 
01105    mylink->vox.speech_energy = 0.0;
01106    mylink->vox.noise_energy = 0.0;
01107    mylink->vox.enacount = 0;
01108    mylink->vox.voxena = 0;
01109    if (!enable) mylink->vox.voxena = -1;
01110    mylink->vox.lastvox = 0;
01111    mylink->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
01112    mylink->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
01113    mylink->wasvox = 0;
01114    mylink->voxtotimer = 0;
01115    mylink->voxtostate = 0;
01116 }
01117 
01118 static int dovox(struct vox *v,short *buf,int bs)
01119 {
01120 
01121    int i;
01122    float esquare = 0.0;
01123    float energy = 0.0;
01124    float threshold = 0.0;
01125    
01126    if (v->voxena < 0) return(v->lastvox);
01127    for(i = 0; i < bs; i++)
01128    {
01129       esquare += (float) buf[i] * (float) buf[i];
01130    }
01131    energy = sqrt(esquare);
01132 
01133    if (energy >= v->speech_energy)
01134       v->speech_energy += (energy - v->speech_energy) / 4;
01135    else
01136       v->speech_energy += (energy - v->speech_energy) / 64;
01137 
01138    if (energy >= v->noise_energy)
01139       v->noise_energy += (energy - v->noise_energy) / 64;
01140    else
01141       v->noise_energy += (energy - v->noise_energy) / 4;
01142    
01143    if (v->voxena) threshold = v->speech_energy / 8;
01144    else
01145    {
01146       threshold = mymax(v->speech_energy / 16,v->noise_energy * 2);
01147       threshold = mymin(threshold,VOX_MAX_THRESHOLD);
01148    }
01149    threshold = mymax(threshold,VOX_MIN_THRESHOLD);
01150    if (energy > threshold)
01151    {
01152       if (v->voxena) v->noise_energy *= 0.75;
01153       v->voxena = 1;
01154    } else   v->voxena = 0;
01155    if (v->lastvox != v->voxena)
01156    {
01157       if (v->enacount++ >= ((v->lastvox) ? v->offdebcnt : v->ondebcnt))
01158       {
01159          v->lastvox = v->voxena;
01160          v->enacount = 0;
01161       }
01162    } else v->enacount = 0;
01163    return(v->lastvox);
01164 }
01165 
01166 
01167 
01168 
01169 /*
01170 * CLI extensions
01171 */
01172 
01173 /* Debug mode */
01174 static int rpt_do_debug(int fd, int argc, const char * const *argv);
01175 static int rpt_do_dump(int fd, int argc, const char * const *argv);
01176 static int rpt_do_stats(int fd, int argc, const char * const *argv);
01177 static int rpt_do_lstats(int fd, int argc, const char * const *argv);
01178 static int rpt_do_nodes(int fd, int argc, const char * const *argv);
01179 static int rpt_do_local_nodes(int fd, int argc, const char * const *argv);
01180 static int rpt_do_reload(int fd, int argc, const char * const *argv);
01181 static int rpt_do_restart(int fd, int argc, const char * const *argv);
01182 static int rpt_do_fun(int fd, int argc, const char * const *argv);
01183 static int rpt_do_fun1(int fd, int argc, const char * const *argv);
01184 static int rpt_do_cmd(int fd, int argc, const char * const *argv);
01185 
01186 static char debug_usage[] =
01187 "Usage: rpt debug level {0-7}\n"
01188 "       Enables debug messages in app_rpt\n";
01189 
01190 static char dump_usage[] =
01191 "Usage: rpt dump <nodename>\n"
01192 "       Dumps struct debug info to log\n";
01193 
01194 static char dump_stats[] =
01195 "Usage: rpt stats <nodename>\n"
01196 "       Dumps node statistics to console\n";
01197 
01198 static char dump_lstats[] =
01199 "Usage: rpt lstats <nodename>\n"
01200 "       Dumps link statistics to console\n";
01201 
01202 static char dump_nodes[] =
01203 "Usage: rpt nodes <nodename>\n"
01204 "       Dumps a list of directly and indirectly connected nodes to the console\n";
01205 
01206 static char usage_local_nodes[] =
01207 "Usage: rpt localnodes\n"
01208 "       Dumps a list of the locally configured node numbers to the console.\n";
01209 
01210 static char reload_usage[] =
01211 "Usage: rpt reload\n"
01212 "       Reloads app_rpt running config parameters\n";
01213 
01214 static char restart_usage[] =
01215 "Usage: rpt restart\n"
01216 "       Restarts app_rpt\n";
01217 
01218 static char fun_usage[] =
01219 "Usage: rpt fun <nodename> <command>\n"
01220 "       Send a DTMF function to a node\n";
01221 
01222 static char cmd_usage[] =
01223 "Usage: rpt cmd <nodename> <cmd-name> <cmd-index> <cmd-args.\n"
01224 "       Send a command to a node.\n        i.e. rpt cmd 2000 ilink 3 2001\n";
01225 
01226 #ifndef  NEW_ASTERISK
01227 
01228 static struct ast_cli_entry  cli_debug =
01229         { { "rpt", "debug", "level" }, rpt_do_debug, 
01230       "Enable app_rpt debugging", debug_usage };
01231 
01232 static struct ast_cli_entry  cli_dump =
01233         { { "rpt", "dump" }, rpt_do_dump,
01234       "Dump app_rpt structs for debugging", dump_usage };
01235 
01236 static struct ast_cli_entry  cli_stats =
01237         { { "rpt", "stats" }, rpt_do_stats,
01238       "Dump node statistics", dump_stats };
01239 
01240 static struct ast_cli_entry  cli_nodes =
01241         { { "rpt", "nodes" }, rpt_do_nodes,
01242       "Dump node list", dump_nodes };
01243 
01244 static struct ast_cli_entry  cli_local_nodes =
01245         { { "rpt", "localnodes" }, rpt_do_local_nodes,
01246       "Dump list of local node numbers", usage_local_nodes };
01247 
01248 static struct ast_cli_entry  cli_lstats =
01249         { { "rpt", "lstats" }, rpt_do_lstats,
01250       "Dump link statistics", dump_lstats };
01251 
01252 static struct ast_cli_entry  cli_reload =
01253         { { "rpt", "reload" }, rpt_do_reload,
01254       "Reload app_rpt config", reload_usage };
01255 
01256 static struct ast_cli_entry  cli_restart =
01257         { { "rpt", "restart" }, rpt_do_restart,
01258       "Restart app_rpt", restart_usage };
01259 
01260 static struct ast_cli_entry  cli_fun =
01261         { { "rpt", "fun" }, rpt_do_fun,
01262       "Execute a DTMF function", fun_usage };
01263 
01264 static struct ast_cli_entry  cli_fun1 =
01265         { { "rpt", "fun1" }, rpt_do_fun1,
01266       "Execute a DTMF function", fun_usage };
01267 
01268 static struct ast_cli_entry  cli_cmd =
01269         { { "rpt", "cmd" }, rpt_do_cmd,
01270       "Execute a DTMF function", cmd_usage };
01271 
01272 #endif
01273 
01274 /*
01275 * Telemetry defaults
01276 */
01277 
01278 
01279 static struct telem_defaults tele_defs[] = {
01280    {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
01281    {"ct2","|t(660,880,150,3072)"},
01282    {"ct3","|t(440,0,150,3072)"},
01283    {"ct4","|t(550,0,150,3072)"},
01284    {"ct5","|t(660,0,150,3072)"},
01285    {"ct6","|t(880,0,150,3072)"},
01286    {"ct7","|t(660,440,150,3072)"},
01287    {"ct8","|t(700,1100,150,3072)"},
01288    {"remotemon","|t(1600,0,75,2048)"},
01289    {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
01290    {"cmdmode","|t(900,904,200,2048)"},
01291    {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
01292 } ;
01293 
01294 /*
01295 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
01296 */
01297 
01298 static int setrbi(struct rpt *myrpt);
01299 static int set_ft897(struct rpt *myrpt);
01300 static int set_ic706(struct rpt *myrpt);
01301 static int setkenwood(struct rpt *myrpt);
01302 static int set_tm271(struct rpt *myrpt);
01303 static int setrbi_check(struct rpt *myrpt);
01304 
01305 
01306 
01307 /*
01308 * Define function protos for function table here
01309 */
01310 
01311 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01312 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01313 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01314 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01315 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01316 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01317 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01318 static int function_playback(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01319 /*
01320 * Function table
01321 */
01322 
01323 static struct function_table_tag function_table[] = {
01324    {"cop", function_cop},
01325    {"autopatchup", function_autopatchup},
01326    {"autopatchdn", function_autopatchdn},
01327    {"ilink", function_ilink},
01328    {"status", function_status},
01329    {"remote", function_remote},
01330    {"macro", function_macro},
01331    {"playback", function_playback}
01332 } ;
01333 
01334 static long diskavail(struct rpt *myrpt)
01335 {
01336 struct   statfs statfsbuf;
01337 
01338    if (!myrpt->p.archivedir) return(0);
01339    if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
01340    {
01341       ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
01342          myrpt->p.archivedir,myrpt->name);
01343       return(-1);
01344    }
01345    return(statfsbuf.f_bavail);
01346 }
01347 
01348 static void flush_telem(struct rpt *myrpt)
01349 {
01350    struct rpt_tele *telem;
01351    if(debug > 2)
01352       ast_log(LOG_NOTICE, "flush_telem()!!");
01353    rpt_mutex_lock(&myrpt->lock);
01354    telem = myrpt->tele.next;
01355    while(telem != &myrpt->tele)
01356    {
01357       if (telem->mode != SETREMOTE) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
01358       telem = telem->next;
01359    }
01360    rpt_mutex_unlock(&myrpt->lock);
01361 }
01362 /*
01363    return via error priority
01364 */
01365 static int priority_jump(struct rpt *myrpt, struct ast_channel *chan)
01366 {
01367    int res=0;
01368 
01369    // if (ast_test_flag(&flags,OPT_JUMP) && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
01370    if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
01371       res = 0;
01372    } else {
01373       res = -1;
01374    }
01375    return res;
01376 }
01377 /*
01378 */
01379 static int linkcount(struct rpt *myrpt)
01380 {
01381    struct   rpt_link *l;
01382    char *reverse_patch_state;
01383    int numoflinks;
01384 
01385    reverse_patch_state = "DOWN";
01386    numoflinks = 0;
01387    l = myrpt->links.next;
01388    while(l && (l != &myrpt->links)){
01389       if(numoflinks >= MAX_STAT_LINKS){
01390          ast_log(LOG_WARNING,
01391          "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
01392          break;
01393       }
01394       //if (l->name[0] == '0'){ /* Skip '0' nodes */
01395       // reverse_patch_state = "UP";
01396       // l = l->next;
01397       // continue;
01398       //}
01399       numoflinks++;
01400     
01401       l = l->next;
01402    }
01403    ast_log(LOG_NOTICE, "numoflinks=%i\n",numoflinks);
01404    return numoflinks;
01405 }
01406 /*
01407  * Retrieve a memory channel
01408  * Return 0 if sucessful,
01409  * -1 if channel not found,
01410  *  1 if parse error
01411  */
01412 static int retreive_memory(struct rpt *myrpt, char *memory)
01413 {
01414    char tmp[30], *s, *s1, *val;
01415 
01416    if (debug)ast_log(LOG_NOTICE, "memory=%s block=%s\n",memory,myrpt->p.memory);
01417 
01418    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, memory);
01419    if (!val){
01420       return -1;
01421    }        
01422    strncpy(tmp,val,sizeof(tmp) - 1);
01423    tmp[sizeof(tmp)-1] = 0;
01424 
01425    s = strchr(tmp,',');
01426    if (!s)
01427       return 1; 
01428    *s++ = 0;
01429    s1 = strchr(s,',');
01430    if (!s1)
01431       return 1;
01432    *s1++ = 0;
01433    strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
01434    strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
01435    strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
01436    myrpt->remmode = REM_MODE_FM;
01437    myrpt->offset = REM_SIMPLEX;
01438    myrpt->powerlevel = REM_MEDPWR;
01439    myrpt->txplon = myrpt->rxplon = 0;
01440    while(*s1){
01441       switch(*s1++){
01442          case 'A':
01443          case 'a':
01444             strcpy(myrpt->rxpl, "100.0");
01445             strcpy(myrpt->txpl, "100.0");
01446             myrpt->remmode = REM_MODE_AM; 
01447             break;
01448          case 'B':
01449          case 'b':
01450             strcpy(myrpt->rxpl, "100.0");
01451             strcpy(myrpt->txpl, "100.0");
01452             myrpt->remmode = REM_MODE_LSB;
01453             break;
01454          case 'F':
01455             myrpt->remmode = REM_MODE_FM;
01456             break;
01457          case 'L':
01458          case 'l':
01459             myrpt->powerlevel = REM_LOWPWR;
01460             break;               
01461          case 'H':
01462          case 'h':
01463             myrpt->powerlevel = REM_HIPWR;
01464             break;
01465                
01466          case 'M':
01467          case 'm':
01468             myrpt->powerlevel = REM_MEDPWR;
01469             break;
01470                   
01471          case '-':
01472             myrpt->offset = REM_MINUS;
01473             break;
01474                   
01475          case '+':
01476             myrpt->offset = REM_PLUS;
01477             break;
01478                   
01479          case 'S':
01480          case 's':
01481             myrpt->offset = REM_SIMPLEX;
01482             break;
01483                   
01484          case 'T':
01485          case 't':
01486             myrpt->txplon = 1;
01487             break;
01488                   
01489          case 'R':
01490          case 'r':
01491             myrpt->rxplon = 1;
01492             break;
01493 
01494          case 'U':
01495          case 'u':
01496             strcpy(myrpt->rxpl, "100.0");
01497             strcpy(myrpt->txpl, "100.0");
01498             myrpt->remmode = REM_MODE_USB;
01499             break;
01500          default:
01501             return 1;
01502       }
01503    }
01504    return 0;
01505 }
01506 /*
01507 
01508 */
01509 static void birdbath(struct rpt *myrpt)
01510 {
01511    struct rpt_tele *telem;
01512    if(debug > 2)
01513       ast_log(LOG_NOTICE, "birdbath!!");
01514    rpt_mutex_lock(&myrpt->lock);
01515    telem = myrpt->tele.next;
01516    while(telem != &myrpt->tele)
01517    {
01518       if (telem->mode == PARROT) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
01519       telem = telem->next;
01520    }
01521    rpt_mutex_unlock(&myrpt->lock);
01522 }
01523 
01524 static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
01525 {
01526 struct        rpt_link *l;
01527 
01528        l = myrpt->links.next;
01529        /* go thru all the links */
01530        while(l != &myrpt->links)
01531        {
01532                if (!l->phonemode)
01533                {
01534                        l = l->next;
01535                        continue;
01536                }
01537                /* don't send to self */
01538                if (mylink && (l == mylink))
01539                {
01540                        l = l->next;
01541                        continue;
01542                }
01543 #ifdef   NEW_ASTERISK
01544                if (l->chan) ast_senddigit(l->chan,c,0);
01545 #else
01546                if (l->chan) ast_senddigit(l->chan,c);
01547 #endif
01548                l = l->next;
01549        }
01550        return;
01551 }
01552 
01553 /* node logging function */
01554 static void donodelog(struct rpt *myrpt,char *str)
01555 {
01556 struct nodelog *nodep;
01557 char  datestr[100];
01558 
01559    if (!myrpt->p.archivedir) return;
01560    nodep = (struct nodelog *)ast_malloc(sizeof(struct nodelog));
01561    if (nodep == NULL)
01562    {
01563       ast_log(LOG_ERROR,"Cannot get memory for node log");
01564       return;
01565    }
01566    time(&nodep->timestamp);
01567    strncpy(nodep->archivedir,myrpt->p.archivedir,
01568       sizeof(nodep->archivedir) - 1);
01569    strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
01570       localtime(&nodep->timestamp));
01571    snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
01572       myrpt->name,datestr,str);
01573    ast_mutex_lock(&nodeloglock);
01574    insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
01575    ast_mutex_unlock(&nodeloglock);
01576 }
01577 
01578 /* must be called locked */
01579 static void do_dtmf_local(struct rpt *myrpt, char c)
01580 {
01581 int   i;
01582 char  digit;
01583 static const char* dtmf_tones[] = {
01584    "!941+1336/200,!0/200", /* 0 */
01585    "!697+1209/200,!0/200", /* 1 */
01586    "!697+1336/200,!0/200", /* 2 */
01587    "!697+1477/200,!0/200", /* 3 */
01588    "!770+1209/200,!0/200", /* 4 */
01589    "!770+1336/200,!0/200", /* 5 */
01590    "!770+1477/200,!0/200", /* 6 */
01591    "!852+1209/200,!0/200", /* 7 */
01592    "!852+1336/200,!0/200", /* 8 */
01593    "!852+1477/200,!0/200", /* 9 */
01594    "!697+1633/200,!0/200", /* A */
01595    "!770+1633/200,!0/200", /* B */
01596    "!852+1633/200,!0/200", /* C */
01597    "!941+1633/200,!0/200", /* D */
01598    "!941+1209/200,!0/200", /* * */
01599    "!941+1477/200,!0/200" };  /* # */
01600 
01601 
01602    if (c)
01603    {
01604       snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
01605       if (!myrpt->dtmf_local_timer) 
01606           myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
01607    }
01608    /* if at timeout */
01609    if (myrpt->dtmf_local_timer == 1)
01610    {
01611       if(debug > 6)
01612          ast_log(LOG_NOTICE,"time out dtmf_local_timer=%i\n",myrpt->dtmf_local_timer);
01613 
01614       /* if anything in the string */
01615       if (myrpt->dtmf_local_str[0])
01616       {
01617          digit = myrpt->dtmf_local_str[0];
01618          myrpt->dtmf_local_str[0] = 0;
01619          for(i = 1; myrpt->dtmf_local_str[i]; i++)
01620          {
01621             myrpt->dtmf_local_str[i - 1] =
01622                myrpt->dtmf_local_str[i];
01623          }
01624          myrpt->dtmf_local_str[i - 1] = 0;
01625          myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
01626          rpt_mutex_unlock(&myrpt->lock);
01627          if (digit >= '0' && digit <='9')
01628             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
01629          else if (digit >= 'A' && digit <= 'D')
01630             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
01631          else if (digit == '*')
01632             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
01633          else if (digit == '#')
01634             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
01635          else {
01636             /* not handled */
01637             ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name);
01638          }
01639          rpt_mutex_lock(&myrpt->lock);
01640       }
01641       else
01642       {
01643          myrpt->dtmf_local_timer = 0;
01644       }
01645    }
01646 }
01647 
01648 static int setdtr(int fd, int enable)
01649 {
01650 struct termios mode;
01651 
01652    if (fd < 0) return -1;
01653    if (tcgetattr(fd, &mode)) {
01654       ast_log(LOG_WARNING, "Unable to get serial parameters for dtr: %s\n", strerror(errno));
01655       return -1;
01656    }
01657    if (enable)
01658    {
01659       cfsetspeed(&mode, B9600);
01660    }
01661    else
01662    {
01663       cfsetspeed(&mode, B0);
01664       usleep(100000);
01665    }
01666    if (tcsetattr(fd, TCSADRAIN, &mode)) {
01667       ast_log(LOG_WARNING, "Unable to set serial parameters for dtr: %s\n", strerror(errno));
01668       return -1;
01669    }
01670    if (enable) usleep(100000);
01671    return 0;
01672 }
01673 
01674 static int openserial(struct rpt *myrpt,char *fname)
01675 {
01676    struct termios mode;
01677    int fd;
01678 
01679    fd = open(fname,O_RDWR);
01680    if (fd == -1)
01681    {
01682       ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
01683       return -1;
01684    }
01685    memset(&mode, 0, sizeof(mode));
01686    if (tcgetattr(fd, &mode)) {
01687       ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
01688       return -1;
01689    }
01690 #ifndef  SOLARIS
01691    cfmakeraw(&mode);
01692 #else
01693         mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
01694                         |INLCR|IGNCR|ICRNL|IXON);
01695         mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
01696         mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
01697         mode.c_cflag |= CS8;
01698    mode.c_cc[VTIME] = 3;
01699    mode.c_cc[VMIN] = 1; 
01700 #endif
01701 
01702    cfsetispeed(&mode, B9600);
01703    cfsetospeed(&mode, B9600);
01704    if (tcsetattr(fd, TCSANOW, &mode)) 
01705       ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
01706    if(!strcmp(myrpt->remoterig, remote_rig_kenwood)) setdtr(fd,0); 
01707    usleep(100000);
01708    if (debug)ast_log(LOG_NOTICE,"Opened serial port %s\n",fname);
01709    return(fd); 
01710 }
01711 
01712 static void mdc1200_notify(struct rpt *myrpt,char *fromnode, unsigned int unit)
01713 {
01714    if (!fromnode)
01715    {
01716       ast_verbose("Got MDC-1200 ID %04X from local system (%s)\n",
01717          unit,myrpt->name);
01718    }
01719    else
01720    {
01721       ast_verbose("Got MDC-1200 ID %04X from node %s (%s)\n",
01722          unit,fromnode,myrpt->name);
01723    }
01724 }
01725 
01726 #ifdef   _MDC_DECODE_H_
01727 
01728 static void mdc1200_send(struct rpt *myrpt, unsigned int unit)
01729 {
01730 struct rpt_link *l;
01731 struct   ast_frame wf;
01732 char  str[200];
01733 
01734 
01735    sprintf(str,"I %s %04X",myrpt->name,unit);
01736 
01737    wf.frametype = AST_FRAME_TEXT;
01738    wf.subclass.integer = 0;
01739    wf.offset = 0;
01740    wf.mallocd = 0;
01741    wf.datalen = strlen(str) + 1;
01742    wf.samples = 0;
01743 
01744 
01745    l = myrpt->links.next;
01746    /* otherwise, send it to all of em */
01747    while(l != &myrpt->links)
01748    {
01749       if (l->name[0] == '0') 
01750       {
01751          l = l->next;
01752          continue;
01753       }
01754       wf.data = str;
01755       if (l->chan) ast_write(l->chan,&wf); 
01756       l = l->next;
01757    }
01758    return;
01759 }
01760 
01761 #endif
01762 
01763 static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
01764 {
01765 time_t   now;
01766 int   gotone;
01767 
01768    time(&now);
01769    gotone = 0;
01770    /* if too much time, reset the skate machine */
01771    if ((now - xlat->lastone) > MAXXLATTIME)
01772    {
01773       xlat->funcindex = xlat->endindex = 0;
01774    }
01775    if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
01776    {
01777       time(&xlat->lastone);
01778       gotone = 1;
01779       if (!xlat->funccharseq[xlat->funcindex])
01780       {
01781          xlat->funcindex = xlat->endindex = 0;
01782          return(myrpt->p.funcchar);
01783       }
01784    } else xlat->funcindex = 0;
01785    if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
01786    {
01787       time(&xlat->lastone);
01788       gotone = 1;
01789       if (!xlat->endcharseq[xlat->endindex])
01790       {
01791          xlat->funcindex = xlat->endindex = 0;
01792          return(myrpt->p.endchar);
01793       }
01794    } else xlat->endindex = 0;
01795    /* if in middle of decode seq, send nothing back */
01796    if (gotone) return(0);
01797    /* if no pass chars specified, return em all */
01798    if (!xlat->passchars[0]) return(c);
01799    /* if a "pass char", pass it */
01800    if (strchr(xlat->passchars,c)) return(c);
01801    return(0);
01802 }
01803 
01804 /*
01805  * Return a pointer to the first non-whitespace character
01806  */
01807 
01808 static char *eatwhite(char *s)
01809 {
01810    while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
01811       if(!*s)
01812          break;
01813       s++;
01814    }
01815    return s;
01816 }
01817 
01818 /*
01819 * Break up a delimited string into a table of substrings
01820 *
01821 * str - delimited string ( will be modified )
01822 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
01823 * limit- maximum number of substrings to process
01824 */
01825    
01826 
01827 
01828 static int finddelim(char *str, char *strp[], int limit)
01829 {
01830 int     i,l,inquo;
01831 
01832         inquo = 0;
01833         i = 0;
01834         strp[i++] = str;
01835         if (!*str)
01836            {
01837                 strp[0] = 0;
01838                 return(0);
01839            }
01840         for(l = 0; *str && (l < limit) ; str++)
01841            {
01842                 if (*str == QUOTECHR)
01843                    {
01844                         if (inquo)
01845                            {
01846                                 *str = 0;
01847                                 inquo = 0;
01848                            }
01849                         else
01850                            {
01851                                 strp[i - 1] = str + 1;
01852                                 inquo = 1;
01853                            }
01854       }
01855                 if ((*str == DELIMCHR) && (!inquo))
01856                 {
01857                         *str = 0;
01858          l++;
01859                         strp[i++] = str + 1;
01860                 }
01861            }
01862         strp[i] = 0;
01863         return(i);
01864 
01865 }
01866 /*
01867    send asterisk frame text message on the current tx channel
01868 */
01869 static int send_usb_txt(struct rpt *myrpt, char *txt) 
01870 {
01871    struct ast_frame wf;
01872  
01873    if (debug)ast_log(LOG_NOTICE, "send_usb_txt %s\n",txt);
01874    wf.frametype = AST_FRAME_TEXT;
01875    wf.subclass.integer = 0;
01876    wf.offset = 0;
01877    wf.mallocd = 0;
01878    wf.datalen = strlen(txt) + 1;
01879    wf.data.ptr = txt;
01880    wf.samples = 0;
01881    ast_write(myrpt->txchannel,&wf); 
01882    return 0;
01883 }
01884 /* must be called locked */
01885 static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
01886 {
01887 struct rpt_link *l;
01888 char mode;
01889 int   i,spos;
01890 
01891    buf[0] = 0; /* clear output buffer */
01892    if (myrpt->remote) return;
01893    /* go thru all links */
01894    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01895    {
01896       /* if is not a real link, ignore it */
01897       if (l->name[0] == '0') continue;
01898       /* don't count our stuff */
01899       if (l == mylink) continue;
01900       if (mylink && (!strcmp(l->name,mylink->name))) continue;
01901       /* figure out mode to report */
01902       mode = 'T'; /* use Tranceive by default */
01903       if (!l->mode) mode = 'R'; /* indicate RX for our mode */
01904       if (!l->thisconnected)  mode = 'C'; /* indicate connecting */
01905       spos = strlen(buf); /* current buf size (b4 we add our stuff) */
01906       if (spos)
01907       {
01908          strcat(buf,",");
01909          spos++;
01910       }
01911       /* add nodes into buffer */
01912       if (l->linklist[0])
01913       {
01914          snprintf(buf + spos,MAXLINKLIST - spos,
01915             "%c%s,%s",mode,l->name,l->linklist);
01916       }
01917       else /* if no nodes, add this node into buffer */
01918       {
01919          snprintf(buf + spos,MAXLINKLIST - spos,
01920             "%c%s",mode,l->name);
01921       }
01922       /* if we are in tranceive mode, let all modes stand */
01923       if (mode == 'T') continue;
01924       /* downgrade everyone on this node if appropriate */
01925       for(i = spos; buf[i]; i++)
01926       {
01927          if (buf[i] == 'T') buf[i] = mode;
01928          if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
01929       }
01930    }
01931    return;
01932 }
01933 
01934 /* must be called locked */
01935 static void __kickshort(struct rpt *myrpt)
01936 {
01937 struct rpt_link *l;
01938 
01939    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01940    {
01941       /* if is not a real link, ignore it */
01942       if (l->name[0] == '0') continue;
01943       l->linklisttimer = LINKLISTSHORTTIME;
01944    }
01945    myrpt->linkposttimer = LINKPOSTSHORTTIME;
01946    return;
01947 }
01948 
01949 static void statpost(struct rpt *myrpt,char *pairs)
01950 {
01951 char *str,*astr;
01952 char *astrs[100];
01953 int   n,pid;
01954 time_t   now;
01955 unsigned int seq;
01956 
01957    if (!myrpt->p.statpost_url) return;
01958    str = ast_malloc(strlen(pairs) + strlen(myrpt->p.statpost_url) + 200);
01959    astr = ast_strdup(myrpt->p.statpost_program);
01960    if ((!str) || (!astr)) {
01961       ast_free(str);
01962       ast_free(astr);
01963       return;
01964    }
01965    n = finddelim(astr,astrs,100);
01966    if (n < 1) {
01967       ast_free(str);
01968       ast_free(astr);
01969       return;
01970    }
01971    ast_mutex_lock(&myrpt->statpost_lock);
01972    seq = ++myrpt->statpost_seqno;
01973    ast_mutex_unlock(&myrpt->statpost_lock);
01974    astrs[n++] = str;
01975    astrs[n] = NULL;
01976    time(&now);
01977    sprintf(str,"%s?node=%s&time=%u&seqno=%u",myrpt->p.statpost_url,
01978       myrpt->name,(unsigned int) now,seq);
01979    if (pairs) sprintf(str + strlen(str),"&%s",pairs);
01980    if (!(pid = ast_safe_fork(0)))
01981    {
01982       execv(astrs[0],astrs);
01983       ast_log(LOG_ERROR, "exec of %s failed.\n", astrs[0]);
01984       perror("asterisk");
01985       exit(0);
01986    }
01987    ast_free(astr);
01988    ast_free(str);
01989    return;
01990 }
01991 
01992 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
01993 {
01994 
01995 char *val;
01996 int longestnode,j;
01997 struct stat mystat;
01998 static time_t last = 0;
01999 static struct ast_config *ourcfg = NULL;
02000 struct ast_variable *vp;
02001 
02002    /* try to look it up locally first */
02003    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
02004    if (val) return(val);
02005    ast_mutex_lock(&nodelookuplock);
02006    /* if file does not exist */
02007    if (stat(myrpt->p.extnodefile,&mystat) == -1)
02008    {
02009       if (ourcfg) ast_config_destroy(ourcfg);
02010       ourcfg = NULL;
02011       ast_mutex_unlock(&nodelookuplock);
02012       return(NULL);
02013    }
02014    /* if we need to reload */
02015    if (mystat.st_mtime > last)
02016    {
02017       if (ourcfg) ast_config_destroy(ourcfg);
02018 #ifdef   NEW_ASTERISK
02019       ourcfg = ast_config_load(myrpt->p.extnodefile,config_flags);
02020 #else
02021       ourcfg = ast_config_load(myrpt->p.extnodefile);
02022 #endif
02023       /* if file not there, just bail */
02024       if (!ourcfg || ourcfg == CONFIG_STATUS_FILEINVALID)
02025       {
02026          ast_mutex_unlock(&nodelookuplock);
02027          return(NULL);
02028       }
02029       /* reset "last" time */
02030       last = mystat.st_mtime;
02031 
02032       /* determine longest node length again */    
02033       longestnode = 0;
02034       vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
02035       while(vp){
02036          j = strlen(vp->name);
02037          if (j > longestnode)
02038             longestnode = j;
02039          vp = vp->next;
02040       }
02041 
02042       vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
02043       while(vp){
02044          j = strlen(vp->name);
02045          if (j > longestnode)
02046             longestnode = j;
02047          vp = vp->next;
02048       }
02049 
02050       myrpt->longestnode = longestnode;
02051    }
02052    val = NULL;
02053    if (ourcfg)
02054       val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
02055    ast_mutex_unlock(&nodelookuplock);
02056    return(val);
02057 }
02058 
02059 /*
02060 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
02061 * If param is passed in non-null, then it will be set to the first character past the match
02062 */
02063 
02064 static int matchkeyword(char *string, char **param, char *keywords[])
02065 {
02066 int   i,ls;
02067    for( i = 0 ; keywords[i] ; i++){
02068       ls = strlen(keywords[i]);
02069       if(!ls){
02070          *param = NULL;
02071          return 0;
02072       }
02073       if(!strncmp(string, keywords[i], ls)){
02074          if(param)
02075             *param = string + ls;
02076          return i + 1; 
02077       }
02078    }
02079    *param = NULL;
02080    return 0;
02081 }
02082 
02083 /*
02084 * Skip characters in string which are in charlist, and return a pointer to the
02085 * first non-matching character
02086 */
02087 
02088 static char *skipchars(char *string, char *charlist)
02089 {
02090 int i;   
02091    while(*string){
02092       for(i = 0; charlist[i] ; i++){
02093          if(*string == charlist[i]){
02094             string++;
02095             break;
02096          }
02097       }
02098       if(!charlist[i])
02099          return string;
02100    }
02101    return string;
02102 }
02103 
02104 static int myatoi(const char *str)
02105 {
02106    int   ret;
02107 
02108    if (!str) {
02109       return -1;
02110    }
02111 
02112    /* leave this %i alone, non-base-10 input is useful here */
02113    if (sscanf(str, "%30i", &ret) != 1) {
02114       return -1;
02115    }
02116 
02117    return ret;
02118 }
02119 
02120 static int mycompar(const void *a, const void *b)
02121 {
02122 char  **x = (char **) a;
02123 char  **y = (char **) b;
02124 int   xoff,yoff;
02125 
02126    if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
02127    if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
02128    return(strcmp((*x) + xoff,(*y) + yoff));
02129 }
02130 
02131 static int topcompar(const void *a, const void *b)
02132 {
02133 struct rpt_topkey *x = (struct rpt_topkey *) a;
02134 struct rpt_topkey *y = (struct rpt_topkey *) b;
02135 
02136    return(x->timesince - y->timesince);
02137 }
02138 
02139 #ifdef   __RPT_NOTCH
02140 
02141 /* rpt filter routine */
02142 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
02143 {
02144 int   i,j;
02145 struct   rptfilter *f;
02146 
02147    for(i = 0; i < len; i++)
02148    {
02149       for(j = 0; j < MAXFILTERS; j++)
02150       {
02151          f = &myrpt->filters[j];
02152          if (!*f->desc) continue;
02153          f->x0 = f->x1; f->x1 = f->x2;
02154               f->x2 = ((float)buf[i]) / f->gain;
02155               f->y0 = f->y1; f->y1 = f->y2;
02156               f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
02157                            + (f->const1 * f->y0) + (f->const2 * f->y1);
02158          buf[i] = (short)f->y2;
02159       }
02160    }
02161 }
02162 
02163 #endif
02164 
02165 
02166 /*
02167  Get the time for the machine's time zone
02168  Note: Asterisk requires a copy of localtime
02169  in the /etc directory for this to work properly.
02170  If /etc/localtime is not present, you will get
02171  GMT time! This is especially important on systems
02172  running embedded linux distributions as they don't usually
02173  have support for locales. 
02174 
02175  If OLD_ASTERISK is defined, then the older localtime_r
02176  function will be used. The /etc/localtime file is not
02177  required in this case. This provides backward compatibility
02178  with Asterisk 1.2 systems.
02179 
02180 */
02181 
02182 #ifdef   NEW_ASTERISK
02183 static void rpt_localtime( time_t * t, struct ast_tm *lt)
02184 {
02185    struct timeval when;
02186 
02187    when.tv_sec = *t;
02188    when.tv_usec = 0;
02189    ast_localtime(&when, lt, NULL);
02190 }
02191 
02192 #else
02193 static void rpt_localtime( time_t * t, struct tm *lt)
02194 {
02195 #ifdef OLD_ASTERISK
02196    localtime_r(t, lt);
02197 #else
02198    ast_localtime(t, lt, NULL);
02199 #endif
02200 }
02201 #endif
02202 
02203 
02204 /* Retrieve an int from a config file */
02205                                                                                 
02206 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
02207 {
02208         char *var;
02209         int ret;
02210    char include_zero = 0;
02211 
02212    if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
02213       min = -min;
02214       include_zero = 1;
02215    }           
02216                                                                      
02217         var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
02218         if(var){
02219                 ret = myatoi(var);
02220       if(include_zero && !ret)
02221          return 0;
02222                 if(ret < min)
02223                         ret = min;
02224                 if(ret > max)
02225                         ret = max;
02226         }
02227         else
02228                 ret = defl;
02229         return ret;
02230 }
02231 
02232 
02233 static void load_rpt_vars(int n,int init)
02234 {
02235 char *this,*val;
02236 int   i,j,longestnode;
02237 struct ast_variable *vp;
02238 struct ast_config *cfg;
02239 char *strs[100];
02240 char s1[256];
02241 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
02242             "ufena","ufdis","atena","atdis",NULL};
02243 
02244    if (option_verbose > 2)
02245       ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
02246          (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
02247    ast_mutex_lock(&rpt_vars[n].lock);
02248    if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
02249 #ifdef   NEW_ASTERISK
02250    cfg = ast_config_load("rpt.conf",config_flags);
02251 #else
02252    cfg = ast_config_load("rpt.conf");
02253 #endif
02254    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
02255       ast_mutex_unlock(&rpt_vars[n].lock);
02256       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
02257       pthread_exit(NULL);
02258    }
02259    rpt_vars[n].cfg = cfg; 
02260    this = rpt_vars[n].name;
02261    memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
02262    if (init)
02263    {
02264       char *cp;
02265       int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
02266 
02267       cp = (char *) &rpt_vars[n].p;
02268       memset(cp + sizeof(rpt_vars[n].p),0,
02269          sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
02270       rpt_vars[n].tele.next = &rpt_vars[n].tele;
02271       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
02272       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
02273       rpt_vars[n].tailmessagen = 0;
02274    }
02275 #ifdef   __RPT_NOTCH
02276    /* zot out filters stuff */
02277    memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
02278 #endif
02279    val = (char *) ast_variable_retrieve(cfg,this,"context");
02280    if (val) rpt_vars[n].p.ourcontext = val;
02281    else rpt_vars[n].p.ourcontext = this;
02282    val = (char *) ast_variable_retrieve(cfg,this,"callerid");
02283    if (val) rpt_vars[n].p.ourcallerid = val;
02284    val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
02285    if (val) rpt_vars[n].p.acctcode = val;
02286    val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
02287    if (val) rpt_vars[n].p.ident = val;
02288    val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
02289    if (val) rpt_vars[n].p.hangtime = atoi(val);
02290       else rpt_vars[n].p.hangtime = HANGTIME;
02291    val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
02292    if (val) rpt_vars[n].p.althangtime = atoi(val);
02293       else rpt_vars[n].p.althangtime = HANGTIME;
02294    val = (char *) ast_variable_retrieve(cfg,this,"totime");
02295    if (val) rpt_vars[n].p.totime = atoi(val);
02296       else rpt_vars[n].p.totime = TOTIME;
02297    val = (char *) ast_variable_retrieve(cfg,this,"voxtimeout");
02298    if (val) rpt_vars[n].p.voxtimeout_ms = atoi(val);
02299       else rpt_vars[n].p.voxtimeout_ms = VOX_TIMEOUT_MS;
02300    val = (char *) ast_variable_retrieve(cfg,this,"voxrecover");
02301    if (val) rpt_vars[n].p.voxrecover_ms = atoi(val);
02302       else rpt_vars[n].p.voxrecover_ms = VOX_RECOVER_MS;
02303    val = (char *) ast_variable_retrieve(cfg,this,"simplexpatchdelay");
02304    if (val) rpt_vars[n].p.simplexpatchdelay = atoi(val);
02305       else rpt_vars[n].p.simplexpatchdelay = SIMPLEX_PATCH_DELAY;
02306    val = (char *) ast_variable_retrieve(cfg,this,"simplexphonedelay");
02307    if (val) rpt_vars[n].p.simplexphonedelay = atoi(val);
02308       else rpt_vars[n].p.simplexphonedelay = SIMPLEX_PHONE_DELAY;
02309    val = (char *) ast_variable_retrieve(cfg,this,"statpost_program");
02310    if (val) rpt_vars[n].p.statpost_program = val;
02311       else rpt_vars[n].p.statpost_program = STATPOST_PROGRAM;
02312    rpt_vars[n].p.statpost_url = 
02313       (char *) ast_variable_retrieve(cfg,this,"statpost_url");
02314    rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);    
02315    rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);     
02316    rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
02317    rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME);   /* Enforce a min max including zero */
02318    rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
02319    val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
02320    if (val) rpt_vars[n].p.tonezone = val;
02321    rpt_vars[n].p.tailmessages[0] = 0;
02322    rpt_vars[n].p.tailmessagemax = 0;
02323    val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
02324    if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
02325    val = (char *) ast_variable_retrieve(cfg,this,"memory");
02326    if (!val) val = MEMORY;
02327    rpt_vars[n].p.memory = val;
02328    val = (char *) ast_variable_retrieve(cfg,this,"macro");
02329    if (!val) val = MACRO;
02330    rpt_vars[n].p.macro = val;
02331    val = (char *) ast_variable_retrieve(cfg,this,"tonemacro");
02332    if (!val) val = TONEMACRO;
02333    rpt_vars[n].p.tonemacro = val;
02334    val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
02335    if (val) rpt_vars[n].p.startupmacro = val;
02336    val = (char *) ast_variable_retrieve(cfg,this,"iobase");
02337    /* do not use atoi() here, we need to be able to have
02338       the input specified in hex or decimal so we use
02339       sscanf with a %i */
02340    if ((!val) || (sscanf(val,"%30i",&rpt_vars[n].p.iobase) != 1))
02341       rpt_vars[n].p.iobase = DEFAULT_IOBASE;
02342    val = (char *) ast_variable_retrieve(cfg,this,"ioport");
02343    rpt_vars[n].p.ioport = val;
02344    val = (char *) ast_variable_retrieve(cfg,this,"functions");
02345    if (!val)
02346       {
02347          val = FUNCTIONS;
02348          rpt_vars[n].p.simple = 1;
02349       } 
02350    rpt_vars[n].p.functions = val;
02351    val =  (char *) ast_variable_retrieve(cfg,this,"link_functions");
02352    if (val) rpt_vars[n].p.link_functions = val;
02353    else 
02354       rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
02355    val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
02356    if (val) rpt_vars[n].p.phone_functions = val;
02357    val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
02358    if (val) rpt_vars[n].p.dphone_functions = val;
02359    val = (char *) ast_variable_retrieve(cfg,this,"alt_functions");
02360    if (val) rpt_vars[n].p.alt_functions = val;
02361    val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
02362    if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
02363       rpt_vars[n].p.funcchar = *val;      
02364    val = (char *) ast_variable_retrieve(cfg,this,"endchar");
02365    if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
02366       rpt_vars[n].p.endchar = *val;    
02367    val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
02368    if (val) rpt_vars[n].p.nobusyout = ast_true(val);
02369    val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
02370    if (val) rpt_vars[n].p.notelemtx = ast_true(val);
02371    val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
02372    if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
02373    val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
02374    if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
02375    val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
02376    if (val) rpt_vars[n].p.linktolink = ast_true(val);
02377    val = (char *) ast_variable_retrieve(cfg,this,"nodes");
02378    if (!val) val = NODES;
02379    rpt_vars[n].p.nodes = val;
02380    val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
02381    if (!val) val = EXTNODES;
02382    rpt_vars[n].p.extnodes = val;
02383    val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
02384    if (!val) val = EXTNODEFILE;
02385    rpt_vars[n].p.extnodefile = val;
02386    val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
02387    if (val) rpt_vars[n].p.archivedir = val;
02388    val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
02389    if (val) rpt_vars[n].p.authlevel = atoi(val); 
02390    else rpt_vars[n].p.authlevel = 0;
02391    val = (char *) ast_variable_retrieve(cfg,this,"parrot");
02392    if (val) rpt_vars[n].p.parrotmode = ast_true(val) * 2;
02393    else rpt_vars[n].p.parrotmode = 0;
02394    val = (char *) ast_variable_retrieve(cfg,this,"parrottime");
02395    if (val) rpt_vars[n].p.parrottime = atoi(val); 
02396    else rpt_vars[n].p.parrottime = PARROTTIME;
02397    val = (char *) ast_variable_retrieve(cfg,this,"rptnode");
02398    rpt_vars[n].p.rptnode = val;
02399    val = (char *) ast_variable_retrieve(cfg,this,"mars");
02400    if (val) rpt_vars[n].p.remote_mars = atoi(val); 
02401    else rpt_vars[n].p.remote_mars = 0;
02402    val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
02403    if (val) rpt_vars[n].p.monminblocks = atol(val); 
02404    else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
02405    val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
02406    if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); 
02407    else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
02408    val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
02409    if (val) rpt_vars[n].p.civaddr = atoi(val); 
02410    else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
02411    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
02412    if (val) rpt_vars[n].p.remotetimeout = atoi(val); 
02413    else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
02414    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
02415    if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); 
02416    else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
02417    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
02418    if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); 
02419    else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
02420 #ifdef   __RPT_NOTCH
02421    val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
02422    if (val) {
02423       i = finddelim(val,strs,MAXFILTERS * 2);
02424       i &= ~1; /* force an even number, rounded down */
02425       if (i >= 2) for(j = 0; j < i; j += 2)
02426       {
02427          rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
02428            &rpt_vars[n].filters[j >> 1].gain,
02429              &rpt_vars[n].filters[j >> 1].const0,
02430             &rpt_vars[n].filters[j >> 1].const1,
02431                 &rpt_vars[n].filters[j >> 1].const2);
02432          sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
02433             strs[j],strs[j + 1]);
02434       }
02435 
02436    }
02437 #endif
02438    val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
02439    if (val) {
02440       memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
02441       i = finddelim(val,strs,3);
02442       if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
02443       if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
02444       if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
02445    }
02446    val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
02447    if (val) {
02448       memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
02449       i = finddelim(val,strs,3);
02450       if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
02451       if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
02452       if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
02453    }
02454    /* retreive the stanza name for the control states if there is one */
02455    val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
02456    rpt_vars[n].p.csstanzaname = val;
02457       
02458    /* retreive the stanza name for the scheduler if there is one */
02459    val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
02460    rpt_vars[n].p.skedstanzaname = val;
02461 
02462    /* retreive the stanza name for the txlimits */
02463    val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
02464    rpt_vars[n].p.txlimitsstanzaname = val;
02465 
02466    longestnode = 0;
02467 
02468    vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
02469       
02470    while(vp){
02471       j = strlen(vp->name);
02472       if (j > longestnode)
02473          longestnode = j;
02474       vp = vp->next;
02475    }
02476 
02477    rpt_vars[n].longestnode = longestnode;
02478       
02479    /*
02480    * For this repeater, Determine the length of the longest function 
02481    */
02482    rpt_vars[n].longestfunc = 0;
02483    vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
02484    while(vp){
02485       j = strlen(vp->name);
02486       if (j > rpt_vars[n].longestfunc)
02487          rpt_vars[n].longestfunc = j;
02488       vp = vp->next;
02489    }
02490    /*
02491    * For this repeater, Determine the length of the longest function 
02492    */
02493    rpt_vars[n].link_longestfunc = 0;
02494    vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
02495    while(vp){
02496       j = strlen(vp->name);
02497       if (j > rpt_vars[n].link_longestfunc)
02498          rpt_vars[n].link_longestfunc = j;
02499       vp = vp->next;
02500    }
02501    rpt_vars[n].phone_longestfunc = 0;
02502    if (rpt_vars[n].p.phone_functions)
02503    {
02504       vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
02505       while(vp){
02506          j = strlen(vp->name);
02507          if (j > rpt_vars[n].phone_longestfunc)
02508             rpt_vars[n].phone_longestfunc = j;
02509          vp = vp->next;
02510       }
02511    }
02512    rpt_vars[n].dphone_longestfunc = 0;
02513    if (rpt_vars[n].p.dphone_functions)
02514    {
02515       vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
02516       while(vp){
02517          j = strlen(vp->name);
02518          if (j > rpt_vars[n].dphone_longestfunc)
02519             rpt_vars[n].dphone_longestfunc = j;
02520          vp = vp->next;
02521       }
02522    }
02523    rpt_vars[n].alt_longestfunc = 0;
02524    if (rpt_vars[n].p.alt_functions)
02525    {
02526       vp = ast_variable_browse(cfg, rpt_vars[n].p.alt_functions);
02527       while(vp){
02528          j = strlen(vp->name);
02529          if (j > rpt_vars[n].alt_longestfunc)
02530             rpt_vars[n].alt_longestfunc = j;
02531          vp = vp->next;
02532       }
02533    }
02534    rpt_vars[n].macro_longest = 1;
02535    vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
02536    while(vp){
02537       j = strlen(vp->name);
02538       if (j > rpt_vars[n].macro_longest)
02539          rpt_vars[n].macro_longest = j;
02540       vp = vp->next;
02541    }
02542    
02543    /* Browse for control states */
02544    if(rpt_vars[n].p.csstanzaname)
02545       vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
02546    else
02547       vp = NULL;
02548    for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
02549       int k,nukw,statenum;
02550       statenum=atoi(vp->name);
02551       strncpy(s1, vp->value, 255);
02552       s1[255] = 0;
02553       nukw  = finddelim(s1,strs,32);
02554       
02555       for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */  
02556          for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
02557             if(!strcmp(strs[k],cs_keywords[j])){
02558                switch(j){
02559                   case 0: /* rptena */
02560                      rpt_vars[n].p.s[statenum].txdisable = 0;
02561                      break;
02562                   case 1: /* rptdis */
02563                      rpt_vars[n].p.s[statenum].txdisable = 1;
02564                      break;
02565          
02566                   case 2: /* apena */
02567                      rpt_vars[n].p.s[statenum].autopatchdisable = 0;
02568                      break;
02569 
02570                   case 3: /* apdis */
02571                      rpt_vars[n].p.s[statenum].autopatchdisable = 1;
02572                      break;
02573 
02574                   case 4: /* lnkena */
02575                      rpt_vars[n].p.s[statenum].linkfundisable = 0;
02576                      break;
02577    
02578                   case 5: /* lnkdis */
02579                      rpt_vars[n].p.s[statenum].linkfundisable = 1;
02580                      break;
02581 
02582                   case 6: /* totena */
02583                      rpt_vars[n].p.s[statenum].totdisable = 0;
02584                      break;
02585                
02586                   case 7: /* totdis */
02587                      rpt_vars[n].p.s[statenum].totdisable = 1;
02588                      break;
02589 
02590                   case 8: /* skena */
02591                      rpt_vars[n].p.s[statenum].schedulerdisable = 0;
02592                      break;
02593 
02594                   case 9: /* skdis */
02595                      rpt_vars[n].p.s[statenum].schedulerdisable = 1;
02596                      break;
02597 
02598                   case 10: /* ufena */
02599                      rpt_vars[n].p.s[statenum].userfundisable = 0;
02600                      break;
02601 
02602                   case 11: /* ufdis */
02603                      rpt_vars[n].p.s[statenum].userfundisable = 1;
02604                      break;
02605 
02606                   case 12: /* atena */
02607                      rpt_vars[n].p.s[statenum].alternatetail = 1;
02608                      break;
02609 
02610                   case 13: /* atdis */
02611                      rpt_vars[n].p.s[statenum].alternatetail = 0;
02612                      break;
02613          
02614                   default:
02615                      ast_log(LOG_WARNING,
02616                         "Unhandled control state keyword %s", cs_keywords[i]);
02617                      break;
02618                }
02619             }
02620          }
02621       }
02622       vp = vp->next;
02623    }
02624    ast_mutex_unlock(&rpt_vars[n].lock);
02625 }
02626 
02627 /*
02628 * Enable or disable debug output at a given level at the console
02629 */
02630 static int rpt_do_debug(int fd, int argc, const char * const *argv)
02631 {
02632    int newlevel;
02633 
02634    if (argc != 4) {
02635       return RESULT_SHOWUSAGE;
02636    }
02637 
02638    newlevel = myatoi(argv[3]);
02639 
02640    if (newlevel < 0 || newlevel > 7) {
02641       return RESULT_SHOWUSAGE;
02642    }
02643 
02644    if (newlevel) {
02645       ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
02646    } else {
02647       ast_cli(fd, "app_rpt Debugging disabled\n");
02648    }
02649 
02650    debug = newlevel;
02651 
02652    return RESULT_SUCCESS;
02653 }
02654 
02655 /*
02656 * Dump rpt struct debugging onto console
02657 */
02658                                                                                                                                  
02659 static int rpt_do_dump(int fd, int argc, const char * const *argv)
02660 {
02661    int i;
02662 
02663         if (argc != 3)
02664                 return RESULT_SHOWUSAGE;
02665 
02666    for(i = 0; i < nrpts; i++)
02667    {
02668       if (!strcmp(argv[2],rpt_vars[i].name))
02669       {
02670          rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
02671               ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
02672               return RESULT_SUCCESS;
02673       }
02674    }
02675    return RESULT_FAILURE;
02676 }
02677 
02678 /*
02679 * Dump statistics onto console
02680 */
02681 
02682 static int rpt_do_stats(int fd, int argc, const char * const *argv)
02683 {
02684    int i,j,numoflinks;
02685    int dailytxtime, dailykerchunks;
02686    time_t now;
02687    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
02688    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
02689    int uptime;
02690    long long totaltxtime;
02691    struct   rpt_link *l;
02692    char *listoflinks[MAX_STAT_LINKS];  
02693    char *lastdtmfcommand,*parrot_ena;
02694    char *tot_state, *ider_state, *patch_state;
02695    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
02696    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
02697    struct rpt *myrpt;
02698 
02699    static char *not_applicable = "N/A";
02700 
02701    if(argc != 3)
02702       return RESULT_SHOWUSAGE;
02703 
02704    tot_state = ider_state = 
02705    patch_state = reverse_patch_state = 
02706    input_signal = not_applicable;
02707    called_number = lastdtmfcommand = NULL;
02708 
02709    time(&now);
02710    for(i = 0; i < nrpts; i++)
02711    {
02712       if (!strcmp(argv[2],rpt_vars[i].name)){
02713          /* Make a copy of all stat variables while locked */
02714          myrpt = &rpt_vars[i];
02715          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02716          uptime = (int)(now - starttime);
02717          dailytxtime = myrpt->dailytxtime;
02718          totaltxtime = myrpt->totaltxtime;
02719          dailykeyups = myrpt->dailykeyups;
02720          totalkeyups = myrpt->totalkeyups;
02721          dailykerchunks = myrpt->dailykerchunks;
02722          totalkerchunks = myrpt->totalkerchunks;
02723          dailyexecdcommands = myrpt->dailyexecdcommands;
02724          totalexecdcommands = myrpt->totalexecdcommands;
02725          timeouts = myrpt->timeouts;
02726 
02727          /* Traverse the list of connected nodes */
02728          reverse_patch_state = "DOWN";
02729          numoflinks = 0;
02730          l = myrpt->links.next;
02731          while(l && (l != &myrpt->links)){
02732             if(numoflinks >= MAX_STAT_LINKS){
02733                ast_log(LOG_NOTICE,
02734                "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
02735                break;
02736             }
02737             if (l->name[0] == '0'){ /* Skip '0' nodes */
02738                reverse_patch_state = "UP";
02739                l = l->next;
02740                continue;
02741             }
02742             listoflinks[numoflinks] = ast_strdup(l->name);
02743             if(listoflinks[numoflinks] == NULL){
02744                break;
02745             }
02746             else{
02747                numoflinks++;
02748             }
02749             l = l->next;
02750          }
02751 
02752          if(myrpt->keyed)
02753             input_signal = "YES";
02754          else
02755             input_signal = "NO";
02756 
02757          if(myrpt->p.parrotmode)
02758             parrot_ena = "ENABLED";
02759          else
02760             parrot_ena = "DISABLED";
02761 
02762          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
02763             sys_ena = "DISABLED";
02764          else
02765             sys_ena = "ENABLED";
02766 
02767          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
02768             tot_ena = "DISABLED";
02769          else
02770             tot_ena = "ENABLED";
02771 
02772          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
02773             link_ena = "DISABLED";
02774          else
02775             link_ena = "ENABLED";
02776 
02777          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
02778             patch_ena = "DISABLED";
02779          else
02780             patch_ena = "ENABLED";
02781 
02782          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
02783             sch_ena = "DISABLED";
02784          else
02785             sch_ena = "ENABLED";
02786 
02787          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
02788             user_funs = "DISABLED";
02789          else
02790             user_funs = "ENABLED";
02791 
02792          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
02793             tail_type = "ALTERNATE";
02794          else
02795             tail_type = "STANDARD";
02796 
02797          if(!myrpt->totimer)
02798             tot_state = "TIMED OUT!";
02799          else if(myrpt->totimer != myrpt->p.totime)
02800             tot_state = "ARMED";
02801          else
02802             tot_state = "RESET";
02803 
02804          if(myrpt->tailid)
02805             ider_state = "QUEUED IN TAIL";
02806          else if(myrpt->mustid)
02807             ider_state = "QUEUED FOR CLEANUP";
02808          else
02809             ider_state = "CLEAN";
02810 
02811          switch(myrpt->callmode){
02812             case 1:
02813                patch_state = "DIALING";
02814                break;
02815             case 2:
02816                patch_state = "CONNECTING";
02817                break;
02818             case 3:
02819                patch_state = "UP";
02820                break;
02821 
02822             case 4:
02823                patch_state = "CALL FAILED";
02824                break;
02825 
02826             default:
02827                patch_state = "DOWN";
02828          }
02829 
02830          if(strlen(myrpt->exten)){
02831             called_number = ast_strdup(myrpt->exten);
02832          }
02833 
02834          if(strlen(myrpt->lastdtmfcommand)){
02835             lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
02836          }
02837          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02838 
02839          ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
02840          ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
02841          ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
02842          ast_cli(fd, "System...........................................: %s\n", sys_ena);
02843          ast_cli(fd, "Parrot Mode......................................: %s\n", parrot_ena);
02844          ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
02845          ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
02846          ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
02847          ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
02848          ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
02849          ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
02850          ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
02851          ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
02852          ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
02853          ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
02854          ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
02855          ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
02856          ast_cli(fd, "Last DTMF command executed.......................: %s\n", 
02857          (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
02858          hours = dailytxtime/3600000;
02859          dailytxtime %= 3600000;
02860          minutes = dailytxtime/60000;
02861          dailytxtime %= 60000;
02862          seconds = dailytxtime/1000;
02863          dailytxtime %= 1000;
02864 
02865          ast_cli(fd, "TX time today....................................: %02d:%02d:%02d.%d\n",
02866             hours, minutes, seconds, dailytxtime);
02867 
02868          hours = (int) totaltxtime/3600000;
02869          totaltxtime %= 3600000;
02870          minutes = (int) totaltxtime/60000;
02871          totaltxtime %= 60000;
02872          seconds = (int)  totaltxtime/1000;
02873          totaltxtime %= 1000;
02874 
02875          ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
02876              hours, minutes, seconds, (int) totaltxtime);
02877 
02878                         hours = uptime/3600;
02879                         uptime %= 3600;
02880                         minutes = uptime/60;
02881                         uptime %= 60;
02882 
02883                         ast_cli(fd, "Uptime...........................................: %02d:%02d:%02d\n",
02884                                 hours, minutes, uptime);
02885 
02886          ast_cli(fd, "Nodes currently connected to us..................: ");
02887                         if(!numoflinks){
02888                          ast_cli(fd,"<NONE>");
02889                         }
02890          else{
02891             for(j = 0 ;j < numoflinks; j++){
02892                ast_cli(fd, "%s", listoflinks[j]);
02893                if(j % 4 == 3){
02894                   ast_cli(fd, "\n");
02895                   ast_cli(fd, "                                                 : ");
02896                }  
02897                else{
02898                   if((numoflinks - 1) - j  > 0)
02899                      ast_cli(fd, ", ");
02900                }
02901             }
02902          }
02903          ast_cli(fd,"\n");
02904 
02905          ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
02906          ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
02907          ast_cli(fd, "Autopatch called number..........................: %s\n",
02908          (called_number && strlen(called_number)) ? called_number : not_applicable);
02909          ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
02910          ast_cli(fd, "User linking commands............................: %s\n", link_ena);
02911          ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
02912 
02913          for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
02914             ast_free(listoflinks[j]);
02915          }
02916          ast_free(called_number);
02917          ast_free(lastdtmfcommand);
02918               return RESULT_SUCCESS;
02919       }
02920    }
02921    return RESULT_FAILURE;
02922 }
02923 
02924 /*
02925 * Link stats function
02926 */
02927 
02928 static int rpt_do_lstats(int fd, int argc, const char * const *argv)
02929 {
02930    int i,j;
02931    char *connstate;
02932    struct rpt *myrpt;
02933    struct rpt_link *l;
02934    struct rpt_lstat *s,*t;
02935    struct rpt_lstat s_head;
02936    if(argc != 3)
02937       return RESULT_SHOWUSAGE;
02938 
02939    s = NULL;
02940    s_head.next = &s_head;
02941    s_head.prev = &s_head;
02942 
02943    for(i = 0; i < nrpts; i++)
02944    {
02945       if (!strcmp(argv[2],rpt_vars[i].name)){
02946          /* Make a copy of all stat variables while locked */
02947          myrpt = &rpt_vars[i];
02948          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02949          /* Traverse the list of connected nodes */
02950          j = 0;
02951          l = myrpt->links.next;
02952          while(l && (l != &myrpt->links)){
02953             if (l->name[0] == '0'){ /* Skip '0' nodes */
02954                l = l->next;
02955                continue;
02956             }
02957             if((s = (struct rpt_lstat *) ast_malloc(sizeof(struct rpt_lstat))) == NULL){
02958                ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
02959                rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02960                return RESULT_FAILURE;
02961             }
02962             memset(s, 0, sizeof(struct rpt_lstat));
02963             strncpy(s->name, l->name, MAXREMSTR - 1);
02964             if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
02965             else strcpy(s->peer,"(none)");
02966             s->mode = l->mode;
02967             s->outbound = l->outbound;
02968             s->reconnects = l->reconnects;
02969             s->connecttime = l->connecttime;
02970             s->thisconnected = l->thisconnected;
02971             memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
02972             insque((struct qelem *) s, (struct qelem *) s_head.next);
02973             memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
02974             l = l->next;
02975          }
02976          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02977          ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME        CONNECT STATE\n");
02978          ast_cli(fd, "----      ----                ----------  ---------  ------------        -------------\n");
02979 
02980          for(s = s_head.next; s != &s_head; s = s->next){
02981             int hours, minutes, seconds;
02982             long long connecttime = s->connecttime;
02983             char conntime[21];
02984             hours = (int) connecttime/3600000;
02985             connecttime %= 3600000;
02986             minutes = (int) connecttime/60000;
02987             connecttime %= 60000;
02988             seconds = (int)  connecttime/1000;
02989             connecttime %= 1000;
02990             snprintf(conntime, 20, "%02d:%02d:%02d.%d",
02991                hours, minutes, seconds, (int) connecttime);
02992             conntime[20] = 0;
02993             if(s->thisconnected)
02994                connstate  = "ESTABLISHED";
02995             else
02996                connstate = "CONNECTING";
02997             ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
02998                s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
02999          }  
03000          /* destroy our local link queue */
03001          s = s_head.next;
03002          while(s != &s_head){
03003             t = s;
03004             s = s->next;
03005             remque((struct qelem *)t);
03006             ast_free(t);
03007          }        
03008          return RESULT_SUCCESS;
03009       }
03010    }
03011    return RESULT_FAILURE;
03012 }
03013 
03014 /*
03015 * List all nodes connected, directly or indirectly
03016 */
03017 
03018 static int rpt_do_nodes(int fd, int argc, const char * const *argv)
03019 {
03020    int i,j;
03021    char ns;
03022    char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
03023    struct rpt *myrpt;
03024    if(argc != 3)
03025       return RESULT_SHOWUSAGE;
03026 
03027    for(i = 0; i < nrpts; i++)
03028    {
03029       if (!strcmp(argv[2],rpt_vars[i].name)){
03030          /* Make a copy of all stat variables while locked */
03031          myrpt = &rpt_vars[i];
03032          rpt_mutex_lock(&myrpt->lock); /* LOCK */
03033          __mklinklist(myrpt,NULL,lbuf);
03034          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
03035          /* parse em */
03036          ns = finddelim(lbuf,strs,MAXLINKLIST);
03037          /* sort em */
03038          if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
03039          ast_cli(fd,"\n");
03040          ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
03041          for(j = 0 ;; j++){
03042             if(!strs[j]){
03043                if(!j){
03044                   ast_cli(fd,"<NONE>");
03045                }
03046                break;
03047             }
03048             ast_cli(fd, "%s", strs[j]);
03049             if(j % 8 == 7){
03050                ast_cli(fd, "\n");
03051             }
03052             else{
03053                if(strs[j + 1])
03054                   ast_cli(fd, ", ");
03055             }
03056          }
03057          ast_cli(fd,"\n\n");
03058          return RESULT_SUCCESS;
03059       }
03060    }
03061    return RESULT_FAILURE;
03062 }
03063 
03064 /*
03065 * List all locally configured nodes
03066 */
03067 
03068 static int rpt_do_local_nodes(int fd, int argc, const char * const *argv)
03069 {
03070 
03071     int i;
03072     ast_cli(fd, "\nNode\n----\n");
03073     for (i=0; i< nrpts; i++)
03074     {
03075         ast_cli(fd, "%s\n", rpt_vars[i].name);        
03076     } /* for i */
03077     ast_cli(fd,"\n");
03078     return RESULT_SUCCESS;
03079 } 
03080 
03081 
03082 /*
03083 * reload vars 
03084 */
03085 
03086 static int rpt_do_reload(int fd, int argc, const char * const *argv)
03087 {
03088 int   n;
03089 
03090         if (argc > 2) return RESULT_SHOWUSAGE;
03091 
03092    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
03093 
03094    return RESULT_FAILURE;
03095 }
03096 
03097 /*
03098 * restart app_rpt
03099 */
03100                                                                                                                                  
03101 static int rpt_do_restart(int fd, int argc, const char * const *argv)
03102 {
03103 int   i;
03104 
03105         if (argc > 2) return RESULT_SHOWUSAGE;
03106    for(i = 0; i < nrpts; i++)
03107    {
03108       if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
03109    }
03110    return RESULT_FAILURE;
03111 }
03112 
03113 
03114 /*
03115 * send an app_rpt DTMF function from the CLI
03116 */
03117                                                                                                                                  
03118 static int rpt_do_fun(int fd, int argc, const char * const *argv)
03119 {
03120    int   i,busy=0;
03121 
03122         if (argc != 4) return RESULT_SHOWUSAGE;
03123 
03124    for(i = 0; i < nrpts; i++){
03125       if(!strcmp(argv[2], rpt_vars[i].name)){
03126          struct rpt *myrpt = &rpt_vars[i];
03127          rpt_mutex_lock(&myrpt->lock);
03128          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
03129             rpt_mutex_unlock(&myrpt->lock);
03130             busy=1;
03131          }
03132          if(!busy){
03133             myrpt->macrotimer = MACROTIME;
03134             strncat(myrpt->macrobuf,argv[3],MAXMACRO - 1);
03135          }
03136          rpt_mutex_unlock(&myrpt->lock);
03137       }
03138    }
03139    if(busy){
03140       ast_cli(fd, "Function decoder busy");
03141    }
03142    return RESULT_FAILURE;
03143 }
03144 /*
03145    the convention is that macros in the data from the rpt() application
03146    are all at the end of the data, separated by the | and start with a *
03147    when put into the macro buffer, the characters have their high bit
03148    set so the macro processor knows they came from the application data
03149    and to use the alt-functions table.
03150    sph:
03151 */
03152 static int rpt_push_alt_macro(struct rpt *myrpt, char *sptr)
03153 {
03154    int   busy=0;
03155 
03156    rpt_mutex_lock(&myrpt->lock);
03157    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(sptr)){
03158       rpt_mutex_unlock(&myrpt->lock);
03159       busy=1;
03160    }
03161    if(!busy){
03162       int x;
03163       if (debug)ast_log(LOG_NOTICE, "rpt_push_alt_macro %s\n",sptr);
03164       myrpt->macrotimer = MACROTIME;
03165       for(x = 0; *(sptr + x); x++)
03166           myrpt->macrobuf[x] = *(sptr + x) | 0x80;
03167       *(sptr + x) = 0;
03168    }
03169    rpt_mutex_unlock(&myrpt->lock);
03170 
03171    if(busy)ast_log(LOG_WARNING, "Function decoder busy on app_rpt command macro.\n");
03172 
03173    return busy;
03174 }
03175 /*
03176    allows us to test rpt() application data commands
03177 */
03178 static int rpt_do_fun1(int fd, int argc, const char * const *argv)
03179 {
03180    int   i;
03181 
03182     if (argc != 4) return RESULT_SHOWUSAGE;
03183 
03184    for(i = 0; i < nrpts; i++){
03185       if(!strcmp(argv[2], rpt_vars[i].name)){
03186          struct rpt *myrpt = &rpt_vars[i];
03187          rpt_push_alt_macro(myrpt, (char *) argv[3]);
03188       }
03189    }
03190    return RESULT_FAILURE;
03191 }
03192 /*
03193 * send an app_rpt **command** from the CLI
03194 */
03195 
03196 static int rpt_do_cmd(int fd, int argc, const char * const *argv)
03197 {
03198    int i, l;
03199    int busy=0;
03200    int maxActions = sizeof(function_table)/sizeof(struct function_table_tag);
03201 
03202    int thisRpt = -1;
03203    int thisAction = -1;
03204    struct rpt *myrpt = NULL;
03205    if (argc != 6) return RESULT_SHOWUSAGE;
03206    
03207    for(i = 0; i < nrpts; i++)
03208    {
03209       if(!strcmp(argv[2], rpt_vars[i].name))
03210       {
03211          thisRpt = i;
03212          myrpt = &rpt_vars[i];
03213          break;
03214       } /* if !strcmp... */
03215    } /* for i */
03216 
03217    if (thisRpt < 0)
03218    {
03219       ast_cli(fd, "Unknown node number %s.\n", argv[2]);
03220       return RESULT_FAILURE;
03221    } /* if thisRpt < 0 */
03222    
03223    /* Look up the action */
03224    l = strlen(argv[3]);
03225    for(i = 0 ; i < maxActions; i++)
03226    {
03227       if(!strncasecmp(argv[3], function_table[i].action, l))
03228       {
03229          thisAction = i;
03230          break;
03231       } /* if !strncasecmp... */
03232    } /* for i */
03233    
03234    if (thisAction < 0)
03235    {
03236       ast_cli(fd, "Unknown action name %s.\n", argv[3]);
03237       return RESULT_FAILURE;
03238    } /* if thisAction < 0 */
03239 
03240    /* at this point, it looks like all the arguments make sense... */
03241 
03242    rpt_mutex_lock(&myrpt->lock);
03243 
03244    if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE)
03245    {
03246       rpt_vars[thisRpt].cmdAction.state = CMD_STATE_BUSY;
03247       rpt_vars[thisRpt].cmdAction.functionNumber = thisAction;
03248       strncpy(rpt_vars[thisRpt].cmdAction.param, argv[4], MAXDTMF);
03249       strncpy(rpt_vars[thisRpt].cmdAction.digits, argv[5], MAXDTMF);
03250       rpt_vars[thisRpt].cmdAction.command_source = SOURCE_RPT;
03251       rpt_vars[thisRpt].cmdAction.state = CMD_STATE_READY;
03252    } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
03253    else
03254    {
03255       busy = 1;
03256    } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
03257    rpt_mutex_unlock(&myrpt->lock);
03258 
03259    return (busy ? RESULT_FAILURE : RESULT_SUCCESS);
03260 } /* rpt_do_cmd() */
03261 
03262 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
03263 {
03264    int res;
03265 
03266         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
03267                 return res;
03268                                                                                                                                             
03269         while(chan->generatordata) {
03270       if (ast_safe_sleep(chan,1)) return -1;
03271    }
03272 
03273         return 0;
03274 }
03275 
03276 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
03277 {
03278    return play_tone_pair(chan, freq, 0, duration, amplitude);
03279 }
03280 
03281 static int play_silence(struct ast_channel *chan, int duration)
03282 {
03283    return play_tone_pair(chan, 0, 0, duration, 0);
03284 }
03285 
03286 #ifdef   NEW_ASTERISK
03287 
03288 static char *res2cli(int r)
03289 
03290 {
03291    switch (r)
03292    {
03293        case RESULT_SUCCESS:
03294       return(CLI_SUCCESS);
03295        case RESULT_SHOWUSAGE:
03296       return(CLI_SHOWUSAGE);
03297        default:
03298       return(CLI_FAILURE);
03299    }
03300 }
03301 
03302 static char *handle_cli_debug(struct ast_cli_entry *e,
03303    int cmd, struct ast_cli_args *a)
03304 {
03305         switch (cmd) {
03306         case CLI_INIT:
03307                 e->command = "rpt debug level";
03308                 e->usage = debug_usage;
03309                 return NULL;
03310         case CLI_GENERATE:
03311                 return NULL;
03312    }
03313    return res2cli(rpt_do_debug(a->fd, a->argc, a->argv));
03314 }
03315 
03316 static char *handle_cli_dump(struct ast_cli_entry *e,
03317    int cmd, struct ast_cli_args *a)
03318 {
03319         switch (cmd) {
03320         case CLI_INIT:
03321                 e->command = "rpt dump level";
03322                 e->usage = dump_usage;
03323                 return NULL;
03324         case CLI_GENERATE:
03325                 return NULL;
03326    }
03327    return res2cli(rpt_do_dump(a->fd,a->argc,a->argv));
03328 }
03329 
03330 
03331 static char *handle_cli_stats(struct ast_cli_entry *e,
03332    int cmd, struct ast_cli_args *a)
03333 {
03334         switch (cmd) {
03335         case CLI_INIT:
03336                 e->command = "rpt stats";
03337                 e->usage = dump_stats;
03338                 return NULL;
03339         case CLI_GENERATE:
03340                 return NULL;
03341    }
03342    return res2cli(rpt_do_stats(a->fd,a->argc,a->argv));
03343 }
03344 
03345 static char *handle_cli_nodes(struct ast_cli_entry *e,
03346    int cmd, struct ast_cli_args *a)
03347 {
03348         switch (cmd) {
03349         case CLI_INIT:
03350                 e->command = "rpt nodes";
03351                 e->usage = dump_nodes;
03352                 return NULL;
03353         case CLI_GENERATE:
03354                 return NULL;
03355    }
03356    return res2cli(rpt_do_nodes(a->fd,a->argc,a->argv));
03357 }
03358 
03359 static char *handle_cli_local_nodes(struct ast_cli_entry *e,
03360    int cmd, struct ast_cli_args *a)
03361 {
03362         switch (cmd) {
03363         case CLI_INIT:
03364                 e->command = "rpt localnodes";
03365                 e->usage = usage_local_nodes;
03366                 return NULL;
03367         case CLI_GENERATE:
03368                 return NULL;
03369    }
03370    return res2cli(rpt_do_local_nodes(a->fd,a->argc,a->argv));
03371 }
03372 
03373 static char *handle_cli_lstats(struct ast_cli_entry *e,
03374    int cmd, struct ast_cli_args *a)
03375 {
03376         switch (cmd) {
03377         case CLI_INIT:
03378                 e->command = "rpt lstats";
03379                 e->usage = dump_lstats;
03380                 return NULL;
03381         case CLI_GENERATE:
03382                 return NULL;
03383    }
03384    return res2cli(rpt_do_lstats(a->fd,a->argc,a->argv));
03385 }
03386 
03387 static char *handle_cli_reload(struct ast_cli_entry *e,
03388    int cmd, struct ast_cli_args *a)
03389 {
03390         switch (cmd) {
03391         case CLI_INIT:
03392                 e->command = "rpt reload";
03393                 e->usage = reload_usage;
03394                 return NULL;
03395         case CLI_GENERATE:
03396                 return NULL;
03397    }
03398    return res2cli(rpt_do_reload(a->fd,a->argc,a->argv));
03399 }
03400 
03401 static char *handle_cli_restart(struct ast_cli_entry *e,
03402    int cmd, struct ast_cli_args *a)
03403 {
03404         switch (cmd) {
03405         case CLI_INIT:
03406                 e->command = "rpt restart";
03407                 e->usage = restart_usage;
03408                 return NULL;
03409         case CLI_GENERATE:
03410                 return NULL;
03411    }
03412    return res2cli(rpt_do_restart(a->fd,a->argc,a->argv));
03413 }
03414 
03415 static char *handle_cli_fun(struct ast_cli_entry *e,
03416    int cmd, struct ast_cli_args *a)
03417 {
03418         switch (cmd) {
03419         case CLI_INIT:
03420                 e->command = "rpt fun";
03421                 e->usage = fun_usage;
03422                 return NULL;
03423         case CLI_GENERATE:
03424                 return NULL;
03425    }
03426    return res2cli(rpt_do_fun(a->fd,a->argc,a->argv));
03427 }
03428 
03429 static char *handle_cli_fun1(struct ast_cli_entry *e,
03430    int cmd, struct ast_cli_args *a)
03431 {
03432         switch (cmd) {
03433         case CLI_INIT:
03434                 e->command = "rpt fun1";
03435                 e->usage = fun_usage;
03436                 return NULL;
03437         case CLI_GENERATE:
03438                 return NULL;
03439    }
03440    return res2cli(rpt_do_fun1(a->fd,a->argc,a->argv));
03441 }
03442 
03443 static char *handle_cli_cmd(struct ast_cli_entry *e,
03444    int cmd, struct ast_cli_args *a)
03445 {
03446         switch (cmd) {
03447         case CLI_INIT:
03448                 e->command = "rpt cmd";
03449                 e->usage = cmd_usage;
03450                 return NULL;
03451         case CLI_GENERATE:
03452                 return NULL;
03453    }
03454    return res2cli(rpt_do_cmd(a->fd,a->argc,a->argv));
03455 }
03456 
03457 static struct ast_cli_entry rpt_cli[] = {
03458    AST_CLI_DEFINE(handle_cli_debug,"Enable app_rpt debugging"),
03459    AST_CLI_DEFINE(handle_cli_dump,"Dump app_rpt structs for debugging"),
03460    AST_CLI_DEFINE(handle_cli_stats,"Dump node statistics"),
03461    AST_CLI_DEFINE(handle_cli_nodes,"Dump node list"),
03462    AST_CLI_DEFINE(handle_cli_local_nodes, "Dump list of local node numbers"),
03463    AST_CLI_DEFINE(handle_cli_lstats,"Dump link statistics"),
03464    AST_CLI_DEFINE(handle_cli_reload,"Reload app_rpt config"),
03465    AST_CLI_DEFINE(handle_cli_restart,"Restart app_rpt"),
03466    AST_CLI_DEFINE(handle_cli_fun,"Execute a DTMF function"),
03467    AST_CLI_DEFINE(handle_cli_fun1,"Execute a DTMF function"),
03468    AST_CLI_DEFINE(handle_cli_cmd,"Execute a DTMF function")
03469 };
03470 
03471 #endif
03472 
03473 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
03474 {
03475 
03476 static struct morse_bits mbits[] = {
03477       {0, 0}, /* SPACE */
03478       {0, 0}, 
03479       {6, 18},/* " */
03480       {0, 0},
03481       {7, 72},/* $ */
03482       {0, 0},
03483       {0, 0},
03484       {6, 30},/* ' */
03485       {5, 13},/* ( */
03486       {6, 29},/* ) */
03487       {0, 0},
03488       {5, 10},/* + */
03489       {6, 51},/* , */
03490       {6, 33},/* - */
03491       {6, 42},/* . */
03492       {5, 9}, /* / */
03493       {5, 31},/* 0 */
03494       {5, 30},/* 1 */
03495       {5, 28},/* 2 */
03496       {5, 24},/* 3 */
03497       {5, 16},/* 4 */
03498       {5, 0}, /* 5 */
03499       {5, 1}, /* 6 */
03500       {5, 3}, /* 7 */
03501       {5, 7}, /* 8 */
03502       {5, 15},/* 9 */
03503       {6, 7}, /* : */
03504       {6, 21},/* ; */
03505       {0, 0},
03506       {5, 33},/* = */
03507       {0, 0},
03508       {6, 12},/* ? */
03509       {0, 0},
03510          {2, 2}, /* A */
03511       {4, 1}, /* B */
03512       {4, 5}, /* C */
03513       {3, 1}, /* D */
03514       {1, 0}, /* E */
03515       {4, 4}, /* F */
03516       {3, 3}, /* G */
03517       {4, 0}, /* H */
03518       {2, 0}, /* I */
03519       {4, 14},/* J */
03520       {3, 5}, /* K */
03521       {4, 2}, /* L */
03522       {2, 3}, /* M */
03523       {2, 1}, /* N */
03524       {3, 7}, /* O */
03525       {4, 6}, /* P */
03526       {4, 11},/* Q */
03527       {3, 2}, /* R */
03528       {3, 0}, /* S */
03529       {1, 1}, /* T */
03530       {3, 4}, /* U */
03531       {4, 8}, /* V */
03532       {3, 6}, /* W */
03533       {4, 9}, /* X */
03534       {4, 13},/* Y */
03535       {4, 3}  /* Z */
03536    };
03537 
03538 
03539    int dottime;
03540    int dashtime;
03541    int intralettertime;
03542    int interlettertime;
03543    int interwordtime;
03544    int len, ddcomb;
03545    int res;
03546    int c;
03547    int i;
03548    int flags;
03549          
03550    res = 0;
03551    
03552    /* Approximate the dot time from the speed arg. */
03553    
03554    dottime = 900/speed;
03555    
03556    /* Establish timing releationships */
03557    
03558    dashtime = 3 * dottime;
03559    intralettertime = dottime;
03560    interlettertime = dottime * 4 ;
03561    interwordtime = dottime * 7;
03562    
03563    for(;(*string) && (!res); string++){
03564    
03565       c = *string;
03566       
03567       /* Convert lower case to upper case */
03568       
03569       if((c >= 'a') && (c <= 'z'))
03570          c -= 0x20;
03571       
03572       /* Can't deal with any char code greater than Z, skip it */
03573       
03574       if(c  > 'Z')
03575          continue;
03576       
03577       /* If space char, wait the inter word time */
03578                
03579       if(c == ' '){
03580          if(!res)
03581             res = play_silence(chan, interwordtime);
03582          continue;
03583       }
03584       
03585       /* Subtract out control char offset to match our table */
03586       
03587       c -= 0x20;
03588       
03589       /* Get the character data */
03590       
03591       len = mbits[c].len;
03592       ddcomb = mbits[c].ddcomb;
03593       
03594       /* Send the character */
03595       
03596       for(; len ; len--){
03597          if(!res)
03598             res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
03599          if(!res)
03600             res = play_silence(chan, intralettertime);
03601          ddcomb >>= 1;
03602       }
03603       
03604       /* Wait the interletter time */
03605       
03606       if(!res)
03607          res = play_silence(chan, interlettertime - intralettertime);
03608    }
03609    
03610    /* Wait for all the frames to be sent */
03611    
03612    if (!res) 
03613       res = ast_waitstream(chan, "");
03614    ast_stopstream(chan);
03615    
03616    /*
03617    * Wait for the DAHDI driver to physically write the tone blocks to the hardware
03618    */
03619 
03620    for(i = 0; i < 20 ; i++){
03621       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
03622       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
03623       if(flags & DAHDI_IOMUX_WRITEEMPTY)
03624          break;
03625       if( ast_safe_sleep(chan, 50)){
03626          res = -1;
03627          break;
03628       }
03629    }
03630 
03631    
03632    return res;
03633 }
03634 
03635 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
03636 {
03637    char *p,*stringp;
03638    char *tonesubset;
03639    int f1,f2;
03640    int duration;
03641    int amplitude;
03642    int res;
03643    int i;
03644    int flags;
03645    
03646    res = 0;
03647 
03648    if(!tonestring)
03649       return res;
03650    
03651    p = stringp = ast_strdup(tonestring);
03652 
03653    for(;tonestring;){
03654       tonesubset = strsep(&stringp,")");
03655       if(!tonesubset)
03656          break;
03657       if(sscanf(tonesubset,"(%30d,%30d,%30d,%30d", &f1, &f2, &duration, &amplitude) != 4)
03658          break;
03659       res = play_tone_pair(chan, f1, f2, duration, amplitude);
03660       if(res)
03661          break;
03662    }
03663    ast_free(p);
03664    if(!res)
03665       res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
03666    
03667    if (!res) 
03668       res = ast_waitstream(chan, "");
03669 
03670    ast_stopstream(chan);
03671 
03672    /*
03673    * Wait for the DAHDI driver to physically write the tone blocks to the hardware
03674    */
03675 
03676    for(i = 0; i < 20 ; i++){
03677       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
03678       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
03679       if(flags & DAHDI_IOMUX_WRITEEMPTY)
03680          break;
03681       if( ast_safe_sleep(chan, 50)){
03682          res = -1;
03683          break;
03684       }
03685    }
03686       
03687    return res;
03688       
03689 }
03690 
03691 static int sayfile(struct ast_channel *mychannel,char *fname)
03692 {
03693 int   res;
03694 
03695    res = ast_streamfile(mychannel, fname, mychannel->language);
03696    if (!res) 
03697       res = ast_waitstream(mychannel, "");
03698    else
03699        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03700    ast_stopstream(mychannel);
03701    return res;
03702 }
03703 
03704 static int saycharstr(struct ast_channel *mychannel,char *str)
03705 {
03706 int   res;
03707 
03708    res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
03709    if (!res) 
03710       res = ast_waitstream(mychannel, "");
03711    else
03712        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03713    ast_stopstream(mychannel);
03714    return res;
03715 }
03716 
03717 static int saynum(struct ast_channel *mychannel, int num)
03718 {
03719    int res;
03720    res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
03721    if(!res)
03722       res = ast_waitstream(mychannel, "");
03723    else
03724       ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03725    ast_stopstream(mychannel);
03726    return res;
03727 }
03728 
03729 /* say a node and nodename. Try to look in dir referred to by nodenames in
03730 config, and see if there's a custom node file to play, and if so, play it */
03731 
03732 static int saynode(struct rpt *myrpt, struct ast_channel *mychannel, char *name)
03733 {
03734 int   res;
03735 char  *val,fname[300];
03736 
03737    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "nodenames");
03738    if (!val) val = NODENAMES;
03739    snprintf(fname,sizeof(fname) - 1,"%s/%s",val,name);
03740    if (ast_fileexists(fname,NULL,mychannel->language) > 0)
03741       return(sayfile(mychannel,fname));
03742    res = sayfile(mychannel,"rpt/node");
03743    if (!res) 
03744       res = ast_say_character_str(mychannel,name,NULL,mychannel->language);
03745    return res;
03746 }
03747 
03748 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
03749 {
03750    int res;
03751    char c;
03752    
03753    static int morsespeed;
03754    static int morsefreq;
03755    static int morseampl;
03756    static int morseidfreq = 0;
03757    static int morseidampl;
03758    static char mcat[] = MORSE;
03759    
03760    res = 0;
03761    
03762    if(!morseidfreq){ /* Get the morse parameters if not already loaded */
03763       morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
03764          morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
03765          morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
03766       morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
03767       morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330); 
03768    }
03769    
03770    /* Is it a file, or a tone sequence? */
03771          
03772    if(entry[0] == '|'){
03773       c = entry[1];
03774       if((c >= 'a')&&(c <= 'z'))
03775          c -= 0x20;
03776    
03777       switch(c){
03778          case 'I': /* Morse ID */
03779             res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
03780             break;
03781          
03782          case 'M': /* Morse Message */
03783             res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
03784             break;
03785          
03786          case 'T': /* Tone sequence */
03787             res = send_tone_telemetry(chan, entry + 2);
03788             break;
03789          default:
03790             res = -1;
03791       }
03792    }
03793    else
03794       res = sayfile(chan, entry); /* File */
03795    return res;
03796 }
03797 
03798 /*
03799 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
03800 *
03801 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
03802 */
03803 
03804 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
03805 {
03806    
03807    int res;
03808    int i;
03809    char *entry;
03810    char *telemetry;
03811    char *telemetry_save;
03812 
03813    res = 0;
03814    telemetry_save = NULL;
03815    entry = NULL;
03816    
03817    /* Retrieve the section name for telemetry from the node section */
03818    telemetry = (char *) ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
03819    if(telemetry ){
03820       telemetry_save = ast_strdup(telemetry);
03821       if(!telemetry_save){
03822          ast_log(LOG_WARNING,"ast_strdup() failed in telem_lookup()\n");
03823          return res;
03824       }
03825       entry = (char *) ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
03826    }
03827    
03828    /* Try to look up the telemetry name */   
03829 
03830    if(!entry){
03831       /* Telemetry name wasn't found in the config file, use the default */
03832       for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
03833          if(!strcasecmp(tele_defs[i].name, name))
03834             entry = tele_defs[i].value;
03835       }
03836    }
03837    if(entry){  
03838       if(strlen(entry))
03839          if (chan) telem_any(myrpt,chan, entry);
03840    }
03841    else{
03842       res = -1;
03843    }
03844    ast_free(telemetry_save);
03845    return res;
03846 }
03847 
03848 /*
03849 * Retrieve a wait interval
03850 */
03851 
03852 static int get_wait_interval(struct rpt *myrpt, int type)
03853 {
03854         int interval;
03855         char *wait_times;
03856         char *wait_times_save;
03857                                                                                                                   
03858         wait_times_save = NULL;
03859         wait_times = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
03860                                                                                                                   
03861         if(wait_times){
03862                 wait_times_save = ast_strdup(wait_times);
03863                 if(!wait_times_save)
03864          return 0;
03865                 
03866         }
03867                                                                                                                   
03868         switch(type){
03869                 case DLY_TELEM:
03870                         if(wait_times)
03871                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
03872                         else
03873                                 interval = 1000;
03874                         break;
03875                                                                                                                   
03876                 case DLY_ID:
03877                         if(wait_times)
03878                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
03879                         else
03880                                 interval = 500;
03881                         break;
03882                                                                                                                   
03883                 case DLY_UNKEY:
03884                         if(wait_times)
03885                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",50,5000,1000);
03886                         else
03887                                 interval = 1000;
03888                         break;
03889                                                                                                                   
03890                 case DLY_LINKUNKEY:
03891                         if(wait_times)
03892                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "linkunkeywait",500,5000,1000);
03893                         else
03894                                 interval = 1000;
03895                         break;
03896                                                                                                                   
03897                 case DLY_CALLTERM:
03898                         if(wait_times)
03899                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
03900                         else
03901                                 interval = 1500;
03902                         break;
03903                                                                                                                   
03904                 case DLY_COMP:
03905                         if(wait_times)
03906                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "compwait",500,5000,200);
03907                         else
03908                                 interval = 200;
03909                         break;
03910                                                                                                                   
03911                 case DLY_PARROT:
03912                         if(wait_times)
03913                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "parrotwait",500,5000,200);
03914                         else
03915                                 interval = 200;
03916                         break;
03917                                                                                                                   
03918                 default:
03919          interval = 0;
03920          break;
03921         }
03922    ast_free(wait_times_save);
03923    return interval;
03924 }                                                                                                                  
03925 
03926 
03927 /*
03928 * Wait a configurable interval of time 
03929 */
03930 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
03931 {
03932    int interval;
03933    interval = get_wait_interval(myrpt, type);
03934    if(debug)
03935       ast_log(LOG_NOTICE,"Delay interval = %d\n", interval);
03936    if(interval)
03937       ast_safe_sleep(chan,interval);
03938    if(debug)
03939       ast_log(LOG_NOTICE,"Delay complete\n");
03940    return;
03941 }
03942 
03943 static int split_freq(char *mhz, char *decimals, char *freq);
03944 
03945 static void *rpt_tele_thread(void *this)
03946 {
03947 struct dahdi_confinfo ci;  /* conference info */
03948 int   res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
03949 struct   rpt_tele *mytele = (struct rpt_tele *)this;
03950 struct  rpt_tele *tlist;
03951 struct   rpt *myrpt;
03952 struct   rpt_link *l,*l1,linkbase;
03953 struct   ast_channel *mychannel;
03954 int vmajor, vminor, m;
03955 char *p,*ct,*ct_copy,*ident, *nodename,*cp;
03956 time_t t;
03957 #ifdef   NEW_ASTERISK
03958 struct ast_tm localtm;
03959 #else
03960 struct tm localtm;
03961 #endif
03962 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
03963 int   i,ns,rbimode;
03964 char mhz[MAXREMSTR];
03965 char decimals[MAXREMSTR];
03966 char  mystr[200];
03967 struct dahdi_params par;
03968 
03969 
03970    /* get a pointer to myrpt */
03971    myrpt = mytele->rpt;
03972 
03973    /* Snag copies of a few key myrpt variables */
03974    rpt_mutex_lock(&myrpt->lock);
03975    nodename = ast_strdup(myrpt->name);
03976    if(!nodename)
03977    {
03978        fprintf(stderr,"rpt:Sorry unable strdup nodename\n");
03979        rpt_mutex_lock(&myrpt->lock);
03980        remque((struct qelem *)mytele);
03981        ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03982        rpt_mutex_unlock(&myrpt->lock);
03983        ast_free(mytele);
03984        pthread_exit(NULL);
03985    }
03986 
03987    if (myrpt->p.ident){
03988       ident = ast_strdup(myrpt->p.ident);
03989          if(!ident)
03990       {
03991                  fprintf(stderr,"rpt:Sorry unable strdup ident\n");
03992          rpt_mutex_lock(&myrpt->lock);
03993                   remque((struct qelem *)mytele);
03994                   ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",
03995          __LINE__, mytele->mode); /*@@@@@@@@@@@*/
03996                   rpt_mutex_unlock(&myrpt->lock);
03997          ast_free(nodename);
03998                   ast_free(mytele);
03999                   pthread_exit(NULL);
04000          }
04001    }
04002    else
04003    {
04004       ident = "";
04005    }
04006    rpt_mutex_unlock(&myrpt->lock);
04007       
04008 
04009 
04010    /* allocate a pseudo-channel thru asterisk */
04011    mychannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
04012    if (!mychannel)
04013    {
04014       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
04015       rpt_mutex_lock(&myrpt->lock);
04016       remque((struct qelem *)mytele);
04017       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04018       rpt_mutex_unlock(&myrpt->lock);
04019       ast_free(nodename);
04020       ast_free(ident);
04021       ast_free(mytele);    
04022       pthread_exit(NULL);
04023    }
04024 #ifdef   AST_CDR_FLAG_POST_DISABLED
04025    if (mychannel->cdr) 
04026       ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
04027 #endif
04028    rpt_mutex_lock(&myrpt->lock);
04029    mytele->chan = mychannel;
04030    rpt_mutex_unlock(&myrpt->lock);
04031 
04032    while((mytele->mode != SETREMOTE) && (mytele->mode != UNKEY) &&
04033       (mytele->mode != LINKUNKEY))
04034    {  
04035                 rpt_mutex_lock(&myrpt->lock);
04036       if (!myrpt->active_telem)
04037       {
04038          myrpt->active_telem = mytele;
04039                    rpt_mutex_unlock(&myrpt->lock);
04040          break;
04041       }
04042                 rpt_mutex_unlock(&myrpt->lock);
04043       usleep(100000);
04044    }
04045 
04046    /* make a conference for the tx */
04047    ci.chan = 0;
04048    /* If the telemetry is only intended for a local audience, */
04049    /* only connect the ID audio to the local tx conference so */
04050    /* linked systems can't hear it */
04051    ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
04052       (mytele->mode == TAILMSG) || (mytele->mode == LINKUNKEY) || (mytele->mode == TIMEOUT) || 
04053       (mytele->mode == PARROT) || (mytele->mode == STATS_TIME_LOCAL)) ? 
04054          myrpt->txconf : myrpt->conf);
04055    ci.confmode = DAHDI_CONF_CONFANN;
04056    /* first put the channel on the conference in announce mode */
04057    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04058    {
04059       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04060       rpt_mutex_lock(&myrpt->lock);
04061       myrpt->active_telem = NULL;
04062       remque((struct qelem *)mytele);
04063       rpt_mutex_unlock(&myrpt->lock);
04064       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04065       ast_free(nodename);
04066       ast_free(ident);
04067       ast_free(mytele);    
04068       ast_hangup(mychannel);
04069       pthread_exit(NULL);
04070    }
04071    ast_stopstream(mychannel);
04072    switch(mytele->mode)
04073    {
04074        case ID:
04075        case ID1:
04076       /* wait a bit */
04077       wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
04078       res = telem_any(myrpt,mychannel, ident); 
04079       imdone=1;   
04080       break;
04081       
04082        case TAILMSG:
04083       res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language); 
04084       break;
04085       
04086        case IDTALKOVER:
04087          p = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
04088          if(p)
04089          res = telem_any(myrpt,mychannel, p); 
04090       imdone=1;   
04091          break;
04092             
04093        case PROC:
04094       /* wait a little bit longer */
04095       wait_interval(myrpt, DLY_TELEM, mychannel);
04096       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
04097       if(res < 0){ /* Then default message */
04098          res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
04099       }
04100       break;
04101        case TERM:
04102       /* wait a little bit longer */
04103       wait_interval(myrpt, DLY_CALLTERM, mychannel);
04104       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
04105       if(res < 0){ /* Then default message */
04106          res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
04107       }
04108       break;
04109        case COMPLETE:
04110       /* wait a little bit */
04111       wait_interval(myrpt, DLY_TELEM, mychannel);
04112       res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04113       break;
04114        case MACRO_NOTFOUND:
04115       /* wait a little bit */
04116       wait_interval(myrpt, DLY_TELEM, mychannel);
04117       res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
04118       break;
04119        case MACRO_BUSY:
04120       /* wait a little bit */
04121       wait_interval(myrpt, DLY_TELEM, mychannel);
04122       res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
04123       break;
04124        case UNKEY:
04125       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
04126          imdone = 1;
04127          break;
04128       }
04129          
04130       /*
04131       * Reset the Unkey to CT timer
04132       */
04133 
04134       x = get_wait_interval(myrpt, DLY_UNKEY);
04135       rpt_mutex_lock(&myrpt->lock);
04136       myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
04137       rpt_mutex_unlock(&myrpt->lock);
04138 
04139       /*
04140       * If there's one already queued, don't do another
04141       */
04142 
04143       tlist = myrpt->tele.next;
04144       unkeys_queued = 0;
04145                 if (tlist != &myrpt->tele)
04146                 {
04147                         rpt_mutex_lock(&myrpt->lock);
04148                         while(tlist != &myrpt->tele){
04149                                 if (tlist->mode == UNKEY) unkeys_queued++;
04150                                 tlist = tlist->next;
04151                         }
04152                         rpt_mutex_unlock(&myrpt->lock);
04153       }
04154       if( unkeys_queued > 1){
04155          imdone = 1;
04156          break;
04157       }
04158 
04159       /* Wait for the telemetry timer to expire */
04160       /* Periodically check the timer since it can be re-initialized above */
04161       while(myrpt->unkeytocttimer)
04162       {
04163          int ctint;
04164          if(myrpt->unkeytocttimer > 100)
04165             ctint = 100;
04166          else
04167             ctint = myrpt->unkeytocttimer;
04168          ast_safe_sleep(mychannel, ctint);
04169          rpt_mutex_lock(&myrpt->lock);
04170          if(myrpt->unkeytocttimer < ctint)
04171             myrpt->unkeytocttimer = 0;
04172          else
04173             myrpt->unkeytocttimer -= ctint;
04174          rpt_mutex_unlock(&myrpt->lock);
04175       }
04176    
04177       /*
04178       * Now, the carrier on the rptr rx should be gone. 
04179       * If it re-appeared, then forget about sending the CT
04180       */
04181       if(myrpt->keyed){
04182          imdone = 1;
04183          break;
04184       }
04185       
04186       rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
04187       myrpt->dailykerchunks++;
04188       myrpt->totalkerchunks++;
04189       rpt_mutex_unlock(&myrpt->lock);
04190    
04191       haslink = 0;
04192       hastx = 0;
04193       hasremote = 0;    
04194       l = myrpt->links.next;
04195       if (l != &myrpt->links)
04196       {
04197          rpt_mutex_lock(&myrpt->lock);
04198          while(l != &myrpt->links)
04199          {
04200             if (l->name[0] == '0')
04201             {
04202                l = l->next;
04203                continue;
04204             }
04205             haslink = 1;
04206             if (l->mode) {
04207                hastx++;
04208                if (l->isremote) hasremote++;
04209             }
04210             l = l->next;
04211          }
04212          rpt_mutex_unlock(&myrpt->lock);
04213       }
04214       if (haslink)
04215       {
04216 
04217          res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
04218          if(res)
04219             ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
04220          
04221       
04222          /* if in remote cmd mode, indicate it */
04223          if (myrpt->cmdnode[0])
04224          {
04225             ast_safe_sleep(mychannel,200);
04226             res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
04227             if(res)
04228                ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
04229             ast_stopstream(mychannel);
04230          }
04231       }
04232       else if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
04233          ct_copy = ast_strdup(ct);
04234          if(ct_copy)
04235          {
04236             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04237             ast_free(ct_copy);
04238          }
04239          else
04240             res = -1;
04241          if(res)
04242             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
04243       }  
04244       if (hasremote && (!myrpt->cmdnode[0]))
04245       {
04246          /* set for all to hear */
04247          ci.chan = 0;
04248          ci.confno = myrpt->conf;
04249          ci.confmode = DAHDI_CONF_CONFANN;
04250          /* first put the channel on the conference in announce mode */
04251          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04252          {
04253             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04254             rpt_mutex_lock(&myrpt->lock);
04255             myrpt->active_telem = NULL;
04256             remque((struct qelem *)mytele);
04257             rpt_mutex_unlock(&myrpt->lock);
04258             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04259             ast_free(nodename);
04260             ast_free(ident);
04261             ast_free(mytele);    
04262             ast_hangup(mychannel);
04263             pthread_exit(NULL);
04264          }
04265          if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
04266             ast_safe_sleep(mychannel,200);
04267             ct_copy = ast_strdup(ct);
04268             if(ct_copy)
04269             {
04270                res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04271                ast_free(ct_copy);
04272             }
04273             else
04274                res = -1;
04275       
04276             if(res)
04277                ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
04278          }  
04279       }
04280 #if   defined(_MDC_DECODE_H_) && defined(MDC_SAY_WHEN_DOING_CT)
04281       if (myrpt->lastunit)
04282       {
04283          char mystr[10];
04284 
04285          ast_safe_sleep(mychannel,200);
04286          /* set for all to hear */
04287          ci.chan = 0;
04288          ci.confno = myrpt->txconf;
04289          ci.confmode = DAHDI_CONF_CONFANN;
04290          /* first put the channel on the conference in announce mode */
04291          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04292          {
04293             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04294             rpt_mutex_lock(&myrpt->lock);
04295             myrpt->active_telem = NULL;
04296             remque((struct qelem *)mytele);
04297             rpt_mutex_unlock(&myrpt->lock);
04298             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04299             ast_free(nodename);
04300             ast_free(ident);
04301             ast_free(mytele);    
04302             ast_hangup(mychannel);
04303             pthread_exit(NULL);
04304          }
04305          sprintf(mystr,"%04x",myrpt->lastunit);
04306          myrpt->lastunit = 0;
04307          ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
04308          break;
04309       }
04310 #endif
04311       imdone = 1;
04312       break;
04313        case LINKUNKEY:
04314       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
04315          imdone = 1;
04316          break;
04317       }
04318          
04319       /*
04320       * Reset the Unkey to CT timer
04321       */
04322 
04323       x = get_wait_interval(myrpt, DLY_LINKUNKEY);
04324       mytele->mylink.linkunkeytocttimer = x; /* Must be protected as it is changed below */
04325 
04326       /*
04327       * If there's one already queued, don't do another
04328       */
04329 
04330       tlist = myrpt->tele.next;
04331       unkeys_queued = 0;
04332                 if (tlist != &myrpt->tele)
04333                 {
04334                         rpt_mutex_lock(&myrpt->lock);
04335                         while(tlist != &myrpt->tele){
04336                                 if (tlist->mode == LINKUNKEY) unkeys_queued++;
04337                                 tlist = tlist->next;
04338                         }
04339                         rpt_mutex_unlock(&myrpt->lock);
04340       }
04341       if( unkeys_queued > 1){
04342          imdone = 1;
04343          break;
04344       }
04345 
04346       /* Wait for the telemetry timer to expire */
04347       /* Periodically check the timer since it can be re-initialized above */
04348       while(mytele->mylink.linkunkeytocttimer)
04349       {
04350          int ctint;
04351          if(mytele->mylink.linkunkeytocttimer > 100)
04352             ctint = 100;
04353          else
04354             ctint = mytele->mylink.linkunkeytocttimer;
04355          ast_safe_sleep(mychannel, ctint);
04356          rpt_mutex_lock(&myrpt->lock);
04357          if(mytele->mylink.linkunkeytocttimer < ctint)
04358             mytele->mylink.linkunkeytocttimer = 0;
04359          else
04360             mytele->mylink.linkunkeytocttimer -= ctint;
04361          rpt_mutex_unlock(&myrpt->lock);
04362       }
04363    
04364       if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "linkunkeyct"))){ /* Unlinked Courtesy Tone */
04365          ct_copy = ast_strdup(ct);
04366          if(ct_copy){
04367             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04368             ast_free(ct_copy);
04369          }
04370          else
04371             res = -1;
04372          if(res)
04373             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
04374       }  
04375       imdone = 1;
04376       break;
04377        case REMDISC:
04378       /* wait a little bit */
04379       wait_interval(myrpt, DLY_TELEM, mychannel);
04380       l = myrpt->links.next;
04381       haslink = 0;
04382       /* don't report if a link for this one still on system */
04383       if (l != &myrpt->links)
04384       {
04385          rpt_mutex_lock(&myrpt->lock);
04386          while(l != &myrpt->links)
04387          {
04388             if (l->name[0] == '0')
04389             {
04390                l = l->next;
04391                continue;
04392             }
04393             if (!strcmp(l->name,mytele->mylink.name))
04394             {
04395                haslink = 1;
04396                break;
04397             }
04398             l = l->next;
04399          }
04400          rpt_mutex_unlock(&myrpt->lock);
04401       }
04402       if (haslink)
04403       {
04404          imdone = 1;
04405          break;
04406       }
04407       res = saynode(myrpt,mychannel,mytele->mylink.name);
04408       if (!res) 
04409           res = ast_streamfile(mychannel, ((mytele->mylink.hasconnected) ? 
04410          "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
04411       break;
04412        case REMALREADY:
04413       /* wait a little bit */
04414       wait_interval(myrpt, DLY_TELEM, mychannel);
04415       res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
04416       break;
04417        case REMNOTFOUND:
04418       /* wait a little bit */
04419       wait_interval(myrpt, DLY_TELEM, mychannel);
04420       res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
04421       break;
04422        case REMGO:
04423       /* wait a little bit */
04424       wait_interval(myrpt, DLY_TELEM, mychannel);
04425       res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
04426       break;
04427        case CONNECTED:
04428       /* wait a little bit */
04429       wait_interval(myrpt, DLY_TELEM,  mychannel);
04430       res = saynode(myrpt,mychannel,mytele->mylink.name);
04431       if (!res)
04432           res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
04433       if (!res) 
04434          res = ast_waitstream(mychannel, "");
04435       else
04436           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04437       ast_stopstream(mychannel);
04438       res = ast_streamfile(mychannel, "digits/2", mychannel->language);
04439       if (!res) 
04440          res = ast_waitstream(mychannel, "");
04441       else
04442           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04443       ast_stopstream(mychannel);
04444       res = saynode(myrpt,mychannel,myrpt->name);
04445       imdone = 1;
04446       break;
04447        case CONNFAIL:
04448       res = saynode(myrpt,mychannel,mytele->mylink.name);
04449       if (!res) 
04450           res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
04451       break;
04452        case MEMNOTFOUND:
04453       /* wait a little bit */
04454       wait_interval(myrpt, DLY_TELEM, mychannel);
04455       res = ast_streamfile(mychannel, "rpt/memory_notfound", mychannel->language);
04456       break;
04457        case PLAYBACK:
04458       /* wait a little bit */
04459       wait_interval(myrpt, DLY_TELEM, mychannel);
04460       res = ast_streamfile(mychannel, mytele->param, mychannel->language);
04461       break;
04462        case TOPKEY:
04463       /* wait a little bit */
04464       wait_interval(myrpt, DLY_TELEM, mychannel);
04465       for(i = 0; i < TOPKEYN; i++)
04466       {
04467          if (!myrpt->topkey[i].node[0]) continue;
04468          if ((!myrpt->topkeylong) && (myrpt->topkey[i].keyed)) continue;
04469          res = saynode(myrpt, mychannel,  myrpt->topkey[i].node);
04470          if (!res) res = sayfile(mychannel,(myrpt->topkey[i].keyed) ?
04471             "rpt/keyedfor" : "rpt/unkeyedfor");
04472          if (!res) res = saynum(mychannel,
04473             myrpt->topkey[i].timesince);
04474          if (!res) res = sayfile(mychannel,"rpt/seconds");
04475          if (!myrpt->topkeylong) break;
04476       }
04477       imdone = 1;
04478       break;
04479        case SETREMOTE:
04480       ast_mutex_lock(&myrpt->remlock);
04481       res = 0;
04482       if(!strcmp(myrpt->remoterig, remote_rig_ft897))
04483       {
04484          res = set_ft897(myrpt);
04485       }
04486       else if(!strcmp(myrpt->remoterig, remote_rig_tm271))
04487       {
04488          res = set_tm271(myrpt);
04489       }
04490       else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
04491       {
04492          res = set_ic706(myrpt);
04493       }
04494 #ifdef HAVE_IOPERM
04495       else if(!strcmp(myrpt->remoterig, remote_rig_rbi)||!strcmp(myrpt->remoterig, remote_rig_ppp16))
04496       {
04497          if (ioperm(myrpt->p.iobase,1,1) == -1)
04498          {
04499             rpt_mutex_unlock(&myrpt->lock);
04500             ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
04501             res = -1;
04502          }
04503          else res = setrbi(myrpt);
04504       }
04505 #endif
04506       else if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
04507       {
04508          if (myrpt->iofd >= 0) setdtr(myrpt->iofd,1);
04509          res = setkenwood(myrpt);
04510          if (myrpt->iofd >= 0) setdtr(myrpt->iofd,0);
04511          if (ast_safe_sleep(mychannel,200) == -1)
04512          {
04513             ast_mutex_unlock(&myrpt->remlock);
04514             res = -1;
04515             break;
04516          }
04517          if (myrpt->iofd < 0)
04518          {
04519             i = DAHDI_FLUSH_EVENT;
04520             if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_FLUSH,&i) == -1)
04521             {
04522                ast_mutex_unlock(&myrpt->remlock);
04523                ast_log(LOG_ERROR,"Cant flush events");
04524                res = -1;
04525                break;
04526             }
04527             if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_GET_PARAMS,&par) == -1)
04528             {
04529                ast_mutex_unlock(&myrpt->remlock);
04530                ast_log(LOG_ERROR,"Cant get params");
04531                res = -1;
04532                break;
04533             }
04534             myrpt->remoterx = 
04535                (par.rxisoffhook || (myrpt->tele.next != &myrpt->tele));
04536          }
04537       }
04538 
04539       ast_mutex_unlock(&myrpt->remlock);
04540       if (!res)
04541       {
04542          imdone = 1;
04543          break;
04544       }
04545       /* fall thru to invalid freq */
04546        case INVFREQ:
04547       /* wait a little bit */
04548       wait_interval(myrpt, DLY_TELEM, mychannel);
04549       res = ast_streamfile(mychannel, "rpt/invalid-freq", mychannel->language);
04550       break;
04551        case REMMODE:
04552       cp = 0;
04553       wait_interval(myrpt, DLY_TELEM, mychannel);
04554       switch(myrpt->remmode)
04555       {
04556           case REM_MODE_FM:
04557          saycharstr(mychannel,"FM");
04558          break;
04559           case REM_MODE_USB:
04560          saycharstr(mychannel,"USB");
04561          break;
04562           case REM_MODE_LSB:
04563          saycharstr(mychannel,"LSB");
04564          break;
04565           case REM_MODE_AM:
04566          saycharstr(mychannel,"AM");
04567          break;
04568       }
04569       wait_interval(myrpt, DLY_COMP, mychannel);
04570       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04571       break;
04572        case LOGINREQ:
04573       wait_interval(myrpt, DLY_TELEM, mychannel);
04574       sayfile(mychannel,"rpt/login");
04575       saycharstr(mychannel,myrpt->name);
04576       break;
04577        case REMLOGIN:
04578       wait_interval(myrpt, DLY_TELEM, mychannel);
04579       saycharstr(mychannel,myrpt->loginuser);
04580       saynode(myrpt,mychannel,myrpt->name);
04581       wait_interval(myrpt, DLY_COMP, mychannel);
04582       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04583       break;
04584        case REMXXX:
04585       wait_interval(myrpt, DLY_TELEM, mychannel);
04586       res = 0;
04587       switch(mytele->submode)
04588       {
04589           case 100: /* RX PL Off */
04590          sayfile(mychannel, "rpt/rxpl");
04591          sayfile(mychannel, "rpt/off");
04592          break;
04593           case 101: /* RX PL On */
04594          sayfile(mychannel, "rpt/rxpl");
04595          sayfile(mychannel, "rpt/on");
04596          break;
04597           case 102: /* TX PL Off */
04598          sayfile(mychannel, "rpt/txpl");
04599          sayfile(mychannel, "rpt/off");
04600          break;
04601           case 103: /* TX PL On */
04602          sayfile(mychannel, "rpt/txpl");
04603          sayfile(mychannel, "rpt/on");
04604          break;
04605           case 104: /* Low Power */
04606          sayfile(mychannel, "rpt/lopwr");
04607          break;
04608           case 105: /* Medium Power */
04609          sayfile(mychannel, "rpt/medpwr");
04610          break;
04611           case 106: /* Hi Power */
04612          sayfile(mychannel, "rpt/hipwr");
04613          break;
04614           case 113: /* Scan down slow */
04615          sayfile(mychannel,"rpt/down");
04616          sayfile(mychannel, "rpt/slow");
04617          break;
04618           case 114: /* Scan down quick */
04619          sayfile(mychannel,"rpt/down");
04620          sayfile(mychannel, "rpt/quick");
04621          break;
04622           case 115: /* Scan down fast */
04623          sayfile(mychannel,"rpt/down");
04624          sayfile(mychannel, "rpt/fast");
04625          break;
04626           case 116: /* Scan up slow */
04627          sayfile(mychannel,"rpt/up");
04628          sayfile(mychannel, "rpt/slow");
04629          break;
04630           case 117: /* Scan up quick */
04631          sayfile(mychannel,"rpt/up");
04632          sayfile(mychannel, "rpt/quick");
04633          break;
04634           case 118: /* Scan up fast */
04635          sayfile(mychannel,"rpt/up");
04636          sayfile(mychannel, "rpt/fast");
04637          break;
04638           default:
04639          res = -1;
04640       }
04641       wait_interval(myrpt, DLY_COMP, mychannel);
04642       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04643       break;
04644        case SCAN:
04645       ast_mutex_lock(&myrpt->remlock);
04646       if (myrpt->hfscanstop)
04647       {
04648          myrpt->hfscanstatus = 0;
04649          myrpt->hfscanmode = 0;
04650          myrpt->hfscanstop = 0;
04651          mytele->mode = SCANSTAT;
04652          ast_mutex_unlock(&myrpt->remlock);
04653          if (ast_safe_sleep(mychannel,1000) == -1) break;
04654          sayfile(mychannel, "rpt/stop"); 
04655          imdone = 1;
04656          break;
04657       }
04658       if (myrpt->hfscanstatus > -2) service_scan(myrpt);
04659       i = myrpt->hfscanstatus;
04660       myrpt->hfscanstatus = 0;
04661       if (i) mytele->mode = SCANSTAT;
04662       ast_mutex_unlock(&myrpt->remlock);
04663       if (i < 0) sayfile(mychannel, "rpt/stop"); 
04664       else if (i > 0) saynum(mychannel,i);
04665       imdone = 1;
04666       break;
04667        case TUNE:
04668       ast_mutex_lock(&myrpt->remlock);
04669       if (!strcmp(myrpt->remoterig,remote_rig_ic706))
04670       {
04671          set_mode_ic706(myrpt, REM_MODE_AM);
04672          if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
04673          ast_safe_sleep(mychannel,500);
04674          set_mode_ic706(myrpt, myrpt->remmode);
04675          myrpt->tunerequest = 0;
04676          ast_mutex_unlock(&myrpt->remlock);
04677          imdone = 1;
04678          break;
04679       }
04680       set_mode_ft897(myrpt, REM_MODE_AM);
04681       simple_command_ft897(myrpt, 8);
04682       if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
04683       simple_command_ft897(myrpt, 0x88);
04684       ast_safe_sleep(mychannel,500);
04685       set_mode_ft897(myrpt, myrpt->remmode);
04686       myrpt->tunerequest = 0;
04687       ast_mutex_unlock(&myrpt->remlock);
04688       imdone = 1;
04689       break;
04690        case REMSHORTSTATUS:
04691        case REMLONGSTATUS: 
04692       wait_interval(myrpt, DLY_TELEM, mychannel);
04693       res = saynode(myrpt,mychannel,myrpt->name);
04694       if(!res)
04695          res = sayfile(mychannel,"rpt/frequency");
04696       if(!res)
04697          res = split_freq(mhz, decimals, myrpt->freq);
04698       if (!multimode_capable(myrpt)) decimals[3] = 0;
04699       if(!res){
04700          m = atoi(mhz);
04701          if(m < 100)
04702             res = saynum(mychannel, m);
04703          else
04704             res = saycharstr(mychannel, mhz);
04705       }
04706       if(!res)
04707          res = sayfile(mychannel, "letters/dot");
04708       if(!res)
04709          res = saycharstr(mychannel, decimals);
04710    
04711       if(res)  break;
04712       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
04713          switch(myrpt->offset){
04714    
04715             case REM_MINUS:
04716                res = sayfile(mychannel,"rpt/minus");
04717                break;
04718             
04719             case REM_SIMPLEX:
04720                res = sayfile(mychannel,"rpt/simplex");
04721                break;
04722                
04723             case REM_PLUS:
04724                res = sayfile(mychannel,"rpt/plus");
04725                break;
04726                
04727             default:
04728                break;
04729          }
04730       }
04731       else{ /* Must be USB, LSB, or AM */
04732          switch(myrpt->remmode){
04733 
04734             case REM_MODE_USB:
04735                res = saycharstr(mychannel, "USB");
04736                break;
04737 
04738             case REM_MODE_LSB:
04739                res = saycharstr(mychannel, "LSB");
04740                break;
04741 
04742             case REM_MODE_AM:
04743                res = saycharstr(mychannel, "AM");
04744                break;
04745 
04746 
04747             default:
04748                break;
04749          }
04750       }
04751 
04752       if (res == -1) break;
04753 
04754       if(mytele->mode == REMSHORTSTATUS){ /* Short status? */
04755          wait_interval(myrpt, DLY_COMP, mychannel);
04756          if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04757          break;
04758       }
04759 
04760       if (strcmp(myrpt->remoterig,remote_rig_ic706))
04761       {
04762          switch(myrpt->powerlevel){
04763 
04764             case REM_LOWPWR:
04765                res = sayfile(mychannel,"rpt/lopwr") ;
04766                break;
04767             case REM_MEDPWR:
04768                res = sayfile(mychannel,"rpt/medpwr");
04769                break;
04770             case REM_HIPWR:
04771                res = sayfile(mychannel,"rpt/hipwr"); 
04772                break;
04773             }
04774       }
04775 
04776       rbimode = ((!strncmp(myrpt->remoterig,remote_rig_rbi,3))
04777         || (!strncmp(myrpt->remoterig,remote_rig_ic706,3)));
04778       if (res || (sayfile(mychannel,"rpt/rxpl") == -1)) break;
04779       if (rbimode && (sayfile(mychannel,"rpt/txpl") == -1)) break;
04780       if ((sayfile(mychannel,"rpt/frequency") == -1) ||
04781          (saycharstr(mychannel,myrpt->rxpl) == -1)) break;
04782       if ((!rbimode) && ((sayfile(mychannel,"rpt/txpl") == -1) ||
04783          (sayfile(mychannel,"rpt/frequency") == -1) ||
04784          (saycharstr(mychannel,myrpt->txpl) == -1))) break;
04785       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
04786          if ((sayfile(mychannel,"rpt/rxpl") == -1) ||
04787             (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1) ||
04788             (sayfile(mychannel,"rpt/txpl") == -1) ||
04789             (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1))
04790             {
04791                break;
04792             }
04793       }
04794       wait_interval(myrpt, DLY_COMP, mychannel);
04795       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04796       break;
04797        case STATUS:
04798       /* wait a little bit */
04799       wait_interval(myrpt, DLY_TELEM, mychannel);
04800       hastx = 0;
04801       linkbase.next = &linkbase;
04802       linkbase.prev = &linkbase;
04803       rpt_mutex_lock(&myrpt->lock);
04804       /* make our own list of links */
04805       l = myrpt->links.next;
04806       while(l != &myrpt->links)
04807       {
04808          if (l->name[0] == '0')
04809          {
04810             l = l->next;
04811             continue;
04812          }
04813          l1 = ast_malloc(sizeof(struct rpt_link));
04814          if (!l1)
04815          {
04816             ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
04817             remque((struct qelem *)mytele);
04818             myrpt->active_telem = NULL;
04819             rpt_mutex_unlock(&myrpt->lock);
04820             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04821             ast_free(nodename);
04822             ast_free(ident);
04823             ast_free(mytele);    
04824             ast_hangup(mychannel);
04825             pthread_exit(NULL);
04826          }
04827          memcpy(l1,l,sizeof(struct rpt_link));
04828          l1->next = l1->prev = NULL;
04829          insque((struct qelem *)l1,(struct qelem *)linkbase.next);
04830          l = l->next;
04831       }
04832       rpt_mutex_unlock(&myrpt->lock);
04833       res = saynode(myrpt,mychannel,myrpt->name);
04834       if (myrpt->callmode)
04835       {
04836          hastx = 1;
04837          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
04838          if (!res) 
04839             res = ast_waitstream(mychannel, "");
04840          else
04841              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04842          ast_stopstream(mychannel);
04843       }
04844       l = linkbase.next;
04845       while(l != &linkbase)
04846       {
04847          char *s;
04848 
04849          hastx = 1;
04850          res = saynode(myrpt,mychannel,l->name);
04851          s = "rpt/tranceive";
04852          if (!l->mode) s = "rpt/monitor";
04853          if (!l->thisconnected) s = "rpt/connecting";
04854          res = ast_streamfile(mychannel, s, mychannel->language);
04855          if (!res) 
04856             res = ast_waitstream(mychannel, "");
04857          else
04858             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04859          ast_stopstream(mychannel);
04860          l = l->next;
04861       }        
04862       if (!hastx)
04863       {
04864          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
04865          if (!res) 
04866             res = ast_waitstream(mychannel, "");
04867          else
04868              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04869          ast_stopstream(mychannel);
04870       }
04871       /* destroy our local link queue */
04872       l = linkbase.next;
04873       while(l != &linkbase)
04874       {
04875          l1 = l;
04876          l = l->next;
04877          remque((struct qelem *)l1);
04878          ast_free(l1);
04879       }        
04880       imdone = 1;
04881       break;
04882        case FULLSTATUS:
04883       rpt_mutex_lock(&myrpt->lock);
04884       /* get all the nodes */
04885       __mklinklist(myrpt,NULL,lbuf);
04886       rpt_mutex_unlock(&myrpt->lock);
04887       /* parse em */
04888       ns = finddelim(lbuf,strs,MAXLINKLIST);
04889       /* sort em */
04890       if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
04891       /* wait a little bit */
04892       wait_interval(myrpt, DLY_TELEM, mychannel);
04893       hastx = 0;
04894       res = saynode(myrpt,mychannel,myrpt->name);
04895       if (myrpt->callmode)
04896       {
04897          hastx = 1;
04898          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
04899          if (!res) 
04900             res = ast_waitstream(mychannel, "");
04901          else
04902              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04903          ast_stopstream(mychannel);
04904       }
04905       /* go thru all the nodes in list */
04906       for(i = 0; i < ns; i++)
04907       {
04908          char *s,mode = 'T';
04909 
04910          /* if a mode spec at first, handle it */
04911          if ((*strs[i] < '0') || (*strs[i] > '9'))
04912          {
04913             mode = *strs[i];
04914             strs[i]++;
04915          }
04916 
04917          hastx = 1;
04918          res = saynode(myrpt,mychannel,strs[i]);
04919          s = "rpt/tranceive";
04920          if (mode == 'R') s = "rpt/monitor";
04921          if (mode == 'C') s = "rpt/connecting";
04922          res = ast_streamfile(mychannel, s, mychannel->language);
04923          if (!res) 
04924             res = ast_waitstream(mychannel, "");
04925          else
04926             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04927          ast_stopstream(mychannel);
04928       }        
04929       if (!hastx)
04930       {
04931          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
04932          if (!res) 
04933             res = ast_waitstream(mychannel, "");
04934          else
04935              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04936          ast_stopstream(mychannel);
04937       }
04938       imdone = 1;
04939       break;
04940 
04941        case LASTNODEKEY: /* Identify last node which keyed us up */
04942       rpt_mutex_lock(&myrpt->lock);
04943       if(myrpt->lastnodewhichkeyedusup){
04944          p = ast_strdup(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
04945          if(!p){
04946             ast_log(LOG_WARNING, "ast_strdup failed in telemetery LASTNODEKEY");
04947             imdone = 1;
04948             break;
04949          }
04950       }
04951       else
04952          p = NULL;
04953       rpt_mutex_unlock(&myrpt->lock);
04954       if(!p){
04955          imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
04956          break;
04957       }
04958       wait_interval(myrpt, DLY_TELEM, mychannel);
04959       res = saynode(myrpt,mychannel,p);
04960       ast_free(p);
04961       imdone = 1;
04962       break;      
04963 
04964        case UNAUTHTX: /* Say unauthorized transmit frequency */
04965       wait_interval(myrpt, DLY_TELEM, mychannel);
04966       res = ast_streamfile(mychannel, "rpt/unauthtx", mychannel->language);
04967       if (!res) 
04968          res = ast_waitstream(mychannel, "");
04969       else
04970           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04971       ast_stopstream(mychannel);
04972       imdone = 1;
04973       break;
04974 
04975        case PARROT: /* Repeat stuff */
04976 
04977       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04978       if (ast_fileexists(mystr,NULL,mychannel->language) <= 0)
04979       {
04980          imdone = 1;
04981          myrpt->parrotstate = 0;
04982          break;
04983       }
04984       wait_interval(myrpt, DLY_PARROT, mychannel);
04985       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04986       res = ast_streamfile(mychannel, mystr, mychannel->language);
04987       if (!res) 
04988          res = ast_waitstream(mychannel, "");
04989       else
04990           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04991       ast_stopstream(mychannel);
04992       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04993       strcat(mystr,".wav");
04994       unlink(mystr);       
04995       imdone = 1;
04996       myrpt->parrotstate = 0;
04997       break;
04998 
04999        case TIMEOUT:
05000       res = saynode(myrpt,mychannel,myrpt->name);
05001       if (!res)
05002          res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
05003       break;
05004       
05005        case TIMEOUT_WARNING:
05006       time(&t);
05007       res = saynode(myrpt,mychannel,myrpt->name);
05008       if (!res)
05009          res = ast_streamfile(mychannel, "rpt/timeout-warning", mychannel->language);
05010       if (!res) 
05011          res = ast_waitstream(mychannel, "");
05012       else
05013           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05014       ast_stopstream(mychannel);
05015       if(!res) /* Say number of seconds */
05016          ast_say_number(mychannel, myrpt->p.remotetimeout - 
05017              (t - myrpt->last_activity_time), 
05018             "", mychannel->language, (char *) NULL);
05019       if (!res) 
05020          res = ast_waitstream(mychannel, "");
05021       ast_stopstream(mychannel); 
05022       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
05023       break;
05024 
05025        case ACT_TIMEOUT_WARNING:
05026       time(&t);
05027       res = saynode(myrpt,mychannel,myrpt->name);
05028       if (!res)
05029           res = ast_streamfile(mychannel, "rpt/act-timeout-warning", mychannel->language);
05030       if (!res) 
05031          res = ast_waitstream(mychannel, "");
05032       else
05033           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05034       ast_stopstream(mychannel);
05035       if(!res) /* Say number of seconds */
05036          ast_say_number(mychannel, myrpt->p.remoteinacttimeout - 
05037              (t - myrpt->last_activity_time), 
05038             "", mychannel->language, (char *) NULL);
05039       if (!res) 
05040          res = ast_waitstream(mychannel, "");
05041       ast_stopstream(mychannel); 
05042       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
05043       break;
05044       
05045        case STATS_TIME:
05046             case STATS_TIME_LOCAL:
05047          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05048       t = time(NULL);
05049       rpt_localtime(&t, &localtm);
05050       /* Say the phase of the day is before the time */
05051       if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
05052          p = "rpt/goodmorning";
05053       else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
05054          p = "rpt/goodafternoon";
05055       else
05056          p = "rpt/goodevening";
05057       if (sayfile(mychannel,p) == -1)
05058       {
05059          imdone = 1;
05060          break;
05061       }
05062       /* Say the time is ... */     
05063       if (sayfile(mychannel,"rpt/thetimeis") == -1)
05064       {
05065          imdone = 1;
05066          break;
05067       }
05068       /* Say the time */            
05069          res = ast_say_time(mychannel, t, "", mychannel->language);
05070       if (!res) 
05071          res = ast_waitstream(mychannel, "");
05072       ast_stopstream(mychannel);    
05073       imdone = 1;
05074          break;
05075        case STATS_VERSION:
05076       p = strstr(tdesc, "version"); 
05077       if(!p)
05078          break;   
05079       if(sscanf(p, "version %30d.%30d", &vmajor, &vminor) != 2)
05080          break;
05081          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05082       /* Say "version" */
05083       if (sayfile(mychannel,"rpt/version") == -1)
05084       {
05085          imdone = 1;
05086          break;
05087       }
05088       if(!res) /* Say "X" */
05089          ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
05090       if (!res) 
05091          res = ast_waitstream(mychannel, "");
05092       ast_stopstream(mychannel); 
05093       if (saycharstr(mychannel,".") == -1)
05094       {
05095          imdone = 1;
05096          break;
05097       }
05098       if(!res) /* Say "Y" */
05099          ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
05100       if (!res){
05101          res = ast_waitstream(mychannel, "");
05102          ast_stopstream(mychannel);
05103       }  
05104       else
05105           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05106       imdone = 1;
05107          break;
05108        case ARB_ALPHA:
05109          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05110          if(mytele->param)
05111             saycharstr(mychannel, mytele->param);
05112          imdone = 1;
05113       break;
05114        case REV_PATCH:
05115          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05116          if(mytele->param) {
05117 
05118          /* Parts of this section taken from app_parkandannounce */
05119          char *tpl_working, *tpl_current;
05120          char *tmp[100], *myparm;
05121          int looptemp=0,idx=0, dres = 0;
05122    
05123 
05124          tpl_working = ast_strdup(mytele->param);
05125          myparm = strsep(&tpl_working,",");
05126          tpl_current=strsep(&tpl_working, ":");
05127 
05128          while(tpl_current && looptemp < sizeof(tmp)) {
05129             tmp[looptemp]=tpl_current;
05130             looptemp++;
05131             tpl_current=strsep(&tpl_working,":");
05132          }
05133 
05134          for(idx=0; idx<looptemp; idx++) {
05135             if(!strcmp(tmp[idx], "PARKED")) {
05136                ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
05137             } else if(!strcmp(tmp[idx], "NODE")) {
05138                ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
05139             } else {
05140                dres = ast_streamfile(mychannel, tmp[idx], mychannel->language);
05141                if(!dres) {
05142                   dres = ast_waitstream(mychannel, "");
05143                } else {
05144                   ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[idx], mychannel->name);
05145                   dres = 0;
05146                }
05147             }
05148          }
05149          ast_free(tpl_working);
05150       }
05151          imdone = 1;
05152       break;
05153        case TEST_TONE:
05154       imdone = 1;
05155       if (myrpt->stopgen) break;
05156       myrpt->stopgen = -1;
05157            if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
05158       {
05159          myrpt->stopgen = 0;
05160          break;
05161       }
05162            while(mychannel->generatordata && (myrpt->stopgen <= 0)) {
05163          if (ast_safe_sleep(mychannel,1)) break;
05164             imdone = 1;
05165          }
05166       myrpt->stopgen = 0;
05167       break;
05168        default:
05169          break;
05170    }
05171    if (!imdone)
05172    {
05173       if (!res) 
05174          res = ast_waitstream(mychannel, "");
05175       else {
05176          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05177          res = 0;
05178       }
05179    }
05180    ast_stopstream(mychannel);
05181    rpt_mutex_lock(&myrpt->lock);
05182    if (mytele->mode == TAILMSG)
05183    {
05184       if (!res)
05185       {
05186          myrpt->tailmessagen++;
05187          if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
05188       }
05189       else
05190       {
05191          myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
05192       }
05193    }
05194    remque((struct qelem *)mytele);
05195    myrpt->active_telem = NULL;
05196    rpt_mutex_unlock(&myrpt->lock);
05197    ast_free(nodename);
05198    ast_free(ident);
05199    ast_free(mytele);    
05200    ast_hangup(mychannel);
05201 #ifdef  APP_RPT_LOCK_DEBUG
05202    {
05203       struct lockthread *t;
05204 
05205       sleep(5);
05206       ast_mutex_lock(&locklock);
05207       t = get_lockthread(pthread_self());
05208       if (t) memset(t,0,sizeof(struct lockthread));
05209       ast_mutex_unlock(&locklock);
05210    }        
05211 #endif
05212    pthread_exit(NULL);
05213 }
05214 
05215 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
05216 {
05217 struct rpt_tele *tele;
05218 struct rpt_link *mylink = NULL;
05219 int res;
05220 pthread_attr_t attr;
05221 char *v1, *v2;
05222 
05223    if(debug > 6)
05224       ast_log(LOG_NOTICE,"mode=%i  data=%s\n",mode, (char *)data);
05225 
05226    switch(mode)
05227    {
05228        case UNKEY:
05229       /* if any of the following are defined, go ahead and do it,
05230          otherwise, don't bother */
05231       v1 = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, 
05232          "unlinkedct");
05233       v2 = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, 
05234          "remotect");
05235       if (telem_lookup(myrpt,NULL, myrpt->name, "remotemon") &&
05236         telem_lookup(myrpt,NULL, myrpt->name, "remotetx") &&
05237         telem_lookup(myrpt,NULL, myrpt->name, "cmdmode") &&
05238         (!(v1 && telem_lookup(myrpt,NULL, myrpt->name, v1))) && 
05239         (!(v2 && telem_lookup(myrpt,NULL, myrpt->name, v2)))) return;
05240       break;
05241        case LINKUNKEY:
05242       if (!ast_variable_retrieve(myrpt->cfg, myrpt->name, "linkunkeyct"))
05243          return;
05244       break;
05245        default:
05246       break;
05247    }
05248    tele = ast_malloc(sizeof(struct rpt_tele));
05249    if (!tele)
05250    {
05251       ast_log(LOG_WARNING, "Unable to allocate memory\n");
05252       pthread_exit(NULL);
05253       return;
05254    }
05255    /* zero it out */
05256    memset((char *)tele,0,sizeof(struct rpt_tele));
05257    tele->rpt = myrpt;
05258    tele->mode = mode;
05259    if (mode == PARROT) tele->parrot = (uintptr_t) data;
05260    else mylink = (struct rpt_link *) data;
05261    rpt_mutex_lock(&myrpt->lock);
05262    if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED) ||
05263        (mode == LINKUNKEY)){
05264       memset(&tele->mylink,0,sizeof(struct rpt_link));
05265       if (mylink){
05266          memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
05267       }
05268    }
05269    else if ((mode == ARB_ALPHA) || (mode == REV_PATCH) || (mode == PLAYBACK)) {
05270       strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
05271       tele->param[TELEPARAMSIZE - 1] = 0;
05272    }
05273    if (mode == REMXXX) tele->submode = (intptr_t) data;
05274    insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
05275    rpt_mutex_unlock(&myrpt->lock);
05276         pthread_attr_init(&attr);
05277         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05278    res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
05279    if(res < 0){
05280       rpt_mutex_lock(&myrpt->lock);
05281       remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
05282       rpt_mutex_unlock(&myrpt->lock);  
05283       ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
05284    }
05285    return;
05286 }
05287 
05288 static void *rpt_call(void *this)
05289 {
05290 struct dahdi_confinfo ci;  /* conference info */
05291 struct   rpt *myrpt = (struct rpt *)this;
05292 int   res;
05293 int stopped,congstarted,dialtimer,lastcidx,aborted;
05294 struct ast_channel *mychannel,*genchannel;
05295 
05296    myrpt->mydtmf = 0;
05297    /* allocate a pseudo-channel thru asterisk */
05298    mychannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
05299    if (!mychannel)
05300    {
05301       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
05302       pthread_exit(NULL);
05303    }
05304 #ifdef   AST_CDR_FLAG_POST_DISABLED
05305    if (mychannel->cdr)
05306       ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
05307 #endif
05308    ci.chan = 0;
05309    ci.confno = myrpt->conf; /* use the pseudo conference */
05310 #if   0
05311    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
05312       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
05313 #endif
05314    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
05315    /* first put the channel on the conference */
05316    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05317    {
05318       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05319       ast_hangup(mychannel);
05320       myrpt->callmode = 0;
05321       pthread_exit(NULL);
05322    }
05323    /* allocate a pseudo-channel thru asterisk */
05324    genchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
05325    if (!genchannel)
05326    {
05327       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
05328       ast_hangup(mychannel);
05329       pthread_exit(NULL);
05330    }
05331 #ifdef   AST_CDR_FLAG_POST_DISABLED
05332    if (genchannel->cdr)
05333       ast_set_flag(genchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
05334 #endif
05335    ci.chan = 0;
05336    ci.confno = myrpt->conf;
05337    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
05338       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
05339    /* first put the channel on the conference */
05340    if (ioctl(genchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05341    {
05342       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05343       ast_hangup(mychannel);
05344       ast_hangup(genchannel);
05345       myrpt->callmode = 0;
05346       pthread_exit(NULL);
05347    }
05348    if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
05349    {
05350       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
05351       ast_hangup(mychannel);
05352       ast_hangup(genchannel);
05353       myrpt->callmode = 0;
05354       pthread_exit(NULL);
05355    }
05356    if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
05357    {
05358       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
05359       ast_hangup(mychannel);
05360       ast_hangup(genchannel);
05361       myrpt->callmode = 0;
05362       pthread_exit(NULL);
05363    }
05364    /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
05365    if ((!myrpt->patchquiet) && (tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_DIALTONE) < 0))
05366    {
05367       ast_log(LOG_WARNING, "Cannot start dialtone\n");
05368       ast_hangup(mychannel);
05369       ast_hangup(genchannel);
05370       myrpt->callmode = 0;
05371       pthread_exit(NULL);
05372    }
05373    stopped = 0;
05374    congstarted = 0;
05375    dialtimer = 0;
05376    lastcidx = 0;
05377    myrpt->calldigittimer = 0;
05378    aborted = 0;
05379 
05380    while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
05381    {
05382       if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
05383          dialtimer = 0;
05384          lastcidx = myrpt->cidx;
05385       }     
05386 
05387       if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){ 
05388           if(debug)
05389             ast_log(LOG_NOTICE, "dialtimer %i > patchdialtime %i\n", dialtimer,myrpt->patchdialtime);
05390          rpt_mutex_lock(&myrpt->lock);
05391          aborted = 1;
05392          myrpt->callmode = 0;
05393          rpt_mutex_unlock(&myrpt->lock);
05394          break;
05395       }
05396    
05397       if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
05398       {
05399          stopped = 1;
05400          /* stop dial tone */
05401          tone_zone_play_tone(genchannel->fds[0],-1);
05402       }
05403       if (myrpt->callmode == 1)
05404       {
05405          if(myrpt->calldigittimer > PATCH_DIALPLAN_TIMEOUT)
05406          {
05407             myrpt->callmode = 2;
05408             break;
05409          }
05410          /* bump timer if active */
05411          if (myrpt->calldigittimer) 
05412             myrpt->calldigittimer += MSWAIT;
05413       }
05414       if (myrpt->callmode == 4)
05415       {
05416          if(!congstarted){
05417             congstarted = 1;
05418             /* start congestion tone */
05419             tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
05420          }
05421       }
05422       res = ast_safe_sleep(mychannel, MSWAIT);
05423       if (res < 0)
05424       {
05425           if(debug)
05426             ast_log(LOG_NOTICE, "ast_safe_sleep=%i\n", res);
05427          ast_hangup(mychannel);
05428          ast_hangup(genchannel);
05429          rpt_mutex_lock(&myrpt->lock);
05430          myrpt->callmode = 0;
05431          rpt_mutex_unlock(&myrpt->lock);
05432          pthread_exit(NULL);
05433       }
05434       dialtimer += MSWAIT;
05435    }
05436    /* stop any tone generation */
05437    tone_zone_play_tone(genchannel->fds[0],-1);
05438    /* end if done */
05439    if (!myrpt->callmode)
05440    {
05441       if(debug)
05442          ast_log(LOG_NOTICE, "callmode==0\n");
05443       ast_hangup(mychannel);
05444       ast_hangup(genchannel);
05445       rpt_mutex_lock(&myrpt->lock);
05446       myrpt->callmode = 0;
05447       myrpt->macropatch=0;
05448       channel_revert(myrpt);
05449       rpt_mutex_unlock(&myrpt->lock);
05450       if((!myrpt->patchquiet) && aborted)
05451          rpt_telemetry(myrpt, TERM, NULL);
05452       pthread_exit(NULL);        
05453    }
05454 
05455    if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
05456       char *name, *loc, *instr;
05457       instr = ast_strdup(myrpt->p.ourcallerid);
05458       if(instr){
05459          ast_callerid_parse(instr, &name, &loc);
05460          if(loc){
05461             mychannel->caller.id.number.valid = 1;
05462             ast_free(mychannel->caller.id.number.str);
05463             mychannel->caller.id.number.str = ast_strdup(loc);
05464          }
05465          if(name){
05466             mychannel->caller.id.name.valid = 1;
05467             ast_free(mychannel->caller.id.name.str);
05468             mychannel->caller.id.name.str = ast_strdup(name);
05469          }
05470          ast_free(instr);
05471       }
05472    }
05473 
05474    ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
05475    ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
05476    
05477    if (myrpt->p.acctcode)
05478       ast_cdr_setaccount(mychannel,myrpt->p.acctcode);
05479    mychannel->priority = 1;
05480    ast_channel_undefer_dtmf(mychannel);
05481    if (ast_pbx_start(mychannel) < 0)
05482    {
05483       ast_log(LOG_WARNING, "Unable to start PBX!!\n");
05484       ast_hangup(mychannel);
05485       ast_hangup(genchannel);
05486       rpt_mutex_lock(&myrpt->lock);
05487       myrpt->callmode = 0;
05488       rpt_mutex_unlock(&myrpt->lock);
05489       pthread_exit(NULL);
05490    }
05491    usleep(10000);
05492    rpt_mutex_lock(&myrpt->lock);
05493    myrpt->callmode = 3;
05494    /* set appropriate conference for the pseudo */
05495    ci.chan = 0;
05496    ci.confno = myrpt->conf;
05497    ci.confmode = (myrpt->p.duplex == 2) ? DAHDI_CONF_CONFANNMON :
05498       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
05499    /* first put the channel on the conference in announce mode */
05500    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05501    {
05502       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05503       ast_hangup(mychannel);
05504       ast_hangup(genchannel);
05505       myrpt->callmode = 0;
05506       pthread_exit(NULL);
05507    }
05508    /* get its channel number */
05509    if (ioctl(mychannel->fds[0],DAHDI_CHANNO,&res) == -1)
05510    {
05511       ast_log(LOG_WARNING, "Unable to get autopatch channel number\n");
05512       ast_hangup(mychannel);
05513       myrpt->callmode = 0;
05514       pthread_exit(NULL);
05515    }
05516    ci.chan = 0;
05517    ci.confno = res;
05518    ci.confmode = DAHDI_CONF_MONITOR;
05519    /* put vox channel monitoring on the channel  */
05520    if (ioctl(myrpt->voxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05521    {
05522       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05523       ast_hangup(mychannel);
05524       myrpt->callmode = 0;
05525       pthread_exit(NULL);
05526    }
05527    while(myrpt->callmode)
05528    {
05529       if ((!mychannel->pbx) && (myrpt->callmode != 4))
05530       {
05531           /* If patch is setup for far end disconnect */
05532          if(myrpt->patchfarenddisconnect || (myrpt->p.duplex < 2)){ 
05533             if(debug)ast_log(LOG_NOTICE,"callmode=%i, patchfarenddisconnect=%i, duplex=%i\n",\
05534                   myrpt->callmode,myrpt->patchfarenddisconnect,myrpt->p.duplex);
05535             myrpt->callmode = 0;
05536             myrpt->macropatch=0;
05537             if(!myrpt->patchquiet){
05538                rpt_mutex_unlock(&myrpt->lock);
05539                rpt_telemetry(myrpt, TERM, NULL);
05540                rpt_mutex_lock(&myrpt->lock);
05541             }
05542          }
05543          else{ /* Send congestion until patch is downed by command */
05544             myrpt->callmode = 4;
05545             rpt_mutex_unlock(&myrpt->lock);
05546             /* start congestion tone */
05547             tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
05548             rpt_mutex_lock(&myrpt->lock);
05549          }
05550       }
05551       if (myrpt->mydtmf)
05552       {
05553          struct ast_frame wf = {AST_FRAME_DTMF, } ;
05554          wf.subclass.integer = myrpt->mydtmf;
05555          rpt_mutex_unlock(&myrpt->lock);
05556          ast_queue_frame(mychannel,&wf);
05557 #ifdef   NEW_ASTERISK
05558          ast_senddigit(genchannel,myrpt->mydtmf,0);
05559 #else
05560          ast_senddigit(genchannel,myrpt->mydtmf);
05561 #endif
05562          rpt_mutex_lock(&myrpt->lock);
05563          myrpt->mydtmf = 0;
05564       }
05565       rpt_mutex_unlock(&myrpt->lock);
05566       usleep(MSWAIT * 1000);
05567       rpt_mutex_lock(&myrpt->lock);
05568    }
05569    if(debug)
05570       ast_log(LOG_NOTICE, "exit channel loop\n");
05571    rpt_mutex_unlock(&myrpt->lock);
05572    tone_zone_play_tone(genchannel->fds[0],-1);
05573    if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
05574    ast_hangup(genchannel);
05575    rpt_mutex_lock(&myrpt->lock);
05576    myrpt->callmode = 0;
05577    myrpt->macropatch=0;
05578    channel_revert(myrpt);
05579    rpt_mutex_unlock(&myrpt->lock);
05580    /* set appropriate conference for the pseudo */
05581    ci.chan = 0;
05582    ci.confno = myrpt->conf;
05583    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
05584       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
05585    /* first put the channel on the conference in announce mode */
05586    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05587    {
05588       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05589    }
05590    pthread_exit(NULL);
05591 }
05592 
05593 static void send_link_dtmf(struct rpt *myrpt,char c)
05594 {
05595 char  str[300];
05596 struct   ast_frame wf;
05597 struct   rpt_link *l;
05598 
05599    snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
05600    wf.frametype = AST_FRAME_TEXT;
05601    wf.subclass.integer = 0;
05602    wf.offset = 0;
05603    wf.mallocd = 0;
05604    wf.datalen = strlen(str) + 1;
05605    wf.samples = 0;
05606    l = myrpt->links.next;
05607    /* first, see if our dude is there */
05608    while(l != &myrpt->links)
05609    {
05610       if (l->name[0] == '0') 
05611       {
05612          l = l->next;
05613          continue;
05614       }
05615       /* if we found it, write it and were done */
05616       if (!strcmp(l->name,myrpt->cmdnode))
05617       {
05618          wf.data.ptr = str;
05619          if (l->chan) ast_write(l->chan,&wf);
05620          return;
05621       }
05622       l = l->next;
05623    }
05624    l = myrpt->links.next;
05625    /* if not, give it to everyone */
05626    while(l != &myrpt->links)
05627    {
05628       wf.data.ptr = str;
05629       if (l->chan) ast_write(l->chan,&wf);
05630       l = l->next;
05631    }
05632    return;
05633 }
05634 
05635 static void send_link_keyquery(struct rpt *myrpt)
05636 {
05637 char  str[300];
05638 struct   ast_frame wf;
05639 struct   rpt_link *l;
05640 
05641    rpt_mutex_lock(&myrpt->lock);
05642    memset(myrpt->topkey,0,sizeof(myrpt->topkey));
05643    myrpt->topkeystate = 1;
05644    time(&myrpt->topkeytime);
05645    rpt_mutex_unlock(&myrpt->lock);
05646    snprintf(str, sizeof(str), "K? * %s 0 0", myrpt->name);
05647    wf.frametype = AST_FRAME_TEXT;
05648    wf.subclass.integer = 0;
05649    wf.offset = 0;
05650    wf.mallocd = 0;
05651    wf.datalen = strlen(str) + 1;
05652    wf.samples = 0;
05653    l = myrpt->links.next;
05654    /* give it to everyone */
05655    while(l != &myrpt->links)
05656    {
05657       wf.data.ptr = str;
05658       if (l->chan) ast_write(l->chan,&wf);
05659       l = l->next;
05660    }
05661    return;
05662 }
05663 
05664 /* send newkey request */
05665 
05666 static void send_newkey(struct ast_channel *chan)
05667 {
05668 
05669    /* ast_safe_sleep(chan,10); */
05670    ast_sendtext(chan,newkeystr);
05671    return;
05672 }
05673 
05674 
05675 /* 
05676  * Connect a link 
05677  *
05678  * Return values:
05679  * -2: Attempt to connect to self 
05680  * -1: No such node
05681  *  0: Success
05682  *  1: No match yet
05683  *  2: Already connected to this node
05684  */
05685 
05686 static int connect_link(struct rpt *myrpt, char* node, int mode, int perma)
05687 {
05688    char *val, *s, *s1, *s2, *tele;
05689    char lstr[MAXLINKLIST],*strs[MAXLINKLIST];
05690    char tmp[300], deststr[300] = "",modechange = 0;
05691    char sx[320],*sy;
05692    struct rpt_link *l;
05693    int reconnects = 0;
05694    int i,n;
05695    struct dahdi_confinfo ci;  /* conference info */
05696 
05697    val = node_lookup(myrpt,node);
05698    if (!val){
05699       if(strlen(node) >= myrpt->longestnode)
05700          return -1; /* No such node */
05701       return 1; /* No match yet */
05702    }
05703 
05704    if(!strcmp(myrpt->name,node)) /* Do not allow connections to self */
05705       return -2;
05706       
05707    if(debug > 3){
05708       ast_log(LOG_NOTICE,"Connect attempt to node %s\n", node);
05709       ast_log(LOG_NOTICE,"Mode: %s\n",(mode)?"Transceive":"Monitor");
05710       ast_log(LOG_NOTICE,"Connection type: %s\n",(perma)?"Permalink":"Normal");
05711    }
05712 
05713    strncpy(tmp,val,sizeof(tmp) - 1);
05714    s = tmp;
05715    s1 = strsep(&s,",");
05716    if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
05717    {
05718       sy = strchr(s1,'/');    
05719       *sy = 0;
05720       sprintf(sx,"%s:4569/%s",s1,sy + 1);
05721       s1 = sx;
05722    }
05723    s2 = strsep(&s,",");
05724    rpt_mutex_lock(&myrpt->lock);
05725    l = myrpt->links.next;
05726    /* try to find this one in queue */
05727    while(l != &myrpt->links){
05728       if (l->name[0] == '0') 
05729       {
05730          l = l->next;
05731          continue;
05732       }
05733    /* if found matching string */
05734       if (!strcmp(l->name, node))
05735          break;
05736       l = l->next;
05737    }
05738    /* if found */
05739    if (l != &myrpt->links){ 
05740    /* if already in this mode, just ignore */
05741       if ((l->mode) || (!l->chan)) {
05742          rpt_mutex_unlock(&myrpt->lock);
05743          return 2; /* Already linked */
05744       }
05745       reconnects = l->reconnects;
05746       rpt_mutex_unlock(&myrpt->lock);
05747       if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
05748       l->retries = l->max_retries + 1;
05749       l->disced = 2;
05750       modechange = 1;
05751    } else
05752    {
05753       __mklinklist(myrpt,NULL,lstr);
05754       rpt_mutex_unlock(&myrpt->lock);
05755       n = finddelim(lstr,strs,MAXLINKLIST);
05756       for(i = 0; i < n; i++)
05757       {
05758          if ((*strs[i] < '0') || 
05759              (*strs[i] > '9')) strs[i]++;
05760          if (!strcmp(strs[i],node))
05761          {
05762             return 2; /* Already linked */
05763          }
05764       }
05765    }
05766    strncpy(myrpt->lastlinknode,node,MAXNODESTR - 1);
05767    /* establish call */
05768    l = ast_malloc(sizeof(struct rpt_link));
05769    if (!l)
05770    {
05771       ast_log(LOG_WARNING, "Unable to malloc\n");
05772       return -1;
05773    }
05774    /* zero the silly thing */
05775    memset((char *)l,0,sizeof(struct rpt_link));
05776    l->mode = mode;
05777    l->outbound = 1;
05778    l->thisconnected = 0;
05779    voxinit_link(l,1);
05780    strncpy(l->name, node, MAXNODESTR - 1);
05781    l->isremote = (s && ast_true(s));
05782    if (modechange) l->connected = 1;
05783    l->hasconnected = l->perma = perma;
05784 #ifdef ALLOW_LOCAL_CHANNELS
05785    if ((strncasecmp(s1,"iax2/", 5) == 0) || (strncasecmp(s1, "local/", 6) == 0))
05786          strncpy(deststr, s1, sizeof(deststr));
05787    else
05788            snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
05789 #else
05790    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
05791 #endif
05792    tele = strchr(deststr, '/');
05793    if (!tele){
05794       ast_log(LOG_WARNING,"link3:Dial number (%s) must be in format tech/number\n",deststr);
05795       ast_free(l);
05796       return -1;
05797    }
05798    *tele++ = 0;
05799    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, NULL, tele, NULL);
05800    if (l->chan){
05801       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
05802       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
05803 #ifdef   AST_CDR_FLAG_POST_DISABLED
05804       if (l->chan->cdr)
05805          ast_set_flag(l->chan->cdr,AST_CDR_FLAG_POST_DISABLED);
05806 #endif
05807 #ifndef  NEW_ASTERISK
05808       l->chan->whentohangup = 0;
05809 #endif
05810       l->chan->appl = "Apprpt";
05811       l->chan->data = "(Remote Rx)";
05812       if (debug > 3)
05813          ast_log(LOG_NOTICE, "rpt (remote) initiating call to %s/%s on %s\n",
05814       deststr, tele, l->chan->name);
05815       l->chan->caller.id.number.valid = 1;
05816       ast_free(l->chan->caller.id.number.str);
05817       l->chan->caller.id.number.str = ast_strdup(myrpt->name);
05818       ast_call(l->chan,tele,999);
05819    }
05820    else {
05821       if(debug > 3) 
05822          ast_log(LOG_NOTICE, "Unable to place call to %s/%s on %s\n",
05823       deststr,tele,l->chan->name);
05824       if (myrpt->p.archivedir)
05825       {
05826          char str[100];
05827          sprintf(str,"LINKFAIL,%s",l->name);
05828          donodelog(myrpt,str);
05829       }
05830       ast_free(l);
05831       return -1;
05832    }
05833    /* allocate a pseudo-channel thru asterisk */
05834    l->pchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
05835    if (!l->pchan){
05836       ast_log(LOG_WARNING,"rpt connect: Sorry unable to obtain pseudo channel\n");
05837       ast_hangup(l->chan);
05838       ast_free(l);
05839       return -1;
05840    }
05841    ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
05842    ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
05843 #ifdef   AST_CDR_FLAG_POST_DISABLED
05844    if (l->pchan->cdr)
05845       ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
05846 #endif
05847    /* make a conference for the tx */
05848    ci.chan = 0;
05849    ci.confno = myrpt->conf;
05850    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
05851    /* first put the channel on the conference in proper mode */
05852    if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1)
05853    {
05854       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05855       ast_hangup(l->chan);
05856       ast_hangup(l->pchan);
05857       ast_free(l);
05858       return -1;
05859    }
05860    rpt_mutex_lock(&myrpt->lock);
05861    l->reconnects = reconnects;
05862    /* insert at end of queue */
05863    l->max_retries = MAX_RETRIES;
05864    if (perma)
05865       l->max_retries = MAX_RETRIES_PERM;
05866    if (l->isremote) l->retries = l->max_retries + 1;
05867    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
05868    __kickshort(myrpt);
05869    rpt_mutex_unlock(&myrpt->lock);
05870    if (!l->phonemode) send_newkey(l->chan);
05871    return 0;
05872 }
05873 
05874 
05875 
05876 /*
05877 * Internet linking function 
05878 */
05879 
05880 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
05881 {
05882 
05883    char *val, *s, *s1, *s2;
05884    char tmp[300];
05885    char digitbuf[MAXNODESTR],*strs[MAXLINKLIST];
05886    char mode,perma;
05887    char sx[320],*sy;
05888    struct rpt_link *l;
05889    int i,r;
05890 
05891    if(!param)
05892       return DC_ERROR;
05893       
05894          
05895    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable )
05896       return DC_ERROR;
05897 
05898    strncpy(digitbuf,digits,MAXNODESTR - 1);
05899 
05900    if(debug > 6)
05901       printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
05902       
05903    switch(myatoi(param)){
05904       case 11: /* Perm Link off */
05905       case 1: /* Link off */
05906          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
05907             strcpy(digitbuf,myrpt->lastlinknode);
05908          val = node_lookup(myrpt,digitbuf);
05909          if (!val){
05910             if(strlen(digitbuf) >= myrpt->longestnode)
05911                return DC_ERROR;
05912             break;
05913          }
05914          strncpy(tmp,val,sizeof(tmp) - 1);
05915          s = tmp;
05916          s1 = strsep(&s,",");
05917          if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
05918          {
05919             sy = strchr(s1,'/');    
05920             *sy = 0;
05921             sprintf(sx,"%s:4569/%s",s1,sy + 1);
05922             s1 = sx;
05923          }
05924          s2 = strsep(&s,",");
05925          rpt_mutex_lock(&myrpt->lock);
05926          l = myrpt->links.next;
05927          /* try to find this one in queue */
05928          while(l != &myrpt->links){
05929             if (l->name[0] == '0') 
05930             {
05931                l = l->next;
05932                continue;
05933             }
05934             /* if found matching string */
05935             if (!strcmp(l->name, digitbuf))
05936                break;
05937             l = l->next;
05938          }
05939          if (l != &myrpt->links){ /* if found */
05940             struct   ast_frame wf;
05941 
05942             /* must use perm command on perm link */
05943             if ((myatoi(param) < 10) && 
05944                 (l->max_retries > MAX_RETRIES))
05945             {
05946                rpt_mutex_unlock(&myrpt->lock);
05947                return DC_COMPLETE;
05948             }
05949             strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
05950             l->retries = l->max_retries + 1;
05951             l->disced = 1;
05952             rpt_mutex_unlock(&myrpt->lock);
05953             wf.frametype = AST_FRAME_TEXT;
05954             wf.subclass.integer = 0;
05955             wf.offset = 0;
05956             wf.mallocd = 0;
05957             wf.datalen = strlen(discstr) + 1;
05958             wf.samples = 0;
05959             wf.data.ptr = discstr;
05960             if (l->chan)
05961             {
05962                ast_write(l->chan,&wf);
05963                if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
05964                ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
05965             }
05966             rpt_telemetry(myrpt, COMPLETE, NULL);
05967             return DC_COMPLETE;
05968          }
05969          rpt_mutex_unlock(&myrpt->lock);  
05970          return DC_COMPLETE;
05971       case 2: /* Link Monitor */
05972       case 3: /* Link transceive */
05973       case 12: /* Link Monitor permanent */
05974       case 13: /* Link transceive permanent */
05975          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
05976             strcpy(digitbuf,myrpt->lastlinknode);
05977          /* Attempt connection  */
05978          perma = (atoi(param) > 10) ? 1 : 0;
05979          mode = (atoi(param) & 1) ? 1 : 0;
05980          r = connect_link(myrpt, digitbuf, mode, perma);
05981          switch(r){
05982             case -2: /* Attempt to connect to self */
05983                return DC_COMPLETE; /* Silent error */
05984 
05985             case 0:
05986                rpt_telemetry(myrpt, COMPLETE, NULL);
05987                return DC_COMPLETE;
05988 
05989             case 1:
05990                break;
05991             
05992             case 2:
05993                rpt_telemetry(myrpt, REMALREADY, NULL);
05994                return DC_COMPLETE;
05995             
05996             default:
05997                rpt_telemetry(myrpt, CONNFAIL, NULL);
05998                return DC_COMPLETE;
05999          }
06000          break;
06001 
06002       case 4: /* Enter Command Mode */
06003       
06004          /* if doesnt allow link cmd, or no links active, return */
06005          if (((command_source != SOURCE_RPT) && 
06006             (command_source != SOURCE_PHONE) &&
06007             (command_source != SOURCE_ALT) &&
06008             (command_source != SOURCE_DPHONE)) ||
06009              (myrpt->links.next == &myrpt->links))
06010             return DC_COMPLETE;
06011          
06012          /* if already in cmd mode, or selected self, fughetabahtit */
06013          if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
06014          
06015             rpt_telemetry(myrpt, REMALREADY, NULL);
06016             return DC_COMPLETE;
06017          }
06018          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
06019             strcpy(digitbuf,myrpt->lastlinknode);
06020          /* node must at least exist in list */
06021          val = node_lookup(myrpt,digitbuf);
06022          if (!val){
06023             if(strlen(digitbuf) >= myrpt->longestnode)
06024                return DC_ERROR;
06025             break;
06026          
06027          }
06028          rpt_mutex_lock(&myrpt->lock);
06029          strcpy(myrpt->lastlinknode,digitbuf);
06030          strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
06031          rpt_mutex_unlock(&myrpt->lock);
06032          rpt_telemetry(myrpt, REMGO, NULL);  
06033          return DC_COMPLETE;
06034          
06035       case 5: /* Status */
06036          rpt_telemetry(myrpt, STATUS, NULL);
06037          return DC_COMPLETE;
06038 
06039       case 15: /* Full Status */
06040          rpt_telemetry(myrpt, FULLSTATUS, NULL);
06041          return DC_COMPLETE;
06042          
06043          
06044       case 6: /* All Links Off, including permalinks */
06045                        rpt_mutex_lock(&myrpt->lock);
06046          myrpt->savednodes[0] = 0;
06047                         l = myrpt->links.next;
06048                         /* loop through all links */
06049                         while(l != &myrpt->links){
06050             struct   ast_frame wf;
06051                                 if (l->name[0] == '0') /* Skip any IAXRPT monitoring */
06052                                 {
06053                                         l = l->next;
06054                                         continue;
06055                                 }
06056             /* Make a string of disconnected nodes for possible restoration */
06057             sprintf(tmp,"%c%c%s",(l->mode) ? 'X' : 'M',(l->perma) ? 'P':'T',l->name);
06058             if(strlen(tmp) + strlen(myrpt->savednodes) + 1 < MAXNODESTR){ 
06059                if(myrpt->savednodes[0])
06060                   strcat(myrpt->savednodes, ",");
06061                strcat(myrpt->savednodes, tmp);
06062             }
06063                               l->retries = l->max_retries + 1;
06064                                 l->disced = 2; /* Silently disconnect */
06065                                 rpt_mutex_unlock(&myrpt->lock);
06066             /* ast_log(LOG_NOTICE,"dumping link %s\n",l->name); */
06067                                 
06068                                 wf.frametype = AST_FRAME_TEXT;
06069                                 wf.subclass.integer = 0;
06070                                 wf.offset = 0;
06071                                 wf.mallocd = 0;
06072                                 wf.datalen = strlen(discstr) + 1;
06073                                 wf.samples = 0;
06074                                 wf.data.ptr = discstr;
06075                                 if (l->chan)
06076                                 {
06077                                         ast_write(l->chan,&wf);
06078                                         ast_safe_sleep(l->chan,250); /* It's dead already, why check the return value? */
06079                                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
06080                                 }
06081             rpt_mutex_lock(&myrpt->lock);
06082                                 l = l->next;
06083                         }
06084          rpt_mutex_unlock(&myrpt->lock);
06085          if(debug > 3)
06086             ast_log(LOG_NOTICE,"Nodes disconnected: %s\n",myrpt->savednodes);
06087                         rpt_telemetry(myrpt, COMPLETE, NULL);
06088          return DC_COMPLETE;
06089 
06090       case 7: /* Identify last node which keyed us up */
06091          rpt_telemetry(myrpt, LASTNODEKEY, NULL);
06092          break;
06093 
06094 
06095 #ifdef   _MDC_DECODE_H_
06096       case 8:
06097          myrpt->lastunit = 0xd00d; 
06098          mdc1200_notify(myrpt,NULL,myrpt->lastunit);
06099          mdc1200_send(myrpt,myrpt->lastunit);
06100          break;
06101 #endif
06102 
06103       case 16: /* Restore links disconnected with "disconnect all links" command */
06104          strcpy(tmp, myrpt->savednodes); /* Make a copy */
06105          finddelim(tmp, strs, MAXLINKLIST); /* convert into substrings */
06106          for(i = 0; tmp[0] && strs[i] != NULL && i < MAXLINKLIST; i++){
06107             s1 = strs[i];
06108             mode = (s1[0] == 'X') ? 1 : 0;
06109             perma = (s1[1] == 'P') ? 1 : 0;
06110             connect_link(myrpt, s1 + 2, mode, perma); /* Try to reconnect */
06111          }
06112                         rpt_telemetry(myrpt, COMPLETE, NULL);
06113          break;
06114    
06115       case 200:
06116       case 201:
06117       case 202:
06118       case 203:
06119       case 204:
06120       case 205:
06121       case 206:
06122       case 207:
06123       case 208:
06124       case 209:
06125       case 210:
06126       case 211:
06127       case 212:
06128       case 213:
06129       case 214:
06130       case 215:
06131          if (((myrpt->p.propagate_dtmf) && 
06132               (command_source == SOURCE_LNK)) ||
06133              ((myrpt->p.propagate_phonedtmf) &&
06134             ((command_source == SOURCE_PHONE) ||
06135               (command_source == SOURCE_ALT) ||
06136                 (command_source == SOURCE_DPHONE))))
06137                do_dtmf_local(myrpt,
06138                   remdtmfstr[myatoi(param) - 200]);
06139       default:
06140          return DC_ERROR;
06141          
06142    }
06143    
06144    return DC_INDETERMINATE;
06145 }  
06146 
06147 /*
06148 * Autopatch up
06149 */
06150 
06151 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06152 {
06153    pthread_attr_t attr;
06154    int i, idx, paramlength;
06155    char *lparam;
06156    char *value = NULL;
06157    char *paramlist[20];
06158 
06159    static char *keywords[] = {
06160    "context",
06161    "dialtime",
06162    "farenddisconnect",
06163    "noct",
06164    "quiet",
06165    NULL
06166    };
06167       
06168    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
06169       return DC_ERROR;
06170       
06171    if(debug)
06172       printf("@@@@ Autopatch up\n");
06173 
06174    if(!myrpt->callmode){
06175       /* Set defaults */
06176       myrpt->patchnoct = 0;
06177       myrpt->patchdialtime = 0;
06178       myrpt->patchfarenddisconnect = 0;
06179       myrpt->patchquiet = 0;
06180       strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
06181 
06182       if(param){
06183          /* Process parameter list */
06184          lparam = ast_strdup(param);
06185          if(!lparam){
06186             ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
06187             return DC_ERROR;  
06188          }
06189          paramlength = finddelim(lparam, paramlist, 20);          
06190          for(i = 0; i < paramlength; i++){
06191             idx = matchkeyword(paramlist[i], &value, keywords);
06192             if(value)
06193                value = skipchars(value, "= ");
06194             switch(idx){
06195 
06196                case 1: /* context */
06197                   strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ;
06198                   break;
06199                   
06200                case 2: /* dialtime */
06201                   myrpt->patchdialtime = atoi(value);
06202                   break;
06203 
06204                case 3: /* farenddisconnect */
06205                   myrpt->patchfarenddisconnect = atoi(value);
06206                   break;
06207 
06208                case 4:  /* noct */
06209                   myrpt->patchnoct = atoi(value);
06210                   break;
06211 
06212                case 5: /* quiet */
06213                   myrpt->patchquiet = atoi(value);
06214                   break;
06215                            
06216                default:
06217                   break;
06218             }
06219          }
06220       ast_free(lparam);
06221       }
06222    }
06223                
06224    rpt_mutex_lock(&myrpt->lock);
06225 
06226    /* if on call, force * into current audio stream */
06227    
06228    if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
06229       myrpt->mydtmf = myrpt->p.endchar;
06230    }
06231    if (myrpt->callmode){
06232       rpt_mutex_unlock(&myrpt->lock);
06233       return DC_COMPLETE;
06234    }
06235    myrpt->callmode = 1;
06236    myrpt->cidx = 0;
06237    myrpt->exten[myrpt->cidx] = 0;
06238    rpt_mutex_unlock(&myrpt->lock);
06239    pthread_attr_init(&attr);
06240    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
06241    ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
06242    return DC_COMPLETE;
06243 }
06244 
06245 /*
06246 * Autopatch down
06247 */
06248 
06249 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06250 {
06251    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
06252       return DC_ERROR;
06253    
06254    if(debug)
06255       printf("@@@@ Autopatch down\n");
06256       
06257    rpt_mutex_lock(&myrpt->lock);
06258    
06259    myrpt->macropatch=0;
06260 
06261    if (!myrpt->callmode){
06262       rpt_mutex_unlock(&myrpt->lock);
06263       return DC_COMPLETE;
06264    }
06265    
06266    myrpt->callmode = 0;
06267    channel_revert(myrpt);
06268    rpt_mutex_unlock(&myrpt->lock);
06269    rpt_telemetry(myrpt, TERM, NULL);
06270    return DC_COMPLETE;
06271 }
06272 
06273 /*
06274 * Status
06275 */
06276 
06277 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06278 {
06279 
06280    if (!param)
06281       return DC_ERROR;
06282 
06283    if ((myrpt->p.s[myrpt->p.sysstate_cur].txdisable) || (myrpt->p.s[myrpt->p.sysstate_cur].userfundisable))
06284       return DC_ERROR;
06285 
06286    if(debug)
06287       printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06288    
06289    switch(myatoi(param)){
06290       case 1: /* System ID */
06291          rpt_telemetry(myrpt, ID1, NULL);
06292          return DC_COMPLETE;
06293       case 2: /* System Time */
06294          rpt_telemetry(myrpt, STATS_TIME, NULL);
06295          return DC_COMPLETE;
06296       case 3: /* app_rpt.c version */
06297          rpt_telemetry(myrpt, STATS_VERSION, NULL);
06298          return DC_COMPLETE;
06299       case 11: /* System ID (local only)*/
06300           rpt_telemetry(myrpt, ID , NULL);
06301             return DC_COMPLETE;
06302         case 12: /* System Time (local only)*/
06303             rpt_telemetry(myrpt, STATS_TIME_LOCAL, NULL);
06304             return DC_COMPLETE;
06305       default:
06306          return DC_ERROR;
06307    }
06308    return DC_INDETERMINATE;
06309 }
06310 /*
06311 *  Macro-oni (without Salami)
06312 */
06313 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06314 {
06315 char  *val;
06316 int   i;
06317    if (myrpt->remote)
06318       return DC_ERROR;
06319 
06320    if(debug) 
06321       printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06322    
06323    if(strlen(digitbuf) < 1) /* needs 1 digit */
06324       return DC_INDETERMINATE;
06325          
06326    for(i = 0 ; i < digitbuf[i] ; i++) {
06327       if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06328          return DC_ERROR;
06329    }
06330    
06331    if (*digitbuf == '0') val = myrpt->p.startupmacro;
06332    else val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
06333    /* param was 1 for local buf */
06334    if (!val){
06335                 if (strlen(digitbuf) < myrpt->macro_longest)
06336                         return DC_INDETERMINATE;
06337       rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
06338       return DC_COMPLETE;
06339    }        
06340    rpt_mutex_lock(&myrpt->lock);
06341    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
06342    {
06343       rpt_mutex_unlock(&myrpt->lock);
06344       rpt_telemetry(myrpt, MACRO_BUSY, NULL);
06345       return DC_ERROR;
06346    }
06347    myrpt->macrotimer = MACROTIME;
06348    strncat(myrpt->macrobuf,val,MAXMACRO - 1);
06349    rpt_mutex_unlock(&myrpt->lock);
06350    return DC_COMPLETE;  
06351 }
06352 
06353 /*
06354 *  Playback a recording
06355 */
06356 
06357 static int function_playback(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06358 {
06359 
06360    if (myrpt->remote)
06361       return DC_ERROR;
06362 
06363    if(debug) 
06364       printf("@@@@ playback param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06365    
06366    if (ast_fileexists(param,NULL,myrpt->rxchannel->language) <= 0)
06367       return DC_ERROR;
06368 
06369    rpt_telemetry(myrpt,PLAYBACK,param);
06370    return DC_COMPLETE;
06371 }
06372 
06373 /*
06374 * COP - Control operator
06375 */
06376 
06377 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06378 {
06379    char string[16];
06380    int res;
06381 
06382    int i, r;
06383 
06384    if(!param)
06385       return DC_ERROR;
06386    
06387    switch(myatoi(param)){
06388       case 1: /* System reset */
06389          res = system("killall -9 asterisk");
06390          return DC_COMPLETE;
06391 
06392       case 2:
06393          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 0;
06394          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
06395          return DC_COMPLETE;
06396          
06397       case 3:
06398          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 1;
06399          return DC_COMPLETE;
06400          
06401       case 4: /* test tone on */
06402          if (myrpt->stopgen < 0) 
06403          {
06404             myrpt->stopgen = 1;
06405          }
06406          else 
06407          {
06408             myrpt->stopgen = 0;
06409             rpt_telemetry(myrpt, TEST_TONE, NULL);
06410          }
06411          return DC_COMPLETE;
06412 
06413       case 5: /* Disgorge variables to log for debug purposes */
06414          myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
06415          return DC_COMPLETE;
06416 
06417       case 6: /* Simulate COR being activated (phone only) */
06418          if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
06419          return DC_DOKEY;  
06420 
06421 
06422       case 7: /* Time out timer enable */
06423          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 0;
06424          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTENA");
06425          return DC_COMPLETE;
06426          
06427       case 8: /* Time out timer disable */
06428          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 1;
06429          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTDIS");
06430          return DC_COMPLETE;
06431 
06432                 case 9: /* Autopatch enable */
06433                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 0;
06434                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APENA");
06435                         return DC_COMPLETE;
06436 
06437                 case 10: /* Autopatch disable */
06438                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 1;
06439                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APDIS");
06440                         return DC_COMPLETE;
06441 
06442                 case 11: /* Link Enable */
06443                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 0;
06444                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKENA");
06445                         return DC_COMPLETE;
06446 
06447                 case 12: /* Link Disable */
06448                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 1;
06449                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKDIS");
06450                         return DC_COMPLETE;
06451 
06452       case 13: /* Query System State */
06453          string[0] = string[1] = 'S';
06454          string[2] = myrpt->p.sysstate_cur + '0';
06455          string[3] = '\0';
06456          rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
06457          return DC_COMPLETE;
06458 
06459       case 14: /* Change System State */
06460          if(strlen(digitbuf) == 0)
06461             break;
06462          if((digitbuf[0] < '0') || (digitbuf[0] > '9'))
06463             return DC_ERROR;
06464          myrpt->p.sysstate_cur = digitbuf[0] - '0';
06465                         string[0] = string[1] = 'S';
06466                         string[2] = myrpt->p.sysstate_cur + '0';
06467                         string[3] = '\0';
06468                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
06469                         return DC_COMPLETE;
06470 
06471                 case 15: /* Scheduler Enable */
06472                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 0;
06473                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKENA");
06474                         return DC_COMPLETE;
06475 
06476                 case 16: /* Scheduler Disable */
06477                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 1;
06478                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKDIS");
06479                         return DC_COMPLETE;
06480 
06481                 case 17: /* User functions Enable */
06482                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 0;
06483                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFENA");
06484                         return DC_COMPLETE;
06485 
06486                 case 18: /* User Functions Disable */
06487                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 1;
06488                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFDIS");
06489                         return DC_COMPLETE;
06490 
06491                 case 19: /* Alternate Tail Enable */
06492                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 1;
06493                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATENA");
06494                         return DC_COMPLETE;
06495 
06496                 case 20: /* Alternate Tail Disable */
06497                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 0;
06498                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATDIS");
06499                         return DC_COMPLETE;
06500 
06501                 case 21: /* Parrot Mode Disable */
06502          birdbath(myrpt);
06503          if (myrpt->p.parrotmode < 2)
06504          {
06505             myrpt->p.parrotmode = 0;
06506             rpt_telemetry(myrpt,COMPLETE,NULL);
06507             return DC_COMPLETE;
06508          }
06509          break;
06510 
06511                 case 22: /* Parrot Mode Enable */
06512          birdbath(myrpt);
06513          if (myrpt->p.parrotmode < 2)
06514          {
06515             myrpt->p.parrotmode = 1;
06516             rpt_telemetry(myrpt,COMPLETE,NULL);
06517             return DC_COMPLETE;
06518          }
06519          break;
06520       case 23: /* flush parrot in progress */
06521          birdbath(myrpt);
06522          rpt_telemetry(myrpt,COMPLETE,NULL);
06523          return DC_COMPLETE;
06524       case 24: /* flush all telemetry */
06525          flush_telem(myrpt);
06526          rpt_telemetry(myrpt,COMPLETE,NULL);
06527          return DC_COMPLETE;
06528       case 25: /* request keying info (brief) */
06529          send_link_keyquery(myrpt);
06530          myrpt->topkeylong = 0;
06531          rpt_telemetry(myrpt,COMPLETE,NULL);
06532          return DC_COMPLETE;
06533       case 26: /* request keying info (full) */
06534          send_link_keyquery(myrpt);
06535          myrpt->topkeylong = 1;
06536          rpt_telemetry(myrpt,COMPLETE,NULL);
06537          return DC_COMPLETE;
06538 
06539       case 30: /* recall memory location on programmable radio */
06540 
06541          if(strlen(digitbuf) < 2) /* needs 2 digits */
06542             break;
06543          
06544          for(i = 0 ; i < 2 ; i++){
06545             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06546                return DC_ERROR;
06547          }
06548        
06549          r = retreive_memory(myrpt, digitbuf);
06550          if (r < 0){
06551             rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
06552             return DC_COMPLETE;
06553          }
06554          if (r > 0){
06555             return DC_ERROR;
06556          }
06557          if (setrem(myrpt) == -1) return DC_ERROR;
06558          return DC_COMPLETE;  
06559 
06560       case 31: 
06561           /* set channel. note that it's going to change channel 
06562              then confirm on the new channel! */
06563          if(strlen(digitbuf) < 2) /* needs 2 digits */
06564             break;
06565          
06566          for(i = 0 ; i < 2 ; i++){
06567             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06568                return DC_ERROR;
06569          }
06570          channel_steer(myrpt,digitbuf);
06571          return DC_COMPLETE;  
06572 
06573       case 32: /* Touch Tone Pad Test */
06574          i = strlen(digitbuf);
06575          if(!i){
06576             if(debug > 3)
06577             ast_log(LOG_NOTICE,"Padtest entered");
06578             myrpt->inpadtest = 1;
06579          }
06580          else{
06581             if(debug > 3)
06582                ast_log(LOG_NOTICE,"Padtest len= %d digits=%s",i,digitbuf);
06583             if(digitbuf[i-1] != myrpt->p.endchar)
06584                break;
06585             rpt_telemetry(myrpt, ARB_ALPHA, digitbuf);
06586             myrpt->inpadtest = 0;
06587             if(debug > 3)
06588                ast_log(LOG_NOTICE,"Padtest exited");
06589             return DC_COMPLETE;
06590          }
06591    }  
06592    return DC_INDETERMINATE;
06593 }
06594 /*
06595 * Collect digits one by one until something matches
06596 */
06597 static int collect_function_digits(struct rpt *myrpt, char *digits, 
06598    int command_source, struct rpt_link *mylink)
06599 {
06600    int i,rv;
06601    char *stringp,*action,*param,*functiondigits;
06602    char function_table_name[30] = "";
06603    char workstring[200];
06604    
06605    struct ast_variable *vp;
06606    
06607    if (debug > 6) ast_log(LOG_NOTICE,"digits=%s  source=%d\n",digits, command_source);
06608 
06609    //if(debug) 
06610    // printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
06611    
06612    if (command_source == SOURCE_DPHONE) {
06613       if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
06614       strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1);
06615       }
06616    else if (command_source == SOURCE_ALT) {
06617       if (!myrpt->p.alt_functions) return DC_INDETERMINATE;
06618       strncpy(function_table_name, myrpt->p.alt_functions, sizeof(function_table_name) - 1);
06619       }
06620    else if (command_source == SOURCE_PHONE) {
06621       if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
06622       strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1);
06623       }
06624    else if (command_source == SOURCE_LNK)
06625       strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1);
06626    else
06627       strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1);
06628     /* find context for function table in rpt.conf file */
06629    vp = ast_variable_browse(myrpt->cfg, function_table_name);
06630    while(vp) {
06631       if(!strncasecmp(vp->name, digits, strlen(vp->name)))
06632          break;
06633       vp = vp->next;
06634    }  
06635    /* if function context not found */
06636    if(!vp) {
06637       int n;
06638 
06639       n = myrpt->longestfunc;
06640       if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
06641       else 
06642       if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
06643       else 
06644       if (command_source == SOURCE_ALT) n = myrpt->alt_longestfunc;
06645       else 
06646       if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
06647       
06648       if(strlen(digits) >= n)
06649          return DC_ERROR;
06650       else
06651          return DC_INDETERMINATE;
06652    }  
06653    /* Found a match, retrieve value part and parse */
06654    strncpy(workstring, vp->value, sizeof(workstring) - 1 );
06655    stringp = workstring;
06656    action = strsep(&stringp, ",");
06657    param = stringp;
06658    if(debug)
06659       printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
06660    /* Look up the action */
06661    for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
06662       if(!strncasecmp(action, function_table[i].action, strlen(action)))
06663          break;
06664    }
06665    if(debug)
06666       printf("@@@@ table index i = %d\n",i);
06667    if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
06668       /* Error, action not in table */
06669       return DC_ERROR;
06670    }
06671    if(function_table[i].function == NULL){
06672       /* Error, function undefined */
06673       if(debug)
06674          printf("@@@@ NULL for action: %s\n",action);
06675       return DC_ERROR;
06676    }
06677    functiondigits = digits + strlen(vp->name);
06678    rv=(*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
06679    if (debug > 6) ast_log(LOG_NOTICE,"rv=%i\n",rv);
06680    return(rv);
06681 }
06682 
06683 
06684 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
06685    char *str)
06686 {
06687 /* XXX ATTENTION: if you change the size of these arrays you MUST
06688  * change the limits in corresponding sscanf() calls below. */
06689 char  tmp[512],tmp1[512],cmd[300] = "",dest[300],src[300],c;
06690 int   i,seq, res, ts;
06691 struct rpt_link *l;
06692 struct   ast_frame wf;
06693 
06694    wf.frametype = AST_FRAME_TEXT;
06695    wf.subclass.integer = 0;
06696    wf.offset = 0;
06697    wf.mallocd = 0;
06698    wf.datalen = strlen(str) + 1;
06699    wf.samples = 0;
06700    /* put string in our buffer */
06701    strncpy(tmp,str,sizeof(tmp) - 1);
06702 
06703         if (!strcmp(tmp,discstr))
06704         {
06705                 mylink->disced = 1;
06706       mylink->retries = mylink->max_retries + 1;
06707                 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
06708                 return;
06709         }
06710         if (!strcmp(tmp,newkeystr))
06711         {
06712       mylink->newkey = 1;
06713                 return;
06714         }
06715    if (tmp[0] == 'L')
06716    {
06717       rpt_mutex_lock(&myrpt->lock);
06718       strcpy(mylink->linklist,tmp + 2);
06719       time(&mylink->linklistreceived);
06720       rpt_mutex_unlock(&myrpt->lock);
06721       if (debug > 6) ast_log(LOG_NOTICE,"@@@@ node %s received node list %s from node %s\n",
06722          myrpt->name,tmp,mylink->name);
06723       return;
06724    }
06725    if (tmp[0] == 'K')
06726    {
06727       if (sscanf(tmp, "%299s %299s %299s %30d %30d", cmd, dest, src, &seq, &ts) != 5)
06728       {
06729          ast_log(LOG_WARNING, "Unable to parse keying string %s\n",str);
06730          return;
06731       }
06732       if (dest[0] == '0')
06733       {
06734          strcpy(dest,myrpt->name);
06735       }     
06736       /* if not for me, redistribute to all links */
06737       if (strcmp(dest,myrpt->name))
06738       {
06739          l = myrpt->links.next;
06740          /* see if this is one in list */
06741          while(l != &myrpt->links)
06742          {
06743             if (l->name[0] == '0') 
06744             {
06745                l = l->next;
06746                continue;
06747             }
06748             /* don't send back from where it came */
06749             if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06750             {
06751                l = l->next;
06752                continue;
06753             }
06754             /* if it is, send it and we're done */
06755             if (!strcmp(l->name,dest))
06756             {
06757                /* send, but not to src */
06758                if (strcmp(l->name,src)) {
06759                   wf.data.ptr = str;
06760                   if (l->chan) ast_write(l->chan,&wf);
06761                }
06762                return;
06763             }
06764             l = l->next;
06765          }
06766       }
06767       /* if not for me, or is broadcast, redistribute to all links */
06768       if ((strcmp(dest,myrpt->name)) || (dest[0] == '*'))
06769       {
06770          l = myrpt->links.next;
06771          /* otherwise, send it to all of em */
06772          while(l != &myrpt->links)
06773          {
06774             if (l->name[0] == '0') 
06775             {
06776                l = l->next;
06777                continue;
06778             }
06779             /* don't send back from where it came */
06780             if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06781             {
06782                l = l->next;
06783                continue;
06784             }
06785             /* send, but not to src */
06786             if (strcmp(l->name,src)) {
06787                wf.data.ptr = str;
06788                if (l->chan) ast_write(l->chan,&wf); 
06789             }
06790             l = l->next;
06791          }
06792       }
06793       /* if not for me, end here */
06794       if (strcmp(dest,myrpt->name) && (dest[0] != '*')) return;
06795       if (cmd[1] == '?')
06796       {
06797          time_t now;
06798          int n = 0;
06799 
06800          time(&now);
06801          if (myrpt->lastkeyedtime)
06802          {
06803             n = (int)(now - myrpt->lastkeyedtime);
06804          }
06805          sprintf(tmp1,"K %s %s %d %d",src,myrpt->name,myrpt->keyed,n);
06806          wf.data.ptr = tmp1;
06807          wf.datalen = strlen(tmp1) + 1;
06808          if (mylink->chan) ast_write(mylink->chan,&wf); 
06809          return;
06810       }
06811       if (myrpt->topkeystate != 1) return;
06812       rpt_mutex_lock(&myrpt->lock);
06813       for(i = 0; i < TOPKEYN; i++)
06814       {
06815          if (!strcmp(myrpt->topkey[i].node,src)) break;
06816       }
06817       if (i >= TOPKEYN)
06818       {
06819          for(i = 0; i < TOPKEYN; i++)
06820          {
06821             if (!myrpt->topkey[i].node[0]) break;
06822          }
06823       }
06824       if (i < TOPKEYN)
06825       {
06826          strncpy(myrpt->topkey[i].node,src,TOPKEYMAXSTR - 1);
06827          myrpt->topkey[i].timesince = ts;
06828          myrpt->topkey[i].keyed = seq;
06829       }
06830       rpt_mutex_unlock(&myrpt->lock);
06831       return;
06832    }
06833    if (tmp[0] == 'I')
06834    {
06835       /* XXX WARNING: be very careful with the limits on the folowing
06836        * sscanf() call, make sure they match the values defined above */
06837       if (sscanf(tmp,"%299s %299s %30x",cmd,src,&seq) != 3)
06838       {
06839          ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
06840          return;
06841       }
06842       mdc1200_notify(myrpt,src,seq);
06843       strcpy(dest,"*");
06844    }
06845    else
06846    {
06847       /* XXX WARNING: be very careful with the limits on the folowing
06848        * sscanf() call, make sure they match the values defined above */
06849       if (sscanf(tmp,"%299s %299s %299s %30d %1c",cmd,dest,src,&seq,&c) != 5)
06850       {
06851          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
06852          return;
06853       }
06854       if (strcmp(cmd,"D"))
06855       {
06856          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
06857          return;
06858       }
06859    }
06860    if (dest[0] == '0')
06861    {
06862       strcpy(dest,myrpt->name);
06863    }     
06864 
06865    /* if not for me, redistribute to all links */
06866    if (strcmp(dest,myrpt->name))
06867    {
06868       l = myrpt->links.next;
06869       /* see if this is one in list */
06870       while(l != &myrpt->links)
06871       {
06872          if (l->name[0] == '0') 
06873          {
06874             l = l->next;
06875             continue;
06876          }
06877          /* don't send back from where it came */
06878          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06879          {
06880             l = l->next;
06881             continue;
06882          }
06883          /* if it is, send it and we're done */
06884          if (!strcmp(l->name,dest))
06885          {
06886             /* send, but not to src */
06887             if (strcmp(l->name,src)) {
06888                wf.data.ptr = str;
06889                if (l->chan) ast_write(l->chan,&wf);
06890             }
06891             return;
06892          }
06893          l = l->next;
06894       }
06895       l = myrpt->links.next;
06896       /* otherwise, send it to all of em */
06897       while(l != &myrpt->links)
06898       {
06899          if (l->name[0] == '0') 
06900          {
06901             l = l->next;
06902             continue;
06903          }
06904          /* don't send back from where it came */
06905          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06906          {
06907             l = l->next;
06908             continue;
06909          }
06910          /* send, but not to src */
06911          if (strcmp(l->name,src)) {
06912             wf.data.ptr = str;
06913             if (l->chan) ast_write(l->chan,&wf); 
06914          }
06915          l = l->next;
06916       }
06917       return;
06918    }
06919    if (myrpt->p.archivedir)
06920    {
06921       char dtmfstr[100];
06922 
06923       sprintf(dtmfstr,"DTMF,%s,%c",mylink->name,c);
06924       donodelog(myrpt,dtmfstr);
06925    }
06926    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
06927    if (!c) return;
06928    rpt_mutex_lock(&myrpt->lock);
06929    if (c == myrpt->p.endchar) myrpt->stopgen = 1;
06930    if (myrpt->callmode == 1)
06931    {
06932       myrpt->exten[myrpt->cidx++] = c;
06933       myrpt->exten[myrpt->cidx] = 0;
06934       /* if this exists */
06935       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
06936       {
06937          /* if this really it, end now */
06938          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
06939             myrpt->exten,1,NULL)) 
06940          {
06941             myrpt->callmode = 2;
06942             if(!myrpt->patchquiet)
06943             {
06944                rpt_mutex_unlock(&myrpt->lock);
06945                rpt_telemetry(myrpt,PROC,NULL); 
06946                rpt_mutex_lock(&myrpt->lock);
06947             }
06948          }
06949          else /* othewise, reset timer */
06950          {
06951             myrpt->calldigittimer = 1;
06952          }
06953       }
06954       /* if can continue, do so */
06955       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
06956       {
06957          /* call has failed, inform user */
06958          myrpt->callmode = 4;
06959       }
06960    }
06961    if ((!myrpt->inpadtest) &&(c == myrpt->p.funcchar))
06962    {
06963       myrpt->rem_dtmfidx = 0;
06964       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
06965       time(&myrpt->rem_dtmf_time);
06966       rpt_mutex_unlock(&myrpt->lock);
06967       return;
06968    } 
06969    else if (myrpt->rem_dtmfidx < 0)
06970    {
06971       if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
06972       {
06973          myrpt->mydtmf = c;
06974       }
06975       if (myrpt->p.propagate_dtmf) do_dtmf_local(myrpt,c);
06976       if (myrpt->p.propagate_phonedtmf) do_dtmf_phone(myrpt,mylink,c);
06977       rpt_mutex_unlock(&myrpt->lock);
06978       return;
06979    }
06980    else if (((myrpt->inpadtest) || (c != myrpt->p.endchar)) && (myrpt->rem_dtmfidx >= 0))
06981    {
06982       time(&myrpt->rem_dtmf_time);
06983       if (myrpt->rem_dtmfidx < MAXDTMF)
06984       {
06985          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
06986          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
06987          
06988          rpt_mutex_unlock(&myrpt->lock);
06989          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
06990          res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
06991          rpt_mutex_lock(&myrpt->lock);
06992          
06993          switch(res){
06994 
06995             case DC_INDETERMINATE:
06996                break;
06997             
06998             case DC_REQ_FLUSH:
06999                myrpt->rem_dtmfidx = 0;
07000                myrpt->rem_dtmfbuf[0] = 0;
07001                break;
07002             
07003             
07004             case DC_COMPLETE:
07005             case DC_COMPLETEQUIET:
07006                myrpt->totalexecdcommands++;
07007                myrpt->dailyexecdcommands++;
07008                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
07009                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
07010                myrpt->rem_dtmfbuf[0] = 0;
07011                myrpt->rem_dtmfidx = -1;
07012                myrpt->rem_dtmf_time = 0;
07013                break;
07014             
07015             case DC_ERROR:
07016             default:
07017                myrpt->rem_dtmfbuf[0] = 0;
07018                myrpt->rem_dtmfidx = -1;
07019                myrpt->rem_dtmf_time = 0;
07020                break;
07021          }
07022       }
07023 
07024    }
07025    rpt_mutex_unlock(&myrpt->lock);
07026    return;
07027 }
07028 
07029 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
07030    char c)
07031 {
07032 
07033 char  cmd[300];
07034 int   res;
07035 
07036    if (myrpt->p.archivedir)
07037    {
07038       char str[100];
07039 
07040       sprintf(str,"DTMF(P),%s,%c",mylink->name,c);
07041       donodelog(myrpt,str);
07042    }
07043    rpt_mutex_lock(&myrpt->lock);
07044 
07045    if (mylink->phonemode == 3) /*If in simplex dumb phone mode */
07046    {
07047       if(c == myrpt->p.endchar) /* If end char */
07048       {
07049          mylink->lastrealrx = 0; /* Keying state = off */
07050          rpt_mutex_unlock(&myrpt->lock);
07051          return;
07052       }
07053 
07054       if(c == myrpt->p.funcchar) /* If lead-in char */
07055       {
07056          mylink->lastrealrx = !mylink->lastrealrx; /* Toggle keying state */
07057          rpt_mutex_unlock(&myrpt->lock);
07058          return;
07059       }
07060    }
07061    else
07062    {
07063       if (c == myrpt->p.endchar)
07064       {
07065          if (mylink->lastrx)
07066          {
07067             mylink->lastrealrx = 0;
07068             rpt_mutex_unlock(&myrpt->lock);
07069             return;
07070          }
07071          myrpt->stopgen = 1;
07072          if (myrpt->cmdnode[0])
07073          {
07074             myrpt->cmdnode[0] = 0;
07075             myrpt->dtmfidx = -1;
07076             myrpt->dtmfbuf[0] = 0;
07077             rpt_mutex_unlock(&myrpt->lock);
07078             rpt_telemetry(myrpt,COMPLETE,NULL);
07079             return;
07080          }
07081       }
07082    }
07083    if (myrpt->cmdnode[0])
07084    {
07085       rpt_mutex_unlock(&myrpt->lock);
07086       send_link_dtmf(myrpt,c);
07087       return;
07088    }
07089    if (myrpt->callmode == 1)
07090    {
07091       myrpt->exten[myrpt->cidx++] = c;
07092       myrpt->exten[myrpt->cidx] = 0;
07093       /* if this exists */
07094       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
07095       {
07096          /* if this really it, end now */
07097          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
07098             myrpt->exten,1,NULL)) 
07099          {
07100             myrpt->callmode = 2;
07101             if(!myrpt->patchquiet)
07102             {
07103                rpt_mutex_unlock(&myrpt->lock);
07104                rpt_telemetry(myrpt,PROC,NULL); 
07105                rpt_mutex_lock(&myrpt->lock);
07106             }
07107          }
07108          else /* othewise, reset timer */
07109          {
07110             myrpt->calldigittimer = 1;
07111          }
07112       }
07113       /* if can continue, do so */
07114       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
07115       {
07116          /* call has failed, inform user */
07117          myrpt->callmode = 4;
07118       }
07119    }
07120    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
07121    {
07122       myrpt->mydtmf = c;
07123    }
07124    if ((!myrpt->inpadtest) && (c == myrpt->p.funcchar))
07125    {
07126       myrpt->rem_dtmfidx = 0;
07127       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
07128       time(&myrpt->rem_dtmf_time);
07129       rpt_mutex_unlock(&myrpt->lock);
07130       return;
07131    } 
07132    else if (((myrpt->inpadtest) || (c != myrpt->p.endchar)) && (myrpt->rem_dtmfidx >= 0))
07133    {
07134       time(&myrpt->rem_dtmf_time);
07135       if (myrpt->rem_dtmfidx < MAXDTMF)
07136       {
07137          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
07138          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
07139          
07140          rpt_mutex_unlock(&myrpt->lock);
07141          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
07142          switch(mylink->phonemode)
07143          {
07144              case 1:
07145             res = collect_function_digits(myrpt, cmd, 
07146                SOURCE_PHONE, mylink);
07147             break;
07148              case 2:
07149             res = collect_function_digits(myrpt, cmd, 
07150                SOURCE_DPHONE,mylink);
07151             break;
07152              case 4:
07153             res = collect_function_digits(myrpt, cmd, 
07154                SOURCE_ALT,mylink);
07155             break;
07156              default:
07157             res = collect_function_digits(myrpt, cmd, 
07158                SOURCE_LNK, mylink);
07159             break;
07160          }
07161 
07162          rpt_mutex_lock(&myrpt->lock);
07163          
07164          switch(res){
07165 
07166             case DC_INDETERMINATE:
07167                break;
07168             
07169             case DC_DOKEY:
07170                mylink->lastrealrx = 1;
07171                break;
07172             
07173             case DC_REQ_FLUSH:
07174                myrpt->rem_dtmfidx = 0;
07175                myrpt->rem_dtmfbuf[0] = 0;
07176                break;
07177             
07178             
07179             case DC_COMPLETE:
07180             case DC_COMPLETEQUIET:
07181                myrpt->totalexecdcommands++;
07182                myrpt->dailyexecdcommands++;
07183                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
07184                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
07185                myrpt->rem_dtmfbuf[0] = 0;
07186                myrpt->rem_dtmfidx = -1;
07187                myrpt->rem_dtmf_time = 0;
07188                break;
07189             
07190             case DC_ERROR:
07191             default:
07192                myrpt->rem_dtmfbuf[0] = 0;
07193                myrpt->rem_dtmfidx = -1;
07194                myrpt->rem_dtmf_time = 0;
07195                break;
07196          }
07197       }
07198 
07199    }
07200    rpt_mutex_unlock(&myrpt->lock);
07201    return;
07202 }
07203 
07204 /* Doug Hall RBI-1 serial data definitions:
07205  *
07206  * Byte 0: Expansion external outputs 
07207  * Byte 1: 
07208  * Bits 0-3 are BAND as follows:
07209  * Bits 4-5 are POWER bits as follows:
07210  *    00 - Low Power
07211  *    01 - Hi Power
07212  *    02 - Med Power
07213  * Bits 6-7 are always set
07214  * Byte 2:
07215  * Bits 0-3 MHZ in BCD format
07216  * Bits 4-5 are offset as follows:
07217  *    00 - minus
07218  *    01 - plus
07219  *    02 - simplex
07220  *    03 - minus minus (whatever that is)
07221  * Bit 6 is the 0/5 KHZ bit
07222  * Bit 7 is always set
07223  * Byte 3:
07224  * Bits 0-3 are 10 KHZ in BCD format
07225  * Bits 4-7 are 100 KHZ in BCD format
07226  * Byte 4: PL Tone code and encode/decode enable bits
07227  * Bits 0-5 are PL tone code (comspec binary codes)
07228  * Bit 6 is encode enable/disable
07229  * Bit 7 is decode enable/disable
07230  */
07231 
07232 /* take the frequency from the 10 mhz digits (and up) and convert it
07233    to a band number */
07234 
07235 static int rbi_mhztoband(char *str)
07236 {
07237 int   i;
07238 
07239    i = atoi(str) / 10; /* get the 10's of mhz */
07240    switch(i)
07241    {
07242        case 2:
07243       return 10;
07244        case 5:
07245       return 11;
07246        case 14:
07247       return 2;
07248        case 22:
07249       return 3;
07250        case 44:
07251       return 4;
07252        case 124:
07253       return 0;
07254        case 125:
07255       return 1;
07256        case 126:
07257       return 8;
07258        case 127:
07259       return 5;
07260        case 128:
07261       return 6;
07262        case 129:
07263       return 7;
07264        default:
07265       break;
07266    }
07267    return -1;
07268 }
07269 
07270 /* take a PL frequency and turn it into a code */
07271 static int rbi_pltocode(char *str)
07272 {
07273 int i;
07274 char *s;
07275 
07276    s = strchr(str,'.');
07277    i = 0;
07278    if (s) i = atoi(s + 1);
07279    i += atoi(str) * 10;
07280    switch(i)
07281    {
07282        case 670:
07283       return 0;
07284        case 719:
07285       return 1;
07286        case 744:
07287       return 2;
07288        case 770:
07289       return 3;
07290        case 797:
07291       return 4;
07292        case 825:
07293       return 5;
07294        case 854:
07295       return 6;
07296        case 885:
07297       return 7;
07298        case 915:
07299       return 8;
07300        case 948:
07301       return 9;
07302        case 974:
07303       return 10;
07304        case 1000:
07305       return 11;
07306        case 1035:
07307       return 12;
07308        case 1072:
07309       return 13;
07310        case 1109:
07311       return 14;
07312        case 1148:
07313       return 15;
07314        case 1188:
07315       return 16;
07316        case 1230:
07317       return 17;
07318        case 1273:
07319       return 18;
07320        case 1318:
07321       return 19;
07322        case 1365:
07323       return 20;
07324        case 1413:
07325       return 21;
07326        case 1462:
07327       return 22;
07328        case 1514:
07329       return 23;
07330        case 1567:
07331       return 24;
07332        case 1622:
07333       return 25;
07334        case 1679:
07335       return 26;
07336        case 1738:
07337       return 27;
07338        case 1799:
07339       return 28;
07340        case 1862:
07341       return 29;
07342        case 1928:
07343       return 30;
07344        case 2035:
07345       return 31;
07346        case 2107:
07347       return 32;
07348        case 2181:
07349       return 33;
07350        case 2257:
07351       return 34;
07352        case 2336:
07353       return 35;
07354        case 2418:
07355       return 36;
07356        case 2503:
07357       return 37;
07358    }
07359    return -1;
07360 }
07361 
07362 /*
07363 * Shift out a formatted serial bit stream
07364 */
07365 
07366 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
07367     {
07368 #ifdef __i386__
07369     int i,j;
07370     unsigned char od,d;
07371     static volatile long long delayvar;
07372 
07373     for(i = 0 ; i < 5 ; i++){
07374         od = *data++; 
07375         for(j = 0 ; j < 8 ; j++){
07376             d = od & 1;
07377             outb(d,myrpt->p.iobase);
07378        /* >= 15 us */
07379        for(delayvar = 1; delayvar < 15000; delayvar++); 
07380             od >>= 1;
07381             outb(d | 2,myrpt->p.iobase);
07382        /* >= 30 us */
07383        for(delayvar = 1; delayvar < 30000; delayvar++); 
07384             outb(d,myrpt->p.iobase);
07385        /* >= 10 us */
07386        for(delayvar = 1; delayvar < 10000; delayvar++); 
07387             }
07388         }
07389    /* >= 50 us */
07390         for(delayvar = 1; delayvar < 50000; delayvar++); 
07391 #endif
07392     }
07393 
07394 static void rbi_out(struct rpt *myrpt,unsigned char *data)
07395 {
07396 struct dahdi_radio_param r;
07397 
07398    memset(&r,0,sizeof(struct dahdi_radio_param));
07399    r.radpar = DAHDI_RADPAR_REMMODE;
07400    r.data = DAHDI_RADPAR_REM_RBI1;
07401    /* if setparam ioctl fails, its probably not a pciradio card */
07402    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
07403    {
07404       rbi_out_parallel(myrpt,data);
07405       return;
07406    }
07407    r.radpar = DAHDI_RADPAR_REMCOMMAND;
07408    memcpy(&r.data,data,5);
07409    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
07410    {
07411       ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->dahdirxchannel->name);
07412       return;
07413    }
07414 }
07415 
07416 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, 
07417    unsigned char *rxbuf, int rxmaxbytes, int asciiflag)
07418 {
07419    int i,j,idx,oldmode,olddata;
07420    struct dahdi_radio_param prm;
07421    char c;
07422 
07423     if(debug) {
07424        ast_log(LOG_NOTICE, "ioport=%s  iofd=0x%x\n",myrpt->p.ioport,myrpt->iofd);
07425       printf("String output was:\n");
07426       for(i = 0; i < txbytes; i++)
07427          printf("%02X ", (unsigned char ) txbuf[i]);
07428       printf("\n");
07429    }
07430 
07431    if (myrpt->iofd >= 0)  /* if to do out a serial port */
07432    {
07433       if (write(myrpt->iofd,txbuf,txbytes) != txbytes)
07434       {
07435          return -1;
07436       }
07437       if ((!rxmaxbytes) || (rxbuf == NULL)) 
07438       {
07439          return(0);
07440       }
07441       memset(rxbuf,0,rxmaxbytes);
07442       for(i = 0; i < rxmaxbytes; i++)
07443       {
07444          j = read(myrpt->iofd,&c,1);
07445          if (j < 1) 
07446          {
07447             return(i);
07448          }
07449          rxbuf[i] = c;
07450          if (asciiflag & 1)
07451          {
07452             rxbuf[i + 1] = 0;
07453             if (c == '\r') break;
07454          }
07455       }              
07456       if(debug) {
07457          printf("String returned was:\n");
07458          for(j = 0; j < i; j++)
07459             printf("%02X ", (unsigned char ) rxbuf[j]);
07460          printf("\n");
07461       }
07462       return(i);
07463    }
07464 
07465    /* if not a DAHDI channel, cant use pciradio stuff */
07466    if (myrpt->rxchannel != myrpt->dahdirxchannel) return -1;   
07467 
07468    prm.radpar = DAHDI_RADPAR_UIOMODE;
07469    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
07470    oldmode = prm.data;
07471    prm.radpar = DAHDI_RADPAR_UIODATA;
07472    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
07473    olddata = prm.data;
07474         prm.radpar = DAHDI_RADPAR_REMMODE;
07475         if (asciiflag & 1)  prm.data = DAHDI_RADPAR_REM_SERIAL_ASCII;
07476         else prm.data = DAHDI_RADPAR_REM_SERIAL;
07477    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07478    if (asciiflag & 2)
07479    {
07480       i = DAHDI_ONHOOK;
07481       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
07482       usleep(100000);
07483    }
07484         prm.radpar = DAHDI_RADPAR_REMCOMMAND;
07485         prm.data = rxmaxbytes;
07486         memcpy(prm.buf,txbuf,txbytes);
07487         prm.index = txbytes;
07488    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07489         if (rxbuf)
07490         {
07491                 *rxbuf = 0;
07492                 memcpy(rxbuf,prm.buf,prm.index);
07493         }
07494    idx = prm.index;
07495         prm.radpar = DAHDI_RADPAR_REMMODE;
07496         prm.data = DAHDI_RADPAR_REM_NONE;
07497    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07498    if (asciiflag & 2)
07499    {
07500       i = DAHDI_OFFHOOK;
07501       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
07502    }
07503    prm.radpar = DAHDI_RADPAR_UIOMODE;
07504    prm.data = oldmode;
07505    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07506    prm.radpar = DAHDI_RADPAR_UIODATA;
07507    prm.data = olddata;
07508    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07509         return(idx);
07510 }
07511 
07512 static int civ_cmd(struct rpt *myrpt,unsigned char *cmd, int cmdlen)
07513 {
07514 unsigned char rxbuf[100];
07515 int   i,rv ;
07516 
07517    rv = serial_remote_io(myrpt,cmd,cmdlen,rxbuf,cmdlen + 6,0);
07518    if (rv == -1) return(-1);
07519    if (rv != (cmdlen + 6)) return(1);
07520    for(i = 0; i < 6; i++)
07521       if (rxbuf[i] != cmd[i]) return(1);
07522    if (rxbuf[cmdlen] != 0xfe) return(1);
07523    if (rxbuf[cmdlen + 1] != 0xfe) return(1);
07524    if (rxbuf[cmdlen + 4] != 0xfb) return(1);
07525    if (rxbuf[cmdlen + 5] != 0xfd) return(1);
07526    return(0);
07527 }
07528 
07529 static int sendkenwood(struct rpt *myrpt,char *txstr, char *rxstr)
07530 {
07531 int   i;
07532 
07533 ast_log(LOG_NOTICE,"Sent to kenwood: %s\n",txstr);
07534    if (debug) printf("Send to kenwood: %s\n",txstr);
07535    i = serial_remote_io(myrpt, (unsigned char *)txstr, strlen(txstr), 
07536       (unsigned char *)rxstr,RAD_SERIAL_BUFLEN - 1,3);
07537    if (i < 0) return -1;
07538    if ((i > 0) && (rxstr[i - 1] == '\r'))
07539       rxstr[i-- - 1] = 0;
07540    if (debug) printf("Got from kenwood: %s\n",rxstr);
07541 ast_log(LOG_NOTICE,"Got from kenwood: %s\n",rxstr);
07542    return(i);
07543 }
07544 
07545 /* take a PL frequency and turn it into a code */
07546 static int kenwood_pltocode(char *str)
07547 {
07548 int i;
07549 char *s;
07550 
07551    s = strchr(str,'.');
07552    i = 0;
07553    if (s) i = atoi(s + 1);
07554    i += atoi(str) * 10;
07555    switch(i)
07556    {
07557        case 670:
07558       return 1;
07559        case 719:
07560       return 3;
07561        case 744:
07562       return 4;
07563        case 770:
07564       return 5;
07565        case 797:
07566       return 6;
07567        case 825:
07568       return 7;
07569        case 854:
07570       return 8;
07571        case 885:
07572       return 9;
07573        case 915:
07574       return 10;
07575        case 948:
07576       return 11;
07577        case 974:
07578       return 12;
07579        case 1000:
07580       return 13;
07581        case 1035:
07582       return 14;
07583        case 1072:
07584       return 15;
07585        case 1109:
07586       return 16;
07587        case 1148:
07588       return 17;
07589        case 1188:
07590       return 18;
07591        case 1230:
07592       return 19;
07593        case 1273:
07594       return 20;
07595        case 1318:
07596       return 21;
07597        case 1365:
07598       return 22;
07599        case 1413:
07600       return 23;
07601        case 1462:
07602       return 24;
07603        case 1514:
07604       return 25;
07605        case 1567:
07606       return 26;
07607        case 1622:
07608       return 27;
07609        case 1679:
07610       return 28;
07611        case 1738:
07612       return 29;
07613        case 1799:
07614       return 30;
07615        case 1862:
07616       return 31;
07617        case 1928:
07618       return 32;
07619        case 2035:
07620       return 33;
07621        case 2107:
07622       return 34;
07623        case 2181:
07624       return 35;
07625        case 2257:
07626       return 36;
07627        case 2336:
07628       return 37;
07629        case 2418:
07630       return 38;
07631        case 2503:
07632       return 39;
07633    }
07634    return -1;
07635 }
07636 
07637 static int sendrxkenwood(struct rpt *myrpt, char *txstr, char *rxstr, 
07638    char *cmpstr)
07639 {
07640 int   i,j;
07641 
07642    for(i = 0;i < KENWOOD_RETRIES;i++)
07643    {
07644       j = sendkenwood(myrpt,txstr,rxstr);
07645       if (j < 0) return(j);
07646       if (j == 0) continue;
07647       if (!strncmp(rxstr,cmpstr,strlen(cmpstr))) return(0);
07648    }
07649    return(-1);
07650 }     
07651 
07652 static int setkenwood(struct rpt *myrpt)
07653 {
07654 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
07655 char mhz[MAXREMSTR],offset[20],band,decimals[MAXREMSTR],band1,band2;
07656 int myrxpl;
07657    
07658 int offsets[] = {0,2,1};
07659 int powers[] = {2,1,0};
07660 
07661    if (sendrxkenwood(myrpt,"VMC 0,0\r",rxstr,"VMC") < 0) return -1;
07662    split_freq(mhz, decimals, myrpt->freq);
07663    if (atoi(mhz) > 400)
07664    {
07665       band = '6';
07666       band1 = '1';
07667       band2 = '5';
07668       strcpy(offset,"005000000");
07669    }
07670    else
07671    {
07672       band = '2';
07673       band1 = '0';
07674       band2 = '2';
07675       strcpy(offset,"000600000");
07676    }
07677    strcpy(freq,"000000");
07678    strncpy(freq,decimals,strlen(decimals));
07679    myrxpl = myrpt->rxplon;
07680    if (IS_XPMR(myrpt)) myrxpl = 0;
07681    sprintf(txstr,"VW %c,%05d%s,0,%d,0,%d,%d,,%02d,,%02d,%s\r",
07682       band,atoi(mhz),freq,offsets[(int)myrpt->offset],
07683       (myrpt->txplon != 0),myrxpl,
07684       kenwood_pltocode(myrpt->txpl),kenwood_pltocode(myrpt->rxpl),
07685       offset);
07686    if (sendrxkenwood(myrpt,txstr,rxstr,"VW") < 0) return -1;
07687    sprintf(txstr,"RBN %c\r",band2);
07688    if (sendrxkenwood(myrpt,txstr,rxstr,"RBN") < 0) return -1;
07689    sprintf(txstr,"PC %c,%d\r",band1,powers[(int)myrpt->powerlevel]);
07690    if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
07691    return 0;
07692 }
07693 
07694 static int set_tm271(struct rpt *myrpt)
07695 {
07696 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
07697 char mhz[MAXREMSTR],decimals[MAXREMSTR];
07698    
07699 int offsets[] = {0,2,1};
07700 int powers[] = {2,1,0};
07701 
07702    split_freq(mhz, decimals, myrpt->freq);
07703    strcpy(freq,"000000");
07704    strncpy(freq,decimals,strlen(decimals));
07705 
07706    sprintf(txstr,"VF %04d%s,4,%d,0,%d,0,0,%d,%d,000,00600000,0,0\r",
07707       atoi(mhz),freq,offsets[(int)myrpt->offset],
07708       (myrpt->txplon != 0),kenwood_pltocode(myrpt->txpl),
07709       kenwood_pltocode(myrpt->rxpl));
07710 
07711    if (sendrxkenwood(myrpt,txstr,rxstr,"VF") < 0) return -1;
07712    if (sendrxkenwood(myrpt,"VM 0\r",rxstr,"VM") < 0) return -1;
07713    sprintf(txstr,"PC %d\r",powers[(int)myrpt->powerlevel]);
07714    if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
07715    return 0;
07716 }
07717 
07718 static int setrbi(struct rpt *myrpt)
07719 {
07720 char tmp[MAXREMSTR] = "",*s;
07721 unsigned char rbicmd[5];
07722 int   band,txoffset = 0,txpower = 0,rxpl;
07723 
07724    /* must be a remote system */
07725    if (!myrpt->remoterig) return(0);
07726    if (!myrpt->remoterig[0]) return(0);
07727    /* must have rbi hardware */
07728    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
07729    if (setrbi_check(myrpt) == -1) return(-1);
07730    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07731    s = strchr(tmp,'.');
07732    /* if no decimal, is invalid */
07733    
07734    if (s == NULL){
07735       if(debug)
07736          printf("@@@@ Frequency needs a decimal\n");
07737       return -1;
07738    }
07739    
07740    *s++ = 0;
07741    if (strlen(tmp) < 2){
07742       if(debug)
07743          printf("@@@@ Bad MHz digits: %s\n", tmp);
07744       return -1;
07745    }
07746     
07747    if (strlen(s) < 3){
07748       if(debug)
07749          printf("@@@@ Bad KHz digits: %s\n", s);
07750       return -1;
07751    }
07752 
07753    if ((s[2] != '0') && (s[2] != '5')){
07754       if(debug)
07755          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
07756       return -1;
07757    }
07758     
07759    band = rbi_mhztoband(tmp);
07760    if (band == -1){
07761       if(debug)
07762          printf("@@@@ Bad Band: %s\n", tmp);
07763       return -1;
07764    }
07765    
07766    rxpl = rbi_pltocode(myrpt->rxpl);
07767    
07768    if (rxpl == -1){
07769       if(debug)
07770          printf("@@@@ Bad TX PL: %s\n", myrpt->rxpl);
07771       return -1;
07772    }
07773 
07774    
07775    switch(myrpt->offset)
07776    {
07777        case REM_MINUS:
07778       txoffset = 0;
07779       break;
07780        case REM_PLUS:
07781       txoffset = 0x10;
07782       break;
07783        case REM_SIMPLEX:
07784       txoffset = 0x20;
07785       break;
07786    }
07787    switch(myrpt->powerlevel)
07788    {
07789        case REM_LOWPWR:
07790       txpower = 0;
07791       break;
07792        case REM_MEDPWR:
07793       txpower = 0x20;
07794       break;
07795        case REM_HIPWR:
07796       txpower = 0x10;
07797       break;
07798    }
07799    rbicmd[0] = 0;
07800    rbicmd[1] = band | txpower | 0xc0;
07801    rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
07802    if (s[2] == '5') rbicmd[2] |= 0x40;
07803    rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
07804    rbicmd[4] = rxpl;
07805    if (myrpt->txplon) rbicmd[4] |= 0x40;
07806    if (myrpt->rxplon) rbicmd[4] |= 0x80;
07807    rbi_out(myrpt,rbicmd);
07808    return 0;
07809 }
07810 
07811 static int setrtx(struct rpt *myrpt)
07812 {
07813 char tmp[MAXREMSTR] = "",*s,rigstr[200],pwr,res = 0;
07814 int   band,txoffset = 0,txpower = 0,rxpl,txpl;
07815 float ofac;
07816 double txfreq;
07817 
07818    /* must be a remote system */
07819    if (!myrpt->remoterig) return(0);
07820    if (!myrpt->remoterig[0]) return(0);
07821    /* must have rtx hardware */
07822    if (!ISRIG_RTX(myrpt->remoterig)) return(0);
07823    /* must be a usbradio interface type */
07824    if (!IS_XPMR(myrpt)) return(0);
07825    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07826    s = strchr(tmp,'.');
07827    /* if no decimal, is invalid */
07828    
07829    if(debug)printf("setrtx() %s %s\n",myrpt->name,myrpt->remoterig);
07830 
07831    if (s == NULL){
07832       if(debug)
07833          printf("@@@@ Frequency needs a decimal\n");
07834       return -1;
07835    }
07836    *s++ = 0;
07837    if (strlen(tmp) < 2){
07838       if(debug)
07839          printf("@@@@ Bad MHz digits: %s\n", tmp);
07840       return -1;
07841    }
07842     
07843    if (strlen(s) < 3){
07844       if(debug)
07845          printf("@@@@ Bad KHz digits: %s\n", s);
07846       return -1;
07847    }
07848 
07849    if ((s[2] != '0') && (s[2] != '5')){
07850       if(debug)
07851          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
07852       return -1;
07853    }
07854     
07855    band = rbi_mhztoband(tmp);
07856    if (band == -1){
07857       if(debug)
07858          printf("@@@@ Bad Band: %s\n", tmp);
07859       return -1;
07860    }
07861    
07862    rxpl = rbi_pltocode(myrpt->rxpl);
07863    
07864    if (rxpl == -1){
07865       if(debug)
07866          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
07867       return -1;
07868    }
07869 
07870    txpl = rbi_pltocode(myrpt->txpl);
07871    
07872    if (txpl == -1){
07873       if(debug)
07874          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
07875       return -1;
07876    }
07877    
07878    switch(myrpt->offset)
07879    {
07880        case REM_MINUS:
07881       txoffset = 0;
07882       break;
07883        case REM_PLUS:
07884       txoffset = 0x10;
07885       break;
07886        case REM_SIMPLEX:
07887       txoffset = 0x20;
07888       break;
07889    }
07890    switch(myrpt->powerlevel)
07891    {
07892        case REM_LOWPWR:
07893       txpower = 0;
07894       break;
07895        case REM_MEDPWR:
07896       txpower = 0x20;
07897       break;
07898        case REM_HIPWR:
07899       txpower = 0x10;
07900       break;
07901    }
07902 
07903    res = setrtx_check(myrpt);
07904    if (res < 0) return res;
07905    ofac = 0.0;
07906    if (myrpt->offset == REM_MINUS) ofac = -1.0;
07907    if (myrpt->offset == REM_PLUS) ofac = 1.0;
07908 
07909    if (!strcmp(myrpt->remoterig,remote_rig_rtx450))
07910       txfreq = atof(myrpt->freq) +  (ofac * 5.0);
07911    else
07912       txfreq = atof(myrpt->freq) +  (ofac * 0.6);
07913 
07914    pwr = 'L';
07915    if (myrpt->powerlevel == REM_HIPWR) pwr = 'H';
07916    if (!res)
07917    {
07918       sprintf(rigstr,"SETFREQ %s %f %s %s %c",myrpt->freq,txfreq,
07919          (myrpt->rxplon) ? myrpt->rxpl : "0.0",
07920          (myrpt->txplon) ? myrpt->txpl : "0.0",pwr);
07921       send_usb_txt(myrpt,rigstr);
07922       rpt_telemetry(myrpt,COMPLETE,NULL);
07923       res = 0;
07924    }
07925    return 0;
07926 }
07927 #if 0
07928 /*
07929    sets current signaling code for xpmr routines
07930    under development for new radios.
07931 */
07932 static int setxpmr(struct rpt *myrpt)
07933 {
07934    char rigstr[200];
07935    int rxpl,txpl;
07936 
07937    /* must be a remote system */
07938    if (!myrpt->remoterig) return(0);
07939    if (!myrpt->remoterig[0]) return(0);
07940    /* must not have rtx hardware */
07941    if (ISRIG_RTX(myrpt->remoterig)) return(0);
07942    /* must be a usbradio interface type */
07943    if (!IS_XPMR(myrpt)) return(0);
07944    
07945    if(debug)printf("setxpmr() %s %s\n",myrpt->name,myrpt->remoterig );
07946 
07947    rxpl = rbi_pltocode(myrpt->rxpl);
07948    
07949    if (rxpl == -1){
07950       if(debug)
07951          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
07952       return -1;
07953    }
07954 
07955    txpl = rbi_pltocode(myrpt->txpl);
07956    if (txpl == -1){
07957       if(debug)
07958          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
07959       return -1;
07960    }
07961    sprintf(rigstr,"SETFREQ 0.0 0.0 %s %s L",
07962       (myrpt->rxplon) ? myrpt->rxpl : "0.0",
07963       (myrpt->txplon) ? myrpt->txpl : "0.0");
07964    send_usb_txt(myrpt,rigstr);
07965    return 0;
07966 }
07967 #endif
07968 
07969 static int setrbi_check(struct rpt *myrpt)
07970 {
07971 char tmp[MAXREMSTR] = "",*s;
07972 int   band,txpl;
07973 
07974    /* must be a remote system */
07975    if (!myrpt->remote) return(0);
07976    /* must have rbi hardware */
07977    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
07978    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07979    s = strchr(tmp,'.');
07980    /* if no decimal, is invalid */
07981    
07982    if (s == NULL){
07983       if(debug)
07984          printf("@@@@ Frequency needs a decimal\n");
07985       return -1;
07986    }
07987    
07988    *s++ = 0;
07989    if (strlen(tmp) < 2){
07990       if(debug)
07991          printf("@@@@ Bad MHz digits: %s\n", tmp);
07992       return -1;
07993    }
07994     
07995    if (strlen(s) < 3){
07996       if(debug)
07997          printf("@@@@ Bad KHz digits: %s\n", s);
07998       return -1;
07999    }
08000 
08001    if ((s[2] != '0') && (s[2] != '5')){
08002       if(debug)
08003          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
08004       return -1;
08005    }
08006     
08007    band = rbi_mhztoband(tmp);
08008    if (band == -1){
08009       if(debug)
08010          printf("@@@@ Bad Band: %s\n", tmp);
08011       return -1;
08012    }
08013    
08014    txpl = rbi_pltocode(myrpt->txpl);
08015    
08016    if (txpl == -1){
08017       if(debug)
08018          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
08019       return -1;
08020    }
08021    return 0;
08022 }
08023 
08024 static int setrtx_check(struct rpt *myrpt)
08025 {
08026 char tmp[MAXREMSTR] = "",*s;
08027 int   band,txpl,rxpl;
08028 
08029    /* must be a remote system */
08030    if (!myrpt->remote) return(0);
08031    /* must have rbi hardware */
08032    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
08033    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
08034    s = strchr(tmp,'.');
08035    /* if no decimal, is invalid */
08036    
08037    if (s == NULL){
08038       if(debug)
08039          printf("@@@@ Frequency needs a decimal\n");
08040       return -1;
08041    }
08042    
08043    *s++ = 0;
08044    if (strlen(tmp) < 2){
08045       if(debug)
08046          printf("@@@@ Bad MHz digits: %s\n", tmp);
08047       return -1;
08048    }
08049     
08050    if (strlen(s) < 3){
08051       if(debug)
08052          printf("@@@@ Bad KHz digits: %s\n", s);
08053       return -1;
08054    }
08055 
08056    if ((s[2] != '0') && (s[2] != '5')){
08057       if(debug)
08058          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
08059       return -1;
08060    }
08061     
08062    band = rbi_mhztoband(tmp);
08063    if (band == -1){
08064       if(debug)
08065          printf("@@@@ Bad Band: %s\n", tmp);
08066       return -1;
08067    }
08068    
08069    txpl = rbi_pltocode(myrpt->txpl);
08070    
08071    if (txpl == -1){
08072       if(debug)
08073          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
08074       return -1;
08075    }
08076 
08077    rxpl = rbi_pltocode(myrpt->rxpl);
08078    
08079    if (rxpl == -1){
08080       if(debug)
08081          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
08082       return -1;
08083    }
08084    return 0;
08085 }
08086 
08087 static int check_freq_kenwood(int m, int d, int *defmode)
08088 {
08089    int dflmd = REM_MODE_FM;
08090 
08091    if (m == 144){ /* 2 meters */
08092       if(d < 10100)
08093          return -1;
08094    }
08095    else if((m >= 145) && (m < 148)){
08096       ;
08097    }
08098    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08099       ;
08100    }
08101    else
08102       return -1;
08103    
08104    if(defmode)
08105       *defmode = dflmd; 
08106 
08107 
08108    return 0;
08109 }
08110 
08111 
08112 static int check_freq_tm271(int m, int d, int *defmode)
08113 {
08114    int dflmd = REM_MODE_FM;
08115 
08116    if (m == 144){ /* 2 meters */
08117       if(d < 10100)
08118          return -1;
08119    }
08120    else if((m >= 145) && (m < 148)){
08121       ;
08122    }
08123       return -1;
08124    
08125    if(defmode)
08126       *defmode = dflmd; 
08127 
08128 
08129    return 0;
08130 }
08131 
08132 
08133 /* Check for valid rbi frequency */
08134 /* Hard coded limits now, configurable later, maybe? */
08135 
08136 static int check_freq_rbi(int m, int d, int *defmode)
08137 {
08138    int dflmd = REM_MODE_FM;
08139 
08140    if(m == 50){ /* 6 meters */
08141       if(d < 10100)
08142          return -1;
08143    }
08144    else if((m >= 51) && ( m < 54)){
08145                 ;
08146    }
08147    else if(m == 144){ /* 2 meters */
08148       if(d < 10100)
08149          return -1;
08150    }
08151    else if((m >= 145) && (m < 148)){
08152       ;
08153    }
08154    else if((m >= 222) && (m < 225)){ /* 1.25 meters */
08155       ;
08156    }
08157    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08158       ;
08159    }
08160    else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
08161       ;
08162    }
08163    else
08164       return -1;
08165    
08166    if(defmode)
08167       *defmode = dflmd; 
08168 
08169 
08170    return 0;
08171 }
08172 
08173 /* Check for valid rtx frequency */
08174 /* Hard coded limits now, configurable later, maybe? */
08175 
08176 static int check_freq_rtx(int m, int d, int *defmode, struct rpt *myrpt)
08177 {
08178    int dflmd = REM_MODE_FM;
08179 
08180    if (!strcmp(myrpt->remoterig,remote_rig_rtx150))
08181    {
08182 
08183       if(m == 144){ /* 2 meters */
08184          if(d < 10100)
08185             return -1;
08186       }
08187       else if((m >= 145) && (m < 148)){
08188          ;
08189       }
08190       else
08191          return -1;
08192    }
08193    else 
08194    {
08195       if((m >= 430) && (m < 450)){ /* 70 centimeters */
08196          ;
08197       }
08198       else
08199          return -1;
08200    }
08201    if(defmode)
08202       *defmode = dflmd; 
08203 
08204 
08205    return 0;
08206 }
08207 
08208 /*
08209  * Convert decimals of frequency to int
08210  */
08211 
08212 static int decimals2int(char *fraction)
08213 {
08214    int i;
08215    char len = strlen(fraction);
08216    int multiplier = 100000;
08217    int res = 0;
08218 
08219    if(!len)
08220       return 0;
08221    for( i = 0 ; i < len ; i++, multiplier /= 10)
08222       res += (fraction[i] - '0') * multiplier;
08223    return res;
08224 }
08225 
08226 
08227 /*
08228 * Split frequency into mhz and decimals
08229 */
08230  
08231 static int split_freq(char *mhz, char *decimals, char *freq)
08232 {
08233    char freq_copy[MAXREMSTR];
08234    char *decp;
08235 
08236    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
08237    if(decp){
08238       *decp++ = 0;
08239       strncpy(mhz, freq_copy, MAXREMSTR);
08240       strcpy(decimals, "00000");
08241       strncpy(decimals, decp, strlen(decp));
08242       decimals[5] = 0;
08243       return 0;
08244    }
08245    else
08246       return -1;
08247 
08248 }
08249    
08250 /*
08251 * Split ctcss frequency into hertz and decimal
08252 */
08253  
08254 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
08255 {
08256    char freq_copy[MAXREMSTR];
08257    char *decp;
08258 
08259    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
08260    if(decp){
08261       *decp++ = 0;
08262       strncpy(hertz, freq_copy, MAXREMSTR);
08263       strncpy(decimal, decp, strlen(decp));
08264       decimal[strlen(decp)] = '\0';
08265       return 0;
08266    }
08267    else
08268       return -1;
08269 }
08270 
08271 
08272 
08273 /*
08274 * FT-897 I/O handlers
08275 */
08276 
08277 /* Check to see that the frequency is valid */
08278 /* Hard coded limits now, configurable later, maybe? */
08279 
08280 
08281 static int check_freq_ft897(int m, int d, int *defmode)
08282 {
08283    int dflmd = REM_MODE_FM;
08284 
08285    if(m == 1){ /* 160 meters */
08286       dflmd =  REM_MODE_LSB; 
08287       if(d < 80000)
08288          return -1;
08289    }
08290    else if(m == 3){ /* 80 meters */
08291       dflmd = REM_MODE_LSB;
08292       if(d < 50000)
08293          return -1;
08294    }
08295    else if(m == 7){ /* 40 meters */
08296       dflmd = REM_MODE_LSB;
08297       if(d > 30000)
08298          return -1;
08299    }
08300    else if(m == 14){ /* 20 meters */
08301       dflmd = REM_MODE_USB;
08302       if(d > 35000)
08303          return -1;
08304    }
08305    else if(m == 18){ /* 17 meters */
08306       dflmd = REM_MODE_USB;
08307       if((d < 6800) || (d > 16800))
08308          return -1;
08309    }
08310    else if(m == 21){ /* 15 meters */
08311       dflmd = REM_MODE_USB;
08312       if((d < 20000) || (d > 45000))
08313          return -1;
08314    }
08315    else if(m == 24){ /* 12 meters */
08316       dflmd = REM_MODE_USB;
08317       if((d < 89000) || (d > 99000))
08318          return -1;
08319    }
08320    else if(m == 28){ /* 10 meters */
08321       dflmd = REM_MODE_USB;
08322    }
08323    else if(m == 29){ 
08324       if(d >= 51000)
08325          dflmd = REM_MODE_FM;
08326       else
08327          dflmd = REM_MODE_USB;
08328       if(d > 70000)
08329          return -1;
08330    }
08331    else if(m == 50){ /* 6 meters */
08332       if(d >= 30000)
08333          dflmd = REM_MODE_FM;
08334       else
08335          dflmd = REM_MODE_USB;
08336 
08337    }
08338    else if((m >= 51) && ( m < 54)){
08339       dflmd = REM_MODE_FM;
08340    }
08341    else if(m == 144){ /* 2 meters */
08342       if(d >= 30000)
08343          dflmd = REM_MODE_FM;
08344       else
08345          dflmd = REM_MODE_USB;
08346    }
08347    else if((m >= 145) && (m < 148)){
08348       dflmd = REM_MODE_FM;
08349    }
08350    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08351       if(m  < 438)
08352          dflmd = REM_MODE_USB;
08353       else
08354          dflmd = REM_MODE_FM;
08355       ;
08356    }
08357    else
08358       return -1;
08359 
08360    if(defmode)
08361       *defmode = dflmd;
08362 
08363    return 0;
08364 }
08365 
08366 /*
08367 * Set a new frequency for the FT897
08368 */
08369 
08370 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
08371 {
08372    unsigned char cmdstr[5];
08373    int fd,m,d;
08374    char mhz[MAXREMSTR];
08375    char decimals[MAXREMSTR];
08376 
08377    fd = 0;
08378    if(debug) 
08379       printf("New frequency: %s\n",newfreq);
08380 
08381    if(split_freq(mhz, decimals, newfreq))
08382       return -1; 
08383 
08384    m = atoi(mhz);
08385    d = atoi(decimals);
08386 
08387    /* The FT-897 likes packed BCD frequencies */
08388 
08389    cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10);        /* 100MHz 10Mhz */
08390    cmdstr[1] = ((m % 10) << 4) + (d / 10000);         /* 1MHz 100KHz */
08391    cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100);  /* 10KHz 1KHz */
08392    cmdstr[3] = (((d % 100)/10) << 4) + (d % 10);         /* 100Hz 10Hz */
08393    cmdstr[4] = 0x01;                /* command */
08394 
08395    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08396 
08397 }
08398 
08399 /* ft-897 simple commands */
08400 
08401 static int simple_command_ft897(struct rpt *myrpt, char command)
08402 {
08403    unsigned char cmdstr[5];
08404    
08405    memset(cmdstr, 0, 5);
08406 
08407    cmdstr[4] = command; 
08408 
08409    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08410 
08411 }
08412 
08413 /* ft-897 offset */
08414 
08415 static int set_offset_ft897(struct rpt *myrpt, char offset)
08416 {
08417    unsigned char cmdstr[5];
08418    
08419    memset(cmdstr, 0, 5);
08420 
08421    switch(offset){
08422       case  REM_SIMPLEX:
08423          cmdstr[0] = 0x89;
08424          break;
08425 
08426       case  REM_MINUS:
08427          cmdstr[0] = 0x09;
08428          break;
08429       
08430       case  REM_PLUS:
08431          cmdstr[0] = 0x49;
08432          break;   
08433 
08434       default:
08435          return -1;
08436    }
08437 
08438    cmdstr[4] = 0x09; 
08439 
08440    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08441 }
08442 
08443 /* ft-897 mode */
08444 
08445 static int set_mode_ft897(struct rpt *myrpt, char newmode)
08446 {
08447    unsigned char cmdstr[5];
08448    
08449    memset(cmdstr, 0, 5);
08450    
08451    switch(newmode){
08452       case  REM_MODE_FM:
08453          cmdstr[0] = 0x08;
08454          break;
08455 
08456       case  REM_MODE_USB:
08457          cmdstr[0] = 0x01;
08458          break;
08459 
08460       case  REM_MODE_LSB:
08461          cmdstr[0] = 0x00;
08462          break;
08463 
08464       case  REM_MODE_AM:
08465          cmdstr[0] = 0x04;
08466          break;
08467       
08468       default:
08469          return -1;
08470    }
08471    cmdstr[4] = 0x07; 
08472 
08473    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08474 }
08475 
08476 /* Set tone encode and decode modes */
08477 
08478 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
08479 {
08480    unsigned char cmdstr[5];
08481    
08482    memset(cmdstr, 0, 5);
08483    
08484    if(rxplon && txplon)
08485       cmdstr[0] = 0x2A; /* Encode and Decode */
08486    else if (!rxplon && txplon)
08487       cmdstr[0] = 0x4A; /* Encode only */
08488    else if (rxplon && !txplon)
08489       cmdstr[0] = 0x3A; /* Encode only */
08490    else
08491       cmdstr[0] = 0x8A; /* OFF */
08492 
08493    cmdstr[4] = 0x0A; 
08494 
08495    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08496 }
08497 
08498 
08499 /* Set transmit and receive ctcss tone frequencies */
08500 
08501 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
08502 {
08503    unsigned char cmdstr[5];
08504    char hertz[MAXREMSTR],decimal[MAXREMSTR];
08505    int h,d; 
08506 
08507    memset(cmdstr, 0, 5);
08508 
08509    if(split_ctcss_freq(hertz, decimal, txtone))
08510       return -1; 
08511 
08512    h = atoi(hertz);
08513    d = atoi(decimal);
08514    
08515    cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
08516    cmdstr[1] = ((h % 10) << 4) + (d % 10);
08517    
08518    if(rxtone){
08519    
08520       if(split_ctcss_freq(hertz, decimal, rxtone))
08521          return -1; 
08522 
08523       h = atoi(hertz);
08524       d = atoi(decimal);
08525    
08526       cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
08527       cmdstr[3] = ((h % 10) << 4) + (d % 10);
08528    }
08529    cmdstr[4] = 0x0B; 
08530 
08531    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08532 }  
08533 
08534 
08535 
08536 static int set_ft897(struct rpt *myrpt)
08537 {
08538    int res;
08539    
08540    if(debug)
08541       printf("@@@@ lock on\n");
08542 
08543    res = simple_command_ft897(myrpt, 0x00);  /* LOCK on */  
08544 
08545    if(debug)
08546       printf("@@@@ ptt off\n");
08547 
08548    if(!res)
08549       res = simple_command_ft897(myrpt, 0x88);     /* PTT off */
08550 
08551    if(debug)
08552       printf("Modulation mode\n");
08553 
08554    if(!res)
08555       res = set_mode_ft897(myrpt, myrpt->remmode);    /* Modulation mode */
08556 
08557    if(debug)
08558       printf("Split off\n");
08559 
08560    if(!res)
08561       simple_command_ft897(myrpt, 0x82);        /* Split off */
08562 
08563    if(debug)
08564       printf("Frequency\n");
08565 
08566    if(!res)
08567       res = set_freq_ft897(myrpt, myrpt->freq);    /* Frequency */
08568    if((myrpt->remmode == REM_MODE_FM)){
08569       if(debug)
08570          printf("Offset\n");
08571       if(!res)
08572          res = set_offset_ft897(myrpt, myrpt->offset);   /* Offset if FM */
08573       if((!res)&&(myrpt->rxplon || myrpt->txplon)){
08574          if(debug)
08575             printf("CTCSS tone freqs.\n");
08576          res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
08577       }
08578       if(!res){
08579          if(debug)
08580             printf("CTCSS mode\n");
08581          res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
08582       }
08583    }
08584    if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
08585       if(debug)
08586          printf("Clarifier off\n");
08587       simple_command_ft897(myrpt, 0x85);        /* Clarifier off if LSB or USB */
08588    }
08589    return res;
08590 }
08591 
08592 static int closerem_ft897(struct rpt *myrpt)
08593 {
08594    simple_command_ft897(myrpt, 0x88); /* PTT off */
08595    return 0;
08596 }  
08597 
08598 /*
08599 * Bump frequency up or down by a small amount 
08600 * Return 0 if the new frequnecy is valid, or -1 if invalid
08601 * Interval is in Hz, resolution is 10Hz 
08602 */
08603 
08604 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
08605 {
08606    int m,d;
08607    char mhz[MAXREMSTR], decimals[MAXREMSTR];
08608 
08609    if(debug)
08610       printf("Before bump: %s\n", myrpt->freq);
08611 
08612    if(split_freq(mhz, decimals, myrpt->freq))
08613       return -1;
08614    
08615    m = atoi(mhz);
08616    d = atoi(decimals);
08617 
08618    d += (interval / 10); /* 10Hz resolution */
08619    if(d < 0){
08620       m--;
08621       d += 100000;
08622    }
08623    else if(d >= 100000){
08624       m++;
08625       d -= 100000;
08626    }
08627 
08628    if(check_freq_ft897(m, d, NULL)){
08629       if(debug)
08630          printf("Bump freq invalid\n");
08631       return -1;
08632    }
08633 
08634    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
08635 
08636    if(debug)
08637       printf("After bump: %s\n", myrpt->freq);
08638 
08639    return set_freq_ft897(myrpt, myrpt->freq);   
08640 }
08641 
08642 
08643 
08644 /*
08645 * IC-706 I/O handlers
08646 */
08647 
08648 /* Check to see that the frequency is valid */
08649 /* returns 0 if frequency is valid          */
08650 
08651 static int check_freq_ic706(int m, int d, int *defmode, char mars)
08652 {
08653    int dflmd = REM_MODE_FM;
08654    int rv=0;
08655 
08656    if(debug > 6)
08657       ast_log(LOG_NOTICE,"(%i,%i,%i,%i)\n",m,d,*defmode,mars);
08658 
08659    /* first test for standard amateur radio bands */
08660 
08661    if(m == 1){                /* 160 meters */
08662       dflmd =  REM_MODE_LSB; 
08663       if(d < 80000)rv=-1;
08664    }
08665    else if(m == 3){           /* 80 meters */
08666       dflmd = REM_MODE_LSB;
08667       if(d < 50000)rv=-1;
08668    }
08669    else if(m == 7){           /* 40 meters */
08670       dflmd = REM_MODE_LSB;
08671       if(d > 30000)rv=-1;
08672    }
08673    else if(m == 14){             /* 20 meters */
08674       dflmd = REM_MODE_USB;
08675       if(d > 35000)rv=-1;
08676    }
08677    else if(m == 18){                      /* 17 meters */
08678       dflmd = REM_MODE_USB;
08679       if((d < 6800) || (d > 16800))rv=-1;
08680    }
08681    else if(m == 21){ /* 15 meters */
08682       dflmd = REM_MODE_USB;
08683       if((d < 20000) || (d > 45000))rv=-1;
08684    }
08685    else if(m == 24){ /* 12 meters */
08686       dflmd = REM_MODE_USB;
08687       if((d < 89000) || (d > 99000))rv=-1;
08688    }
08689    else if(m == 28){                      /* 10 meters */
08690       dflmd = REM_MODE_USB;
08691    }
08692    else if(m == 29){ 
08693       if(d >= 51000)
08694          dflmd = REM_MODE_FM;
08695       else
08696          dflmd = REM_MODE_USB;
08697       if(d > 70000)rv=-1;
08698    }
08699    else if(m == 50){                      /* 6 meters */
08700       if(d >= 30000)
08701          dflmd = REM_MODE_FM;
08702       else
08703          dflmd = REM_MODE_USB;
08704    }
08705    else if((m >= 51) && ( m < 54)){
08706       dflmd = REM_MODE_FM;
08707    }
08708    else if(m == 144){ /* 2 meters */
08709       if(d >= 30000)
08710          dflmd = REM_MODE_FM;
08711       else
08712          dflmd = REM_MODE_USB;
08713    }
08714    else if((m >= 145) && (m < 148)){
08715       dflmd = REM_MODE_FM;
08716    }
08717    else if((m >= 430) && (m < 450)){         /* 70 centimeters */
08718       if(m  < 438)
08719          dflmd = REM_MODE_USB;
08720       else
08721          dflmd = REM_MODE_FM;
08722    }
08723 
08724    /* check expanded coverage */
08725    if(mars && rv<0){
08726       if((m >= 450) && (m < 470)){        /* LMR */
08727          dflmd = REM_MODE_FM;
08728          rv=0;
08729       }
08730       else if((m >= 148) && (m < 174)){      /* LMR */
08731          dflmd = REM_MODE_FM;
08732          rv=0;
08733       }
08734       else if((m >= 138) && (m < 144)){      /* VHF-AM AIRCRAFT */
08735          dflmd = REM_MODE_AM;
08736          rv=0;
08737       }
08738       else if((m >= 108) && (m < 138)){      /* VHF-AM AIRCRAFT */
08739          dflmd = REM_MODE_AM;
08740          rv=0;
08741       }
08742       else if( (m==0 && d>=55000) || (m==1 && d<=75000) ){  /* AM BCB*/
08743          dflmd = REM_MODE_AM;
08744          rv=0;
08745       }
08746       else if( (m == 1 && d>75000) || (m>1 && m<30) ){      /* HF SWL*/
08747          dflmd = REM_MODE_AM;
08748          rv=0;
08749       }
08750    }
08751 
08752    if(defmode)
08753       *defmode = dflmd;
08754 
08755    if(debug > 1)
08756       ast_log(LOG_NOTICE,"(%i,%i,%i,%i) returning %i\n",m,d,*defmode,mars,rv);
08757 
08758    return rv;
08759 }
08760 
08761 /* take a PL frequency and turn it into a code */
08762 static int ic706_pltocode(char *str)
08763 {
08764    int i;
08765    char *s;
08766    int rv=-1;
08767 
08768    s = strchr(str,'.');
08769    i = 0;
08770    if (s) i = atoi(s + 1);
08771    i += atoi(str) * 10;
08772    switch(i)
08773    {
08774        case 670:
08775          rv=0;
08776        case 693:
08777          rv=1;
08778        case 719:
08779          rv=2;
08780        case 744:
08781          rv=3;
08782        case 770:
08783          rv=4;
08784        case 797:
08785          rv=5;
08786        case 825:
08787          rv=6;
08788        case 854:
08789          rv=7;
08790        case 885:
08791          rv=8;
08792        case 915:
08793          rv=9;
08794        case 948:
08795          rv=10;
08796        case 974:
08797          rv=11;
08798        case 1000:
08799          rv=12;
08800        case 1035:
08801          rv=13;
08802        case 1072:
08803          rv=14;
08804        case 1109:
08805          rv=15;
08806        case 1148:
08807          rv=16;
08808        case 1188:
08809          rv=17;
08810        case 1230:
08811          rv=18;
08812        case 1273:
08813          rv=19;
08814        case 1318:
08815          rv=20;
08816        case 1365:
08817          rv=21;
08818        case 1413:
08819          rv=22;
08820        case 1462:
08821          rv=23;
08822        case 1514:
08823          rv=24;
08824        case 1567:
08825          rv=25;
08826        case 1598:
08827          rv=26;
08828        case 1622:
08829          rv=27;
08830        case 1655:
08831          rv=28;      
08832        case 1679:
08833          rv=29;
08834        case 1713:
08835          rv=30;
08836        case 1738:
08837          rv=31;
08838        case 1773:
08839          rv=32;
08840        case 1799:
08841          rv=33;
08842         case 1835:
08843          rv=34;
08844        case 1862:
08845          rv=35;
08846        case 1899:
08847          rv=36;
08848        case 1928:
08849          rv=37;
08850        case 1966:
08851          rv=38;
08852        case 1995:
08853          rv=39;
08854        case 2035:
08855          rv=40;
08856        case 2065:
08857          rv=41;
08858        case 2107:
08859          rv=42;
08860        case 2181:
08861          rv=43;
08862        case 2257:
08863          rv=44;
08864        case 2291:
08865          rv=45;
08866        case 2336:
08867          rv=46;
08868        case 2418:
08869          rv=47;
08870        case 2503:
08871          rv=48;
08872        case 2541:
08873          rv=49;
08874    }
08875    if(debug > 1)
08876       ast_log(LOG_NOTICE,"%i  rv=%i\n",i, rv);
08877 
08878    return rv;
08879 }
08880 
08881 /* ic-706 simple commands */
08882 
08883 static int simple_command_ic706(struct rpt *myrpt, char command, char subcommand)
08884 {
08885    unsigned char cmdstr[10];
08886    
08887    cmdstr[0] = cmdstr[1] = 0xfe;
08888    cmdstr[2] = myrpt->p.civaddr;
08889    cmdstr[3] = 0xe0;
08890    cmdstr[4] = command;
08891    cmdstr[5] = subcommand;
08892    cmdstr[6] = 0xfd;
08893 
08894    return(civ_cmd(myrpt,cmdstr,7));
08895 }
08896 
08897 /*
08898 * Set a new frequency for the ic706
08899 */
08900 
08901 static int set_freq_ic706(struct rpt *myrpt, char *newfreq)
08902 {
08903    unsigned char cmdstr[20];
08904    char mhz[MAXREMSTR], decimals[MAXREMSTR];
08905    int fd,m,d;
08906 
08907    fd = 0;
08908    if(debug) 
08909       ast_log(LOG_NOTICE,"newfreq:%s\n",newfreq);        
08910 
08911    if(split_freq(mhz, decimals, newfreq))
08912       return -1; 
08913 
08914    m = atoi(mhz);
08915    d = atoi(decimals);
08916 
08917    /* The ic-706 likes packed BCD frequencies */
08918 
08919    cmdstr[0] = cmdstr[1] = 0xfe;
08920    cmdstr[2] = myrpt->p.civaddr;
08921    cmdstr[3] = 0xe0;
08922    cmdstr[4] = 5;
08923    cmdstr[5] = ((d % 10) << 4);
08924    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
08925    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
08926    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
08927    cmdstr[9] = (m / 100);
08928    cmdstr[10] = 0xfd;
08929 
08930    return(civ_cmd(myrpt,cmdstr,11));
08931 }
08932 
08933 /* ic-706 offset */
08934 
08935 static int set_offset_ic706(struct rpt *myrpt, char offset)
08936 {
08937    unsigned char c;
08938 
08939    if(debug > 6)
08940       ast_log(LOG_NOTICE,"offset=%i\n",offset);
08941 
08942    switch(offset){
08943       case  REM_SIMPLEX:
08944          c = 0x10;
08945          break;
08946 
08947       case  REM_MINUS:
08948          c = 0x11;
08949          break;
08950       
08951       case  REM_PLUS:
08952          c = 0x12;
08953          break;   
08954 
08955       default:
08956          return -1;
08957    }
08958 
08959    return simple_command_ic706(myrpt,0x0f,c);
08960 
08961 }
08962 
08963 /* ic-706 mode */
08964 
08965 static int set_mode_ic706(struct rpt *myrpt, char newmode)
08966 {
08967    unsigned char c;
08968    
08969    if(debug > 6)
08970       ast_log(LOG_NOTICE,"newmode=%i\n",newmode);
08971 
08972    switch(newmode){
08973       case  REM_MODE_FM:
08974          c = 5;
08975          break;
08976 
08977       case  REM_MODE_USB:
08978          c = 1;
08979          break;
08980 
08981       case  REM_MODE_LSB:
08982          c = 0;
08983          break;
08984 
08985       case  REM_MODE_AM:
08986          c = 2;
08987          break;
08988       
08989       default:
08990          return -1;
08991    }
08992    return simple_command_ic706(myrpt,6,c);
08993 }
08994 
08995 /* Set tone encode and decode modes */
08996 
08997 static int set_ctcss_mode_ic706(struct rpt *myrpt, char txplon, char rxplon)
08998 {
08999    unsigned char cmdstr[10];
09000    int rv;
09001 
09002    if(debug > 6)
09003       ast_log(LOG_NOTICE,"txplon=%i  rxplon=%i \n",txplon,rxplon);
09004 
09005    cmdstr[0] = cmdstr[1] = 0xfe;
09006    cmdstr[2] = myrpt->p.civaddr;
09007    cmdstr[3] = 0xe0;
09008    cmdstr[4] = 0x16;
09009    cmdstr[5] = 0x42;
09010    cmdstr[6] = (txplon != 0);
09011    cmdstr[7] = 0xfd;
09012 
09013    rv = civ_cmd(myrpt,cmdstr,8);
09014    if (rv) return(-1);
09015 
09016    cmdstr[0] = cmdstr[1] = 0xfe;
09017    cmdstr[2] = myrpt->p.civaddr;
09018    cmdstr[3] = 0xe0;
09019    cmdstr[4] = 0x16;
09020    cmdstr[5] = 0x43;
09021    cmdstr[6] = (rxplon != 0);
09022    cmdstr[7] = 0xfd;
09023 
09024    return(civ_cmd(myrpt,cmdstr,8));
09025 }
09026 
09027 #if 0
09028 /* Set transmit and receive ctcss tone frequencies */
09029 
09030 static int set_ctcss_freq_ic706(struct rpt *myrpt, char *txtone, char *rxtone)
09031 {
09032    unsigned char cmdstr[10];
09033    char hertz[MAXREMSTR],decimal[MAXREMSTR];
09034    int h,d,rv;
09035 
09036    memset(cmdstr, 0, 5);
09037 
09038    if(debug > 6)
09039       ast_log(LOG_NOTICE,"txtone=%s  rxtone=%s \n",txtone,rxtone);
09040 
09041    if(split_ctcss_freq(hertz, decimal, txtone))
09042       return -1; 
09043 
09044    h = atoi(hertz);
09045    d = atoi(decimal);
09046    
09047    cmdstr[0] = cmdstr[1] = 0xfe;
09048    cmdstr[2] = myrpt->p.civaddr;
09049    cmdstr[3] = 0xe0;
09050    cmdstr[4] = 0x1b;
09051    cmdstr[5] = 0;
09052    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
09053    cmdstr[7] = ((h % 10) << 4) + (d % 10);
09054    cmdstr[8] = 0xfd;
09055 
09056    rv = civ_cmd(myrpt,cmdstr,9);
09057    if (rv) return(-1);
09058 
09059    if (!rxtone) return(0);
09060 
09061    if(split_ctcss_freq(hertz, decimal, rxtone))
09062       return -1; 
09063 
09064    h = atoi(hertz);
09065    d = atoi(decimal);
09066 
09067    cmdstr[0] = cmdstr[1] = 0xfe;
09068    cmdstr[2] = myrpt->p.civaddr;
09069    cmdstr[3] = 0xe0;
09070    cmdstr[4] = 0x1b;
09071    cmdstr[5] = 1;
09072    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
09073    cmdstr[7] = ((h % 10) << 4) + (d % 10);
09074    cmdstr[8] = 0xfd;
09075    return(civ_cmd(myrpt,cmdstr,9));
09076 }  
09077 #endif
09078 
09079 static int vfo_ic706(struct rpt *myrpt)
09080 {
09081    unsigned char cmdstr[10];
09082    
09083    cmdstr[0] = cmdstr[1] = 0xfe;
09084    cmdstr[2] = myrpt->p.civaddr;
09085    cmdstr[3] = 0xe0;
09086    cmdstr[4] = 7;
09087    cmdstr[5] = 0xfd;
09088 
09089    return(civ_cmd(myrpt,cmdstr,6));
09090 }
09091 
09092 static int mem2vfo_ic706(struct rpt *myrpt)
09093 {
09094    unsigned char cmdstr[10];
09095    
09096    cmdstr[0] = cmdstr[1] = 0xfe;
09097    cmdstr[2] = myrpt->p.civaddr;
09098    cmdstr[3] = 0xe0;
09099    cmdstr[4] = 0x0a;
09100    cmdstr[5] = 0xfd;
09101 
09102    return(civ_cmd(myrpt,cmdstr,6));
09103 }
09104 
09105 static int select_mem_ic706(struct rpt *myrpt, int slot)
09106 {
09107    unsigned char cmdstr[10];
09108    
09109    cmdstr[0] = cmdstr[1] = 0xfe;
09110    cmdstr[2] = myrpt->p.civaddr;
09111    cmdstr[3] = 0xe0;
09112    cmdstr[4] = 8;
09113    cmdstr[5] = 0;
09114    cmdstr[6] = ((slot / 10) << 4) + (slot % 10);
09115    cmdstr[7] = 0xfd;
09116 
09117    return(civ_cmd(myrpt,cmdstr,8));
09118 }
09119 
09120 static int set_ic706(struct rpt *myrpt)
09121 {
09122    int res = 0,i;
09123    
09124    if(debug)ast_log(LOG_NOTICE, "Set to VFO A iobase=%i\n",myrpt->p.iobase);
09125 
09126    if (!res)
09127       res = simple_command_ic706(myrpt,7,0);
09128 
09129    if((myrpt->remmode == REM_MODE_FM))
09130    {
09131       i = ic706_pltocode(myrpt->rxpl);
09132       if (i == -1) return -1;
09133       if(debug)
09134          printf("Select memory number\n");
09135       if (!res)
09136          res = select_mem_ic706(myrpt,i + IC706_PL_MEMORY_OFFSET);
09137       if(debug)
09138          printf("Transfer memory to VFO\n");
09139       if (!res)
09140          res = mem2vfo_ic706(myrpt);
09141    }
09142       
09143    if(debug)
09144       printf("Set to VFO\n");
09145 
09146    if (!res)
09147       res = vfo_ic706(myrpt);
09148 
09149    if(debug)
09150       printf("Modulation mode\n");
09151 
09152    if (!res)
09153       res = set_mode_ic706(myrpt, myrpt->remmode);    /* Modulation mode */
09154 
09155    if(debug)
09156       printf("Split off\n");
09157 
09158    if(!res)
09159       simple_command_ic706(myrpt, 0x82,0);         /* Split off */
09160 
09161    if(debug)
09162       printf("Frequency\n");
09163 
09164    if(!res)
09165       res = set_freq_ic706(myrpt, myrpt->freq);    /* Frequency */
09166    if((myrpt->remmode == REM_MODE_FM)){
09167       if(debug)
09168          printf("Offset\n");
09169       if(!res)
09170          res = set_offset_ic706(myrpt, myrpt->offset);   /* Offset if FM */
09171       if(!res){
09172          if(debug)
09173             printf("CTCSS mode\n");
09174          res = set_ctcss_mode_ic706(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
09175       }
09176    }
09177    return res;
09178 }
09179 
09180 /*
09181 * Bump frequency up or down by a small amount 
09182 * Return 0 if the new frequnecy is valid, or -1 if invalid
09183 * Interval is in Hz, resolution is 10Hz 
09184 */
09185 
09186 static int multimode_bump_freq_ic706(struct rpt *myrpt, int interval)
09187 {
09188    int m,d;
09189    char mhz[MAXREMSTR], decimals[MAXREMSTR];
09190    unsigned char cmdstr[20];
09191 
09192    if(debug)
09193       printf("Before bump: %s\n", myrpt->freq);
09194 
09195    if(split_freq(mhz, decimals, myrpt->freq))
09196       return -1;
09197    
09198    m = atoi(mhz);
09199    d = atoi(decimals);
09200 
09201    d += (interval / 10); /* 10Hz resolution */
09202    if(d < 0){
09203       m--;
09204       d += 100000;
09205    }
09206    else if(d >= 100000){
09207       m++;
09208       d -= 100000;
09209    }
09210 
09211    if(check_freq_ic706(m, d, NULL,myrpt->p.remote_mars)){
09212       if(debug)
09213          printf("Bump freq invalid\n");
09214       return -1;
09215    }
09216 
09217    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
09218 
09219    if(debug)
09220       printf("After bump: %s\n", myrpt->freq);
09221 
09222    /* The ic-706 likes packed BCD frequencies */
09223 
09224    cmdstr[0] = cmdstr[1] = 0xfe;
09225    cmdstr[2] = myrpt->p.civaddr;
09226    cmdstr[3] = 0xe0;
09227    cmdstr[4] = 0;
09228    cmdstr[5] = ((d % 10) << 4);
09229    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
09230    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
09231    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
09232    cmdstr[9] = (m / 100);
09233    cmdstr[10] = 0xfd;
09234 
09235    return(serial_remote_io(myrpt,cmdstr,11,NULL,0,0));
09236 }
09237 
09238 
09239 
09240 /*
09241 * Dispatch to correct I/O handler 
09242 */
09243 static int setrem(struct rpt *myrpt)
09244 {
09245 char  str[300];
09246 char  *offsets[] = {"SIMPLEX","MINUS","PLUS"};
09247 char  *powerlevels[] = {"LOW","MEDIUM","HIGH"};
09248 char  *modes[] = {"FM","USB","LSB","AM"};
09249 int   res = -1;
09250 
09251 #if   0
09252 printf("FREQ,%s,%s,%s,%s,%s,%s,%d,%d\n",myrpt->freq,
09253    modes[(int)myrpt->remmode],
09254    myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
09255    powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
09256    myrpt->rxplon);
09257 #endif
09258    if (myrpt->p.archivedir)
09259    {
09260       sprintf(str,"FREQ,%s,%s,%s,%s,%s,%s,%d,%d",myrpt->freq,
09261          modes[(int)myrpt->remmode],
09262          myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
09263          powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
09264          myrpt->rxplon);
09265       donodelog(myrpt,str);
09266    }
09267    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09268    {
09269       rpt_telemetry(myrpt,SETREMOTE,NULL);
09270       res = 0;
09271    }
09272    if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09273    {
09274       rpt_telemetry(myrpt,SETREMOTE,NULL);
09275       res = 0;
09276    }
09277    if(!strcmp(myrpt->remoterig, remote_rig_tm271))
09278    {
09279       rpt_telemetry(myrpt,SETREMOTE,NULL);
09280       res = 0;
09281    }
09282    else if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09283    {
09284       res = setrbi_check(myrpt);
09285       if (!res)
09286       {
09287          rpt_telemetry(myrpt,SETREMOTE,NULL);
09288          res = 0;
09289       }
09290    }
09291    else if(ISRIG_RTX(myrpt->remoterig))
09292    {
09293       setrtx(myrpt);
09294       res = 0;
09295    }
09296    else if(!strcmp(myrpt->remoterig, remote_rig_kenwood)) {
09297       rpt_telemetry(myrpt,SETREMOTE,NULL);
09298       res = 0;
09299    }
09300    else
09301       res = 0;
09302 
09303    if (res < 0) ast_log(LOG_ERROR,"Unable to send remote command on node %s\n",myrpt->name);
09304 
09305    return res;
09306 }
09307 
09308 static int closerem(struct rpt *myrpt)
09309 {
09310    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09311       return closerem_ft897(myrpt);
09312    else
09313       return 0;
09314 }
09315 
09316 /*
09317 * Dispatch to correct RX frequency checker
09318 */
09319 
09320 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
09321 {
09322    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09323       return check_freq_ft897(m, d, defmode);
09324    else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09325       return check_freq_ic706(m, d, defmode,myrpt->p.remote_mars);
09326    else if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09327       return check_freq_rbi(m, d, defmode);
09328    else if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
09329       return check_freq_kenwood(m, d, defmode);
09330    else if(!strcmp(myrpt->remoterig, remote_rig_tm271))
09331       return check_freq_tm271(m, d, defmode);
09332    else if(ISRIG_RTX(myrpt->remoterig))
09333       return check_freq_rtx(m, d, defmode, myrpt);
09334    else
09335       return -1;
09336 }
09337 
09338 /*
09339  * Check TX frequency before transmitting
09340    rv=1 if tx frequency in ok.
09341 */
09342 
09343 static char check_tx_freq(struct rpt *myrpt)
09344 {
09345    int i,rv=0;
09346    int radio_mhz, radio_decimals, ulimit_mhz, ulimit_decimals, llimit_mhz, llimit_decimals;
09347    char radio_mhz_char[MAXREMSTR];
09348    char radio_decimals_char[MAXREMSTR];
09349    char limit_mhz_char[MAXREMSTR];
09350    char limit_decimals_char[MAXREMSTR];
09351    char limits[256];
09352    char *limit_ranges[40];
09353    struct ast_variable *limitlist;
09354    
09355    if(debug > 3){
09356       ast_log(LOG_NOTICE, "myrpt->freq = %s\n", myrpt->freq);
09357    }
09358 
09359    /* Must have user logged in and tx_limits defined */
09360 
09361    if(!myrpt->p.txlimitsstanzaname || !myrpt->loginuser[0] || !myrpt->loginlevel[0]){
09362       if(debug > 3){
09363          ast_log(LOG_NOTICE, "No tx band table defined, or no user logged in. rv=1\n");
09364       }
09365       rv=1;
09366       return 1; /* Assume it's ok otherwise */
09367    }
09368 
09369    /* Retrieve the band table for the loginlevel */
09370    limitlist = ast_variable_browse(myrpt->cfg, myrpt->p.txlimitsstanzaname);
09371 
09372    if(!limitlist){
09373       ast_log(LOG_WARNING, "No entries in %s band table stanza. rv=0\n", myrpt->p.txlimitsstanzaname);
09374       rv=0;
09375       return 0;
09376    }
09377 
09378    split_freq(radio_mhz_char, radio_decimals_char, myrpt->freq);
09379    radio_mhz = atoi(radio_mhz_char);
09380    radio_decimals = decimals2int(radio_decimals_char);
09381 
09382    if(debug > 3){
09383       ast_log(LOG_NOTICE, "Login User = %s, login level = %s\n", myrpt->loginuser, myrpt->loginlevel);
09384    }
09385 
09386    /* Find our entry */
09387 
09388    for(;limitlist; limitlist=limitlist->next){
09389       if(!strcmp(limitlist->name, myrpt->loginlevel))
09390          break;
09391    }
09392 
09393    if(!limitlist){
09394       ast_log(LOG_WARNING, "Can't find %s entry in band table stanza %s. rv=0\n", myrpt->loginlevel, myrpt->p.txlimitsstanzaname);
09395       rv=0;
09396        return 0;
09397    }
09398    
09399    if(debug > 3){
09400       ast_log(LOG_NOTICE, "Auth: %s = %s\n", limitlist->name, limitlist->value);
09401    }
09402 
09403    /* Parse the limits */
09404 
09405    strncpy(limits, limitlist->value, 256);
09406    limits[255] = 0;
09407    finddelim(limits, limit_ranges, 40);
09408    for(i = 0; i < 40 && limit_ranges[i] ; i++){
09409       char range[40];
09410       char *r,*s;
09411       strncpy(range, limit_ranges[i], 40);
09412       range[39] = 0;
09413         if(debug > 3) 
09414          ast_log(LOG_NOTICE, "Check %s within %s\n", myrpt->freq, range);
09415    
09416       r = strchr(range, '-');
09417       if(!r){
09418          ast_log(LOG_WARNING, "Malformed range in %s tx band table entry. rv=0\n", limitlist->name);
09419          rv=0;
09420          break;
09421       }
09422       *r++ = 0;
09423       s = eatwhite(range);
09424       r = eatwhite(r);
09425       split_freq(limit_mhz_char, limit_decimals_char, s);
09426       llimit_mhz = atoi(limit_mhz_char);
09427       llimit_decimals = decimals2int(limit_decimals_char);
09428       split_freq(limit_mhz_char, limit_decimals_char, r);
09429       ulimit_mhz = atoi(limit_mhz_char);
09430       ulimit_decimals = decimals2int(limit_decimals_char);
09431          
09432       if((radio_mhz >= llimit_mhz) && (radio_mhz <= ulimit_mhz)){
09433          if(radio_mhz == llimit_mhz){ /* CASE 1: TX freq is in llimit mhz portion of band */
09434             if(radio_decimals >= llimit_decimals){ /* Cannot be below llimit decimals */
09435                if(llimit_mhz == ulimit_mhz){ /* If bandwidth < 1Mhz, check ulimit decimals */
09436                   if(radio_decimals <= ulimit_decimals){
09437                      rv=1;
09438                      break;
09439                   }
09440                   else{
09441                      if(debug > 3)
09442                         ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 1\n");
09443                      rv=0;
09444                      break;
09445                   }
09446                }
09447                else{
09448                   rv=1;
09449                   break;
09450                }
09451             }
09452             else{ /* Is below llimit decimals */
09453                if(debug > 3)
09454                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 2\n");
09455                rv=0;
09456                break;
09457             }
09458          }
09459          else if(radio_mhz == ulimit_mhz){ /* CASE 2: TX freq not in llimit mhz portion of band */
09460             if(radio_decimals <= ulimit_decimals){
09461                if(debug > 3)
09462                   ast_log(LOG_NOTICE, "radio_decimals <= ulimit_decimals\n");
09463                rv=1;
09464                break;
09465             }
09466             else{ /* Is above ulimit decimals */
09467                if(debug > 3)
09468                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 3\n");
09469                rv=0;
09470                break;
09471             }
09472          }
09473          else /* CASE 3: TX freq within a multi-Mhz band and ok */
09474             if(debug > 3)
09475                   ast_log(LOG_NOTICE, "Valid TX freq within a multi-Mhz band and ok.\n");
09476             rv=1;
09477             break;
09478       }
09479    }
09480    if(debug > 3)  
09481       ast_log(LOG_NOTICE, "rv=%i\n",rv);
09482 
09483    return rv;
09484 }
09485 
09486 
09487 /*
09488 * Dispatch to correct frequency bumping function
09489 */
09490 
09491 static int multimode_bump_freq(struct rpt *myrpt, int interval)
09492 {
09493    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09494       return multimode_bump_freq_ft897(myrpt, interval);
09495    else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09496       return multimode_bump_freq_ic706(myrpt, interval);
09497    else
09498       return -1;
09499 }
09500 
09501 
09502 /*
09503 * Queue announcment that scan has been stopped 
09504 */
09505 
09506 static void stop_scan(struct rpt *myrpt)
09507 {
09508    myrpt->hfscanstop = 1;
09509    rpt_telemetry(myrpt,SCAN,0);
09510 }
09511 
09512 /*
09513 * This is called periodically when in scan mode
09514 */
09515 
09516 
09517 static int service_scan(struct rpt *myrpt)
09518 {
09519    int res, interval;
09520    char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
09521 
09522    switch(myrpt->hfscanmode){
09523 
09524       case HF_SCAN_DOWN_SLOW:
09525          interval = -10; /* 100Hz /sec */
09526          break;
09527 
09528       case HF_SCAN_DOWN_QUICK:
09529          interval = -50; /* 500Hz /sec */
09530          break;
09531 
09532       case HF_SCAN_DOWN_FAST:
09533          interval = -200; /* 2KHz /sec */
09534          break;
09535 
09536       case HF_SCAN_UP_SLOW:
09537          interval = 10; /* 100Hz /sec */
09538          break;
09539 
09540       case HF_SCAN_UP_QUICK:
09541          interval = 50; /* 500 Hz/sec */
09542          break;
09543 
09544       case HF_SCAN_UP_FAST:
09545          interval = 200; /* 2KHz /sec */
09546          break;
09547 
09548       default:
09549          myrpt->hfscanmode = 0; /* Huh? */
09550          return -1;
09551    }
09552 
09553    res = split_freq(mhz, decimals, myrpt->freq);
09554       
09555    if(!res){
09556       k100 =decimals[0];
09557       k10 = decimals[1];
09558       res = multimode_bump_freq(myrpt, interval);
09559    }
09560 
09561    if(!res)
09562       res = split_freq(mhz, decimals, myrpt->freq);
09563 
09564 
09565    if(res){
09566       myrpt->hfscanmode = 0;
09567       myrpt->hfscanstatus = -2;
09568       return -1;
09569    }
09570 
09571    /* Announce 10KHz boundaries */
09572    if(k10 != decimals[1]){
09573       int myhund = (interval < 0) ? k100 : decimals[0];
09574       int myten = (interval < 0) ? k10 : decimals[1];
09575       myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
09576    } else myrpt->hfscanstatus = 0;
09577    return res;
09578 
09579 }
09580 /*
09581    retrieve memory setting and set radio
09582 */
09583 static int get_mem_set(struct rpt *myrpt, char *digitbuf)
09584 {
09585    int res=0;
09586    if(debug)ast_log(LOG_NOTICE," digitbuf=%s\n", digitbuf);
09587    res = retreive_memory(myrpt, digitbuf);
09588    if(!res)res=setrem(myrpt); 
09589    if(debug)ast_log(LOG_NOTICE," freq=%s  res=%i\n", myrpt->freq, res);
09590    return res;
09591 }
09592 /*
09593    steer the radio selected channel to either one programmed into the radio
09594    or if the radio is VFO agile, to an rpt.conf memory location.
09595 */
09596 static int channel_steer(struct rpt *myrpt, char *data)
09597 {
09598    int res=0;
09599 
09600    if(debug)ast_log(LOG_NOTICE,"remoterig=%s, data=%s\n",myrpt->remoterig,data);
09601    if (!myrpt->remoterig) return(0);
09602    if(data<=0)
09603    {
09604       res=-1;
09605    }
09606    else
09607    {
09608       myrpt->nowchan=strtod(data,NULL);
09609       if(!strcmp(myrpt->remoterig, remote_rig_ppp16))
09610       {
09611          char string[16];
09612          sprintf(string,"SETCHAN %d ",myrpt->nowchan);
09613          send_usb_txt(myrpt,string);   
09614       }
09615       else
09616       {
09617          if(get_mem_set(myrpt, data))res=-1;
09618       }
09619    }
09620    if(debug)ast_log(LOG_NOTICE,"nowchan=%i  res=%i\n",myrpt->nowchan, res);
09621    return res;
09622 }
09623 /*
09624 */
09625 static int channel_revert(struct rpt *myrpt)
09626 {
09627    int res=0;
09628    if(debug)ast_log(LOG_NOTICE,"remoterig=%s, nowchan=%02d, waschan=%02d\n",myrpt->remoterig,myrpt->nowchan,myrpt->waschan);
09629    if (!myrpt->remoterig) return(0);
09630    if(myrpt->nowchan!=myrpt->waschan)
09631    {
09632       char data[8];
09633         if(debug)ast_log(LOG_NOTICE,"reverting.\n");
09634       sprintf(data,"%02d",myrpt->waschan);
09635       myrpt->nowchan=myrpt->waschan;
09636       channel_steer(myrpt,data);
09637       res=1;
09638    }
09639    return(res);
09640 }
09641 /*
09642 * Remote base function
09643 */
09644 
09645 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
09646 {
09647    char *s,*s1,*s2;
09648    int i,j,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode=0;
09649    intptr_t p;
09650    char multimode = 0;
09651    char oc,*cp,*cp1,*cp2;
09652    char tmp[20], freq[20] = "", savestr[20] = "";
09653    char mhz[MAXREMSTR], decimals[MAXREMSTR];
09654 
09655     if(debug > 6) {
09656       ast_log(LOG_NOTICE,"%s param=%s digitbuf=%s source=%i\n",myrpt->name,param,digitbuf,command_source);
09657    }
09658 
09659    if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
09660       return DC_ERROR;
09661       
09662    p = myatoi(param);
09663 
09664    if ((p != 99) && (p != 5) && (p != 140) && myrpt->p.authlevel && 
09665       (!myrpt->loginlevel[0])) return DC_ERROR;
09666    multimode = multimode_capable(myrpt);
09667 
09668    switch(p){
09669 
09670       case 1:  /* retrieve memory */
09671          if(strlen(digitbuf) < 2) /* needs 2 digits */
09672             break;
09673          
09674          for(i = 0 ; i < 2 ; i++){
09675             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09676                return DC_ERROR;
09677          }
09678          r=get_mem_set(myrpt, digitbuf);
09679          if (r < 0){
09680             rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
09681             return DC_COMPLETE;
09682          }
09683          else if (r > 0){
09684             return DC_ERROR;
09685          }
09686          return DC_COMPLETE;  
09687          
09688       case 2:  /* set freq and offset */
09689       
09690          
09691             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
09692             if(digitbuf[i] == '*'){
09693                j++;
09694                continue;
09695             }
09696             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09697                goto invalid_freq;
09698             else{
09699                if(j == 0)
09700                   l++; /* # of digits before first * */
09701                if(j == 1)
09702                   k++; /* # of digits after first * */
09703             }
09704          }
09705       
09706          i = strlen(digitbuf) - 1;
09707          if(multimode){
09708             if((j > 2) || (l > 3) || (k > 6))
09709                goto invalid_freq; /* &^@#! */
09710          }
09711          else{
09712             if((j > 2) || (l > 4) || (k > 3))
09713                goto invalid_freq; /* &^@#! */
09714          }
09715 
09716          /* Wait for M+*K+* */
09717 
09718          if(j < 2)
09719             break; /* Not yet */
09720 
09721          /* We have a frequency */
09722 
09723          strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
09724          
09725          s = tmp;
09726          s1 = strsep(&s, "*"); /* Pick off MHz */
09727          s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
09728          ls2 = strlen(s2); 
09729          
09730          switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
09731             case 1:
09732                ht = 0;
09733                k = 100 * atoi(s2);
09734                break;
09735             
09736             case 2:
09737                ht = 0;
09738                k = 10 * atoi(s2);
09739                break;
09740                
09741             case 3:
09742                if(!multimode){
09743                   if((s2[2] != '0')&&(s2[2] != '5'))
09744                      goto invalid_freq;
09745                }
09746                ht = 0;
09747                k = atoi(s2);
09748                   break;
09749             case 4:
09750                k = atoi(s2)/10;
09751                ht = 10 * (atoi(s2+(ls2-1)));
09752                break;
09753 
09754             case 5:
09755                k = atoi(s2)/100;
09756                ht = (atoi(s2+(ls2-2)));
09757                break;
09758                
09759             default:
09760                goto invalid_freq;
09761          }
09762 
09763          /* Check frequency for validity and establish a default mode */
09764          
09765          snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
09766 
09767          if(debug)
09768             ast_log(LOG_NOTICE, "New frequency: %s\n", freq);
09769    
09770          split_freq(mhz, decimals, freq);
09771          m = atoi(mhz);
09772          d = atoi(decimals);
09773 
09774          if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
09775                  goto invalid_freq;
09776 
09777 
09778          if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
09779             break; /* Not yet */
09780 
09781 
09782          offset = REM_SIMPLEX; /* Assume simplex */
09783 
09784          if(defmode == REM_MODE_FM){
09785             oc = *s; /* Pick off offset */
09786          
09787             if (oc){
09788                switch(oc){
09789                   case '1':
09790                      offset = REM_MINUS;
09791                      break;
09792                   
09793                   case '2':
09794                      offset = REM_SIMPLEX;
09795                   break;
09796                   
09797                   case '3':
09798                      offset = REM_PLUS;
09799                      break;
09800                   
09801                   default:
09802                      goto invalid_freq;
09803                } 
09804             } 
09805          }  
09806          offsave = myrpt->offset;
09807          modesave = myrpt->remmode;
09808          strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
09809          strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
09810          myrpt->offset = offset;
09811          myrpt->remmode = defmode;
09812 
09813          if (setrem(myrpt) == -1){
09814             myrpt->offset = offsave;
09815             myrpt->remmode = modesave;
09816             strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
09817             goto invalid_freq;
09818          }
09819 
09820          return DC_COMPLETE;
09821 
09822 invalid_freq:
09823          rpt_telemetry(myrpt,INVFREQ,NULL);
09824          return DC_ERROR; 
09825       
09826       case 3: /* set rx PL tone */
09827             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
09828             if(digitbuf[i] == '*'){
09829                j++;
09830                continue;
09831             }
09832             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09833                return DC_ERROR;
09834             else{
09835                if(j)
09836                   l++;
09837                else
09838                   k++;
09839             }
09840          }
09841          if((j > 1) || (k > 3) || (l > 1))
09842             return DC_ERROR; /* &$@^! */
09843          i = strlen(digitbuf) - 1;
09844          if((j != 1) || (k < 2)|| (l != 1))
09845             break; /* Not yet */
09846          if(debug)
09847             printf("PL digits entered %s\n", digitbuf);
09848             
09849          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
09850          /* see if we have at least 1 */
09851          s = strchr(tmp,'*');
09852          if(s)
09853             *s = '.';
09854          strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
09855          strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
09856          if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09857          {
09858             strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
09859          }
09860          if (setrem(myrpt) == -1){
09861             strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
09862             return DC_ERROR;
09863          }
09864          return DC_COMPLETE;
09865       
09866       case 4: /* set tx PL tone */
09867          /* cant set tx tone on RBI (rx tone does both) */
09868          if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09869             return DC_ERROR;
09870          /*  eventually for the ic706 instead of just throwing the exception
09871             we can check if we are in encode only mode and allow the tx
09872             ctcss code to be changed. but at least the warning message is
09873             issued for now.
09874          */
09875          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09876          {
09877             if(debug)
09878                ast_log(LOG_WARNING,"Setting IC706 Tx CTCSS Code Not Supported. Set Rx Code for both.\n");
09879             return DC_ERROR;
09880          }
09881          for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
09882             if(digitbuf[i] == '*'){
09883                j++;
09884                continue;
09885             }
09886             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09887                return DC_ERROR;
09888             else{
09889                if(j)
09890                   l++;
09891                else
09892                   k++;
09893             }
09894          }
09895          if((j > 1) || (k > 3) || (l > 1))
09896             return DC_ERROR; /* &$@^! */
09897          i = strlen(digitbuf) - 1;
09898          if((j != 1) || (k < 2)|| (l != 1))
09899             break; /* Not yet */
09900          if(debug)
09901             printf("PL digits entered %s\n", digitbuf);
09902             
09903          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
09904          /* see if we have at least 1 */
09905          s = strchr(tmp,'*');
09906          if(s)
09907             *s = '.';
09908          strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1);
09909          strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
09910          
09911          if (setrem(myrpt) == -1){
09912             strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
09913             return DC_ERROR;
09914          }
09915          return DC_COMPLETE;
09916       
09917 
09918       case 6: /* MODE (FM,USB,LSB,AM) */
09919          if(strlen(digitbuf) < 1)
09920             break;
09921 
09922          if(!multimode)
09923             return DC_ERROR; /* Multimode radios only */
09924 
09925          switch(*digitbuf){
09926             case '1':
09927                split_freq(mhz, decimals, myrpt->freq); 
09928                m=atoi(mhz);
09929                if(m < 29) /* No FM allowed below 29MHz! */
09930                   return DC_ERROR;
09931                myrpt->remmode = REM_MODE_FM;
09932                
09933                rpt_telemetry(myrpt,REMMODE,NULL);
09934                break;
09935 
09936             case '2':
09937                myrpt->remmode = REM_MODE_USB;
09938                rpt_telemetry(myrpt,REMMODE,NULL);
09939                break;   
09940 
09941             case '3':
09942                myrpt->remmode = REM_MODE_LSB;
09943                rpt_telemetry(myrpt,REMMODE,NULL);
09944                break;
09945             
09946             case '4':
09947                myrpt->remmode = REM_MODE_AM;
09948                rpt_telemetry(myrpt,REMMODE,NULL);
09949                break;
09950       
09951             default:
09952                return DC_ERROR;
09953          }
09954 
09955          if(setrem(myrpt))
09956             return DC_ERROR;
09957          return DC_COMPLETEQUIET;
09958       case 99:
09959          /* cant log in when logged in */
09960          if (myrpt->loginlevel[0]) 
09961             return DC_ERROR;
09962          *myrpt->loginuser = 0;
09963          myrpt->loginlevel[0] = 0;
09964          cp = ast_strdup(param);
09965          cp1 = strchr(cp,',');
09966          ast_mutex_lock(&myrpt->lock);
09967          if (cp1) 
09968          {
09969             *cp1 = 0;
09970             cp2 = strchr(cp1 + 1,',');
09971             if (cp2) 
09972             {
09973                *cp2 = 0;
09974                strncpy(myrpt->loginlevel,cp2 + 1,
09975                   sizeof(myrpt->loginlevel) - 1);
09976             }
09977             strncpy(myrpt->loginuser,cp1 + 1,sizeof(myrpt->loginuser));
09978             ast_mutex_unlock(&myrpt->lock);
09979             if (myrpt->p.archivedir)
09980             {
09981                char str[100];
09982 
09983                sprintf(str,"LOGIN,%s,%s",
09984                    myrpt->loginuser,myrpt->loginlevel);
09985                donodelog(myrpt,str);
09986             }
09987             if (debug) 
09988                printf("loginuser %s level %s\n",myrpt->loginuser,myrpt->loginlevel);
09989             rpt_telemetry(myrpt,REMLOGIN,NULL);
09990          }
09991          ast_free(cp);
09992          return DC_COMPLETEQUIET;
09993       case 100: /* RX PL Off */
09994          myrpt->rxplon = 0;
09995          setrem(myrpt);
09996          rpt_telemetry(myrpt,REMXXX,(void *)p);
09997          return DC_COMPLETEQUIET;
09998       case 101: /* RX PL On */
09999          myrpt->rxplon = 1;
10000          setrem(myrpt);
10001          rpt_telemetry(myrpt,REMXXX,(void *)p);
10002          return DC_COMPLETEQUIET;
10003       case 102: /* TX PL Off */
10004          myrpt->txplon = 0;
10005          setrem(myrpt);
10006          rpt_telemetry(myrpt,REMXXX,(void *)p);
10007          return DC_COMPLETEQUIET;
10008       case 103: /* TX PL On */
10009          myrpt->txplon = 1;
10010          setrem(myrpt);
10011          rpt_telemetry(myrpt,REMXXX,(void *)p);
10012          return DC_COMPLETEQUIET;
10013       case 104: /* Low Power */
10014          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10015             return DC_ERROR;
10016          myrpt->powerlevel = REM_LOWPWR;
10017          setrem(myrpt);
10018          rpt_telemetry(myrpt,REMXXX,(void *)p);
10019          return DC_COMPLETEQUIET;
10020       case 105: /* Medium Power */
10021          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10022             return DC_ERROR;
10023          if (ISRIG_RTX(myrpt->remoterig)) return DC_ERROR;
10024          myrpt->powerlevel = REM_MEDPWR;
10025          setrem(myrpt);
10026          rpt_telemetry(myrpt,REMXXX,(void *)p);
10027          return DC_COMPLETEQUIET;
10028       case 106: /* Hi Power */
10029          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10030             return DC_ERROR;
10031          myrpt->powerlevel = REM_HIPWR;
10032          setrem(myrpt);
10033          rpt_telemetry(myrpt,REMXXX,(void *)p);
10034          return DC_COMPLETEQUIET;
10035       case 107: /* Bump down 20Hz */
10036          multimode_bump_freq(myrpt, -20);
10037          return DC_COMPLETE;
10038       case 108: /* Bump down 100Hz */
10039          multimode_bump_freq(myrpt, -100);
10040          return DC_COMPLETE;
10041       case 109: /* Bump down 500Hz */
10042          multimode_bump_freq(myrpt, -500);
10043          return DC_COMPLETE;
10044       case 110: /* Bump up 20Hz */
10045          multimode_bump_freq(myrpt, 20);
10046          return DC_COMPLETE;
10047       case 111: /* Bump up 100Hz */
10048          multimode_bump_freq(myrpt, 100);
10049          return DC_COMPLETE;
10050       case 112: /* Bump up 500Hz */
10051          multimode_bump_freq(myrpt, 500);
10052          return DC_COMPLETE;
10053       case 113: /* Scan down slow */
10054          myrpt->scantimer = REM_SCANTIME;
10055          myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
10056          rpt_telemetry(myrpt,REMXXX,(void *)p);
10057          return DC_COMPLETEQUIET;
10058       case 114: /* Scan down quick */
10059          myrpt->scantimer = REM_SCANTIME;
10060          myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
10061          rpt_telemetry(myrpt,REMXXX,(void *)p);
10062          return DC_COMPLETEQUIET;
10063       case 115: /* Scan down fast */
10064          myrpt->scantimer = REM_SCANTIME;
10065          myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
10066          rpt_telemetry(myrpt,REMXXX,(void *)p);
10067          return DC_COMPLETEQUIET;
10068       case 116: /* Scan up slow */
10069          myrpt->scantimer = REM_SCANTIME;
10070          myrpt->hfscanmode = HF_SCAN_UP_SLOW;
10071          rpt_telemetry(myrpt,REMXXX,(void *)p);
10072          return DC_COMPLETEQUIET;
10073       case 117: /* Scan up quick */
10074          myrpt->scantimer = REM_SCANTIME;
10075          myrpt->hfscanmode = HF_SCAN_UP_QUICK;
10076          rpt_telemetry(myrpt,REMXXX,(void *)p);
10077          return DC_COMPLETEQUIET;
10078       case 118: /* Scan up fast */
10079          myrpt->scantimer = REM_SCANTIME;
10080          myrpt->hfscanmode = HF_SCAN_UP_FAST;
10081          rpt_telemetry(myrpt,REMXXX,(void *)p);
10082          return DC_COMPLETEQUIET;
10083       case 119: /* Tune Request */
10084          if(debug > 3)
10085             ast_log(LOG_NOTICE,"TUNE REQUEST\n");
10086          /* if not currently going, and valid to do */
10087          if((!myrpt->tunerequest) && 
10088              ((!strcmp(myrpt->remoterig, remote_rig_ft897) || 
10089             !strcmp(myrpt->remoterig, remote_rig_ic706)) )) { 
10090             myrpt->remotetx = 0;
10091             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
10092             myrpt->tunerequest = 1;
10093             rpt_telemetry(myrpt,TUNE,NULL);
10094             return DC_COMPLETEQUIET;
10095          }
10096          return DC_ERROR;        
10097       case 5: /* Long Status */
10098          rpt_telemetry(myrpt,REMLONGSTATUS,NULL);
10099          return DC_COMPLETEQUIET;
10100       case 140: /* Short Status */
10101          rpt_telemetry(myrpt,REMSHORTSTATUS,NULL);
10102          return DC_COMPLETEQUIET;
10103       case 200:
10104       case 201:
10105       case 202:
10106       case 203:
10107       case 204:
10108       case 205:
10109       case 206:
10110       case 207:
10111       case 208:
10112       case 209:
10113       case 210:
10114       case 211:
10115       case 212:
10116       case 213:
10117       case 214:
10118       case 215:
10119          do_dtmf_local(myrpt,remdtmfstr[p - 200]);
10120          return DC_COMPLETEQUIET;
10121       default:
10122          break;
10123    }
10124    return DC_INDETERMINATE;
10125 }
10126 
10127 
10128 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode)
10129 {
10130 time_t   now;
10131 int   ret,res = 0,src;
10132 
10133    if(debug > 6)
10134       ast_log(LOG_NOTICE,"c=%c  phonemode=%i  dtmfidx=%i\n",c,phonemode,myrpt->dtmfidx);
10135 
10136    time(&myrpt->last_activity_time);
10137    /* Stop scan mode if in scan mode */
10138    if(myrpt->hfscanmode){
10139       stop_scan(myrpt);
10140       return 0;
10141    }
10142 
10143    time(&now);
10144    /* if timed-out */
10145    if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
10146    {
10147       myrpt->dtmfidx = -1;
10148       myrpt->dtmfbuf[0] = 0;
10149       myrpt->dtmf_time_rem = 0;
10150    }
10151    /* if decode not active */
10152    if (myrpt->dtmfidx == -1)
10153    {
10154       /* if not lead-in digit, don't worry */
10155       if (c != myrpt->p.funcchar)
10156       {
10157          if (!myrpt->p.propagate_dtmf)
10158          {
10159             rpt_mutex_lock(&myrpt->lock);
10160             do_dtmf_local(myrpt,c);
10161             rpt_mutex_unlock(&myrpt->lock);
10162          }
10163          return 0;
10164       }
10165       myrpt->dtmfidx = 0;
10166       myrpt->dtmfbuf[0] = 0;
10167       myrpt->dtmf_time_rem = now;
10168       return 0;
10169    }
10170    /* if too many in buffer, start over */
10171    if (myrpt->dtmfidx >= MAXDTMF)
10172    {
10173       myrpt->dtmfidx = 0;
10174       myrpt->dtmfbuf[0] = 0;
10175       myrpt->dtmf_time_rem = now;
10176    }
10177    if (c == myrpt->p.funcchar)
10178    {
10179       /* if star at beginning, or 2 together, erase buffer */
10180       if ((myrpt->dtmfidx < 1) || 
10181          (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
10182       {
10183          myrpt->dtmfidx = 0;
10184          myrpt->dtmfbuf[0] = 0;
10185          myrpt->dtmf_time_rem = now;
10186          return 0;
10187       }
10188    }
10189    myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
10190    myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10191    myrpt->dtmf_time_rem = now;
10192    
10193    
10194    src = SOURCE_RMT;
10195    if (phonemode == 2) src = SOURCE_DPHONE;
10196    else if (phonemode) src = SOURCE_PHONE;
10197    else if (phonemode == 4) src = SOURCE_ALT;
10198    ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
10199    
10200    switch(ret){
10201    
10202       case DC_INDETERMINATE:
10203          res = 0;
10204          break;
10205             
10206       case DC_DOKEY:
10207          if (keyed) *keyed = 1;
10208          res = 0;
10209          break;
10210             
10211       case DC_REQ_FLUSH:
10212          myrpt->dtmfidx = 0;
10213          myrpt->dtmfbuf[0] = 0;
10214          res = 0;
10215          break;
10216             
10217             
10218       case DC_COMPLETE:
10219          res = 1;
10220       case DC_COMPLETEQUIET:
10221          myrpt->totalexecdcommands++;
10222          myrpt->dailyexecdcommands++;
10223          strncpy(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF-1);
10224          myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
10225          myrpt->dtmfbuf[0] = 0;
10226          myrpt->dtmfidx = -1;
10227          myrpt->dtmf_time_rem = 0;
10228          break;
10229             
10230       case DC_ERROR:
10231       default:
10232          myrpt->dtmfbuf[0] = 0;
10233          myrpt->dtmfidx = -1;
10234          myrpt->dtmf_time_rem = 0;
10235          res = 0;
10236          break;
10237    }
10238 
10239    return res;
10240 }
10241 
10242 static int handle_remote_data(struct rpt *myrpt, char *str)
10243 {
10244 /* XXX ATTENTION: if you change the size of these arrays you MUST
10245  * change the limits in corresponding sscanf() calls below. */
10246 char  tmp[300],cmd[300],dest[300],src[300],c;
10247 int   seq,res;
10248 
10249    /* put string in our buffer */
10250    strncpy(tmp,str,sizeof(tmp) - 1);
10251    if (!strcmp(tmp,discstr)) return 0;
10252         if (!strcmp(tmp,newkeystr))
10253         {
10254       myrpt->newkey = 1;
10255                 return 0;
10256         }
10257 
10258 #ifndef  DO_NOT_NOTIFY_MDC1200_ON_REMOTE_BASES
10259    if (tmp[0] == 'I')
10260    {
10261       /* XXX WARNING: be very careful with the limits on the folowing
10262        * sscanf() call, make sure they match the values defined above */
10263       if (sscanf(tmp,"%299s %299s %30x",cmd,src,&seq) != 3)
10264       {
10265          ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
10266          return 0;
10267       }
10268       mdc1200_notify(myrpt,src,seq);
10269       return 0;
10270    }
10271 #endif
10272    /* XXX WARNING: be very careful with the limits on the folowing
10273     * sscanf() call, make sure they match the values defined above */
10274    if (sscanf(tmp,"%299s %299s %299s %30d %1c",cmd,dest,src,&seq,&c) != 5)
10275    {
10276       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
10277       return 0;
10278    }
10279    if (strcmp(cmd,"D"))
10280    {
10281       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
10282       return 0;
10283    }
10284    /* if not for me, ignore */
10285    if (strcmp(dest,myrpt->name)) return 0;
10286    if (myrpt->p.archivedir)
10287    {
10288       char dtmfstr[100];
10289 
10290       sprintf(dtmfstr,"DTMF,%c",c);
10291       donodelog(myrpt,dtmfstr);
10292    }
10293    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
10294    if (!c) return(0);
10295    res = handle_remote_dtmf_digit(myrpt,c, NULL, 0);
10296    if (res != 1)
10297       return res;
10298    rpt_telemetry(myrpt,COMPLETE,NULL);
10299    return 0;
10300 }
10301 
10302 static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode)
10303 {
10304 int   res;
10305 
10306 
10307    if(phonemode == 3) /* simplex phonemode, funcchar key/unkey toggle */
10308    {
10309       if (keyed && *keyed && ((c == myrpt->p.funcchar) || (c == myrpt->p.endchar)))
10310       {
10311          *keyed = 0; /* UNKEY */
10312          return 0;
10313       }
10314       else if (keyed && !*keyed && (c = myrpt->p.funcchar))
10315       {
10316          *keyed = 1; /* KEY */
10317          return 0;
10318       }
10319    }
10320    else /* endchar unkey */
10321    {
10322 
10323       if (keyed && *keyed && (c == myrpt->p.endchar))
10324       {
10325          *keyed = 0;
10326          return DC_INDETERMINATE;
10327       }
10328    }
10329    if (myrpt->p.archivedir)
10330    {
10331       char str[100];
10332 
10333       sprintf(str,"DTMF(P),%c",c);
10334       donodelog(myrpt,str);
10335    }
10336    res = handle_remote_dtmf_digit(myrpt,c,keyed, phonemode);
10337    if (res != 1)
10338       return res;
10339    rpt_telemetry(myrpt,COMPLETE,NULL);
10340    return 0;
10341 }
10342 
10343 static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
10344 {
10345    char *val, *s, *s1, *s2, *tele;
10346    char tmp[300], deststr[300] = "";
10347    char sx[320],*sy;
10348 
10349 
10350    val = node_lookup(myrpt,l->name);
10351    if (!val)
10352    {
10353       fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
10354       return -1;
10355    }
10356 
10357    rpt_mutex_lock(&myrpt->lock);
10358    /* remove from queue */
10359    remque((struct qelem *) l);
10360    rpt_mutex_unlock(&myrpt->lock);
10361    strncpy(tmp,val,sizeof(tmp) - 1);
10362    s = tmp;
10363    s1 = strsep(&s,",");
10364    if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
10365    {
10366       sy = strchr(s1,'/');    
10367       *sy = 0;
10368       sprintf(sx,"%s:4569/%s",s1,sy + 1);
10369       s1 = sx;
10370    }
10371    s2 = strsep(&s,",");
10372    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
10373    tele = strchr(deststr, '/');
10374    if (!tele) {
10375       fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
10376       return -1;
10377    }
10378    *tele++ = 0;
10379    l->elaptime = 0;
10380    l->connecttime = 0;
10381    l->thisconnected = 0;
10382    l->newkey = 0;
10383    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, NULL, tele, NULL);
10384    if (l->chan){
10385       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
10386       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
10387 #ifndef  NEW_ASTERISK
10388       l->chan->whentohangup = 0;
10389 #endif
10390       l->chan->appl = "Apprpt";
10391       l->chan->data = "(Remote Rx)";
10392       if (option_verbose > 2)
10393          ast_verbose(VERBOSE_PREFIX_3 "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
10394             deststr, tele, l->chan->name);
10395       l->chan->caller.id.number.valid = 1;
10396       ast_free(l->chan->caller.id.number.str);
10397       l->chan->caller.id.number.str = ast_strdup(myrpt->name);
10398                 ast_call(l->chan,tele,999); 
10399 
10400    }
10401    else 
10402    {
10403       if (option_verbose > 2)
10404          ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
10405             deststr,tele,l->chan->name);
10406       return -1;
10407    }
10408    rpt_mutex_lock(&myrpt->lock);
10409    /* put back in queue */
10410    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
10411    rpt_mutex_unlock(&myrpt->lock);
10412    ast_log(LOG_WARNING,"Reconnect Attempt to %s in process\n",l->name);
10413    if (!l->phonemode) send_newkey(l->chan);
10414    return 0;
10415 }
10416 
10417 /* 0 return=continue, 1 return = break, -1 return = error */
10418 static void local_dtmf_helper(struct rpt *myrpt,char c_in)
10419 {
10420 int   res;
10421 pthread_attr_t attr;
10422 char  cmd[MAXDTMF+1] = "",c;
10423 
10424 
10425    c = c_in & 0x7f;
10426    if (myrpt->p.archivedir)
10427    {
10428       char str[100];
10429 
10430       sprintf(str,"DTMF,MAIN,%c",c);
10431       donodelog(myrpt,str);
10432    }
10433    if (c == myrpt->p.endchar)
10434    {
10435    /* if in simple mode, kill autopatch */
10436       if (myrpt->p.simple && myrpt->callmode)
10437       {   
10438          if(debug)
10439             ast_log(LOG_WARNING, "simple mode autopatch kill\n");
10440          rpt_mutex_lock(&myrpt->lock);
10441          myrpt->callmode = 0;
10442          myrpt->macropatch=0;
10443          channel_revert(myrpt);
10444          rpt_mutex_unlock(&myrpt->lock);
10445          rpt_telemetry(myrpt,TERM,NULL);
10446          return;
10447       }
10448       rpt_mutex_lock(&myrpt->lock);
10449       myrpt->stopgen = 1;
10450       if (myrpt->cmdnode[0])
10451       {
10452          myrpt->cmdnode[0] = 0;
10453          myrpt->dtmfidx = -1;
10454          myrpt->dtmfbuf[0] = 0;
10455          rpt_mutex_unlock(&myrpt->lock);
10456          rpt_telemetry(myrpt,COMPLETE,NULL);
10457          return;
10458       } 
10459       else if(!myrpt->inpadtest)
10460                 {
10461                         rpt_mutex_unlock(&myrpt->lock);
10462                         if (myrpt->p.propagate_phonedtmf)
10463                                do_dtmf_phone(myrpt,NULL,c);
10464          return;
10465                 }
10466       else
10467          rpt_mutex_unlock(&myrpt->lock);
10468    }
10469    rpt_mutex_lock(&myrpt->lock);
10470    if (myrpt->cmdnode[0])
10471    {
10472       rpt_mutex_unlock(&myrpt->lock);
10473       send_link_dtmf(myrpt,c);
10474       return;
10475    }
10476    if (!myrpt->p.simple)
10477    {
10478       if ((!myrpt->inpadtest)&&(c == myrpt->p.funcchar))
10479       {
10480          myrpt->dtmfidx = 0;
10481          myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10482          rpt_mutex_unlock(&myrpt->lock);
10483          time(&myrpt->dtmf_time);
10484          return;
10485       } 
10486       else if (((myrpt->inpadtest)||(c != myrpt->p.endchar)) && (myrpt->dtmfidx >= 0))
10487       {
10488          time(&myrpt->dtmf_time);
10489          
10490          if (myrpt->dtmfidx < MAXDTMF)
10491          {
10492             int src;
10493 
10494             myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
10495             myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10496             
10497             strncpy(cmd, myrpt->dtmfbuf, sizeof(cmd) - 1);
10498             
10499             rpt_mutex_unlock(&myrpt->lock);
10500             src = SOURCE_RPT;
10501             if (c_in & 0x80) src = SOURCE_ALT;
10502             res = collect_function_digits(myrpt, cmd, src, NULL);
10503             rpt_mutex_lock(&myrpt->lock);
10504             switch(res){
10505                 case DC_INDETERMINATE:
10506                break;
10507                 case DC_REQ_FLUSH:
10508                myrpt->dtmfidx = 0;
10509                myrpt->dtmfbuf[0] = 0;
10510                break;
10511                 case DC_COMPLETE:
10512                 case DC_COMPLETEQUIET:
10513                myrpt->totalexecdcommands++;
10514                myrpt->dailyexecdcommands++;
10515                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
10516                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
10517                myrpt->dtmfbuf[0] = 0;
10518                myrpt->dtmfidx = -1;
10519                myrpt->dtmf_time = 0;
10520                break;
10521 
10522                 case DC_ERROR:
10523                 default:
10524                myrpt->dtmfbuf[0] = 0;
10525                myrpt->dtmfidx = -1;
10526                myrpt->dtmf_time = 0;
10527                break;
10528             }
10529             if(res != DC_INDETERMINATE) {
10530                rpt_mutex_unlock(&myrpt->lock);
10531                return;
10532             }
10533          } 
10534       }
10535    }
10536    else /* if simple */
10537    {
10538       if ((!myrpt->callmode) && (c == myrpt->p.funcchar))
10539       {
10540          myrpt->callmode = 1;
10541          myrpt->patchnoct = 0;
10542          myrpt->patchquiet = 0;
10543          myrpt->patchfarenddisconnect = 0;
10544          myrpt->patchdialtime = 0;
10545          strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
10546          myrpt->cidx = 0;
10547          myrpt->exten[myrpt->cidx] = 0;
10548          rpt_mutex_unlock(&myrpt->lock);
10549               pthread_attr_init(&attr);
10550               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10551          ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
10552          return;
10553       }
10554    }
10555    if (myrpt->callmode == 1)
10556    {
10557       myrpt->exten[myrpt->cidx++] = c;
10558       myrpt->exten[myrpt->cidx] = 0;
10559       /* if this exists */
10560       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
10561       {
10562          /* if this really it, end now */
10563          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
10564             myrpt->exten,1,NULL)) 
10565          {
10566             myrpt->callmode = 2;
10567             rpt_mutex_unlock(&myrpt->lock);
10568             if(!myrpt->patchquiet)
10569                rpt_telemetry(myrpt,PROC,NULL); 
10570             return;
10571          }
10572          else /* othewise, reset timer */
10573          {
10574             myrpt->calldigittimer = 1;
10575          }
10576       }
10577       /* if can continue, do so */
10578       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
10579       {
10580          /* call has failed, inform user */
10581          myrpt->callmode = 4;
10582       }
10583       rpt_mutex_unlock(&myrpt->lock);
10584       return;
10585    }
10586    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
10587    {
10588       myrpt->mydtmf = c;
10589    }
10590    rpt_mutex_unlock(&myrpt->lock);
10591    if ((myrpt->dtmfidx < 0) && myrpt->p.propagate_phonedtmf)
10592       do_dtmf_phone(myrpt,NULL,c);
10593    return;
10594 }
10595 
10596 
10597 /* place an ID event in the telemetry queue */
10598 
10599 static void queue_id(struct rpt *myrpt)
10600 {
10601    if(myrpt->p.idtime){ /* ID time must be non-zero */
10602       myrpt->mustid = myrpt->tailid = 0;
10603       myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
10604       rpt_mutex_unlock(&myrpt->lock);
10605       rpt_telemetry(myrpt,ID,NULL);
10606       rpt_mutex_lock(&myrpt->lock);
10607    }
10608 }
10609 
10610 /* Scheduler */
10611 /* must be called locked */
10612 
10613 static void do_scheduler(struct rpt *myrpt)
10614 {
10615    int i,res;
10616 
10617 #ifdef   NEW_ASTERISK
10618    struct ast_tm tmnow;
10619 #else
10620    struct tm tmnow;
10621 #endif
10622    struct ast_variable *skedlist;
10623    char *strs[5],*vp,*val,value[100];
10624 
10625    memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
10626    
10627    if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
10628       ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
10629 
10630    /* Try to get close to a 1 second resolution */
10631    
10632    if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
10633       return;
10634 
10635    rpt_localtime(&myrpt->curtv.tv_sec, &tmnow);
10636 
10637    /* If midnight, then reset all daily statistics */
10638    
10639    if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
10640       myrpt->dailykeyups = 0;
10641       myrpt->dailytxtime = 0;
10642       myrpt->dailykerchunks = 0;
10643       myrpt->dailyexecdcommands = 0;
10644    }
10645 
10646    if(tmnow.tm_sec != 0)
10647       return;
10648 
10649    /* Code below only executes once per minute */
10650 
10651 
10652    /* Don't schedule if remote */
10653 
10654         if (myrpt->remote)
10655                 return;
10656 
10657    /* Don't schedule if disabled */
10658 
10659         if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable){
10660       if(debug > 6)
10661          ast_log(LOG_NOTICE, "Scheduler disabled\n");
10662       return;
10663    }
10664 
10665    if(!myrpt->p.skedstanzaname){ /* No stanza means we do nothing */
10666       if(debug > 6)
10667          ast_log(LOG_NOTICE,"No stanza for scheduler in rpt.conf\n");
10668       return;
10669    }
10670 
10671     /* get pointer to linked list of scheduler entries */
10672     skedlist = ast_variable_browse(myrpt->cfg, myrpt->p.skedstanzaname);
10673 
10674    if(debug > 6){
10675       ast_log(LOG_NOTICE, "Time now: %02d:%02d %02d %02d %02d\n",
10676          tmnow.tm_hour,tmnow.tm_min,tmnow.tm_mday,tmnow.tm_mon + 1, tmnow.tm_wday); 
10677    }
10678    /* walk the list */
10679    for(; skedlist; skedlist = skedlist->next){
10680       if(debug > 6)
10681          ast_log(LOG_NOTICE, "Scheduler entry %s = %s being considered\n",skedlist->name, skedlist->value);
10682       strncpy(value,skedlist->value,99);
10683       value[99] = 0;
10684       /* point to the substrings for minute, hour, dom, month, and dow */
10685       for( i = 0, vp = value ; i < 5; i++){
10686          if(!*vp)
10687             break;
10688          while((*vp == ' ') || (*vp == 0x09)) /* get rid of any leading white space */
10689             vp++;
10690          strs[i] = vp; /* save pointer to beginning of substring */
10691          while((*vp != ' ') && (*vp != 0x09) && (*vp != 0)) /* skip over substring */
10692             vp++;
10693          if(*vp)
10694             *vp++ = 0; /* mark end of substring */
10695       }
10696       if(debug > 6)
10697          ast_log(LOG_NOTICE, "i = %d, min = %s, hour = %s, mday=%s, mon=%s, wday=%s\n",i,
10698             strs[0], strs[1], strs[2], strs[3], strs[4]); 
10699       if(i == 5){
10700          if((*strs[0] != '*')&&(atoi(strs[0]) != tmnow.tm_min))
10701             continue;
10702          if((*strs[1] != '*')&&(atoi(strs[1]) != tmnow.tm_hour))
10703             continue;
10704          if((*strs[2] != '*')&&(atoi(strs[2]) != tmnow.tm_mday))
10705             continue;
10706          if((*strs[3] != '*')&&(atoi(strs[3]) != tmnow.tm_mon + 1))
10707             continue;
10708          if(atoi(strs[4]) == 7)
10709             strs[4] = "0";
10710          if((*strs[4] != '*')&&(atoi(strs[4]) != tmnow.tm_wday))
10711             continue;
10712          if(debug)
10713             ast_log(LOG_NOTICE, "Executing scheduler entry %s = %s\n", skedlist->name, skedlist->value);
10714          if(atoi(skedlist->name) == 0)
10715             return; /* Zero is reserved for the startup macro */
10716          val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, skedlist->name);
10717          if (!val){
10718             ast_log(LOG_WARNING,"Scheduler could not find macro %s\n",skedlist->name);
10719             return; /* Macro not found */
10720          }
10721          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)){
10722             ast_log(LOG_WARNING, "Scheduler could not execute macro %s: Macro buffer full\n",
10723                skedlist->name);
10724             return; /* Macro buffer full */
10725          }
10726          myrpt->macrotimer = MACROTIME;
10727          strncat(myrpt->macrobuf,val,MAXMACRO - 1);
10728       }
10729       else{
10730          ast_log(LOG_WARNING,"Malformed scheduler entry in rpt.conf: %s = %s\n",
10731             skedlist->name, skedlist->value);
10732       }
10733    }
10734 
10735 }
10736 
10737 /* single thread with one file (request) to dial */
10738 static void *rpt(void *this)
10739 {
10740 struct   rpt *myrpt = (struct rpt *)this;
10741 char *tele,*idtalkover,c,myfirst,*p;
10742 int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued;
10743 int tailmessagequeued,ctqueued,dtmfed,lastmyrx,localmsgqueued;
10744 struct ast_channel *who;
10745 struct dahdi_confinfo ci;  /* conference info */
10746 time_t   t;
10747 struct rpt_link *l,*m;
10748 struct rpt_tele *telem;
10749 char tmpstr[300],lstr[MAXLINKLIST];
10750 
10751 
10752    if (myrpt->p.archivedir) mkdir(myrpt->p.archivedir,0600);
10753    sprintf(tmpstr,"%s/%s",myrpt->p.archivedir,myrpt->name);
10754    mkdir(tmpstr,0600);
10755    rpt_mutex_lock(&myrpt->lock);
10756 
10757    telem = myrpt->tele.next;
10758    while(telem != &myrpt->tele)
10759    {
10760       ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
10761       telem = telem->next;
10762    }
10763    rpt_mutex_unlock(&myrpt->lock);
10764    /* find our index, and load the vars initially */
10765    for(i = 0; i < nrpts; i++)
10766    {
10767       if (&rpt_vars[i] == myrpt)
10768       {
10769          load_rpt_vars(i,0);
10770          break;
10771       }
10772    }
10773 
10774    rpt_mutex_lock(&myrpt->lock);
10775    while(myrpt->xlink)
10776    {
10777       myrpt->xlink = 3;
10778       rpt_mutex_unlock(&myrpt->lock);
10779       usleep(100000);
10780       rpt_mutex_lock(&myrpt->lock);
10781    }
10782 #ifdef HAVE_IOPERM
10783    if ((!strcmp(myrpt->remoterig, remote_rig_rbi)) &&
10784      (ioperm(myrpt->p.iobase,1,1) == -1))
10785    {
10786       rpt_mutex_unlock(&myrpt->lock);
10787       ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
10788       myrpt->rpt_thread = AST_PTHREADT_STOP;
10789       pthread_exit(NULL);
10790    }
10791 #endif
10792    strncpy(tmpstr,myrpt->rxchanname,sizeof(tmpstr) - 1);
10793    tele = strchr(tmpstr,'/');
10794    if (!tele)
10795    {
10796       fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
10797       rpt_mutex_unlock(&myrpt->lock);
10798       myrpt->rpt_thread = AST_PTHREADT_STOP;
10799       pthread_exit(NULL);
10800    }
10801    *tele++ = 0;
10802    myrpt->rxchannel = ast_request(tmpstr, AST_FORMAT_SLINEAR, NULL, tele, NULL);
10803    myrpt->dahdirxchannel = NULL;
10804    if (!strcasecmp(tmpstr,"DAHDI"))
10805       myrpt->dahdirxchannel = myrpt->rxchannel;
10806    if (myrpt->rxchannel)
10807    {
10808       if (myrpt->rxchannel->_state == AST_STATE_BUSY)
10809       {
10810          fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
10811          rpt_mutex_unlock(&myrpt->lock);
10812          ast_hangup(myrpt->rxchannel);
10813          myrpt->rpt_thread = AST_PTHREADT_STOP;
10814          pthread_exit(NULL);
10815       }
10816       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10817       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10818 #ifdef   AST_CDR_FLAG_POST_DISABLED
10819       if (myrpt->rxchannel->cdr)
10820          ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10821 #endif
10822 #ifndef  NEW_ASTERISK
10823       myrpt->rxchannel->whentohangup = 0;
10824 #endif
10825       myrpt->rxchannel->appl = "Apprpt";
10826       myrpt->rxchannel->data = "(Repeater Rx)";
10827       if (option_verbose > 2)
10828          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
10829             tmpstr,tele,myrpt->rxchannel->name);
10830       ast_call(myrpt->rxchannel,tele,999);
10831       if (myrpt->rxchannel->_state != AST_STATE_UP)
10832       {
10833          rpt_mutex_unlock(&myrpt->lock);
10834          ast_hangup(myrpt->rxchannel);
10835          myrpt->rpt_thread = AST_PTHREADT_STOP;
10836          pthread_exit(NULL);
10837       }
10838    }
10839    else
10840    {
10841       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
10842       rpt_mutex_unlock(&myrpt->lock);
10843       myrpt->rpt_thread = AST_PTHREADT_STOP;
10844       pthread_exit(NULL);
10845    }
10846    myrpt->dahditxchannel = NULL;
10847    if (myrpt->txchanname)
10848    {
10849       strncpy(tmpstr,myrpt->txchanname,sizeof(tmpstr) - 1);
10850       tele = strchr(tmpstr,'/');
10851       if (!tele)
10852       {
10853          fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
10854          rpt_mutex_unlock(&myrpt->lock);
10855          ast_hangup(myrpt->rxchannel);
10856          myrpt->rpt_thread = AST_PTHREADT_STOP;
10857          pthread_exit(NULL);
10858       }
10859       *tele++ = 0;
10860       myrpt->txchannel = ast_request(tmpstr, AST_FORMAT_SLINEAR, NULL, tele, NULL);
10861       if (!strcasecmp(tmpstr,"DAHDI"))
10862          myrpt->dahditxchannel = myrpt->txchannel;
10863       if (myrpt->txchannel)
10864       {
10865          if (myrpt->txchannel->_state == AST_STATE_BUSY)
10866          {
10867             fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
10868             rpt_mutex_unlock(&myrpt->lock);
10869             ast_hangup(myrpt->txchannel);
10870             ast_hangup(myrpt->rxchannel);
10871             myrpt->rpt_thread = AST_PTHREADT_STOP;
10872             pthread_exit(NULL);
10873          }        
10874          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
10875          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
10876 #ifdef   AST_CDR_FLAG_POST_DISABLED
10877          if (myrpt->txchannel->cdr)
10878             ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10879 #endif
10880 #ifndef  NEW_ASTERISK
10881          myrpt->txchannel->whentohangup = 0;
10882 #endif
10883          myrpt->txchannel->appl = "Apprpt";
10884          myrpt->txchannel->data = "(Repeater Tx)";
10885          if (option_verbose > 2)
10886             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
10887                tmpstr,tele,myrpt->txchannel->name);
10888          ast_call(myrpt->txchannel,tele,999);
10889          if (myrpt->rxchannel->_state != AST_STATE_UP)
10890          {
10891             rpt_mutex_unlock(&myrpt->lock);
10892             ast_hangup(myrpt->rxchannel);
10893             ast_hangup(myrpt->txchannel);
10894             myrpt->rpt_thread = AST_PTHREADT_STOP;
10895             pthread_exit(NULL);
10896          }
10897       }
10898       else
10899       {
10900          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
10901          rpt_mutex_unlock(&myrpt->lock);
10902          ast_hangup(myrpt->rxchannel);
10903          myrpt->rpt_thread = AST_PTHREADT_STOP;
10904          pthread_exit(NULL);
10905       }
10906    }
10907    else
10908    {
10909       myrpt->txchannel = myrpt->rxchannel;
10910       if (!strncasecmp(myrpt->rxchanname,"DAHDI",3))
10911          myrpt->dahditxchannel = myrpt->txchannel;
10912    }
10913    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
10914    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
10915    /* allocate a pseudo-channel thru asterisk */
10916    myrpt->pchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
10917    if (!myrpt->pchannel)
10918    {
10919       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10920       rpt_mutex_unlock(&myrpt->lock);
10921       if (myrpt->txchannel != myrpt->rxchannel) 
10922          ast_hangup(myrpt->txchannel);
10923       ast_hangup(myrpt->rxchannel);
10924       myrpt->rpt_thread = AST_PTHREADT_STOP;
10925       pthread_exit(NULL);
10926    }
10927 #ifdef   AST_CDR_FLAG_POST_DISABLED
10928    if (myrpt->pchannel->cdr)
10929       ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10930 #endif
10931    if (!myrpt->dahdirxchannel) myrpt->dahdirxchannel = myrpt->pchannel;
10932    if (!myrpt->dahditxchannel)
10933    {
10934       /* allocate a pseudo-channel thru asterisk */
10935       myrpt->dahditxchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
10936       if (!myrpt->dahditxchannel)
10937       {
10938          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10939          rpt_mutex_unlock(&myrpt->lock);
10940          if (myrpt->txchannel != myrpt->rxchannel) 
10941             ast_hangup(myrpt->txchannel);
10942          ast_hangup(myrpt->rxchannel);
10943          myrpt->rpt_thread = AST_PTHREADT_STOP;
10944          pthread_exit(NULL);
10945       }
10946       ast_set_read_format(myrpt->dahditxchannel,AST_FORMAT_SLINEAR);
10947       ast_set_write_format(myrpt->dahditxchannel,AST_FORMAT_SLINEAR);
10948 #ifdef   AST_CDR_FLAG_POST_DISABLED
10949       if (myrpt->dahditxchannel->cdr)
10950          ast_set_flag(myrpt->dahditxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10951 #endif
10952    }
10953    /* allocate a pseudo-channel thru asterisk */
10954    myrpt->monchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
10955    if (!myrpt->monchannel)
10956    {
10957       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10958       rpt_mutex_unlock(&myrpt->lock);
10959       if (myrpt->txchannel != myrpt->rxchannel) 
10960          ast_hangup(myrpt->txchannel);
10961       ast_hangup(myrpt->rxchannel);
10962       myrpt->rpt_thread = AST_PTHREADT_STOP;
10963       pthread_exit(NULL);
10964    }
10965    ast_set_read_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
10966    ast_set_write_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
10967 #ifdef   AST_CDR_FLAG_POST_DISABLED
10968    if (myrpt->monchannel->cdr)
10969       ast_set_flag(myrpt->monchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10970 #endif
10971    /* make a conference for the tx */
10972    ci.chan = 0;
10973    ci.confno = -1; /* make a new conf */
10974    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER;
10975    /* first put the channel on the conference in proper mode */
10976    if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
10977    {
10978       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10979       rpt_mutex_unlock(&myrpt->lock);
10980       ast_hangup(myrpt->pchannel);
10981       ast_hangup(myrpt->monchannel);
10982       if (myrpt->txchannel != myrpt->rxchannel) 
10983          ast_hangup(myrpt->txchannel);
10984       ast_hangup(myrpt->rxchannel);
10985       myrpt->rpt_thread = AST_PTHREADT_STOP;
10986       pthread_exit(NULL);
10987    }
10988    /* save tx conference number */
10989    myrpt->txconf = ci.confno;
10990    /* make a conference for the pseudo */
10991    ci.chan = 0;
10992    ci.confno = -1; /* make a new conf */
10993    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
10994       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
10995    /* first put the channel on the conference in announce mode */
10996    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
10997    {
10998       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10999       rpt_mutex_unlock(&myrpt->lock);
11000       ast_hangup(myrpt->pchannel);
11001       ast_hangup(myrpt->monchannel);
11002       if (myrpt->txchannel != myrpt->rxchannel) 
11003          ast_hangup(myrpt->txchannel);
11004       ast_hangup(myrpt->rxchannel);
11005       myrpt->rpt_thread = AST_PTHREADT_STOP;
11006       pthread_exit(NULL);
11007    }
11008    /* save pseudo channel conference number */
11009    myrpt->conf = ci.confno;
11010    /* make a conference for the pseudo */
11011    ci.chan = 0;
11012    if ((strstr(myrpt->txchannel->name,"pseudo") == NULL) &&
11013       (myrpt->dahditxchannel == myrpt->txchannel))
11014    {
11015       /* get tx channel's port number */
11016       if (ioctl(myrpt->txchannel->fds[0],DAHDI_CHANNO,&ci.confno) == -1)
11017       {
11018          ast_log(LOG_WARNING, "Unable to set tx channel's chan number\n");
11019          rpt_mutex_unlock(&myrpt->lock);
11020          ast_hangup(myrpt->pchannel);
11021          ast_hangup(myrpt->monchannel);
11022          if (myrpt->txchannel != myrpt->rxchannel) 
11023             ast_hangup(myrpt->txchannel);
11024          ast_hangup(myrpt->rxchannel);
11025          myrpt->rpt_thread = AST_PTHREADT_STOP;
11026          pthread_exit(NULL);
11027       }
11028       ci.confmode = DAHDI_CONF_MONITORTX;
11029    }
11030    else
11031    {
11032       ci.confno = myrpt->txconf;
11033       ci.confmode = DAHDI_CONF_CONFANNMON;
11034    }
11035    /* first put the channel on the conference in announce mode */
11036    if (ioctl(myrpt->monchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11037    {
11038       ast_log(LOG_WARNING, "Unable to set conference mode for monitor\n");
11039       rpt_mutex_unlock(&myrpt->lock);
11040       ast_hangup(myrpt->pchannel);
11041       ast_hangup(myrpt->monchannel);
11042       if (myrpt->txchannel != myrpt->rxchannel) 
11043          ast_hangup(myrpt->txchannel);
11044       ast_hangup(myrpt->rxchannel);
11045       myrpt->rpt_thread = AST_PTHREADT_STOP;
11046       pthread_exit(NULL);
11047    }
11048    /* allocate a pseudo-channel thru asterisk */
11049    myrpt->parrotchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
11050    if (!myrpt->parrotchannel)
11051    {
11052       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11053       rpt_mutex_unlock(&myrpt->lock);
11054       if (myrpt->txchannel != myrpt->rxchannel) 
11055          ast_hangup(myrpt->txchannel);
11056       ast_hangup(myrpt->rxchannel);
11057       myrpt->rpt_thread = AST_PTHREADT_STOP;
11058       pthread_exit(NULL);
11059    }
11060    ast_set_read_format(myrpt->parrotchannel,AST_FORMAT_SLINEAR);
11061    ast_set_write_format(myrpt->parrotchannel,AST_FORMAT_SLINEAR);
11062 #ifdef   AST_CDR_FLAG_POST_DISABLED
11063    if (myrpt->parrotchannel->cdr)
11064       ast_set_flag(myrpt->parrotchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11065 #endif
11066    /* allocate a pseudo-channel thru asterisk */
11067    myrpt->voxchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
11068    if (!myrpt->voxchannel)
11069    {
11070       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11071       rpt_mutex_unlock(&myrpt->lock);
11072       if (myrpt->txchannel != myrpt->rxchannel) 
11073          ast_hangup(myrpt->txchannel);
11074       ast_hangup(myrpt->rxchannel);
11075       myrpt->rpt_thread = AST_PTHREADT_STOP;
11076       pthread_exit(NULL);
11077    }
11078    ast_set_read_format(myrpt->voxchannel,AST_FORMAT_SLINEAR);
11079    ast_set_write_format(myrpt->voxchannel,AST_FORMAT_SLINEAR);
11080 #ifdef   AST_CDR_FLAG_POST_DISABLED
11081    if (myrpt->voxchannel->cdr)
11082       ast_set_flag(myrpt->voxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11083 #endif
11084    /* allocate a pseudo-channel thru asterisk */
11085    myrpt->txpchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
11086    if (!myrpt->txpchannel)
11087    {
11088       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11089       rpt_mutex_unlock(&myrpt->lock);
11090       ast_hangup(myrpt->pchannel);
11091       ast_hangup(myrpt->monchannel);
11092       if (myrpt->txchannel != myrpt->rxchannel) 
11093          ast_hangup(myrpt->txchannel);
11094       ast_hangup(myrpt->rxchannel);
11095       myrpt->rpt_thread = AST_PTHREADT_STOP;
11096       pthread_exit(NULL);
11097    }
11098 #ifdef   AST_CDR_FLAG_POST_DISABLED
11099    if (myrpt->txpchannel->cdr)
11100       ast_set_flag(myrpt->txpchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11101 #endif
11102    /* make a conference for the tx */
11103    ci.chan = 0;
11104    ci.confno = myrpt->txconf;
11105    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER ;
11106    /* first put the channel on the conference in proper mode */
11107    if (ioctl(myrpt->txpchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11108    {
11109       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
11110       rpt_mutex_unlock(&myrpt->lock);
11111       ast_hangup(myrpt->txpchannel);
11112       ast_hangup(myrpt->monchannel);
11113       if (myrpt->txchannel != myrpt->rxchannel) 
11114          ast_hangup(myrpt->txchannel);
11115       ast_hangup(myrpt->rxchannel);
11116       myrpt->rpt_thread = AST_PTHREADT_STOP;
11117       pthread_exit(NULL);
11118    }
11119    /* if serial io port, open it */
11120    myrpt->iofd = -1;
11121    if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt,myrpt->p.ioport)) == -1))
11122    {
11123       ast_log(LOG_ERROR, "Unable to open %s\n",myrpt->p.ioport);
11124       rpt_mutex_unlock(&myrpt->lock);
11125       ast_hangup(myrpt->pchannel);
11126       if (myrpt->txchannel != myrpt->rxchannel) 
11127          ast_hangup(myrpt->txchannel);
11128       ast_hangup(myrpt->rxchannel);
11129       pthread_exit(NULL);
11130    }
11131    /* Now, the idea here is to copy from the physical rx channel buffer
11132       into the pseudo tx buffer, and from the pseudo rx buffer into the 
11133       tx channel buffer */
11134    myrpt->links.next = &myrpt->links;
11135    myrpt->links.prev = &myrpt->links;
11136    myrpt->tailtimer = 0;
11137    myrpt->totimer = 0;
11138    myrpt->tmsgtimer = myrpt->p.tailmessagetime;
11139    myrpt->idtimer = myrpt->p.politeid;
11140    myrpt->mustid = myrpt->tailid = 0;
11141    myrpt->callmode = 0;
11142    myrpt->tounkeyed = 0;
11143    myrpt->tonotify = 0;
11144    myrpt->retxtimer = 0;
11145    myrpt->rerxtimer = 0;
11146    myrpt->skedtimer = 0;
11147    myrpt->tailevent = 0;
11148    lasttx = 0;
11149    myrpt->keyed = 0;
11150    myrpt->txkeyed = 0;
11151    time(&myrpt->lastkeyedtime);
11152    myrpt->lastkeyedtime -= RPT_LOCKOUT_SECS;
11153    time(&myrpt->lasttxkeyedtime);
11154    myrpt->lasttxkeyedtime -= RPT_LOCKOUT_SECS;
11155    idtalkover = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
11156    myrpt->dtmfidx = -1;
11157    myrpt->dtmfbuf[0] = 0;
11158    myrpt->rem_dtmfidx = -1;
11159    myrpt->rem_dtmfbuf[0] = 0;
11160    myrpt->dtmf_time = 0;
11161    myrpt->rem_dtmf_time = 0;
11162    myrpt->inpadtest = 0;
11163    myrpt->disgorgetime = 0;
11164    myrpt->lastnodewhichkeyedusup[0] = '\0';
11165    myrpt->dailytxtime = 0;
11166    myrpt->totaltxtime = 0;
11167    myrpt->dailykeyups = 0;
11168    myrpt->totalkeyups = 0;
11169    myrpt->dailykerchunks = 0;
11170    myrpt->totalkerchunks = 0;
11171    myrpt->dailyexecdcommands = 0;
11172    myrpt->totalexecdcommands = 0;
11173    myrpt->timeouts = 0;
11174    myrpt->exten[0] = '\0';
11175    myrpt->lastdtmfcommand[0] = '\0';
11176    voxinit_rpt(myrpt,1);
11177    myrpt->wasvox = 0;
11178    if (myrpt->p.startupmacro)
11179    {
11180       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
11181    }
11182    rpt_mutex_unlock(&myrpt->lock);
11183    val = 1;
11184    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
11185    val = 1;
11186    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
11187    if (myrpt->p.archivedir) donodelog(myrpt,"STARTUP");
11188    dtmfed = 0;
11189    if (myrpt->remoterig && !ISRIG_RTX(myrpt->remoterig)) setrem(myrpt);
11190    lastmyrx = 0;
11191    myfirst = 0;
11192    while (ms >= 0)
11193    {
11194       struct ast_frame *f,*f1,*f2;
11195       struct ast_channel *cs[300],*cs1[300];
11196       int totx=0,elap=0,n,x,toexit=0;
11197 
11198       /* DEBUG Dump */
11199       if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){
11200          struct rpt_link *dl;
11201          struct rpt_tele *dt;
11202 
11203          myrpt->disgorgetime = 0;
11204          ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n");
11205          ast_log(LOG_NOTICE,"totx = %d\n",totx);
11206          ast_log(LOG_NOTICE,"remrx = %d\n",remrx);
11207          ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx);
11208          ast_log(LOG_NOTICE,"elap = %d\n",elap);
11209          ast_log(LOG_NOTICE,"toexit = %d\n",toexit);
11210 
11211          ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed);
11212          ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx);
11213          ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode);
11214          ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
11215          ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed);
11216          ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify);
11217          ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
11218          ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
11219          ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
11220          ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
11221 
11222          dl = myrpt->links.next;
11223                   while(dl != &myrpt->links){
11224             ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",dl->name);
11225             ast_log(LOG_NOTICE,"        link->lasttx %d\n",dl->lasttx);
11226             ast_log(LOG_NOTICE,"        link->lastrx %d\n",dl->lastrx);
11227             ast_log(LOG_NOTICE,"        link->connected %d\n",dl->connected);
11228             ast_log(LOG_NOTICE,"        link->hasconnected %d\n",dl->hasconnected);
11229             ast_log(LOG_NOTICE,"        link->outbound %d\n",dl->outbound);
11230             ast_log(LOG_NOTICE,"        link->disced %d\n",dl->disced);
11231             ast_log(LOG_NOTICE,"        link->killme %d\n",dl->killme);
11232             ast_log(LOG_NOTICE,"        link->disctime %ld\n",dl->disctime);
11233             ast_log(LOG_NOTICE,"        link->retrytimer %ld\n",dl->retrytimer);
11234             ast_log(LOG_NOTICE,"        link->retries = %d\n",dl->retries);
11235             ast_log(LOG_NOTICE,"        link->reconnects = %d\n",dl->reconnects);
11236             ast_log(LOG_NOTICE,"        link->newkey = %d\n",dl->newkey);
11237                            dl = dl->next;
11238                   }
11239                                                                                                                                
11240          dt = myrpt->tele.next;
11241          if(dt != &myrpt->tele)
11242             ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n");
11243                   while(dt != &myrpt->tele){
11244             ast_log(LOG_NOTICE,"        Telemetry mode: %d\n",dt->mode);
11245                            dt = dt->next;
11246                   }
11247          ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n");
11248 
11249       }  
11250 
11251 
11252       if (myrpt->reload)
11253       {
11254          struct rpt_tele *inner_telem;
11255 
11256          rpt_mutex_lock(&myrpt->lock);
11257          inner_telem = myrpt->tele.next;
11258          while(inner_telem != &myrpt->tele)
11259          {
11260             ast_softhangup(inner_telem->chan,AST_SOFTHANGUP_DEV);
11261             inner_telem = inner_telem->next;
11262          }
11263          myrpt->reload = 0;
11264          rpt_mutex_unlock(&myrpt->lock);
11265          usleep(10000);
11266          /* find our index, and load the vars */
11267          for(i = 0; i < nrpts; i++)
11268          {
11269             if (&rpt_vars[i] == myrpt)
11270             {
11271                load_rpt_vars(i,0);
11272                break;
11273             }
11274          }
11275       }
11276 
11277       rpt_mutex_lock(&myrpt->lock);
11278       if (ast_check_hangup(myrpt->rxchannel)) break;
11279       if (ast_check_hangup(myrpt->txchannel)) break;
11280       if (ast_check_hangup(myrpt->pchannel)) break;
11281       if (ast_check_hangup(myrpt->monchannel)) break;
11282       if (myrpt->parrotchannel && 
11283          ast_check_hangup(myrpt->parrotchannel)) break;
11284       if (myrpt->voxchannel && 
11285          ast_check_hangup(myrpt->voxchannel)) break;
11286       if (ast_check_hangup(myrpt->txpchannel)) break;
11287       if (myrpt->dahditxchannel && ast_check_hangup(myrpt->dahditxchannel)) break;
11288 
11289       /* Set local tx with keyed */
11290       myrpt->localtx = myrpt->keyed;
11291       /* If someone's connected, and they're transmitting from their end to us, set remrx true */
11292       l = myrpt->links.next;
11293       remrx = 0;
11294       while(l != &myrpt->links)
11295       {
11296          if (l->lastrx){
11297             remrx = 1;
11298             if(l->name[0] != '0') /* Ignore '0' nodes */
11299                strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
11300          }
11301          l = l->next;
11302       }
11303       /* Create a "must_id" flag for the cleanup ID */      
11304       if(myrpt->p.idtime) /* ID time must be non-zero */
11305          myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
11306       /* Build a fresh totx from myrpt->keyed and autopatch activated */
11307       /* If full duplex, add local tx to totx */
11308       if (myrpt->p.duplex > 1) 
11309       {
11310          totx = myrpt->callmode;
11311          totx = totx || myrpt->localtx;
11312       }
11313       else
11314       {
11315          int myrx = myrpt->localtx || remrx || (!myrpt->callmode);
11316 
11317          if (lastmyrx != myrx)
11318          {
11319             voxinit_rpt(myrpt,!myrx);
11320             lastmyrx = myrx;
11321          }
11322          totx = 0;
11323          if (myrpt->callmode && (myrpt->voxtotimer <= 0))
11324          {
11325             if (myrpt->voxtostate)
11326             {
11327                myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
11328                myrpt->voxtostate = 0;
11329             }           
11330             else
11331             {
11332                myrpt->voxtotimer = myrpt->p.voxrecover_ms;
11333                myrpt->voxtostate = 1;
11334             }
11335          }
11336          if (!myrpt->voxtostate)
11337             totx = myrpt->callmode && myrpt->wasvox;
11338       }
11339       /* Traverse the telemetry list to see what's queued */
11340       identqueued = 0;
11341       localmsgqueued = 0;
11342       othertelemqueued = 0;
11343       tailmessagequeued = 0;
11344       ctqueued = 0;
11345       telem = myrpt->tele.next;
11346       while(telem != &myrpt->tele)
11347       {
11348          if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
11349             identqueued = 1; /* Identification telemetry */
11350          }
11351          else if(telem->mode == TAILMSG)
11352          {
11353             tailmessagequeued = 1; /* Tail message telemetry */
11354          }
11355          else if(telem->mode == STATS_TIME_LOCAL) 
11356          {
11357             localmsgqueued = 1; /* Local message */
11358          }
11359          else
11360          {
11361             if ((telem->mode != UNKEY) && (telem->mode != LINKUNKEY))
11362                othertelemqueued = 1;  /* Other telemetry */
11363             else
11364                ctqueued = 1; /* Courtesy tone telemetry */
11365          }
11366          telem = telem->next;
11367       }
11368    
11369       /* Add in any "other" telemetry, unless specified otherwise */
11370       if (!myrpt->p.notelemtx) totx = totx || othertelemqueued;
11371       /* Update external (to links) transmitter PTT state with everything but */
11372       /* ID, CT, local messages, and tailmessage telemetry */
11373       myrpt->exttx = totx;
11374       totx = totx || myrpt->dtmf_local_timer;
11375       /* If half or 3/4 duplex, add localtx to external link tx */
11376       if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
11377       /* Add in ID telemetry to local transmitter */
11378       totx = totx || remrx;
11379       /* If 3/4 or full duplex, add in ident, CT telemetry, and local messages */
11380       if (myrpt->p.duplex > 0)
11381          totx = totx || identqueued || ctqueued || localmsgqueued;
11382       /* If full duplex, add local dtmf stuff active */
11383       if (myrpt->p.duplex > 1) 
11384       {
11385          totx = totx || (myrpt->dtmfidx > -1) ||
11386             myrpt->cmdnode[0];
11387       }
11388       /* add in parrot stuff */
11389       totx = totx || (myrpt->parrotstate > 1);
11390       /* Reset time out timer variables if there is no activity */
11391       if (!totx) 
11392       {
11393          myrpt->totimer = myrpt->p.totime;
11394          myrpt->tounkeyed = 0;
11395          myrpt->tonotify = 0;
11396       }
11397       else{
11398          myrpt->tailtimer = myrpt->p.s[myrpt->p.sysstate_cur].alternatetail ?
11399             myrpt->p.althangtime : /* Initialize tail timer */
11400             myrpt->p.hangtime;
11401       }
11402       /* Disable the local transmitter if we are timed out */
11403       totx = totx && myrpt->totimer;
11404       /* if timed-out and not said already, say it */
11405       if ((!myrpt->totimer) && (!myrpt->tonotify))
11406       {
11407          myrpt->tonotify = 1;
11408          myrpt->timeouts++;
11409          rpt_mutex_unlock(&myrpt->lock);
11410          rpt_telemetry(myrpt,TIMEOUT,NULL);
11411          rpt_mutex_lock(&myrpt->lock);
11412       }
11413 
11414       /* If unkey and re-key, reset time out timer */
11415       if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
11416       {
11417          myrpt->tounkeyed = 1;
11418       }
11419       if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
11420       {
11421          myrpt->totimer = myrpt->p.totime;
11422          myrpt->tounkeyed = 0;
11423          myrpt->tonotify = 0;
11424          rpt_mutex_unlock(&myrpt->lock);
11425          continue;
11426       }
11427       /* if timed-out and in circuit busy after call */
11428       if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
11429       {
11430           if(debug)
11431             ast_log(LOG_NOTICE, "timed-out and in circuit busy after call\n");
11432          myrpt->callmode = 0;
11433          myrpt->macropatch=0;
11434          channel_revert(myrpt);
11435       }
11436       /* get rid of tail if timed out */
11437       if (!myrpt->totimer) myrpt->tailtimer = 0;
11438       /* if not timed-out, add in tail */
11439       if (myrpt->totimer) totx = totx || myrpt->tailtimer;
11440       /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
11441       /* If tail message, kill the message if someone keys up over it */ 
11442       if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
11443          int hasid = 0,hastalkover = 0;
11444 
11445          telem = myrpt->tele.next;
11446          while(telem != &myrpt->tele){
11447             if(telem->mode == ID){
11448                if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
11449                hasid = 1;
11450             }
11451             if(telem->mode == TAILMSG){
11452                                         if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
11453                                 }
11454             if (telem->mode == IDTALKOVER) hastalkover = 1;
11455             telem = telem->next;
11456          }
11457          rpt_mutex_unlock(&myrpt->lock);
11458          if (hasid && (!hastalkover)) rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
11459          rpt_mutex_lock(&myrpt->lock);
11460       }
11461       /* Try to be polite */
11462       /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
11463       /* If within 30 seconds of the time to ID, try do it in the tail */
11464       /* else if at ID time limit, do it right over the top of them */
11465       /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
11466       if(myrpt->mustid && (!myrpt->idtimer))
11467          queue_id(myrpt);
11468 
11469       if ((myrpt->p.idtime && totx && (!myrpt->exttx) &&
11470           (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) /* ID time must be non-zero */ 
11471          {
11472             myrpt->tailid = 1;
11473          }
11474 
11475       /* If tail timer expires, then check for tail messages */
11476 
11477       if(myrpt->tailevent){
11478          myrpt->tailevent = 0;
11479          if(myrpt->tailid){
11480             totx = 1;
11481             queue_id(myrpt);
11482          }
11483          else if ((myrpt->p.tailmessages[0]) &&
11484             (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
11485                totx = 1;
11486                myrpt->tmsgtimer = myrpt->p.tailmessagetime; 
11487                rpt_mutex_unlock(&myrpt->lock);
11488                rpt_telemetry(myrpt, TAILMSG, NULL);
11489                rpt_mutex_lock(&myrpt->lock);
11490          }  
11491       }
11492 
11493       /* Main TX control */
11494 
11495       /* let telemetry transmit anyway (regardless of timeout) */
11496       if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
11497       totx = totx && !myrpt->p.s[myrpt->p.sysstate_cur].txdisable;
11498       myrpt->txrealkeyed = totx;
11499       totx = totx || (!AST_LIST_EMPTY(&myrpt->txq));
11500       if (totx && (!lasttx))
11501       {
11502          char mydate[100],myfname[100];
11503          time_t myt;
11504 
11505          if (myrpt->monstream) ast_closestream(myrpt->monstream);
11506          if (myrpt->p.archivedir)
11507          {
11508             long blocksleft;
11509 
11510             time(&myt);
11511             strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
11512                localtime(&myt));
11513             sprintf(myfname,"%s/%s/%s",myrpt->p.archivedir,
11514                myrpt->name,mydate);
11515             myrpt->monstream = ast_writefile(myfname,"wav49",
11516                "app_rpt Air Archive",O_CREAT | O_APPEND,0,0600);
11517             if (myrpt->p.monminblocks)
11518             {
11519                blocksleft = diskavail(myrpt);
11520                if (blocksleft >= myrpt->p.monminblocks)
11521                   donodelog(myrpt,"TXKEY,MAIN");
11522             } else donodelog(myrpt,"TXKEY,MAIN");
11523          }
11524          lasttx = 1;
11525          myrpt->txkeyed = 1;
11526          time(&myrpt->lasttxkeyedtime);
11527          myrpt->dailykeyups++;
11528          myrpt->totalkeyups++;
11529          rpt_mutex_unlock(&myrpt->lock);
11530          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
11531          rpt_mutex_lock(&myrpt->lock);
11532       }
11533       if ((!totx) && lasttx)
11534       {
11535          if (myrpt->monstream) ast_closestream(myrpt->monstream);
11536          myrpt->monstream = NULL;
11537 
11538          lasttx = 0;
11539          myrpt->txkeyed = 0;
11540          time(&myrpt->lasttxkeyedtime);
11541          rpt_mutex_unlock(&myrpt->lock);
11542          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
11543          rpt_mutex_lock(&myrpt->lock);
11544          donodelog(myrpt,"TXUNKEY,MAIN");
11545       }
11546       time(&t);
11547       /* if DTMF timeout */
11548       if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t))
11549       {
11550          myrpt->inpadtest = 0;
11551          myrpt->dtmfidx = -1;
11552          myrpt->dtmfbuf[0] = 0;
11553       }        
11554       /* if remote DTMF timeout */
11555       if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
11556       {
11557          myrpt->inpadtest = 0;
11558          myrpt->rem_dtmfidx = -1;
11559          myrpt->rem_dtmfbuf[0] = 0;
11560       }  
11561 
11562       if (myrpt->exttx && myrpt->parrotchannel && 
11563          myrpt->p.parrotmode && (!myrpt->parrotstate))
11564       {
11565          char myfname[300];
11566 
11567          ci.confno = myrpt->conf;
11568          ci.confmode = DAHDI_CONF_CONFANNMON;
11569          ci.chan = 0;
11570 
11571          /* first put the channel on the conference in announce mode */
11572          if (ioctl(myrpt->parrotchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11573          {
11574             ast_log(LOG_WARNING, "Unable to set conference mode for parrot\n");
11575             break;
11576          }
11577 
11578          sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
11579          strcat(myfname,".wav");
11580          unlink(myfname);        
11581          sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
11582          myrpt->parrotstate = 1;
11583          myrpt->parrottimer = myrpt->p.parrottime;
11584          if (myrpt->parrotstream) 
11585             ast_closestream(myrpt->parrotstream);
11586          myrpt->parrotstream = NULL;
11587          myrpt->parrotstream = ast_writefile(myfname,"wav",
11588             "app_rpt Parrot",O_CREAT | O_TRUNC,0,0600);
11589       }
11590 
11591       /* Reconnect */
11592    
11593       l = myrpt->links.next;
11594       while(l != &myrpt->links)
11595       {
11596          if (l->killme)
11597          {
11598             /* remove from queue */
11599             remque((struct qelem *) l);
11600             if (!strcmp(myrpt->cmdnode,l->name))
11601                myrpt->cmdnode[0] = 0;
11602             rpt_mutex_unlock(&myrpt->lock);
11603             /* hang-up on call to device */
11604             if (l->chan) ast_hangup(l->chan);
11605             ast_hangup(l->pchan);
11606             ast_free(l);
11607             rpt_mutex_lock(&myrpt->lock);
11608             /* re-start link traversal */
11609             l = myrpt->links.next;
11610             continue;
11611          }
11612          l = l->next;
11613       }
11614       n = 0;
11615       cs[n++] = myrpt->rxchannel;
11616       cs[n++] = myrpt->pchannel;
11617       cs[n++] = myrpt->monchannel;
11618       if (myrpt->parrotchannel) cs[n++] = myrpt->parrotchannel;
11619       if (myrpt->voxchannel) cs[n++] = myrpt->voxchannel;
11620       cs[n++] = myrpt->txpchannel;
11621       if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
11622       if (myrpt->dahditxchannel != myrpt->txchannel)
11623          cs[n++] = myrpt->dahditxchannel;
11624       l = myrpt->links.next;
11625       while(l != &myrpt->links)
11626       {
11627          if ((!l->killme) && (!l->disctime) && l->chan)
11628          {
11629             cs[n++] = l->chan;
11630             cs[n++] = l->pchan;
11631          }
11632          l = l->next;
11633       }
11634       if ((myrpt->topkeystate == 1) && 
11635           ((t - myrpt->topkeytime) > TOPKEYWAIT))
11636       {
11637          myrpt->topkeystate = 2;
11638          qsort(myrpt->topkey,TOPKEYN,sizeof(struct rpt_topkey),
11639             topcompar);
11640       }
11641       rpt_mutex_unlock(&myrpt->lock);
11642 
11643       if (myrpt->topkeystate == 2)
11644       {
11645          rpt_telemetry(myrpt,TOPKEY,NULL);
11646          myrpt->topkeystate = 3;
11647       }
11648       ms = MSWAIT;
11649       for(x = 0; x < n; x++)
11650       {
11651          int s = -(-x - myrpt->scram - 1) % n;
11652          cs1[x] = cs[s];
11653       }
11654       myrpt->scram++;
11655       who = ast_waitfor_n(cs1,n,&ms);
11656       if (who == NULL) ms = 0;
11657       elap = MSWAIT - ms;
11658       rpt_mutex_lock(&myrpt->lock);
11659       l = myrpt->links.next;
11660       while(l != &myrpt->links)
11661       {
11662          int myrx;
11663 
11664          if (l->voxtotimer) l->voxtotimer -= elap;
11665          if (l->voxtotimer < 0) l->voxtotimer = 0;
11666 
11667          if (l->lasttx != l->lasttx1)
11668          {
11669             voxinit_link(l,!l->lasttx);
11670             l->lasttx1 = l->lasttx;
11671          }
11672          myrx = l->lastrealrx;
11673          if ((l->phonemode) && (l->phonevox))
11674          {
11675             myrx = myrx || (!AST_LIST_EMPTY(&l->rxq));
11676             if (l->voxtotimer <= 0)
11677             {
11678                if (l->voxtostate)
11679                {
11680                   l->voxtotimer = myrpt->p.voxtimeout_ms;
11681                   l->voxtostate = 0;
11682                }           
11683                else
11684                {
11685                   l->voxtotimer = myrpt->p.voxrecover_ms;
11686                   l->voxtostate = 1;
11687                }
11688             }
11689             if (!l->voxtostate)
11690                myrx = myrx || l->wasvox ;
11691          }
11692          l->lastrx = myrx;
11693          if (l->linklisttimer)
11694          {
11695             l->linklisttimer -= elap;
11696             if (l->linklisttimer < 0) l->linklisttimer = 0;
11697          }
11698          if ((!l->linklisttimer) && (l->name[0] != '0') && (!l->isremote))
11699          {
11700             struct   ast_frame lf;
11701 
11702             memset(&lf,0,sizeof(lf));
11703             lf.frametype = AST_FRAME_TEXT;
11704             lf.subclass.integer = 0;
11705             lf.offset = 0;
11706             lf.mallocd = 0;
11707             lf.samples = 0;
11708             l->linklisttimer = LINKLISTTIME;
11709             strcpy(lstr,"L ");
11710             __mklinklist(myrpt,l,lstr + 2);
11711             if (l->chan)
11712             {
11713                lf.datalen = strlen(lstr) + 1;
11714                lf.data.ptr = lstr;
11715                ast_write(l->chan,&lf);
11716                if (debug > 6) ast_log(LOG_NOTICE,
11717                   "@@@@ node %s sent node string %s to node %s\n",
11718                      myrpt->name,lstr,l->name);
11719             }
11720          }
11721          if (l->newkey)
11722          {
11723             if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
11724             {
11725                l->retxtimer = 0;
11726                if (l->chan && l->phonemode == 0) 
11727                {
11728                   if (l->lasttx)
11729                      ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
11730                   else
11731                      ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
11732                }
11733             }
11734             if ((l->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 5))
11735             {
11736                if (debug == 7) printf("@@@@ rx un-key\n");
11737                l->lastrealrx = 0;
11738                l->rerxtimer = 0;
11739                if (l->lastrx1)
11740                {
11741                   if (myrpt->p.archivedir)
11742                   {
11743                      char str[100];
11744    
11745                      sprintf(str,"RXUNKEY(T),%s",l->name);
11746                      donodelog(myrpt,str);
11747                   }
11748                   if(myrpt->p.duplex) 
11749                      rpt_telemetry(myrpt,LINKUNKEY,l);
11750                   l->lastrx1 = 0;
11751                }
11752             }
11753          }
11754          if (l->disctime) /* Disconnect timer active on a channel ? */
11755          {
11756             l->disctime -= elap;
11757             if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
11758                l->disctime = 0; /* Yep */
11759          }
11760 
11761          if (l->retrytimer)
11762          {
11763             l->retrytimer -= elap;
11764             if (l->retrytimer < 0) l->retrytimer = 0;
11765          }
11766 
11767          /* Tally connect time */
11768          l->connecttime += elap;
11769 
11770          /* ignore non-timing channels */
11771          if (l->elaptime < 0)
11772          {
11773             l = l->next;
11774             continue;
11775          }
11776          l->elaptime += elap;
11777          /* if connection has taken too long */
11778          if ((l->elaptime > MAXCONNECTTIME) && 
11779             ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
11780          {
11781             l->elaptime = 0;
11782             rpt_mutex_unlock(&myrpt->lock);
11783             if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
11784             rpt_mutex_lock(&myrpt->lock);
11785             break;
11786          }
11787          if ((!l->chan) && (!l->retrytimer) && l->outbound && 
11788             (l->retries++ < l->max_retries) && (l->hasconnected))
11789          {
11790             if (l->chan) ast_hangup(l->chan);
11791             l->chan = 0;
11792             rpt_mutex_unlock(&myrpt->lock);
11793             if ((l->name[0] != '0') && (!l->isremote))
11794             {
11795                if (attempt_reconnect(myrpt,l) == -1)
11796                {
11797                   l->retrytimer = RETRY_TIMER_MS;
11798                } 
11799             }
11800             else 
11801             {
11802                l->retrytimer = l->max_retries + 1;
11803             }
11804 
11805             rpt_mutex_lock(&myrpt->lock);
11806             break;
11807          }
11808          if ((!l->chan) && (!l->retrytimer) && l->outbound &&
11809             (l->retries >= l->max_retries))
11810          {
11811             /* remove from queue */
11812             remque((struct qelem *) l);
11813             if (!strcmp(myrpt->cmdnode,l->name))
11814                myrpt->cmdnode[0] = 0;
11815             rpt_mutex_unlock(&myrpt->lock);
11816             if (l->name[0] != '0')
11817             {
11818                if (!l->hasconnected)
11819                   rpt_telemetry(myrpt,CONNFAIL,l);
11820                else rpt_telemetry(myrpt,REMDISC,l);
11821             }
11822             if (myrpt->p.archivedir)
11823             {
11824                char str[100];
11825 
11826                if (!l->hasconnected)
11827                   sprintf(str,"LINKFAIL,%s",l->name);
11828                else
11829                   sprintf(str,"LINKDISC,%s",l->name);
11830                donodelog(myrpt,str);
11831             }
11832             /* hang-up on call to device */
11833             ast_hangup(l->pchan);
11834             ast_free(l);
11835                                 rpt_mutex_lock(&myrpt->lock);
11836             break;
11837          }
11838             if ((!l->chan) && (!l->disctime) && (!l->outbound))
11839             {
11840             if(debug)ast_log(LOG_NOTICE, "LINKDISC AA\n");
11841                 /* remove from queue */
11842                 remque((struct qelem *) l);
11843             if(myrpt->links.next==&myrpt->links)channel_revert(myrpt);
11844                 if (!strcmp(myrpt->cmdnode,l->name))myrpt->cmdnode[0] = 0;
11845                 rpt_mutex_unlock(&myrpt->lock);
11846             if (l->name[0] != '0') 
11847             {
11848                   rpt_telemetry(myrpt,REMDISC,l);
11849             }
11850             if (myrpt->p.archivedir)
11851             {
11852                char str[100];
11853                sprintf(str,"LINKDISC,%s",l->name);
11854                donodelog(myrpt,str);
11855             }
11856                 /* hang-up on call to device */
11857                 ast_hangup(l->pchan);
11858                 ast_free(l);
11859                 rpt_mutex_lock(&myrpt->lock);
11860                 break;
11861             }
11862          l = l->next;
11863       }
11864       if (myrpt->linkposttimer)
11865       {
11866          myrpt->linkposttimer -= elap;
11867          if (myrpt->linkposttimer < 0) myrpt->linkposttimer = 0;
11868       }
11869       if (myrpt->linkposttimer <= 0)
11870       {
11871          int nstr;
11872          char lst,*str;
11873          time_t now;
11874 
11875          myrpt->linkposttimer = LINKPOSTTIME;
11876          nstr = 0;
11877          for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
11878          {
11879             /* if is not a real link, ignore it */
11880             if (l->name[0] == '0') continue;
11881             nstr += strlen(l->name) + 1;
11882          }
11883          str = ast_malloc(nstr + 256);
11884          if (!str)
11885          {
11886             ast_log(LOG_NOTICE,"Cannot ast_malloc()\n");
11887             break;
11888          }
11889          nstr = 0;
11890          strcpy(str,"nodes=");
11891          for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
11892          {
11893             /* if is not a real link, ignore it */
11894             if (l->name[0] == '0') continue;
11895             lst = 'T';
11896             if (!l->mode) lst = 'R';
11897             if (!l->thisconnected) lst = 'C';
11898             if (nstr) strcat(str,",");
11899             sprintf(str + strlen(str),"%c%s",lst,l->name);
11900             nstr = 1;
11901          }
11902                   p = strstr(tdesc, "version");
11903                   if(p){
11904             int vmajor,vminor;
11905             if(sscanf(p, "version %30d.%30d", &vmajor, &vminor) == 2)
11906                sprintf(str + strlen(str),"&apprptvers=%d.%d",vmajor,vminor);
11907          }
11908          time(&now);
11909          sprintf(str + strlen(str),"&apprptuptime=%d",(int)(now-starttime));
11910          sprintf(str + strlen(str),
11911          "&totalkerchunks=%d&totalkeyups=%d&totaltxtime=%d&timeouts=%d&totalexecdcommands=%d",
11912          myrpt->totalkerchunks,myrpt->totalkeyups,(int) myrpt->totaltxtime/1000,
11913          myrpt->timeouts,myrpt->totalexecdcommands);
11914          rpt_mutex_unlock(&myrpt->lock);
11915          statpost(myrpt,str);
11916          rpt_mutex_lock(&myrpt->lock);
11917          ast_free(str);
11918       }
11919       if (myrpt->keyposttimer)
11920       {
11921          myrpt->keyposttimer -= elap;
11922          if (myrpt->keyposttimer < 0) myrpt->keyposttimer = 0;
11923       }
11924       if (myrpt->keyposttimer <= 0)
11925       {
11926          char str[100];
11927          int diff = 0;
11928          time_t now;
11929 
11930          myrpt->keyposttimer = KEYPOSTTIME;
11931          time(&now);
11932          if (myrpt->lastkeyedtime)
11933          {
11934             diff = (int)(now - myrpt->lastkeyedtime);
11935          }
11936          sprintf(str,"keyed=%d&keytime=%d",myrpt->keyed,diff);
11937          rpt_mutex_unlock(&myrpt->lock);
11938          statpost(myrpt,str);
11939          rpt_mutex_lock(&myrpt->lock);
11940       }
11941       if(totx){
11942          myrpt->dailytxtime += elap;
11943          myrpt->totaltxtime += elap;
11944       }
11945       i = myrpt->tailtimer;
11946       if (myrpt->tailtimer) myrpt->tailtimer -= elap;
11947       if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
11948       if((i) && (myrpt->tailtimer == 0))
11949          myrpt->tailevent = 1;
11950       if ((!myrpt->p.s[myrpt->p.sysstate_cur].totdisable) && myrpt->totimer) myrpt->totimer -= elap;
11951       if (myrpt->totimer < 0) myrpt->totimer = 0;
11952       if (myrpt->idtimer) myrpt->idtimer -= elap;
11953       if (myrpt->idtimer < 0) myrpt->idtimer = 0;
11954       if (myrpt->tmsgtimer) myrpt->tmsgtimer -= elap;
11955       if (myrpt->tmsgtimer < 0) myrpt->tmsgtimer = 0;
11956       if (myrpt->voxtotimer) myrpt->voxtotimer -= elap;
11957       if (myrpt->voxtotimer < 0) myrpt->voxtotimer = 0;
11958       if (myrpt->exttx)
11959       {
11960          myrpt->parrottimer = myrpt->p.parrottime;
11961       }
11962       else
11963       {
11964          if (myrpt->parrottimer) myrpt->parrottimer -= elap;
11965          if (myrpt->parrottimer < 0) myrpt->parrottimer = 0;
11966       }
11967       /* do macro timers */
11968       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
11969       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
11970       /* do local dtmf timer */
11971       if (myrpt->dtmf_local_timer)
11972       {
11973          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
11974          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
11975       }
11976       do_dtmf_local(myrpt,0);
11977       /* Execute scheduler appx. every 2 tenths of a second */
11978       if (myrpt->skedtimer <= 0){
11979          myrpt->skedtimer = 200;
11980          do_scheduler(myrpt);
11981       }
11982       else
11983          myrpt->skedtimer -=elap;
11984       if (!ms) 
11985       {
11986          rpt_mutex_unlock(&myrpt->lock);
11987          continue;
11988       }
11989       if (myrpt->p.parrotmode && (myrpt->parrotstate == 1) &&
11990          (myrpt->parrottimer <= 0))
11991       {
11992 
11993          ci.confno = 0;
11994          ci.confmode = 0;
11995          ci.chan = 0;
11996 
11997          /* first put the channel on the conference in announce mode */
11998          if (ioctl(myrpt->parrotchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11999          {
12000             ast_log(LOG_WARNING, "Unable to set conference mode for parrot\n");
12001             break;
12002          }
12003          if (myrpt->parrotstream) 
12004             ast_closestream(myrpt->parrotstream);
12005          myrpt->parrotstream = NULL;
12006          myrpt->parrotstate = 2;
12007          rpt_telemetry(myrpt,PARROT,(void *) ((intptr_t)myrpt->parrotcnt++)); 
12008       }        
12009       if (myrpt->cmdAction.state == CMD_STATE_READY)
12010       { /* there is a command waiting to be processed */
12011          int status;
12012          myrpt->cmdAction.state = CMD_STATE_EXECUTING;
12013          // lose the lock
12014          rpt_mutex_unlock(&myrpt->lock);
12015          // do the function
12016          status = (*function_table[myrpt->cmdAction.functionNumber].function)(myrpt,myrpt->cmdAction.param, myrpt->cmdAction.digits, myrpt->cmdAction.command_source, NULL);
12017          // get the lock again
12018          rpt_mutex_lock(&myrpt->lock);
12019          myrpt->cmdAction.state = CMD_STATE_IDLE;
12020       } /* if myrpt->cmdAction.state == CMD_STATE_READY */
12021       
12022       c = myrpt->macrobuf[0];
12023       time(&t);
12024       if (c && (!myrpt->macrotimer) && 
12025          starttime && (t > (starttime + START_DELAY)))
12026       {
12027          char cin = c & 0x7f;
12028          myrpt->macrotimer = MACROTIME;
12029          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
12030          if ((cin == 'p') || (cin == 'P'))
12031             myrpt->macrotimer = MACROPTIME;
12032          rpt_mutex_unlock(&myrpt->lock);
12033          if (myrpt->p.archivedir)
12034          {
12035             char str[100];
12036 
12037             sprintf(str,"DTMF(M),MAIN,%c",cin);
12038             donodelog(myrpt,str);
12039          }
12040          local_dtmf_helper(myrpt,c);
12041       } else rpt_mutex_unlock(&myrpt->lock);
12042       if (who == myrpt->rxchannel) /* if it was a read from rx */
12043       {
12044          int ismuted;
12045 
12046          f = ast_read(myrpt->rxchannel);
12047          if (!f)
12048          {
12049             if (debug) printf("@@@@ rpt:Hung Up\n");
12050             break;
12051          }
12052          if (f->frametype == AST_FRAME_VOICE)
12053          {
12054 #ifdef   _MDC_DECODE_H_
12055             unsigned char ubuf[2560];
12056             short *sp;
12057             int n;
12058 #endif
12059 
12060             if ((!myrpt->localtx) && (!myrpt->p.linktolink)) {
12061                memset(f->data.ptr,0,f->datalen);
12062             }
12063 
12064 #ifdef   _MDC_DECODE_H_
12065             sp = (short *) f->data;
12066             /* convert block to unsigned char */
12067             for(n = 0; n < f->datalen / 2; n++)
12068             {
12069                ubuf[n] = (*sp++ >> 8) + 128;
12070             }
12071             n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
12072             if (n == 1)
12073             {
12074                   unsigned char op,arg;
12075                   unsigned short unitID;
12076 
12077                   mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
12078                   if (debug > 2)
12079                   {
12080                      ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
12081                      ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
12082                         op & 255,arg & 255,unitID);
12083                   }
12084                   if ((op == 1) && (arg == 0))
12085                   {
12086                      myrpt->lastunit = unitID;
12087                      mdc1200_notify(myrpt,NULL,myrpt->lastunit);
12088                      mdc1200_send(myrpt,myrpt->lastunit);
12089                   }
12090             }
12091             if ((debug > 2) && (i == 2))
12092             {
12093                unsigned char op,arg,ex1,ex2,ex3,ex4;
12094                unsigned short unitID;
12095 
12096                mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
12097                   &ex1,&ex2,&ex3,&ex4);
12098                ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
12099                ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
12100                   op & 255,arg & 255,unitID);
12101                ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
12102                   ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
12103             }
12104 #endif
12105 #ifdef   __RPT_NOTCH
12106             /* apply inbound filters, if any */
12107             rpt_filter(myrpt,f->data,f->datalen / 2);
12108 #endif
12109             if (ioctl(myrpt->dahdirxchannel->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
12110             {
12111                ismuted = 0;
12112             }
12113             if (dtmfed) ismuted = 1;
12114             dtmfed = 0;
12115             if (ismuted)
12116             {
12117                memset(f->data.ptr,0,f->datalen);
12118                if (myrpt->lastf1)
12119                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12120                if (myrpt->lastf2)
12121                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12122             } 
12123             if (f) f2 = ast_frdup(f);
12124             else f2 = NULL;
12125             f1 = myrpt->lastf2;
12126             myrpt->lastf2 = myrpt->lastf1;
12127             myrpt->lastf1 = f2;
12128             if (ismuted)
12129             {
12130                if (myrpt->lastf1)
12131                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12132                if (myrpt->lastf2)
12133                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12134             }
12135             if (f1)
12136             {
12137                ast_write(myrpt->pchannel,f1);
12138                ast_frfree(f1);
12139             }
12140          }
12141 #ifndef  OLD_ASTERISK
12142          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
12143          {
12144             if (myrpt->lastf1)
12145                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12146             if (myrpt->lastf2)
12147                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12148             dtmfed = 1;
12149          }
12150 #endif
12151          else if (f->frametype == AST_FRAME_DTMF)
12152          {
12153             c = (char) f->subclass.integer; /* get DTMF char */
12154             ast_frfree(f);
12155             if (myrpt->lastf1)
12156                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12157             if (myrpt->lastf2)
12158                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12159             dtmfed = 1;
12160             if (!myrpt->keyed) continue;
12161             c = func_xlat(myrpt,c,&myrpt->p.inxlat);
12162             if (c) local_dtmf_helper(myrpt,c);
12163             continue;
12164          }                 
12165          else if (f->frametype == AST_FRAME_CONTROL)
12166          {
12167             if (f->subclass.integer == AST_CONTROL_HANGUP)
12168             {
12169                if (debug) printf("@@@@ rpt:Hung Up\n");
12170                ast_frfree(f);
12171                break;
12172             }
12173             /* if RX key */
12174             if (f->subclass.integer == AST_CONTROL_RADIO_KEY)
12175             {
12176                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink)) 
12177                {
12178                   if (debug == 7) printf("@@@@ rx key\n");
12179                   myrpt->keyed = 1;
12180                   time(&myrpt->lastkeyedtime);
12181                   myrpt->keyposttimer = KEYPOSTSHORTTIME;
12182                }
12183                if (myrpt->p.archivedir)
12184                {
12185                   donodelog(myrpt,"RXKEY,MAIN");
12186                }
12187                if (f->datalen && f->data.ptr)
12188                {
12189                   char busy = 0;
12190 
12191                   if (debug) ast_log(LOG_NOTICE,"Got PL %s on node %s\n",(char *)f->data.ptr,myrpt->name);
12192                   // ctcss code autopatch initiate
12193                   if (strstr((char *)f->data.ptr,"/M/")&& !myrpt->macropatch)
12194                   {
12195                      char value[16] = "";
12196                      strcat(value,"*6");
12197                      myrpt->macropatch=1;
12198                      rpt_mutex_lock(&myrpt->lock);
12199                      if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(value)){
12200                         rpt_mutex_unlock(&myrpt->lock);
12201                         busy=1;
12202                      }
12203                      if(!busy){
12204                         myrpt->macrotimer = MACROTIME;
12205                         strncat(myrpt->macrobuf,value,MAXMACRO - 1);
12206                         if (!busy) strcpy(myrpt->lasttone,(char*)f->data.ptr);
12207                      }
12208                      rpt_mutex_unlock(&myrpt->lock);
12209                   }
12210                   else if (strcmp((char *)f->data.ptr,myrpt->lasttone))
12211                   {
12212                      char *value = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.tonemacro, (char *)f->data.ptr);
12213                      if (value)
12214                      {
12215                         if (debug) ast_log(LOG_NOTICE,"Tone %s doing %s on node %s\n",(char *) f->data.ptr,value,myrpt->name);
12216                         rpt_mutex_lock(&myrpt->lock);
12217                         if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(value)){
12218                            rpt_mutex_unlock(&myrpt->lock);
12219                            busy=1;
12220                         }
12221                         if(!busy){
12222                            myrpt->macrotimer = MACROTIME;
12223                            strncat(myrpt->macrobuf,value,MAXMACRO - 1);
12224                         }
12225                         rpt_mutex_unlock(&myrpt->lock);
12226                      }
12227                      if (!busy) strcpy(myrpt->lasttone,(char*)f->data.ptr);
12228                   }
12229                } else myrpt->lasttone[0] = 0;
12230             }
12231             /* if RX un-key */
12232             if (f->subclass.integer == AST_CONTROL_RADIO_UNKEY)
12233             {
12234                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
12235                {
12236                   if (debug == 7) printf("@@@@ rx un-key\n");
12237                   if(myrpt->p.duplex && myrpt->keyed) {
12238                      rpt_telemetry(myrpt,UNKEY,NULL);
12239                   }
12240                }
12241                myrpt->keyed = 0;
12242                time(&myrpt->lastkeyedtime);
12243                myrpt->keyposttimer = KEYPOSTSHORTTIME;
12244                if (myrpt->p.archivedir)
12245                {
12246                   donodelog(myrpt,"RXUNKEY,MAIN");
12247                }
12248             }
12249          }
12250          ast_frfree(f);
12251          continue;
12252       }
12253       if (who == myrpt->pchannel) /* if it was a read from pseudo */
12254       {
12255          f = ast_read(myrpt->pchannel);
12256          if (!f)
12257          {
12258             if (debug) printf("@@@@ rpt:Hung Up\n");
12259             break;
12260          }
12261          if (f->frametype == AST_FRAME_VOICE)
12262          {
12263             ast_write(myrpt->txpchannel,f);
12264          }
12265          if (f->frametype == AST_FRAME_CONTROL)
12266          {
12267             if (f->subclass.integer == AST_CONTROL_HANGUP)
12268             {
12269                if (debug) printf("@@@@ rpt:Hung Up\n");
12270                ast_frfree(f);
12271                break;
12272             }
12273          }
12274          ast_frfree(f);
12275          continue;
12276       }
12277       if (who == myrpt->txchannel) /* if it was a read from tx */
12278       {
12279          f = ast_read(myrpt->txchannel);
12280          if (!f)
12281          {
12282             if (debug) printf("@@@@ rpt:Hung Up\n");
12283             break;
12284          }
12285          if (f->frametype == AST_FRAME_CONTROL)
12286          {
12287             if (f->subclass.integer == AST_CONTROL_HANGUP)
12288             {
12289                if (debug) printf("@@@@ rpt:Hung Up\n");
12290                ast_frfree(f);
12291                break;
12292             }
12293          }
12294          ast_frfree(f);
12295          continue;
12296       }
12297       if (who == myrpt->dahditxchannel) /* if it was a read from pseudo-tx */
12298       {
12299          f = ast_read(myrpt->dahditxchannel);
12300          if (!f)
12301          {
12302             if (debug) printf("@@@@ rpt:Hung Up\n");
12303             break;
12304          }
12305          if (f->frametype == AST_FRAME_VOICE)
12306          {
12307             struct ast_frame *vframe;
12308 
12309             if (myrpt->p.duplex < 2)
12310             {
12311                if (myrpt->txrealkeyed) 
12312                {
12313                   if ((!myfirst) && myrpt->callmode)
12314                   {
12315                       x = 0;
12316                       AST_LIST_TRAVERSE(&myrpt->txq, vframe,
12317                      frame_list) x++;
12318                       for(;x < myrpt->p.simplexpatchdelay; x++)
12319                       {
12320                         vframe = ast_frdup(f);
12321                         memset(vframe->data.ptr,0,vframe->datalen);
12322                         AST_LIST_INSERT_TAIL(&myrpt->txq,vframe,frame_list);
12323                       }
12324                       myfirst = 1;
12325                   }
12326                   vframe = ast_frdup(f);
12327                   AST_LIST_INSERT_TAIL(&myrpt->txq,
12328                      vframe,frame_list);
12329                } else myfirst = 0;
12330                x = 0;
12331                AST_LIST_TRAVERSE(&myrpt->txq, vframe,
12332                   frame_list) x++;
12333                if (!x)
12334                {
12335                   memset(f->data.ptr,0,f->datalen);
12336                }
12337                else
12338                {
12339                   ast_frfree(f);
12340                   f = AST_LIST_REMOVE_HEAD(&myrpt->txq,
12341                      frame_list);
12342                }
12343             }
12344             else
12345             {
12346                while((vframe = AST_LIST_REMOVE_HEAD(&myrpt->txq,
12347                   frame_list))) ast_frfree(vframe);
12348             }
12349             ast_write(myrpt->txchannel,f);
12350          }
12351          if (f->frametype == AST_FRAME_CONTROL)
12352          {
12353             if (f->subclass.integer == AST_CONTROL_HANGUP)
12354             {
12355                if (debug) printf("@@@@ rpt:Hung Up\n");
12356                ast_frfree(f);
12357                break;
12358             }
12359          }
12360          ast_frfree(f);
12361          continue;
12362       }
12363       toexit = 0;
12364       rpt_mutex_lock(&myrpt->lock);
12365       l = myrpt->links.next;
12366       while(l != &myrpt->links)
12367       {
12368          int remnomute;
12369          struct timeval now;
12370 
12371          if (l->disctime)
12372          {
12373             l = l->next;
12374             continue;
12375          }
12376 
12377          remrx = 0;
12378          /* see if any other links are receiving */
12379          m = myrpt->links.next;
12380          while(m != &myrpt->links)
12381          {
12382             /* if not us, count it */
12383             if ((m != l) && (m->lastrx)) remrx = 1;
12384             m = m->next;
12385          }
12386          rpt_mutex_unlock(&myrpt->lock);
12387          now = ast_tvnow();
12388          if ((who == l->chan) || (!l->lastlinktv.tv_sec) ||
12389             (ast_tvdiff_ms(now,l->lastlinktv) >= 19))
12390          {
12391             l->lastlinktv = now;
12392             remnomute = myrpt->localtx && 
12393                 (!(myrpt->cmdnode[0] || 
12394                (myrpt->dtmfidx > -1)));
12395             totx = (((l->isremote) ? (remnomute) : 
12396                myrpt->exttx) || remrx) && l->mode;
12397             if (l->phonemode == 0 && l->chan && (l->lasttx != totx))
12398             {
12399                if (totx)
12400                {
12401                   ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
12402                }
12403                else
12404                {
12405                   ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
12406                }
12407                if (myrpt->p.archivedir)
12408                {
12409                   char str[100];
12410 
12411                   if (totx)
12412                      sprintf(str,"TXKEY,%s",l->name);
12413                   else
12414                      sprintf(str,"TXUNKEY,%s",l->name);
12415                   donodelog(myrpt,str);
12416                }
12417             }
12418             l->lasttx = totx;
12419          }
12420          rpt_mutex_lock(&myrpt->lock);
12421          if (who == l->chan) /* if it was a read from rx */
12422          {
12423             rpt_mutex_unlock(&myrpt->lock);
12424             f = ast_read(l->chan);
12425             if (!f)
12426             {
12427                rpt_mutex_lock(&myrpt->lock);
12428                __kickshort(myrpt);
12429                rpt_mutex_unlock(&myrpt->lock);
12430                if ((!l->disced) && (!l->outbound))
12431                {
12432                   if ((l->name[0] == '0') || l->isremote)
12433                      l->disctime = 1;
12434                   else
12435                      l->disctime = DISC_TIME;
12436                   rpt_mutex_lock(&myrpt->lock);
12437                   ast_hangup(l->chan);
12438                   l->chan = 0;
12439                   break;
12440                }
12441 
12442                if (l->retrytimer) 
12443                {
12444                   ast_hangup(l->chan);
12445                   l->chan = 0;
12446                   rpt_mutex_lock(&myrpt->lock);
12447                   break; 
12448                }
12449                if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
12450                {
12451                   rpt_mutex_lock(&myrpt->lock);
12452                   if (l->chan) ast_hangup(l->chan);
12453                   l->chan = 0;
12454                   l->hasconnected = 1;
12455                   l->retrytimer = RETRY_TIMER_MS;
12456                   l->elaptime = 0;
12457                   l->connecttime = 0;
12458                   l->thisconnected = 0;
12459                   break;
12460                }
12461                rpt_mutex_lock(&myrpt->lock);
12462                /* remove from queue */
12463                remque((struct qelem *) l);
12464                if (!strcmp(myrpt->cmdnode,l->name))
12465                   myrpt->cmdnode[0] = 0;
12466                __kickshort(myrpt);
12467                rpt_mutex_unlock(&myrpt->lock);
12468                if (!l->hasconnected)
12469                   rpt_telemetry(myrpt,CONNFAIL,l);
12470                else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
12471                if (myrpt->p.archivedir)
12472                {
12473                   char str[100];
12474 
12475                   if (!l->hasconnected)
12476                      sprintf(str,"LINKFAIL,%s",l->name);
12477                   else
12478                      sprintf(str,"LINKDISC,%s",l->name);
12479                   donodelog(myrpt,str);
12480                }
12481                if (l->lastf1) ast_frfree(l->lastf1);
12482                l->lastf1 = NULL;
12483                if (l->lastf2) ast_frfree(l->lastf2);
12484                l->lastf2 = NULL;
12485                /* hang-up on call to device */
12486                ast_hangup(l->chan);
12487                ast_hangup(l->pchan);
12488                ast_free(l);
12489                rpt_mutex_lock(&myrpt->lock);
12490                break;
12491             }
12492             if (f->frametype == AST_FRAME_VOICE)
12493             {
12494                int ismuted,n1;
12495 
12496                if ((l->phonemode) && (l->phonevox))
12497                {
12498                   n1 = dovox(&l->vox,
12499                      f->data.ptr,f->datalen / 2);
12500                   if (n1 != l->wasvox)
12501                   {
12502                      if (debug)ast_log(LOG_DEBUG,"Link Node %s, vox %d\n",l->name,n1);
12503                      l->wasvox = n1;
12504                      l->voxtostate = 0;
12505                      if (n1) l->voxtotimer = myrpt->p.voxtimeout_ms;
12506                      else l->voxtotimer = 0;
12507                   }
12508                   if (l->lastrealrx || n1)
12509                   {
12510                      if (!myfirst)
12511                      {
12512                          x = 0;
12513                          AST_LIST_TRAVERSE(&l->rxq, f1,
12514                         frame_list) x++;
12515                          for(;x < myrpt->p.simplexphonedelay; x++)
12516                         {
12517                            f1 = ast_frdup(f);
12518                            memset(f1->data.ptr,0,f1->datalen);
12519                            AST_LIST_INSERT_TAIL(&l->rxq,
12520                               f1,frame_list);
12521                          }
12522                          myfirst = 1;
12523                      }
12524                      f1 = ast_frdup(f);
12525                      AST_LIST_INSERT_TAIL(&l->rxq,f1,frame_list);
12526                   } else myfirst = 0; 
12527                   x = 0;
12528                   AST_LIST_TRAVERSE(&l->rxq, f1,frame_list) x++;
12529                   if (!x)
12530                   {
12531                      memset(f->data.ptr,0,f->datalen);
12532                   }
12533                   else
12534                   {
12535                      ast_frfree(f);
12536                      f = AST_LIST_REMOVE_HEAD(&l->rxq,frame_list);
12537                   }
12538                   if (ioctl(l->chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
12539                   {
12540                      ismuted = 0;
12541                   }
12542                   /* if not receiving, zero-out audio */
12543                   ismuted |= (!l->lastrx);
12544                   if (l->dtmfed && l->phonemode) ismuted = 1;
12545                   l->dtmfed = 0;
12546                   if (ismuted)
12547                   {
12548                      memset(f->data.ptr,0,f->datalen);
12549                      if (l->lastf1)
12550                         memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12551                      if (l->lastf2)
12552                         memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12553                   } 
12554                   if (f) f2 = ast_frdup(f);
12555                   else f2 = NULL;
12556                   f1 = l->lastf2;
12557                   l->lastf2 = l->lastf1;
12558                   l->lastf1 = f2;
12559                   if (ismuted)
12560                   {
12561                      if (l->lastf1)
12562                         memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12563                      if (l->lastf2)
12564                         memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12565                   }
12566                   if (f1)
12567                   {
12568                      ast_write(l->pchan,f1);
12569                      ast_frfree(f1);
12570                   }
12571                }
12572                else
12573                {
12574                   if (!l->lastrx)
12575                      memset(f->data.ptr,0,f->datalen);
12576                   ast_write(l->pchan,f);
12577                }
12578             }
12579 #ifndef  OLD_ASTERISK
12580             else if (f->frametype == AST_FRAME_DTMF_BEGIN)
12581             {
12582                if (l->lastf1)
12583                   memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12584                if (l->lastf2)
12585                   memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12586                l->dtmfed = 1;
12587             }
12588 #endif
12589             if (f->frametype == AST_FRAME_TEXT)
12590             {
12591                handle_link_data(myrpt,l,f->data.ptr);
12592             }
12593             if (f->frametype == AST_FRAME_DTMF)
12594             {
12595                if (l->lastf1)
12596                   memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12597                if (l->lastf2)
12598                   memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12599                l->dtmfed = 1;
12600                handle_link_phone_dtmf(myrpt,l,f->subclass.integer);
12601             }
12602             if (f->frametype == AST_FRAME_CONTROL)
12603             {
12604                if (f->subclass.integer == AST_CONTROL_ANSWER)
12605                {
12606                   char lconnected = l->connected;
12607 
12608                   __kickshort(myrpt);
12609                   l->connected = 1;
12610                   l->hasconnected = 1;
12611                   l->thisconnected = 1;
12612                   l->elaptime = -1;
12613                   if (!l->phonemode) send_newkey(l->chan);
12614                   if (!l->isremote) l->retries = 0;
12615                   if (!lconnected) 
12616                   {
12617                      rpt_telemetry(myrpt,CONNECTED,l);
12618                      if (myrpt->p.archivedir)
12619                      {
12620                         char str[100];
12621 
12622                         if (l->mode)
12623                            sprintf(str,"LINKTRX,%s",l->name);
12624                         else
12625                            sprintf(str,"LINKMONITOR,%s",l->name);
12626                         donodelog(myrpt,str);
12627                      }
12628                   }     
12629                   else
12630                      l->reconnects++;
12631                }
12632                /* if RX key */
12633                if (f->subclass.integer == AST_CONTROL_RADIO_KEY)
12634                {
12635                   if (debug == 7 ) printf("@@@@ rx key\n");
12636                   l->lastrealrx = 1;
12637                   l->rerxtimer = 0;
12638                   if (!l->lastrx1)
12639                   {
12640                      if (myrpt->p.archivedir)
12641                      {
12642                         char str[100];
12643 
12644                         sprintf(str,"RXKEY,%s",l->name);
12645                         donodelog(myrpt,str);
12646                      }
12647                      l->lastrx1 = 1;
12648                   }
12649                }
12650                /* if RX un-key */
12651                if (f->subclass.integer == AST_CONTROL_RADIO_UNKEY)
12652                {
12653                   if (debug == 7) printf("@@@@ rx un-key\n");
12654                   l->lastrealrx = 0;
12655                   l->rerxtimer = 0;
12656                   if (l->lastrx1)
12657                   {
12658                      if (myrpt->p.archivedir)
12659                      {
12660                         char str[100];
12661 
12662                         sprintf(str,"RXUNKEY,%s",l->name);
12663                         donodelog(myrpt,str);
12664                      }
12665                      l->lastrx1 = 0;
12666                      if(myrpt->p.duplex) 
12667                         rpt_telemetry(myrpt,LINKUNKEY,l);
12668                   }
12669                }
12670                if (f->subclass.integer == AST_CONTROL_HANGUP)
12671                {
12672                   ast_frfree(f);
12673                   rpt_mutex_lock(&myrpt->lock);
12674                   __kickshort(myrpt);
12675                   rpt_mutex_unlock(&myrpt->lock);
12676                   if ((!l->outbound) && (!l->disced))
12677                   {
12678                      if ((l->name[0] == '0') || l->isremote)
12679                         l->disctime = 1;
12680                      else
12681                         l->disctime = DISC_TIME;
12682                      rpt_mutex_lock(&myrpt->lock);
12683                      ast_hangup(l->chan);
12684                      l->chan = 0;
12685                      break;
12686                   }
12687                   if (l->retrytimer) 
12688                   {
12689                      if (l->chan) ast_hangup(l->chan);
12690                      l->chan = 0;
12691                      rpt_mutex_lock(&myrpt->lock);
12692                      break;
12693                   }
12694                   if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
12695                   {
12696                      rpt_mutex_lock(&myrpt->lock);
12697                      if (l->chan) ast_hangup(l->chan);
12698                      l->chan = 0;
12699                      l->hasconnected = 1;
12700                      l->elaptime = 0;
12701                      l->retrytimer = RETRY_TIMER_MS;
12702                      l->connecttime = 0;
12703                      l->thisconnected = 0;
12704                      break;
12705                   }
12706                   rpt_mutex_lock(&myrpt->lock);
12707                   /* remove from queue */
12708                   remque((struct qelem *) l);
12709                   if (!strcmp(myrpt->cmdnode,l->name))
12710                      myrpt->cmdnode[0] = 0;
12711                   __kickshort(myrpt);
12712                   rpt_mutex_unlock(&myrpt->lock);
12713                   if (!l->hasconnected)
12714                      rpt_telemetry(myrpt,CONNFAIL,l);
12715                   else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
12716                   if (myrpt->p.archivedir)
12717                   {
12718                      char str[100];
12719 
12720                      if (!l->hasconnected)
12721                         sprintf(str,"LINKFAIL,%s",l->name);
12722                      else
12723                         sprintf(str,"LINKDISC,%s",l->name);
12724                      donodelog(myrpt,str);
12725                   }
12726                   if (l->lastf1) ast_frfree(l->lastf1);
12727                   l->lastf1 = NULL;
12728                   if (l->lastf2) ast_frfree(l->lastf2);
12729                   l->lastf2 = NULL;
12730                   /* hang-up on call to device */
12731                   ast_hangup(l->chan);
12732                   ast_hangup(l->pchan);
12733                   ast_free(l);
12734                   rpt_mutex_lock(&myrpt->lock);
12735                   break;
12736                }
12737             }
12738             ast_frfree(f);
12739             rpt_mutex_lock(&myrpt->lock);
12740             break;
12741          }
12742          if (who == l->pchan) 
12743          {
12744             rpt_mutex_unlock(&myrpt->lock);
12745             f = ast_read(l->pchan);
12746             if (!f)
12747             {
12748                if (debug) printf("@@@@ rpt:Hung Up\n");
12749                toexit = 1;
12750                rpt_mutex_lock(&myrpt->lock);
12751                break;
12752             }
12753             if (f->frametype == AST_FRAME_VOICE)
12754             {
12755                if (l->chan) ast_write(l->chan,f);
12756             }
12757             if (f->frametype == AST_FRAME_CONTROL)
12758             {
12759                if (f->subclass.integer == AST_CONTROL_HANGUP)
12760                {
12761                   if (debug) printf("@@@@ rpt:Hung Up\n");
12762                   ast_frfree(f);
12763                   toexit = 1;
12764                   rpt_mutex_lock(&myrpt->lock);
12765                   break;
12766                }
12767             }
12768             ast_frfree(f);
12769             rpt_mutex_lock(&myrpt->lock);
12770             break;
12771          }
12772          l = l->next;
12773       }
12774       rpt_mutex_unlock(&myrpt->lock);
12775       if (toexit) break;
12776       if (who == myrpt->monchannel) 
12777       {
12778          f = ast_read(myrpt->monchannel);
12779          if (!f)
12780          {
12781             if (debug) printf("@@@@ rpt:Hung Up\n");
12782             break;
12783          }
12784          if (f->frametype == AST_FRAME_VOICE)
12785          {
12786             if (myrpt->monstream) 
12787                ast_writestream(myrpt->monstream,f);
12788          }
12789          if (f->frametype == AST_FRAME_CONTROL)
12790          {
12791             if (f->subclass.integer == AST_CONTROL_HANGUP)
12792             {
12793                if (debug) printf("@@@@ rpt:Hung Up\n");
12794                ast_frfree(f);
12795                break;
12796             }
12797          }
12798          ast_frfree(f);
12799          continue;
12800       }
12801       if (myrpt->parrotchannel && (who == myrpt->parrotchannel))
12802       {
12803          f = ast_read(myrpt->parrotchannel);
12804          if (!f)
12805          {
12806             if (debug) printf("@@@@ rpt:Hung Up\n");
12807             break;
12808          }
12809          if (!myrpt->p.parrotmode)
12810          {
12811             char myfname[300];
12812 
12813             if (myrpt->parrotstream)
12814             {
12815                ast_closestream(myrpt->parrotstream);
12816                myrpt->parrotstream = 0;
12817             }
12818             sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
12819             strcat(myfname,".wav");
12820             unlink(myfname);        
12821          } else if (f->frametype == AST_FRAME_VOICE)
12822          {
12823             if (myrpt->parrotstream) 
12824                ast_writestream(myrpt->parrotstream,f);
12825          }
12826          if (f->frametype == AST_FRAME_CONTROL)
12827          {
12828             if (f->subclass.integer == AST_CONTROL_HANGUP)
12829             {
12830                if (debug) printf("@@@@ rpt:Hung Up\n");
12831                ast_frfree(f);
12832                break;
12833             }
12834          }
12835          ast_frfree(f);
12836          continue;
12837       }
12838       if (myrpt->voxchannel && (who == myrpt->voxchannel))
12839       {
12840          f = ast_read(myrpt->voxchannel);
12841          if (!f)
12842          {
12843             if (debug) printf("@@@@ rpt:Hung Up\n");
12844             break;
12845          }
12846          if (f->frametype == AST_FRAME_VOICE)
12847          {
12848             n = dovox(&myrpt->vox,f->data.ptr,f->datalen / 2);
12849             if (n != myrpt->wasvox)
12850             {
12851                if (debug) ast_log(LOG_DEBUG,"Node %s, vox %d\n",myrpt->name,n);
12852                myrpt->wasvox = n;
12853                myrpt->voxtostate = 0;
12854                if (n) myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
12855                else myrpt->voxtotimer = 0;
12856             }
12857          }
12858          if (f->frametype == AST_FRAME_CONTROL)
12859          {
12860             if (f->subclass.integer == AST_CONTROL_HANGUP)
12861             {
12862                if (debug) printf("@@@@ rpt:Hung Up\n");
12863                ast_frfree(f);
12864                break;
12865             }
12866          }
12867          ast_frfree(f);
12868          continue;
12869       }
12870       if (who == myrpt->txpchannel) /* if it was a read from remote tx */
12871       {
12872          f = ast_read(myrpt->txpchannel);
12873          if (!f)
12874          {
12875             if (debug) printf("@@@@ rpt:Hung Up\n");
12876             break;
12877          }
12878          if (f->frametype == AST_FRAME_CONTROL)
12879          {
12880             if (f->subclass.integer == AST_CONTROL_HANGUP)
12881             {
12882                if (debug) printf("@@@@ rpt:Hung Up\n");
12883                ast_frfree(f);
12884                break;
12885             }
12886          }
12887          ast_frfree(f);
12888          continue;
12889       }
12890    }
12891    usleep(100000);
12892    ast_hangup(myrpt->pchannel);
12893    ast_hangup(myrpt->monchannel);
12894    if (myrpt->parrotchannel) ast_hangup(myrpt->parrotchannel);
12895    myrpt->parrotstate = 0;
12896    if (myrpt->voxchannel) ast_hangup(myrpt->voxchannel);
12897    ast_hangup(myrpt->txpchannel);
12898    if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
12899    if (myrpt->dahditxchannel != myrpt->txchannel) ast_hangup(myrpt->dahditxchannel);
12900    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
12901    myrpt->lastf1 = NULL;
12902    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
12903    myrpt->lastf2 = NULL;
12904    ast_hangup(myrpt->rxchannel);
12905    rpt_mutex_lock(&myrpt->lock);
12906    l = myrpt->links.next;
12907    while(l != &myrpt->links)
12908    {
12909       struct rpt_link *ll = l;
12910       /* remove from queue */
12911       remque((struct qelem *) l);
12912       /* hang-up on call to device */
12913       if (l->chan) ast_hangup(l->chan);
12914       ast_hangup(l->pchan);
12915       l = l->next;
12916       ast_free(ll);
12917    }
12918    if (myrpt->xlink  == 1) myrpt->xlink = 2;
12919    rpt_mutex_unlock(&myrpt->lock);
12920    if (debug) printf("@@@@ rpt:Hung up channel\n");
12921    myrpt->rpt_thread = AST_PTHREADT_STOP;
12922    pthread_exit(NULL); 
12923    return NULL;
12924 }
12925 
12926    
12927 static void *rpt_master(void *ignore)
12928 {
12929 int   i,n;
12930 pthread_attr_t attr;
12931 struct ast_config *cfg;
12932 char *this,*val;
12933 
12934    /* init nodelog queue */
12935    nodelog.next = nodelog.prev = &nodelog;
12936    /* go thru all the specified repeaters */
12937    this = NULL;
12938    n = 0;
12939 #ifndef OLD_ASTERISK
12940    /* wait until asterisk starts */
12941         while(!ast_test_flag(&ast_options,AST_OPT_FLAG_FULLY_BOOTED))
12942                 usleep(250000);
12943 #endif
12944 #ifdef   NEW_ASTERISK
12945    rpt_vars[n].cfg = ast_config_load("rpt.conf",config_flags);
12946 #else
12947    rpt_vars[n].cfg = ast_config_load("rpt.conf");
12948 #endif
12949    cfg = rpt_vars[n].cfg;
12950    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
12951       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
12952       pthread_exit(NULL);
12953    }
12954    while((this = ast_category_browse(cfg,this)) != NULL)
12955    {
12956       for(i = 0 ; i < strlen(this) ; i++){
12957          if((this[i] < '0') || (this[i] > '9'))
12958             break;
12959       }
12960       if(i != strlen(this)) continue; /* Not a node defn */
12961       memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
12962       rpt_vars[n].name = ast_strdup(this);
12963       val = (char *) ast_variable_retrieve(cfg,this,"rxchannel");
12964       if (val) rpt_vars[n].rxchanname = ast_strdup(val);
12965       val = (char *) ast_variable_retrieve(cfg,this,"txchannel");
12966       if (val) rpt_vars[n].txchanname = ast_strdup(val);
12967       rpt_vars[n].remote = 0;
12968       rpt_vars[n].remoterig = "";
12969       val = (char *) ast_variable_retrieve(cfg,this,"remote");
12970       if (val) 
12971       {
12972          rpt_vars[n].remoterig = ast_strdup(val);
12973          rpt_vars[n].remote = 1;
12974       }
12975       val = (char *) ast_variable_retrieve(cfg,this,"radiotype");
12976       if (val) rpt_vars[n].remoterig = ast_strdup(val);
12977       ast_mutex_init(&rpt_vars[n].lock);
12978       ast_mutex_init(&rpt_vars[n].remlock);
12979       ast_mutex_init(&rpt_vars[n].statpost_lock);
12980       rpt_vars[n].tele.next = &rpt_vars[n].tele;
12981       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
12982       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
12983       rpt_vars[n].tailmessagen = 0;
12984 #ifdef   _MDC_DECODE_H_
12985       rpt_vars[n].mdc = mdc_decoder_new(8000);
12986 #endif
12987       n++;
12988    }
12989    nrpts = n;
12990    ast_config_destroy(cfg);
12991 
12992    /* start em all */
12993    for(i = 0; i < n; i++)
12994    {
12995       load_rpt_vars(i,1);
12996 
12997       /* if is a remote, don't start one for it */
12998       if (rpt_vars[i].remote)
12999       {
13000          if(retreive_memory(&rpt_vars[i],"init")){ /* Try to retreive initial memory channel */
13001             if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx450))
13002                strncpy(rpt_vars[i].freq, "446.500", sizeof(rpt_vars[i].freq) - 1);
13003             else
13004                strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
13005             strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
13006 
13007             strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
13008             rpt_vars[i].remmode = REM_MODE_FM;
13009             rpt_vars[i].offset = REM_SIMPLEX;
13010             rpt_vars[i].powerlevel = REM_LOWPWR;
13011          }
13012          continue;
13013       }
13014       else /* is a normal repeater */
13015       {
13016           rpt_vars[i].p.memory = rpt_vars[i].name;
13017          if(retreive_memory(&rpt_vars[i],"radiofreq")){ /* Try to retreive initial memory channel */
13018             if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx450))
13019                strncpy(rpt_vars[i].freq, "446.500", sizeof(rpt_vars[i].freq) - 1);
13020             else if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx150))
13021                strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
13022             strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
13023 
13024             strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
13025             rpt_vars[i].remmode = REM_MODE_FM;
13026             rpt_vars[i].offset = REM_SIMPLEX;
13027             rpt_vars[i].powerlevel = REM_LOWPWR;
13028          }
13029          ast_log(LOG_NOTICE,"Normal Repeater Init  %s  %s  %s\n",rpt_vars[i].name, rpt_vars[i].remoterig, rpt_vars[i].freq);
13030       }
13031       if (!rpt_vars[i].p.ident)
13032       {
13033          ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
13034          ast_config_destroy(cfg);
13035          pthread_exit(NULL);
13036       }
13037            pthread_attr_init(&attr);
13038            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13039       ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
13040    }
13041    usleep(500000);
13042    time(&starttime);
13043    for(;;)
13044    {
13045       /* Now monitor each thread, and restart it if necessary */
13046       for(i = 0; i < n; i++)
13047       { 
13048          int rv;
13049          if (rpt_vars[i].remote) continue;
13050          if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP) 
13051             rv = -1;
13052          else
13053             rv = pthread_kill(rpt_vars[i].rpt_thread,0);
13054          if (rv)
13055          {
13056             if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15)
13057             {
13058                if(rpt_vars[i].threadrestarts >= 5)
13059                {
13060                   ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n");
13061                   exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
13062                }
13063                else
13064                {
13065                   ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name);
13066                   rpt_vars[i].threadrestarts++;
13067                }
13068             }
13069             else
13070                rpt_vars[i].threadrestarts = 0;
13071 
13072             rpt_vars[i].lastthreadrestarttime = time(NULL);
13073                  pthread_attr_init(&attr);
13074                  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13075             ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
13076             /* if (!rpt_vars[i].xlink) */
13077                ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
13078          }
13079 
13080       }
13081       for(;;)
13082       {
13083          struct nodelog *nodep;
13084          char *space,datestr[100],fname[300];
13085          int fd;
13086 
13087          ast_mutex_lock(&nodeloglock);
13088          nodep = nodelog.next;
13089          if(nodep == &nodelog) /* if nothing in queue */
13090          {
13091             ast_mutex_unlock(&nodeloglock);
13092             break;
13093          }
13094          remque((struct qelem *)nodep);
13095          ast_mutex_unlock(&nodeloglock);
13096          space = strchr(nodep->str,' ');
13097          if (!space) 
13098          {
13099             ast_free(nodep);
13100             continue;
13101          }
13102          *space = 0;
13103          strftime(datestr,sizeof(datestr) - 1,"%Y%m%d",
13104             localtime(&nodep->timestamp));
13105          sprintf(fname,"%s/%s/%s.txt",nodep->archivedir,
13106             nodep->str,datestr);
13107          fd = open(fname,O_WRONLY | O_CREAT | O_APPEND,0600);
13108          if (fd == -1)
13109          {
13110             ast_log(LOG_ERROR,"Cannot open node log file %s for write",space + 1);
13111             ast_free(nodep);
13112             continue;
13113          }
13114          if (write(fd,space + 1,strlen(space + 1)) !=
13115             strlen(space + 1))
13116          {
13117             ast_log(LOG_ERROR,"Cannot write node log file %s for write",space + 1);
13118             ast_free(nodep);
13119             continue;
13120          }
13121          close(fd);
13122          ast_free(nodep);
13123       }
13124       sleep(2);
13125    }
13126    ast_config_destroy(cfg);
13127    pthread_exit(NULL);
13128 }
13129 
13130 static int rpt_exec(struct ast_channel *chan, const char *data)
13131 {
13132    int res=-1,i,rem_totx,rem_rx,remkeyed,n,phone_mode = 0;
13133    int iskenwood_pci4,authtold,authreq,setting,notremming,reming;
13134    int ismuted,dtmfed,phone_vox = 0;
13135 #ifdef   OLD_ASTERISK
13136    struct localuser *u;
13137 #endif
13138    char tmp[256], keyed = 0,keyed1 = 0;
13139    char *options,*stringp,*tele,c,*altp,*memp;
13140    char sx[320],*sy;
13141    struct   rpt *myrpt;
13142    struct ast_frame *f,*f1,*f2;
13143    struct ast_channel *who;
13144    struct ast_channel *cs[20];
13145    struct   rpt_link *l;
13146    struct dahdi_confinfo ci;  /* conference info */
13147    struct dahdi_params par;
13148    int ms,elap,nullfd;
13149    time_t t,last_timeout_warning;
13150    struct   dahdi_radio_param z;
13151    struct rpt_tele *telem;
13152    int   numlinks;
13153 
13154    nullfd = open("/dev/null",O_RDWR);
13155    if (ast_strlen_zero(data)) {
13156       ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
13157       return -1;
13158    }
13159 
13160    strncpy(tmp, (char *)data, sizeof(tmp)-1);
13161    time(&t);
13162    /* if time has externally shifted negative, screw it */
13163    if (t < starttime) t = starttime + START_DELAY;
13164    if ((!starttime) || (t < (starttime + START_DELAY)))
13165    {
13166       ast_log(LOG_NOTICE,"Node %s rejecting call: too soon!\n",tmp);
13167       ast_safe_sleep(chan,3000);
13168       return -1;
13169    }
13170 
13171    ast_log(LOG_NOTICE,"parsing argument=%s \n",tmp);
13172 
13173    altp=strstr(tmp, "|*");
13174    if(altp){
13175       altp[0]=0;
13176       altp++;
13177     }
13178 
13179    memp=strstr(tmp, "|M");
13180    if(memp){
13181       memp[0]=0;
13182       memp+=2;
13183     }
13184 
13185    stringp=tmp;
13186    strsep(&stringp, "|");
13187    options = stringp;
13188 
13189    ast_log(LOG_NOTICE,"options=%s \n",options);
13190    if(memp>0)ast_log(LOG_NOTICE,"memp=%s \n",memp);
13191    if(altp>0)ast_log(LOG_NOTICE,"altp=%s \n",altp);
13192 
13193    myrpt = NULL;
13194    /* see if we can find our specified one */
13195    for(i = 0; i < nrpts; i++)
13196    {
13197       /* if name matches, assign it and exit loop */
13198       if (!strcmp(tmp,rpt_vars[i].name))
13199       {
13200          myrpt = &rpt_vars[i];
13201          break;
13202       }
13203    }
13204 
13205    pbx_builtin_setvar_helper(chan, "RPT_STAT_ERR", "");
13206 
13207    if (myrpt == NULL)
13208    {
13209       pbx_builtin_setvar_helper(chan, "RPT_STAT_ERR", "NODE_NOT_FOUND");
13210       ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
13211       return (priority_jump(NULL,chan));
13212    }
13213 
13214    numlinks=linkcount(myrpt);
13215 
13216    if(options && *options == 'q')
13217    {
13218       char buf2[128];
13219 
13220       if(myrpt->keyed)
13221          pbx_builtin_setvar_helper(chan, "RPT_STAT_RXKEYED", "1");
13222       else
13223          pbx_builtin_setvar_helper(chan, "RPT_STAT_RXKEYED", "0");   
13224 
13225       if(myrpt->txkeyed)
13226          pbx_builtin_setvar_helper(chan, "RPT_STAT_TXKEYED", "1");
13227       else
13228          pbx_builtin_setvar_helper(chan, "RPT_STAT_TXKEYED", "0");   
13229 
13230       snprintf(buf2,sizeof(buf2),"%s=%i", "RPT_STAT_XLINK", myrpt->xlink);
13231       pbx_builtin_setvar(chan, buf2);
13232       snprintf(buf2,sizeof(buf2),"%s=%i", "RPT_STAT_LINKS", numlinks);
13233       pbx_builtin_setvar(chan, buf2);
13234       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_WASCHAN", myrpt->waschan);
13235       pbx_builtin_setvar(chan, buf2);
13236       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_NOWCHAN", myrpt->nowchan);
13237       pbx_builtin_setvar(chan, buf2);
13238       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_DUPLEX", myrpt->p.duplex);
13239       pbx_builtin_setvar(chan, buf2);
13240       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_PARROT", myrpt->p.parrotmode);
13241       pbx_builtin_setvar(chan, buf2);
13242       //snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_PHONEVOX", myrpt->phonevox);
13243       //pbx_builtin_setvar(chan, buf2);
13244       //snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_CONNECTED", myrpt->connected);
13245       //pbx_builtin_setvar(chan, buf2);
13246       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_CALLMODE", myrpt->callmode);
13247       pbx_builtin_setvar(chan, buf2);
13248       snprintf(buf2,sizeof(buf2),"%s=%s", "RPT_STAT_LASTTONE", myrpt->lasttone);
13249       pbx_builtin_setvar(chan, buf2);
13250 
13251       return priority_jump(myrpt,chan);
13252    }
13253 
13254    if(options && *options == 'o')
13255    {
13256       return(channel_revert(myrpt));
13257    }
13258 
13259    #if 0
13260    if((altp)&&(*options == 'Z'))
13261    {
13262       rpt_push_alt_macro(myrpt,altp);
13263       return 0;
13264    }
13265    #endif
13266 
13267 
13268    /* if not phone access, must be an IAX connection */
13269    if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R') || (*options == 'S')))
13270    {
13271       int val;
13272 
13273       pbx_builtin_setvar_helper(chan, "RPT_STAT_BUSY", "0");
13274        
13275       myrpt->bargechan=0;
13276       if(options && strstr(options, "f")>0)
13277       {
13278          myrpt->bargechan=1;     
13279       }
13280 
13281       if(memp>0)
13282       {
13283          char radiochan;
13284          radiochan=strtod(data,NULL);
13285          // if(myrpt->nowchan!=0 && radiochan!=myrpt->nowchan && !myrpt->bargechan)
13286 
13287          if(numlinks>0 && radiochan!=myrpt->nowchan && !myrpt->bargechan)
13288          {
13289             pbx_builtin_setvar_helper(chan, "RPT_STAT_BUSY", "1");
13290             ast_log(LOG_NOTICE, "Radio Channel Busy.\n");
13291             return (priority_jump(myrpt,chan));
13292          }
13293          else if(radiochan!=myrpt->nowchan || myrpt->bargechan)
13294          {
13295             channel_steer(myrpt,memp); 
13296          }
13297       }
13298       if(altp)rpt_push_alt_macro(myrpt,altp);
13299       phone_mode = 1;
13300       if (*options == 'D') phone_mode = 2;
13301       if (*options == 'S') phone_mode = 3;
13302       ast_set_callerid(chan,"0","app_rpt user","0");
13303       val = 1;
13304       ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
13305       if ((*(options + 1) == 'V') || (*(options + 1) == 'v')) phone_vox = 1;
13306    }
13307    else
13308    {
13309 #ifdef ALLOW_LOCAL_CHANNELS
13310            /* Check to insure the connection is IAX2 or Local*/
13311            if ( (strncmp(chan->name,"IAX2",4)) && (strncmp(chan->name,"Local",5)) ) {
13312                ast_log(LOG_WARNING, "We only accept links via IAX2 or Local!!\n");
13313                return -1;
13314            }
13315 #else
13316       if (strncmp(chan->name,"IAX2",4))
13317       {
13318          ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
13319          return -1;
13320       }
13321 #endif
13322            if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable){ /* Do not allow incoming radio connections if disabled */
13323                  ast_log(LOG_NOTICE, "Connect attempt to node %s  with tx disabled", myrpt->name);
13324                   return -1;
13325          }  
13326    }
13327    if (options && (*options == 'R'))
13328    {
13329       /* Parts of this section taken from app_parkandannounce */
13330       char *return_context;
13331       int length, m, lot, timeout = 0;
13332       char buffer[256],*template;
13333       char *working, *context, *exten, *priority;
13334       char *s,*orig_s;
13335 
13336       rpt_mutex_lock(&myrpt->lock);
13337       m = myrpt->callmode;
13338       rpt_mutex_unlock(&myrpt->lock);
13339 
13340       if ((!myrpt->p.nobusyout) && m)
13341       {
13342          if (chan->_state != AST_STATE_UP)
13343          {
13344             ast_indicate(chan,AST_CONTROL_BUSY);
13345          }
13346          while(ast_safe_sleep(chan,10000) != -1);
13347          return -1;
13348       }
13349 
13350       if (chan->_state != AST_STATE_UP)
13351       {
13352          ast_answer(chan);
13353          if (!phone_mode) send_newkey(chan);
13354       }
13355 
13356       length=strlen(options)+2;
13357       orig_s=ast_malloc(length);
13358       if(!orig_s) {
13359          ast_log(LOG_WARNING, "Out of memory\n");
13360          return -1;
13361       }
13362       s=orig_s;
13363       strncpy(s,options,length);
13364 
13365       template=strsep(&s,"|");
13366       if(!template) {
13367          ast_log(LOG_WARNING, "An announce template must be defined\n");
13368          ast_free(orig_s);
13369          return -1;
13370       } 
13371   
13372       if(s) {
13373          timeout = atoi(strsep(&s, "|"));
13374          timeout *= 1000;
13375       }
13376    
13377       return_context = s;
13378   
13379       if(return_context != NULL) {
13380          /* set the return context. Code borrowed from the Goto builtin */
13381     
13382          working = return_context;
13383          context = strsep(&working, "|");
13384          exten = strsep(&working, "|");
13385          if(!exten) {
13386             /* Only a priority in this one */
13387             priority = context;
13388             exten = NULL;
13389             context = NULL;
13390          } else {
13391             priority = strsep(&working, "|");
13392             if(!priority) {
13393                /* Only an extension and priority in this one */
13394                priority = exten;
13395                exten = context;
13396                context = NULL;
13397          }
13398       }
13399       if(atoi(priority) < 0) {
13400          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
13401          ast_free(orig_s);
13402          return -1;
13403       }
13404       /* At this point we have a priority and maybe an extension and a context */
13405       chan->priority = atoi(priority);
13406 #ifdef OLD_ASTERISK
13407       if(exten && strcasecmp(exten, "BYEXTENSION"))
13408 #else
13409       if(exten)
13410 #endif
13411          strncpy(chan->exten, exten, sizeof(chan->exten)-1);
13412       if(context)
13413          strncpy(chan->context, context, sizeof(chan->context)-1);
13414       } else {  /* increment the priority by default*/
13415          chan->priority++;
13416       }
13417 
13418       if(option_verbose > 2) {
13419          ast_verbose(VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n",
13420             chan->context, chan->exten, chan->priority,
13421             S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""));
13422          if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority,
13423             S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
13424             ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
13425          }
13426       }
13427   
13428       /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
13429       before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
13430 
13431       ast_masq_park_call(chan, NULL, timeout, &lot);
13432 
13433       if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
13434 
13435       snprintf(buffer, sizeof(buffer) - 1, "%d,%s", lot, template + 1);
13436 
13437       rpt_telemetry(myrpt,REV_PATCH,buffer);
13438 
13439       ast_free(orig_s);
13440 
13441       return 0;
13442 
13443    }
13444 
13445    if (!options)
13446    {
13447         struct ast_hostent ahp;
13448         struct hostent *hp;
13449         struct in_addr ia;
13450         char hisip[100],nodeip[100],*val, *s, *s1, *s2, *s3, *b,*b1;
13451 
13452       /* look at callerid to see what node this comes from */
13453       b = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL);
13454       if (!b) /* if doesn't have caller id */
13455       {
13456          ast_log(LOG_WARNING, "Does not have callerid on %s\n",tmp);
13457          return -1;
13458       }
13459       /* get his IP from IAX2 module */
13460       memset(hisip,0,sizeof(hisip));
13461 #ifdef ALLOW_LOCAL_CHANNELS
13462         /* set IP address if this is a local connection*/
13463         if (strncmp(chan->name,"Local",5)==0) {
13464             strcpy(hisip,"127.0.0.1");
13465         } else {
13466          pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
13467       }
13468 #else
13469       pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
13470 #endif
13471 
13472       if (!hisip[0])
13473       {
13474          ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
13475          return -1;
13476       }
13477       
13478       b1 = ast_strdupa(b);
13479       ast_shrink_phone_number(b1);
13480       if (!strcmp(myrpt->name,b1))
13481       {
13482          ast_log(LOG_WARNING, "Trying to link to self!!\n");
13483          return -1;
13484       }
13485 
13486       if (*b1 < '1')
13487       {
13488          ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n",b1);
13489          return -1;
13490       }
13491 
13492 
13493       /* look for his reported node string */
13494       val = node_lookup(myrpt,b1);
13495       if (!val)
13496       {
13497          ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
13498          return -1;
13499       }
13500       strncpy(tmp,val,sizeof(tmp) - 1);
13501       s = tmp;
13502       s1 = strsep(&s,",");
13503       if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
13504       {
13505          sy = strchr(s1,'/');    
13506          *sy = 0;
13507          sprintf(sx,"%s:4569/%s",s1,sy + 1);
13508          s1 = sx;
13509       }
13510       s2 = strsep(&s,",");
13511       if (!s2)
13512       {
13513          ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n",b1);
13514          return -1;
13515       }
13516                 if (strcmp(s2,"NONE")) {
13517          hp = ast_gethostbyname(s2, &ahp);
13518          if (!hp)
13519          {
13520             ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s2);
13521             return -1;
13522          }
13523          memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
13524 #ifdef   OLD_ASTERISK
13525          ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
13526 #else
13527          strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
13528 #endif
13529          s3 = strchr(hisip,':');
13530          if (s3) *s3 = 0;
13531          if (strcmp(hisip,nodeip))
13532          {
13533             s3 = strchr(s1,'@');
13534             if (s3) s1 = s3 + 1;
13535             s3 = strchr(s1,'/');
13536             if (s3) *s3 = 0;
13537             s3 = strchr(s1,':');
13538             if (s3) *s3 = 0;
13539             hp = ast_gethostbyname(s1, &ahp);
13540             if (!hp)
13541             {
13542                ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s1);
13543                return -1;
13544             }
13545             memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
13546 #ifdef   OLD_ASTERISK
13547             ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
13548 #else
13549             strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
13550 #endif
13551             if (strcmp(hisip,nodeip))
13552             {
13553                ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip);
13554                return -1;
13555             }
13556          }
13557       }
13558    }
13559 
13560    /* if is not a remote */
13561    if (!myrpt->remote)
13562    {
13563       char *b,*b1;
13564       int reconnects = 0;
13565 
13566       rpt_mutex_lock(&myrpt->lock);
13567       i = myrpt->xlink;
13568       rpt_mutex_unlock(&myrpt->lock);
13569       if (i)
13570       {
13571          ast_log(LOG_WARNING, "Cannot connect to node %s, system busy\n",myrpt->name);
13572          return -1;
13573       }
13574       /* look at callerid to see what node this comes from */
13575       b = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL);
13576       if (!b) /* if doesn't have caller id */
13577       {
13578          ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
13579          return -1;
13580       }
13581 
13582       b1 = ast_strdupa(b);
13583       ast_shrink_phone_number(b1);
13584       if (!strcmp(myrpt->name,b1))
13585       {
13586          ast_log(LOG_WARNING, "Trying to link to self!!\n");
13587          return -1;
13588       }
13589       rpt_mutex_lock(&myrpt->lock);
13590       l = myrpt->links.next;
13591       /* try to find this one in queue */
13592       while(l != &myrpt->links)
13593       {
13594          if (l->name[0] == '0') 
13595          {
13596             l = l->next;
13597             continue;
13598          }
13599          /* if found matching string */
13600          if (!strcmp(l->name,b1)) break;
13601          l = l->next;
13602       }
13603       /* if found */
13604       if (l != &myrpt->links) 
13605       {
13606          l->killme = 1;
13607          l->retries = l->max_retries + 1;
13608          l->disced = 2;
13609          reconnects = l->reconnects;
13610          reconnects++;
13611                         rpt_mutex_unlock(&myrpt->lock);
13612          usleep(500000);   
13613       } else 
13614          rpt_mutex_unlock(&myrpt->lock);
13615       /* establish call in tranceive mode */
13616       l = ast_malloc(sizeof(struct rpt_link));
13617       if (!l)
13618       {
13619          ast_log(LOG_WARNING, "Unable to malloc\n");
13620          pthread_exit(NULL);
13621       }
13622       /* zero the silly thing */
13623       memset((char *)l,0,sizeof(struct rpt_link));
13624       l->mode = 1;
13625       strncpy(l->name,b1,MAXNODESTR - 1);
13626       l->isremote = 0;
13627       l->chan = chan;
13628       l->connected = 1;
13629       l->thisconnected = 1;
13630       l->hasconnected = 1;
13631       l->reconnects = reconnects;
13632       l->phonemode = phone_mode;
13633       l->phonevox = phone_vox;
13634       l->lastf1 = NULL;
13635       l->lastf2 = NULL;
13636       l->dtmfed = 0;
13637       voxinit_link(l,1);
13638       ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
13639       ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
13640       /* allocate a pseudo-channel thru asterisk */
13641       l->pchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
13642       if (!l->pchan)
13643       {
13644          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
13645          pthread_exit(NULL);
13646       }
13647       ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
13648       ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
13649 #ifdef   AST_CDR_FLAG_POST_DISABLED
13650       if (l->pchan->cdr)
13651          ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
13652 #endif
13653       /* make a conference for the tx */
13654       ci.chan = 0;
13655       ci.confno = myrpt->conf;
13656       ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
13657       /* first put the channel on the conference in proper mode */
13658       if (ioctl(l->pchan->fds[0],DAHDI_SETCONF,&ci) == -1)
13659       {
13660          ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
13661          pthread_exit(NULL);
13662       }
13663       rpt_mutex_lock(&myrpt->lock);
13664       if ((phone_mode == 2) && (!phone_vox)) l->lastrealrx = 1;
13665       l->max_retries = MAX_RETRIES;
13666       /* insert at end of queue */
13667       insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
13668       __kickshort(myrpt);
13669       rpt_mutex_unlock(&myrpt->lock);
13670       if (chan->_state != AST_STATE_UP) {
13671          ast_answer(chan);
13672          if (!phone_mode) send_newkey(chan);
13673       }
13674       if (myrpt->p.archivedir)
13675       {
13676          char str[100];
13677 
13678          if (l->phonemode)
13679             sprintf(str,"LINK(P),%s",l->name);
13680          else
13681             sprintf(str,"LINK,%s",l->name);
13682          donodelog(myrpt,str);
13683       }
13684       if (!phone_mode) send_newkey(chan);
13685       return 0;
13686    }
13687    /* well, then it is a remote */
13688    rpt_mutex_lock(&myrpt->lock);
13689    /* if remote, error if anyone else already linked */
13690    if (myrpt->remoteon)
13691    {
13692       rpt_mutex_unlock(&myrpt->lock);
13693       usleep(500000);
13694       if (myrpt->remoteon)
13695       {
13696          ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
13697 #ifdef   AST_CDR_FLAG_POST_DISABLED
13698          if (chan->cdr)
13699             ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13700 #endif
13701          return -1;
13702       }     
13703       rpt_mutex_lock(&myrpt->lock);
13704    }
13705    if (myrpt->p.rptnode)
13706    {
13707       char killedit = 0;
13708       time_t now;
13709 
13710       time(&now);
13711       for(i = 0; i < nrpts; i++)
13712       {
13713          if (!strcasecmp(rpt_vars[i].name,myrpt->p.rptnode))
13714          {
13715             if ((rpt_vars[i].links.next != &rpt_vars[i].links) ||
13716                rpt_vars[i].keyed ||
13717                 ((rpt_vars[i].lastkeyedtime + RPT_LOCKOUT_SECS) > now) ||
13718                  rpt_vars[i].txkeyed ||
13719                   ((rpt_vars[i].lasttxkeyedtime + RPT_LOCKOUT_SECS) > now))
13720             {
13721                rpt_mutex_unlock(&myrpt->lock);
13722                ast_log(LOG_WARNING, "Trying to use busy link (repeater node %s) on %s\n",rpt_vars[i].name,tmp);
13723 #ifdef   AST_CDR_FLAG_POST_DISABLED
13724                if (chan->cdr)
13725                   ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13726 #endif
13727                return -1;
13728             }
13729             while(rpt_vars[i].xlink != 3)
13730             {
13731                if (!killedit)
13732                {
13733                   ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
13734                   rpt_vars[i].xlink = 1;
13735                   killedit = 1;
13736                }
13737                rpt_mutex_unlock(&myrpt->lock);
13738                if (ast_safe_sleep(chan,500) == -1)
13739                {
13740 #ifdef   AST_CDR_FLAG_POST_DISABLED
13741                   if (chan->cdr)
13742                      ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13743 #endif
13744                   return -1;
13745                }
13746                rpt_mutex_lock(&myrpt->lock);
13747             }
13748             break;
13749          }
13750       }
13751    }
13752 
13753 #ifdef HAVE_IOPERM
13754    if ( (!strcmp(myrpt->remoterig, remote_rig_rbi)||!strcmp(myrpt->remoterig, remote_rig_ppp16)) &&
13755      (ioperm(myrpt->p.iobase,1,1) == -1))
13756    {
13757       rpt_mutex_unlock(&myrpt->lock);
13758       ast_log(LOG_WARNING, "Can't get io permission on IO port %x hex\n",myrpt->p.iobase);
13759       return -1;
13760    }
13761 #endif
13762    myrpt->remoteon = 1;
13763 #ifdef   OLD_ASTERISK
13764    LOCAL_USER_ADD(u);
13765 #endif
13766    rpt_mutex_unlock(&myrpt->lock);
13767    /* find our index, and load the vars initially */
13768    for(i = 0; i < nrpts; i++)
13769    {
13770       if (&rpt_vars[i] == myrpt)
13771       {
13772          load_rpt_vars(i,0);
13773          break;
13774       }
13775    }
13776    rpt_mutex_lock(&myrpt->lock);
13777    tele = strchr(myrpt->rxchanname,'/');
13778    if (!tele)
13779    {
13780       fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
13781       rpt_mutex_unlock(&myrpt->lock);
13782       pthread_exit(NULL);
13783    }
13784    *tele++ = 0;
13785    myrpt->rxchannel = ast_request(myrpt->rxchanname, AST_FORMAT_SLINEAR, NULL, tele, NULL);
13786    myrpt->dahdirxchannel = NULL;
13787    if (!strcasecmp(myrpt->rxchanname,"DAHDI"))
13788       myrpt->dahdirxchannel = myrpt->rxchannel;
13789    if (myrpt->rxchannel)
13790    {
13791       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
13792       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
13793 #ifdef   AST_CDR_FLAG_POST_DISABLED
13794       if (myrpt->rxchannel->cdr)
13795          ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13796 #endif
13797 #ifndef  NEW_ASTERISK
13798       myrpt->rxchannel->whentohangup = 0;
13799 #endif
13800       myrpt->rxchannel->appl = "Apprpt";
13801       myrpt->rxchannel->data = "(Link Rx)";
13802       if (option_verbose > 2)
13803          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
13804             myrpt->rxchanname,tele,myrpt->rxchannel->name);
13805       rpt_mutex_unlock(&myrpt->lock);
13806       ast_call(myrpt->rxchannel,tele,999);
13807       rpt_mutex_lock(&myrpt->lock);
13808    }
13809    else
13810    {
13811       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
13812       rpt_mutex_unlock(&myrpt->lock);
13813       pthread_exit(NULL);
13814    }
13815    *--tele = '/';
13816    myrpt->dahditxchannel = NULL;
13817    if (myrpt->txchanname)
13818    {
13819       tele = strchr(myrpt->txchanname,'/');
13820       if (!tele)
13821       {
13822          fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
13823          rpt_mutex_unlock(&myrpt->lock);
13824          ast_hangup(myrpt->rxchannel);
13825          pthread_exit(NULL);
13826       }
13827       *tele++ = 0;
13828       myrpt->txchannel = ast_request(myrpt->txchanname, AST_FORMAT_SLINEAR, NULL, tele, NULL);
13829       if (!strncasecmp(myrpt->txchanname,"DAHDI",3))
13830          myrpt->dahditxchannel = myrpt->txchannel;
13831       if (myrpt->txchannel)
13832       {
13833          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
13834          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
13835 #ifdef   AST_CDR_FLAG_POST_DISABLED
13836          if (myrpt->txchannel->cdr)
13837             ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13838 #endif
13839 #ifndef  NEW_ASTERISK
13840          myrpt->txchannel->whentohangup = 0;
13841 #endif
13842          myrpt->txchannel->appl = "Apprpt";
13843          myrpt->txchannel->data = "(Link Tx)";
13844          if (option_verbose > 2)
13845             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
13846                myrpt->txchanname,tele,myrpt->txchannel->name);
13847          rpt_mutex_unlock(&myrpt->lock);
13848          ast_call(myrpt->txchannel,tele,999);
13849          rpt_mutex_lock(&myrpt->lock);
13850       }
13851       else
13852       {
13853          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
13854          rpt_mutex_unlock(&myrpt->lock);
13855          ast_hangup(myrpt->rxchannel);
13856          pthread_exit(NULL);
13857       }
13858       *--tele = '/';
13859    }
13860    else
13861    {
13862       myrpt->txchannel = myrpt->rxchannel;
13863       if (!strncasecmp(myrpt->rxchanname,"DAHDI",3))
13864          myrpt->dahditxchannel = myrpt->rxchannel;
13865    }
13866    /* allocate a pseudo-channel thru asterisk */
13867    myrpt->pchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
13868    if (!myrpt->pchannel)
13869    {
13870       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
13871       rpt_mutex_unlock(&myrpt->lock);
13872       if (myrpt->txchannel != myrpt->rxchannel) 
13873          ast_hangup(myrpt->txchannel);
13874       ast_hangup(myrpt->rxchannel);
13875       pthread_exit(NULL);
13876    }
13877    ast_set_read_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
13878    ast_set_write_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
13879 #ifdef   AST_CDR_FLAG_POST_DISABLED
13880    if (myrpt->pchannel->cdr)
13881       ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13882 #endif
13883    if (!myrpt->dahdirxchannel) myrpt->dahdirxchannel = myrpt->pchannel;
13884    if (!myrpt->dahditxchannel) myrpt->dahditxchannel = myrpt->pchannel;
13885    /* make a conference for the pseudo */
13886    ci.chan = 0;
13887    ci.confno = -1; /* make a new conf */
13888    ci.confmode = DAHDI_CONF_CONFANNMON ;
13889    /* first put the channel on the conference in announce/monitor mode */
13890    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
13891    {
13892       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
13893       rpt_mutex_unlock(&myrpt->lock);
13894       ast_hangup(myrpt->pchannel);
13895       if (myrpt->txchannel != myrpt->rxchannel) 
13896          ast_hangup(myrpt->txchannel);
13897       ast_hangup(myrpt->rxchannel);
13898       pthread_exit(NULL);
13899    }
13900    /* save pseudo channel conference number */
13901    myrpt->conf = myrpt->txconf = ci.confno;
13902    /* if serial io port, open it */
13903    myrpt->iofd = -1;
13904    if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt,myrpt->p.ioport)) == -1))
13905    {
13906       rpt_mutex_unlock(&myrpt->lock);
13907       ast_hangup(myrpt->pchannel);
13908       if (myrpt->txchannel != myrpt->rxchannel) 
13909          ast_hangup(myrpt->txchannel);
13910       ast_hangup(myrpt->rxchannel);
13911       pthread_exit(NULL);
13912    }
13913    iskenwood_pci4 = 0;
13914    memset(&z,0,sizeof(z));
13915    if ((myrpt->iofd < 1) && (myrpt->txchannel == myrpt->dahditxchannel))
13916    {
13917       z.radpar = DAHDI_RADPAR_REMMODE;
13918       z.data = DAHDI_RADPAR_REM_NONE;
13919       res = ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z);
13920       /* if PCIRADIO and kenwood selected */
13921       if ((!res) && (!strcmp(myrpt->remoterig,remote_rig_kenwood)))
13922       {
13923          z.radpar = DAHDI_RADPAR_UIOMODE;
13924          z.data = 1;
13925          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13926          {
13927             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
13928             return -1;
13929          }
13930          z.radpar = DAHDI_RADPAR_UIODATA;
13931          z.data = 3;
13932          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13933          {
13934             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
13935             return -1;
13936          }
13937          i = DAHDI_OFFHOOK;
13938          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i) == -1)
13939          {
13940             ast_log(LOG_ERROR,"Cannot set hook\n");
13941             return -1;
13942          }
13943          iskenwood_pci4 = 1;
13944       }
13945    }
13946    if (myrpt->txchannel == myrpt->dahditxchannel)
13947    {
13948       i = DAHDI_ONHOOK;
13949       ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i);
13950       /* if PCIRADIO and Yaesu ft897/ICOM IC-706 selected */
13951       if ((myrpt->iofd < 1) && (!res) &&
13952          ((!strcmp(myrpt->remoterig,remote_rig_ft897)) ||
13953             (!strcmp(myrpt->remoterig,remote_rig_ic706)) ||
13954                (!strcmp(myrpt->remoterig,remote_rig_tm271))))
13955       {
13956          z.radpar = DAHDI_RADPAR_UIOMODE;
13957          z.data = 1;
13958          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13959          {
13960             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
13961             return -1;
13962          }
13963          z.radpar = DAHDI_RADPAR_UIODATA;
13964          z.data = 3;
13965          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13966          {
13967             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
13968             return -1;
13969          }
13970       }
13971    }
13972    myrpt->remoterx = 0;
13973    myrpt->remotetx = 0;
13974    myrpt->retxtimer = 0;
13975    myrpt->rerxtimer = 0;
13976    myrpt->remoteon = 1;
13977    myrpt->dtmfidx = -1;
13978    myrpt->dtmfbuf[0] = 0;
13979    myrpt->dtmf_time_rem = 0;
13980    myrpt->hfscanmode = 0;
13981    myrpt->hfscanstatus = 0;
13982    if (myrpt->p.startupmacro)
13983    {
13984       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
13985    }
13986    time(&myrpt->start_time);
13987    myrpt->last_activity_time = myrpt->start_time;
13988    last_timeout_warning = 0;
13989    myrpt->reload = 0;
13990    myrpt->tele.next = &myrpt->tele;
13991    myrpt->tele.prev = &myrpt->tele;
13992    myrpt->newkey = 0;
13993    rpt_mutex_unlock(&myrpt->lock);
13994    ast_set_write_format(chan, AST_FORMAT_SLINEAR);
13995    ast_set_read_format(chan, AST_FORMAT_SLINEAR);
13996    rem_rx = 0;
13997    remkeyed = 0;
13998    /* if we are on 2w loop and are a remote, turn EC on */
13999    if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
14000    {
14001       i = 128;
14002       ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_ECHOCANCEL,&i);
14003    }
14004    if (chan->_state != AST_STATE_UP) {
14005       ast_answer(chan);
14006       if (!phone_mode) send_newkey(chan);
14007    }
14008 
14009    if (myrpt->rxchannel == myrpt->dahdirxchannel)
14010    {
14011       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_GET_PARAMS,&par) != -1)
14012       {
14013          if (par.rxisoffhook)
14014          {
14015             ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14016             myrpt->remoterx = 1;
14017             remkeyed = 1;
14018          }
14019       }
14020    }
14021    if (myrpt->p.archivedir)
14022    {
14023       char mycmd[100],mydate[100],*b,*b1;
14024       time_t myt;
14025       long blocksleft;
14026 
14027 
14028       mkdir(myrpt->p.archivedir,0600);
14029       sprintf(mycmd,"%s/%s",myrpt->p.archivedir,myrpt->name);
14030       mkdir(mycmd,0600);
14031       time(&myt);
14032       strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
14033          localtime(&myt));
14034       sprintf(mycmd,"mixmonitor start %s %s/%s/%s.wav49 a",chan->name,
14035          myrpt->p.archivedir,myrpt->name,mydate);
14036       if (myrpt->p.monminblocks)
14037       {
14038          blocksleft = diskavail(myrpt);
14039          if (myrpt->p.remotetimeout)
14040          {
14041             blocksleft -= (myrpt->p.remotetimeout *
14042                MONITOR_DISK_BLOCKS_PER_MINUTE) / 60;
14043          }
14044          if (blocksleft >= myrpt->p.monminblocks)
14045             ast_cli_command(nullfd,mycmd);
14046       } else ast_cli_command(nullfd,mycmd);
14047       /* look at callerid to see what node this comes from */
14048       b = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL);
14049       if (!b) /* if doesn't have caller id */
14050       {
14051          b1 = "0";
14052       } else {
14053          b1 = ast_strdupa(b);
14054          ast_shrink_phone_number(b1);
14055       }
14056       sprintf(mycmd,"CONNECT,%s",b1);
14057       donodelog(myrpt,mycmd);
14058    }
14059    myrpt->loginuser[0] = 0;
14060    myrpt->loginlevel[0] = 0;
14061    myrpt->authtelltimer = 0;
14062    myrpt->authtimer = 0;
14063    authtold = 0;
14064    authreq = 0;
14065    if (myrpt->p.authlevel > 1) authreq = 1;
14066    setrem(myrpt); 
14067    n = 0;
14068    dtmfed = 0;
14069    cs[n++] = chan;
14070    cs[n++] = myrpt->rxchannel;
14071    cs[n++] = myrpt->pchannel;
14072    if (myrpt->rxchannel != myrpt->txchannel)
14073       cs[n++] = myrpt->txchannel;
14074    if (!phone_mode) send_newkey(chan);
14075    /* start un-locked */
14076    for(;;) 
14077    {
14078       if (ast_check_hangup(chan)) break;
14079       if (ast_check_hangup(myrpt->rxchannel)) break;
14080       notremming = 0;
14081       setting = 0;
14082       reming = 0;
14083       telem = myrpt->tele.next;
14084       while(telem != &myrpt->tele)
14085       {
14086          if (telem->mode == SETREMOTE) setting = 1;
14087          if ((telem->mode == SETREMOTE) ||
14088              (telem->mode == SCAN) ||
14089             (telem->mode == TUNE))  reming = 1;
14090          else notremming = 1;
14091          telem = telem->next;
14092       }
14093       if (myrpt->reload)
14094       {
14095          myrpt->reload = 0;
14096          /* find our index, and load the vars */
14097          for(i = 0; i < nrpts; i++)
14098          {
14099             if (&rpt_vars[i] == myrpt)
14100             {
14101                load_rpt_vars(i,0);
14102                break;
14103             }
14104          }
14105       }
14106       time(&t);
14107       if (myrpt->p.remotetimeout)
14108       { 
14109          time_t r;
14110 
14111          r = (t - myrpt->start_time);
14112          if (r >= myrpt->p.remotetimeout)
14113          {
14114             saynode(myrpt,chan,myrpt->name);
14115             sayfile(chan,"rpt/timeout");
14116             ast_safe_sleep(chan,1000);
14117             break;
14118          }
14119          if ((myrpt->p.remotetimeoutwarning) && 
14120              (r >= (myrpt->p.remotetimeout -
14121             myrpt->p.remotetimeoutwarning)) &&
14122                 (r <= (myrpt->p.remotetimeout - 
14123                   myrpt->p.remotetimeoutwarningfreq)))
14124          {
14125             if (myrpt->p.remotetimeoutwarningfreq)
14126             {
14127                 if ((t - last_timeout_warning) >=
14128                myrpt->p.remotetimeoutwarningfreq)
14129                 {
14130                time(&last_timeout_warning);
14131                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
14132                 }
14133             }
14134             else
14135             {
14136                 if (!last_timeout_warning)
14137                 {
14138                time(&last_timeout_warning);
14139                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
14140                 }
14141             }
14142          }
14143       }
14144       if (myrpt->p.remoteinacttimeout && myrpt->last_activity_time)
14145       { 
14146          time_t r;
14147 
14148          r = (t - myrpt->last_activity_time);
14149          if (r >= myrpt->p.remoteinacttimeout)
14150          {
14151             saynode(myrpt,chan,myrpt->name);
14152             ast_safe_sleep(chan,1000);
14153             break;
14154          }
14155          if ((myrpt->p.remotetimeoutwarning) && 
14156              (r >= (myrpt->p.remoteinacttimeout -
14157             myrpt->p.remotetimeoutwarning)) &&
14158                 (r <= (myrpt->p.remoteinacttimeout - 
14159                   myrpt->p.remotetimeoutwarningfreq)))
14160          {
14161             if (myrpt->p.remotetimeoutwarningfreq)
14162             {
14163                 if ((t - last_timeout_warning) >=
14164                myrpt->p.remotetimeoutwarningfreq)
14165                 {
14166                time(&last_timeout_warning);
14167                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
14168                 }
14169             }
14170             else
14171             {
14172                 if (!last_timeout_warning)
14173                 {
14174                time(&last_timeout_warning);
14175                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
14176                 }
14177             }
14178          }
14179       }
14180       ms = MSWAIT;
14181       who = ast_waitfor_n(cs,n,&ms);
14182       if (who == NULL) ms = 0;
14183       elap = MSWAIT - ms;
14184       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
14185       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
14186       if (!ms) continue;
14187       /* do local dtmf timer */
14188       if (myrpt->dtmf_local_timer)
14189       {
14190          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
14191          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
14192       }
14193       rpt_mutex_lock(&myrpt->lock);
14194       do_dtmf_local(myrpt,0);
14195       rpt_mutex_unlock(&myrpt->lock);
14196       //
14197       rem_totx =  myrpt->dtmf_local_timer && (!phone_mode);
14198       rem_totx |= keyed && (!myrpt->tunerequest);
14199       rem_rx = (remkeyed && (!setting)) || (myrpt->tele.next != &myrpt->tele);
14200       if(!strcmp(myrpt->remoterig, remote_rig_ic706))
14201          rem_totx |= myrpt->tunerequest;
14202       //
14203        if((debug > 6) && rem_totx) {
14204          ast_log(LOG_NOTICE,"Set rem_totx=%i.  dtmf_local_timer=%i phone_mode=%i keyed=%i tunerequest=%i\n",rem_totx,myrpt->dtmf_local_timer,phone_mode,keyed,myrpt->tunerequest);
14205       }
14206       if (keyed && (!keyed1))
14207       {
14208          keyed1 = 1;
14209       }
14210 
14211       if (!keyed && (keyed1))
14212       {
14213          time_t myt;
14214 
14215          keyed1 = 0;
14216          time(&myt);
14217          /* if login necessary, and not too soon */
14218          if ((myrpt->p.authlevel) && 
14219              (!myrpt->loginlevel[0]) &&
14220             (myt > (t + 3)))
14221          {
14222             authreq = 1;
14223             authtold = 0;
14224             myrpt->authtelltimer = AUTHTELLTIME - AUTHTXTIME;
14225          }
14226       }
14227 
14228       if (rem_rx && (!myrpt->remoterx))
14229       {
14230          myrpt->remoterx = 1;
14231          ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14232       }
14233       if ((!rem_rx) && (myrpt->remoterx))
14234       {
14235          myrpt->remoterx = 0;
14236          ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
14237       }
14238       /* if auth requested, and not authed yet */
14239       if (authreq && (!myrpt->loginlevel[0]))
14240       {
14241          if ((!authtold) && ((myrpt->authtelltimer += elap)
14242              >= AUTHTELLTIME))
14243          {
14244             authtold = 1;
14245             rpt_telemetry(myrpt,LOGINREQ,NULL);
14246          }
14247          if ((myrpt->authtimer += elap) >= AUTHLOGOUTTIME)
14248          {
14249             break; /* if not logged in, hang up after a time */
14250          }
14251       }
14252       if (myrpt->newkey)
14253       {
14254          if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
14255          {
14256             myrpt->retxtimer = 0;
14257             if ((myrpt->remoterx) && (!myrpt->remotetx))
14258                ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14259             else
14260                ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
14261          }
14262 
14263          if ((myrpt->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 2))
14264          {
14265             keyed = 0;
14266             myrpt->rerxtimer = 0;
14267          }
14268       }
14269       if (rem_totx && (!myrpt->remotetx))
14270       {
14271          /* if not authed, and needed, do not transmit */
14272          if ((!myrpt->p.authlevel) || myrpt->loginlevel[0])
14273          {
14274             if(debug > 6)
14275                ast_log(LOG_NOTICE,"Handle rem_totx=%i.  dtmf_local_timer=%i  tunerequest=%i\n",rem_totx,myrpt->dtmf_local_timer,myrpt->tunerequest);
14276 
14277             myrpt->remotetx = 1;
14278             /* asdf maw ??? is this really what you want? Doesn't it always get executed? */
14279             if((myrpt->remtxfreqok = check_tx_freq(myrpt)))
14280             {
14281                time(&myrpt->last_activity_time);
14282                if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14283                {
14284                   z.radpar = DAHDI_RADPAR_UIODATA;
14285                   z.data = 1;
14286                   if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14287                   {
14288                      ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14289                      return -1;
14290                   }
14291                }
14292                else
14293                {
14294                   ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
14295                }
14296                if (myrpt->p.archivedir) donodelog(myrpt,"TXKEY");
14297             }
14298          }
14299       }
14300       if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
14301       {
14302          myrpt->remotetx = 0;
14303          if(!myrpt->remtxfreqok){
14304             rpt_telemetry(myrpt,UNAUTHTX,NULL);
14305          }
14306          if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14307          {
14308             z.radpar = DAHDI_RADPAR_UIODATA;
14309             z.data = 3;
14310             if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14311             {
14312                ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14313                return -1;
14314             }
14315          }
14316          else
14317          {
14318             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
14319          }
14320          if (myrpt->p.archivedir) donodelog(myrpt,"TXUNKEY");
14321       }
14322       if (myrpt->hfscanmode){
14323          myrpt->scantimer -= elap;
14324          if(myrpt->scantimer <= 0){
14325             if (!reming)
14326             {
14327                myrpt->scantimer = REM_SCANTIME;
14328                rpt_telemetry(myrpt,SCAN,0);
14329             } else myrpt->scantimer = 1;
14330          }
14331       }
14332       rpt_mutex_lock(&myrpt->lock);
14333       c = myrpt->macrobuf[0];
14334       if (c && (!myrpt->macrotimer))
14335       {
14336          myrpt->macrotimer = MACROTIME;
14337          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
14338          if ((c == 'p') || (c == 'P'))
14339             myrpt->macrotimer = MACROPTIME;
14340          rpt_mutex_unlock(&myrpt->lock);
14341          if (myrpt->p.archivedir)
14342          {
14343             char str[100];
14344                sprintf(str,"DTMF(M),%c",c);
14345             donodelog(myrpt,str);
14346          }
14347          if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
14348          continue;
14349       } else rpt_mutex_unlock(&myrpt->lock);
14350       if (who == chan) /* if it was a read from incoming */
14351       {
14352          f = ast_read(chan);
14353          if (!f)
14354          {
14355             if (debug) printf("@@@@ link:Hung Up\n");
14356             break;
14357          }
14358          if (f->frametype == AST_FRAME_VOICE)
14359          {
14360             if (ioctl(chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
14361             {
14362                ismuted = 0;
14363             }
14364             /* if not transmitting, zero-out audio */
14365             ismuted |= (!myrpt->remotetx);
14366             if (dtmfed && phone_mode) ismuted = 1;
14367             dtmfed = 0;
14368             if (ismuted)
14369             {
14370                memset(f->data.ptr,0,f->datalen);
14371                if (myrpt->lastf1)
14372                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14373                if (myrpt->lastf2)
14374                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14375             } 
14376             if (f) f2 = ast_frdup(f);
14377             else f2 = NULL;
14378             f1 = myrpt->lastf2;
14379             myrpt->lastf2 = myrpt->lastf1;
14380             myrpt->lastf1 = f2;
14381             if (ismuted)
14382             {
14383                if (myrpt->lastf1)
14384                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14385                if (myrpt->lastf2)
14386                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14387             }
14388             if (f1)
14389             {
14390                if (phone_mode)
14391                   ast_write(myrpt->txchannel,f1);
14392                else
14393                   ast_write(myrpt->txchannel,f);
14394                ast_frfree(f1);
14395             }
14396          }
14397 #ifndef  OLD_ASTERISK
14398          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
14399          {
14400             if (myrpt->lastf1)
14401                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14402             if (myrpt->lastf2)
14403                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14404             dtmfed = 1;
14405          }
14406 #endif
14407          if (f->frametype == AST_FRAME_DTMF)
14408          {
14409             if (myrpt->lastf1)
14410                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14411             if (myrpt->lastf2)
14412                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14413             dtmfed = 1;
14414             if (handle_remote_phone_dtmf(myrpt,f->subclass.integer,&keyed,phone_mode) == -1)
14415             {
14416                if (debug) printf("@@@@ rpt:Hung Up\n");
14417                ast_frfree(f);
14418                break;
14419             }
14420          }
14421          if (f->frametype == AST_FRAME_TEXT)
14422          {
14423             if (handle_remote_data(myrpt,f->data.ptr) == -1)
14424             {
14425                if (debug) printf("@@@@ rpt:Hung Up\n");
14426                ast_frfree(f);
14427                break;
14428             }
14429          }
14430          if (f->frametype == AST_FRAME_CONTROL)
14431          {
14432             if (f->subclass.integer == AST_CONTROL_HANGUP)
14433             {
14434                if (debug) printf("@@@@ rpt:Hung Up\n");
14435                ast_frfree(f);
14436                break;
14437             }
14438             /* if RX key */
14439             if (f->subclass.integer == AST_CONTROL_RADIO_KEY)
14440             {
14441                if (debug == 7) printf("@@@@ rx key\n");
14442                keyed = 1;
14443                myrpt->rerxtimer = 0;
14444             }
14445             /* if RX un-key */
14446             if (f->subclass.integer == AST_CONTROL_RADIO_UNKEY)
14447             {
14448                myrpt->rerxtimer = 0;
14449                if (debug == 7) printf("@@@@ rx un-key\n");
14450                keyed = 0;
14451             }
14452          }
14453          ast_frfree(f);
14454          continue;
14455       }
14456       if (who == myrpt->rxchannel) /* if it was a read from radio */
14457       {
14458          f = ast_read(myrpt->rxchannel);
14459          if (!f)
14460          {
14461             if (debug) printf("@@@@ link:Hung Up\n");
14462             break;
14463          }
14464          if (f->frametype == AST_FRAME_VOICE)
14465          {
14466             int myreming = 0;
14467 
14468             if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
14469                myreming = reming;
14470 
14471             if (myreming || (!remkeyed) ||
14472             ((myrpt->remote) && (myrpt->remotetx)) ||
14473               ((myrpt->remmode != REM_MODE_FM) &&
14474                 notremming))
14475                memset(f->data.ptr,0,f->datalen); 
14476              ast_write(myrpt->pchannel,f);
14477          }
14478          else if (f->frametype == AST_FRAME_CONTROL)
14479          {
14480             if (f->subclass.integer == AST_CONTROL_HANGUP)
14481             {
14482                if (debug) printf("@@@@ rpt:Hung Up\n");
14483                ast_frfree(f);
14484                break;
14485             }
14486             /* if RX key */
14487             if (f->subclass.integer == AST_CONTROL_RADIO_KEY)
14488             {
14489                if (debug == 7) printf("@@@@ remote rx key\n");
14490                if (!myrpt->remotetx)
14491                {
14492                   remkeyed = 1;
14493                }
14494             }
14495             /* if RX un-key */
14496             if (f->subclass.integer == AST_CONTROL_RADIO_UNKEY)
14497             {
14498                if (debug == 7) printf("@@@@ remote rx un-key\n");
14499                if (!myrpt->remotetx) 
14500                {
14501                   remkeyed = 0;
14502                }
14503             }
14504          }
14505          ast_frfree(f);
14506          continue;
14507       }
14508       if (who == myrpt->pchannel) /* if is remote mix output */
14509       {
14510          f = ast_read(myrpt->pchannel);
14511          if (!f)
14512          {
14513             if (debug) printf("@@@@ link:Hung Up\n");
14514             break;
14515          }
14516          if (f->frametype == AST_FRAME_VOICE)
14517          {
14518             ast_write(chan,f);
14519          }
14520          if (f->frametype == AST_FRAME_CONTROL)
14521          {
14522             if (f->subclass.integer == AST_CONTROL_HANGUP)
14523             {
14524                if (debug) printf("@@@@ rpt:Hung Up\n");
14525                ast_frfree(f);
14526                break;
14527             }
14528          }
14529          ast_frfree(f);
14530          continue;
14531       }
14532       if ((myrpt->rxchannel != myrpt->txchannel) && 
14533          (who == myrpt->txchannel)) /* do this cuz you have to */
14534       {
14535          f = ast_read(myrpt->txchannel);
14536          if (!f)
14537          {
14538             if (debug) printf("@@@@ link:Hung Up\n");
14539             break;
14540          }
14541          if (f->frametype == AST_FRAME_CONTROL)
14542          {
14543             if (f->subclass.integer == AST_CONTROL_HANGUP)
14544             {
14545                if (debug) printf("@@@@ rpt:Hung Up\n");
14546                ast_frfree(f);
14547                break;
14548             }
14549          }
14550          ast_frfree(f);
14551          continue;
14552       }
14553    }
14554    if (myrpt->p.archivedir)
14555    {
14556       char mycmd[100],*b,*b1;
14557 
14558       /* look at callerid to see what node this comes from */
14559       b = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL);
14560       if (!b) /* if doesn't have caller id */
14561       {
14562          b1 = "0";
14563       } else {
14564          b1 = ast_strdupa(b);
14565          ast_shrink_phone_number(b1);
14566       }
14567       sprintf(mycmd,"DISCONNECT,%s",b1);
14568       donodelog(myrpt,mycmd);
14569    }
14570    /* wait for telem to be done */
14571    while(myrpt->tele.next != &myrpt->tele) usleep(100000);
14572    sprintf(tmp,"mixmonitor stop %s",chan->name);
14573    ast_cli_command(nullfd,tmp);
14574    close(nullfd);
14575    rpt_mutex_lock(&myrpt->lock);
14576    myrpt->hfscanmode = 0;
14577    myrpt->hfscanstatus = 0;
14578    myrpt->remoteon = 0;
14579    rpt_mutex_unlock(&myrpt->lock);
14580    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
14581    myrpt->lastf1 = NULL;
14582    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
14583    myrpt->lastf2 = NULL;
14584    if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14585    {
14586       z.radpar = DAHDI_RADPAR_UIOMODE;
14587       z.data = 3;
14588       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14589       {
14590          ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
14591          return -1;
14592       }
14593       z.radpar = DAHDI_RADPAR_UIODATA;
14594       z.data = 3;
14595       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14596       {
14597          ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14598          return -1;
14599       }
14600       i = DAHDI_OFFHOOK;
14601       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i) == -1)
14602       {
14603          ast_log(LOG_ERROR,"Cannot set hook\n");
14604          return -1;
14605       }
14606    }
14607    if (myrpt->iofd) close(myrpt->iofd);
14608    myrpt->iofd = -1;
14609    ast_hangup(myrpt->pchannel);
14610    if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
14611    ast_hangup(myrpt->rxchannel);
14612    closerem(myrpt);
14613    if (myrpt->p.rptnode)
14614    {
14615       rpt_mutex_lock(&myrpt->lock);
14616       for(i = 0; i < nrpts; i++)
14617       {
14618          if (!strcasecmp(rpt_vars[i].name,myrpt->p.rptnode))
14619          {
14620             rpt_vars[i].xlink = 0;
14621             break;
14622          }
14623       }
14624       rpt_mutex_unlock(&myrpt->lock);
14625    }
14626 #ifdef   OLD_ASTERISK
14627    LOCAL_USER_REMOVE(u);
14628 #endif
14629    return res;
14630 }
14631 
14632 #ifndef OLD_ASTERISK
14633 /*!\brief callback to display list of locally configured nodes
14634    \addtogroup Group_AMI
14635  */
14636 static int manager_rpt_local_nodes(struct mansession *s, const struct message *m)
14637 {
14638     int i;
14639     astman_append(s, "<?xml version=\"1.0\"?>\r\n");
14640     astman_append(s, "<nodes>\r\n");
14641     for (i=0; i< nrpts; i++)
14642     {
14643         astman_append(s, "  <node>%s</node>\r\n", rpt_vars[i].name);        
14644     } /* for i */
14645     astman_append(s, "</nodes>\r\n");
14646     astman_append(s, "\r\n"); /* Properly terminate Manager output */
14647     return RESULT_SUCCESS;
14648 } /* manager_rpt_local_nodes() */
14649 
14650 
14651 
14652 /*
14653  * Append Success and ActionID to manager response message
14654  */
14655 
14656 static void rpt_manager_success(struct mansession *s, const struct message *m)
14657 {
14658    const char *id = astman_get_header(m, "ActionID");
14659    if (!ast_strlen_zero(id))
14660       astman_append(s, "ActionID: %s\r\n", id);
14661    astman_append(s, "Response: Success\r\n");
14662 }
14663 
14664 /*
14665 * Dump statistics to manager session
14666 */
14667 
14668 static int rpt_manager_do_stats(struct mansession *s, const struct message *m, char *str)
14669 {
14670    int i,j,numoflinks;
14671    int dailytxtime, dailykerchunks;
14672    time_t now;
14673    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
14674    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
14675    long long totaltxtime;
14676    struct   rpt_link *l;
14677    char *listoflinks[MAX_STAT_LINKS];  
14678    char *lastdtmfcommand,*parrot_ena;
14679    char *tot_state, *ider_state, *patch_state;
14680    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
14681    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
14682    char *transmitterkeyed;
14683    const char *node = astman_get_header(m, "Node");
14684    struct rpt *myrpt;
14685 
14686    static char *not_applicable = "N/A";
14687 
14688    tot_state = ider_state = 
14689    patch_state = reverse_patch_state = 
14690    input_signal = not_applicable;
14691    called_number = lastdtmfcommand = transmitterkeyed = NULL;
14692 
14693    time(&now);
14694    for(i = 0; i < nrpts; i++)
14695    {
14696       if ((node)&&(!strcmp(node,rpt_vars[i].name))){
14697          rpt_manager_success(s,m);
14698 
14699          myrpt = &rpt_vars[i];
14700 
14701          if(myrpt->remote){ /* Remote base ? */
14702             char *loginuser, *loginlevel, *freq, *rxpl, *txpl, *modestr;
14703             char offset = 0, powerlevel = 0, rxplon = 0, txplon = 0, remoteon, remmode = 0, reportfmstuff;
14704             char offsetc,powerlevelc;
14705 
14706             loginuser = loginlevel = freq = rxpl = txpl = NULL;
14707             /* Make a copy of all stat variables while locked */
14708             rpt_mutex_lock(&myrpt->lock); /* LOCK */
14709             if((remoteon = myrpt->remoteon)){
14710                if(!ast_strlen_zero(myrpt->loginuser))
14711                   loginuser = ast_strdup(myrpt->loginuser);
14712                if(!ast_strlen_zero(myrpt->loginlevel))
14713                   loginlevel = ast_strdup(myrpt->loginlevel);
14714                if(!ast_strlen_zero(myrpt->freq))
14715                   freq = ast_strdup(myrpt->freq);
14716                if(!ast_strlen_zero(myrpt->rxpl))
14717                   rxpl = ast_strdup(myrpt->rxpl);
14718                if(!ast_strlen_zero(myrpt->txpl))
14719                   txpl = ast_strdup(myrpt->txpl);
14720                remmode = myrpt->remmode;
14721                offset = myrpt->offset;
14722                powerlevel = myrpt->powerlevel;
14723                rxplon = myrpt->rxplon;
14724                txplon = myrpt->txplon;       
14725             }
14726             rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
14727             astman_append(s, "IsRemoteBase: YES\r\n");
14728             astman_append(s, "RemoteOn: %s\r\n",(remoteon) ? "YES": "NO");
14729             if(remoteon){
14730                if(loginuser){
14731                   astman_append(s, "LogInUser: %s\r\n", loginuser);
14732                   ast_free(loginuser);
14733                }
14734                if(loginlevel){
14735                   astman_append(s, "LogInLevel: %s\r\n", loginlevel);
14736                   ast_free(loginlevel);
14737                }
14738                if(freq){
14739                   astman_append(s, "Freq: %s\r\n", freq);
14740                   ast_free(freq);
14741                }
14742                reportfmstuff = 0;
14743                switch(remmode){
14744                   case REM_MODE_FM:
14745                      modestr = "FM";   
14746                      reportfmstuff = 1;
14747                      break;
14748                   case REM_MODE_AM:
14749                      modestr = "AM";
14750                      break;
14751                   case REM_MODE_USB:
14752                      modestr = "USB";
14753                      break;
14754                   default:
14755                      modestr = "LSB";
14756                      break;
14757                }
14758                astman_append(s, "RemMode: %s\r\n", modestr);
14759                if(reportfmstuff){
14760                   switch(offset){
14761                      case REM_SIMPLEX:
14762                         offsetc = 'S';
14763                         break;
14764                      case REM_MINUS:
14765                         offsetc = '-';
14766                         break;
14767                      default:
14768                         offsetc = '+';
14769                         break;
14770                   }
14771                   astman_append(s, "RemOffset: %c\r\n", offsetc);
14772                   if(rxplon && rxpl){
14773                      astman_append(s, "RxPl: %s\r\n",rxpl);
14774                      ast_free(rxpl);
14775                   }
14776                   if(txplon && txpl){
14777                      astman_append(s, "TxPl: %s\r\n",txpl);
14778                      ast_free(txpl);
14779                   }
14780                }
14781                switch(powerlevel){
14782                   case REM_LOWPWR:
14783                      powerlevelc = 'L';
14784                      break;
14785                   case REM_MEDPWR:
14786                      powerlevelc = 'M';
14787                      break;
14788                   default:
14789                      powerlevelc = 'H';
14790                      break;
14791                }
14792                astman_append(s,"PowerLevel: %c\r\n", powerlevelc);
14793             }
14794             astman_append(s, "\r\n");
14795             return 0; /* End of remote base status reporting */
14796          }  
14797 
14798          /* ELSE Process as a repeater node */
14799          /* Make a copy of all stat variables while locked */
14800          rpt_mutex_lock(&myrpt->lock); /* LOCK */
14801          dailytxtime = myrpt->dailytxtime;
14802          totaltxtime = myrpt->totaltxtime;
14803          dailykeyups = myrpt->dailykeyups;
14804          totalkeyups = myrpt->totalkeyups;
14805          dailykerchunks = myrpt->dailykerchunks;
14806          totalkerchunks = myrpt->totalkerchunks;
14807          dailyexecdcommands = myrpt->dailyexecdcommands;
14808          totalexecdcommands = myrpt->totalexecdcommands;
14809          timeouts = myrpt->timeouts;
14810 
14811 
14812          /* Traverse the list of connected nodes */
14813          reverse_patch_state = "DOWN";
14814          numoflinks = 0;
14815          l = myrpt->links.next;
14816          while(l && (l != &myrpt->links)){
14817             if(numoflinks >= MAX_STAT_LINKS){
14818                ast_log(LOG_NOTICE,
14819                "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
14820                break;
14821             }
14822             if (l->name[0] == '0'){ /* Skip '0' nodes */
14823                reverse_patch_state = "UP";
14824                l = l->next;
14825                continue;
14826             }
14827             listoflinks[numoflinks] = ast_strdup(l->name);
14828             if(listoflinks[numoflinks] == NULL){
14829                break;
14830             }
14831             else{
14832                numoflinks++;
14833             }
14834             l = l->next;
14835          }
14836 
14837          if(myrpt->keyed)
14838             input_signal = "YES";
14839          else
14840             input_signal = "NO";
14841          
14842          if(myrpt->txkeyed)
14843             transmitterkeyed = "YES";
14844          else
14845             transmitterkeyed = "NO";
14846 
14847          if(myrpt->p.parrotmode)
14848             parrot_ena = "ENABLED";
14849          else
14850             parrot_ena = "DISABLED";
14851 
14852          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
14853             sys_ena = "DISABLED";
14854          else
14855             sys_ena = "ENABLED";
14856 
14857          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
14858             tot_ena = "DISABLED";
14859          else
14860             tot_ena = "ENABLED";
14861 
14862          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
14863             link_ena = "DISABLED";
14864          else
14865             link_ena = "ENABLED";
14866 
14867          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
14868             patch_ena = "DISABLED";
14869          else
14870             patch_ena = "ENABLED";
14871 
14872          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
14873             sch_ena = "DISABLED";
14874          else
14875             sch_ena = "ENABLED";
14876 
14877          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
14878             user_funs = "DISABLED";
14879          else
14880             user_funs = "ENABLED";
14881 
14882          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
14883             tail_type = "ALTERNATE";
14884          else
14885             tail_type = "STANDARD";
14886 
14887          if(!myrpt->totimer)
14888             tot_state = "TIMED OUT!";
14889          else if(myrpt->totimer != myrpt->p.totime)
14890             tot_state = "ARMED";
14891          else
14892             tot_state = "RESET";
14893 
14894          if(myrpt->tailid)
14895             ider_state = "QUEUED IN TAIL";
14896          else if(myrpt->mustid)
14897             ider_state = "QUEUED FOR CLEANUP";
14898          else
14899             ider_state = "CLEAN";
14900 
14901          switch(myrpt->callmode){
14902             case 1:
14903                patch_state = "DIALING";
14904                break;
14905             case 2:
14906                patch_state = "CONNECTING";
14907                break;
14908             case 3:
14909                patch_state = "UP";
14910                break;
14911 
14912             case 4:
14913                patch_state = "CALL FAILED";
14914                break;
14915 
14916             default:
14917                patch_state = "DOWN";
14918          }
14919 
14920          if(strlen(myrpt->exten)){
14921             called_number = ast_strdup(myrpt->exten);
14922          }
14923 
14924          if(strlen(myrpt->lastdtmfcommand)){
14925             lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
14926          }
14927          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
14928 
14929          astman_append(s, "IsRemoteBase: NO\r\n");
14930          astman_append(s, "NodeState: %d\r\n", myrpt->p.sysstate_cur);
14931          astman_append(s, "SignalOnInput: %s\r\n", input_signal);
14932          astman_append(s, "TransmitterKeyed: %s\r\n", transmitterkeyed);
14933          astman_append(s, "Transmitter: %s\r\n", sys_ena);
14934          astman_append(s, "Parrot: %s\r\n", parrot_ena);
14935          astman_append(s, "Scheduler: %s\r\n", sch_ena);
14936          astman_append(s, "TailLength: %s\r\n", tail_type);
14937          astman_append(s, "TimeOutTimer: %s\r\n", tot_ena);
14938          astman_append(s, "TimeOutTimerState: %s\r\n", tot_state);
14939          astman_append(s, "TimeOutsSinceSystemInitialization: %d\r\n", timeouts);
14940          astman_append(s, "IdentifierState: %s\r\n", ider_state);
14941          astman_append(s, "KerchunksToday: %d\r\n", dailykerchunks);
14942          astman_append(s, "KerchunksSinceSystemInitialization: %d\r\n", totalkerchunks);
14943          astman_append(s, "KeyupsToday: %d\r\n", dailykeyups);
14944          astman_append(s, "KeyupsSinceSystemInitialization: %d\r\n", totalkeyups);
14945          astman_append(s, "DtmfCommandsToday: %d\r\n", dailyexecdcommands);
14946          astman_append(s, "DtmfCommandsSinceSystemInitialization: %d\r\n", totalexecdcommands);
14947          astman_append(s, "LastDtmfCommandExecuted: %s\r\n", 
14948          (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
14949          hours = dailytxtime/3600000;
14950          dailytxtime %= 3600000;
14951          minutes = dailytxtime/60000;
14952          dailytxtime %= 60000;
14953          seconds = dailytxtime/1000;
14954          dailytxtime %= 1000;
14955 
14956          astman_append(s, "TxTimeToday: %02d:%02d:%02d.%d\r\n",
14957             hours, minutes, seconds, dailytxtime);
14958 
14959          hours = (int) totaltxtime/3600000;
14960          totaltxtime %= 3600000;
14961          minutes = (int) totaltxtime/60000;
14962          totaltxtime %= 60000;
14963          seconds = (int)  totaltxtime/1000;
14964          totaltxtime %= 1000;
14965 
14966          astman_append(s, "TxTimeSinceSystemInitialization: %02d:%02d:%02d.%d\r\n",
14967              hours, minutes, seconds, (int) totaltxtime);
14968 
14969          sprintf(str, "NodesCurrentlyConnectedToUs: ");
14970                         if(!numoflinks){
14971                          strcat(str,"<NONE>");
14972                         }
14973          else{
14974             for(j = 0 ;j < numoflinks; j++){
14975                sprintf(str+strlen(str), "%s", listoflinks[j]);
14976                if(j < numoflinks - 1)
14977                   strcat(str,",");
14978             }
14979          }
14980          astman_append(s,"%s\r\n", str);
14981 
14982          astman_append(s, "Autopatch: %s\r\n", patch_ena);
14983          astman_append(s, "AutopatchState: %s\r\n", patch_state);
14984          astman_append(s, "AutopatchCalledNumber: %s\r\n",
14985          (called_number && strlen(called_number)) ? called_number : not_applicable);
14986          astman_append(s, "ReversePatchIaxrptConnected: %s\r\n", reverse_patch_state);
14987          astman_append(s, "UserLinkingCommands: %s\r\n", link_ena);
14988          astman_append(s, "UserFunctions: %s\r\n", user_funs);
14989 
14990          for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
14991             ast_free(listoflinks[j]);
14992          }
14993          if(called_number){
14994             ast_free(called_number);
14995          }
14996          if(lastdtmfcommand){
14997             ast_free(lastdtmfcommand);
14998          }
14999          astman_append(s, "\r\n"); /* We're Done! */
15000               return 0;
15001       }
15002    }
15003    astman_send_error(s, m, "RptStatus unknown or missing node");
15004    return -1;
15005 }
15006 
15007 
15008 
15009 /*
15010  * Implement the RptStatus Manager Interface
15011  */
15012 
15013 static int manager_rpt_status(struct mansession *s, const struct message *m)
15014 {
15015    int i,res,len,idx;
15016    int uptime,hours,minutes;
15017    time_t now;
15018    const char *cmd = astman_get_header(m, "Command");
15019    char *str;
15020    enum {MGRCMD_RPTSTAT,MGRCMD_NODESTAT};
15021    struct mgrcmdtbl{
15022       const char *cmd;
15023       int index;
15024    };
15025    static struct mgrcmdtbl mct[] = {
15026       {"RptStat",MGRCMD_RPTSTAT},
15027       {"NodeStat",MGRCMD_NODESTAT},
15028       {NULL,0} /* NULL marks end of command table */
15029    };
15030 
15031    time(&now);
15032 
15033    len = 1024; /* Allocate a working buffer */
15034    if(!(str = ast_malloc(len)))
15035       return -1;
15036 
15037    /* Check for Command */
15038    if(ast_strlen_zero(cmd)){
15039       astman_send_error(s, m, "RptStatus missing command");
15040       ast_free(str);
15041       return 0;
15042    }
15043    /* Try to find the command in the table */
15044    for(i = 0 ; mct[i].cmd ; i++){
15045       if(!strcmp(mct[i].cmd, cmd))
15046          break;
15047    }
15048 
15049    if(!mct[i].cmd){ /* Found or not found ? */
15050       astman_send_error(s, m, "RptStatus unknown command");
15051       ast_free(str);
15052       return 0;
15053    }
15054    else
15055       idx = mct[i].index;
15056 
15057    switch(idx){ /* Use the index to go to the correct command */
15058 
15059       case MGRCMD_RPTSTAT:
15060          /* Return Nodes: and a comma separated list of nodes */
15061          if((res = snprintf(str, len, "Nodes: ")) > -1)
15062             len -= res;
15063          else{
15064             ast_free(str);
15065             return 0;
15066          }
15067          for(i = 0; i < nrpts; i++){
15068             if(i < nrpts - 1){
15069                if((res = snprintf(str+strlen(str), len, "%s,",rpt_vars[i].name)) < 0){
15070                   ast_free(str);
15071                   return 0;
15072                }
15073             }
15074             else{
15075                if((res = snprintf(str+strlen(str), len, "%s",rpt_vars[i].name)) < 0){
15076                   ast_free(str);
15077                   return 0;
15078                }
15079             }
15080             len -= res;
15081          }
15082 
15083          rpt_manager_success(s,m);
15084          
15085          if(!nrpts)
15086             astman_append(s, "<NONE>\r\n");
15087          else
15088             astman_append(s, "%s\r\n", str);
15089 
15090          uptime = (int)(now - starttime);
15091                         hours = uptime/3600;
15092                         uptime %= 3600;
15093                         minutes = uptime/60;
15094                         uptime %= 60;
15095 
15096                         astman_append(s, "RptUptime: %02d:%02d:%02d\r\n",
15097                                 hours, minutes, uptime);
15098 
15099          astman_append(s, "\r\n");
15100          break;      
15101 
15102       case  MGRCMD_NODESTAT:
15103          res = rpt_manager_do_stats(s,m,str);
15104          ast_free(str);
15105          return res;
15106 
15107       default:
15108          astman_send_error(s, m, "RptStatus invalid command");
15109          break;
15110    }
15111    ast_free(str);
15112    return 0;
15113 }
15114 
15115 #endif
15116 
15117 #ifdef   OLD_ASTERISK
15118 int unload_module()
15119 #else
15120 static int unload_module(void)
15121 #endif
15122 {
15123    int i, res;
15124 
15125 #ifdef   OLD_ASTERISK
15126    STANDARD_HANGUP_LOCALUSERS;
15127 #endif
15128    for(i = 0; i < nrpts; i++) {
15129       if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
15130                 ast_mutex_destroy(&rpt_vars[i].lock);
15131                 ast_mutex_destroy(&rpt_vars[i].remlock);
15132    }
15133    res = ast_unregister_application(app);
15134 
15135 #ifdef   NEW_ASTERISK
15136    ast_cli_unregister_multiple(rpt_cli, ARRAY_LEN(rpt_cli));
15137 #else
15138    /* Unregister cli extensions */
15139    ast_cli_unregister(&cli_debug);
15140    ast_cli_unregister(&cli_dump);
15141    ast_cli_unregister(&cli_stats);
15142    ast_cli_unregister(&cli_lstats);
15143    ast_cli_unregister(&cli_nodes);
15144    ast_cli_unregister(&cli_local_nodes);
15145    ast_cli_unregister(&cli_reload);
15146    ast_cli_unregister(&cli_restart);
15147    ast_cli_unregister(&cli_fun);
15148    ast_cli_unregister(&cli_fun1);
15149    res |= ast_cli_unregister(&cli_cmd);
15150 #endif
15151 #ifndef OLD_ASTERISK
15152    res |= ast_manager_unregister("RptLocalNodes");
15153    res |= ast_manager_unregister("RptStatus");
15154 #endif
15155    return res;
15156 }
15157 
15158 #ifdef   OLD_ASTERISK
15159 int load_module()
15160 #else
15161 static int load_module(void)
15162 #endif
15163 {
15164    int res;
15165    ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
15166 
15167 #ifdef   NEW_ASTERISK
15168    ast_cli_register_multiple(rpt_cli, ARRAY_LEN(rpt_cli));
15169    res = 0;
15170 #else
15171    /* Register cli extensions */
15172    ast_cli_register(&cli_debug);
15173    ast_cli_register(&cli_dump);
15174    ast_cli_register(&cli_stats);
15175    ast_cli_register(&cli_lstats);
15176    ast_cli_register(&cli_nodes);
15177    ast_cli_register(&cli_local_nodes);
15178    ast_cli_register(&cli_reload);
15179    ast_cli_register(&cli_restart);
15180    ast_cli_register(&cli_fun);
15181    ast_cli_register(&cli_fun1);
15182    res = ast_cli_register(&cli_cmd);
15183 #endif
15184 #ifndef OLD_ASTERISK
15185    res |= ast_manager_register("RptLocalNodes", 0, manager_rpt_local_nodes, "List local node numbers");
15186    res |= ast_manager_register("RptStatus", 0, manager_rpt_status, "Return Rpt Status for CGI");
15187 
15188 #endif
15189    res |= ast_register_application(app, rpt_exec, synopsis, descrip);
15190    return res;
15191 }
15192 
15193 #ifdef   OLD_ASTERISK
15194 char *description()
15195 {
15196    return tdesc;
15197 }
15198 int usecount(void)
15199 {
15200    int res;
15201    STANDARD_USECOUNT(res);
15202    return res;
15203 }
15204 
15205 char *key()
15206 {
15207    return ASTERISK_GPL_KEY;
15208 }
15209 #endif
15210 
15211 #ifdef   OLD_ASTERISK
15212 int reload()
15213 #else
15214 static int reload(void)
15215 #endif
15216 {
15217 int   n;
15218 
15219    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
15220    return(0);
15221 }
15222 
15223 
15224 #ifndef  OLD_ASTERISK
15225 /* STD_MOD(MOD_1, reload, NULL, NULL); */
15226 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application",
15227       .load = load_module,
15228       .unload = unload_module,
15229       .reload = reload,
15230           );
15231 #endif
15232