Thu Apr 28 2011 17:15:15

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    <defaultenabled>no</defaultenabled>
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: 211580 $")
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 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, char *argv[]);
01175 static int rpt_do_dump(int fd, int argc, char *argv[]);
01176 static int rpt_do_stats(int fd, int argc, char *argv[]);
01177 static int rpt_do_lstats(int fd, int argc, char *argv[]);
01178 static int rpt_do_nodes(int fd, int argc, char *argv[]);
01179 static int rpt_do_local_nodes(int fd, int argc, char *argv[]);
01180 static int rpt_do_reload(int fd, int argc, char *argv[]);
01181 static int rpt_do_restart(int fd, int argc, char *argv[]);
01182 static int rpt_do_fun(int fd, int argc, char *argv[]);
01183 static int rpt_do_fun1(int fd, int argc, char *argv[]);
01184 static int rpt_do_cmd(int fd, int argc, char *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                /* dont 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 = 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 = 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       /* dont 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)) return;
01961    n = finddelim(astr,astrs,100);
01962    if (n < 1) return;
01963    ast_mutex_lock(&myrpt->statpost_lock);
01964    seq = ++myrpt->statpost_seqno;
01965    ast_mutex_unlock(&myrpt->statpost_lock);
01966    astrs[n++] = str;
01967    astrs[n] = NULL;
01968    time(&now);
01969    sprintf(str,"%s?node=%s&time=%u&seqno=%u",myrpt->p.statpost_url,
01970       myrpt->name,(unsigned int) now,seq);
01971    if (pairs) sprintf(str + strlen(str),"&%s",pairs);
01972    if (!(pid = ast_safe_fork(0)))
01973    {
01974       execv(astrs[0],astrs);
01975       ast_log(LOG_ERROR, "exec of %s failed.\n", astrs[0]);
01976       perror("asterisk");
01977       exit(0);
01978    }
01979    ast_free(astr);
01980    ast_free(str);
01981    return;
01982 }
01983 
01984 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
01985 {
01986 
01987 char *val;
01988 int longestnode,j;
01989 struct stat mystat;
01990 static time_t last = 0;
01991 static struct ast_config *ourcfg = NULL;
01992 struct ast_variable *vp;
01993 
01994    /* try to look it up locally first */
01995    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
01996    if (val) return(val);
01997    ast_mutex_lock(&nodelookuplock);
01998    /* if file does not exist */
01999    if (stat(myrpt->p.extnodefile,&mystat) == -1)
02000    {
02001       if (ourcfg) ast_config_destroy(ourcfg);
02002       ourcfg = NULL;
02003       ast_mutex_unlock(&nodelookuplock);
02004       return(NULL);
02005    }
02006    /* if we need to reload */
02007    if (mystat.st_mtime > last)
02008    {
02009       if (ourcfg) ast_config_destroy(ourcfg);
02010 #ifdef   NEW_ASTERISK
02011       ourcfg = ast_config_load(myrpt->p.extnodefile,config_flags);
02012 #else
02013       ourcfg = ast_config_load(myrpt->p.extnodefile);
02014 #endif
02015       /* if file not there, just bail */
02016       if (!ourcfg || ourcfg == CONFIG_STATUS_FILEINVALID)
02017       {
02018          ast_mutex_unlock(&nodelookuplock);
02019          return(NULL);
02020       }
02021       /* reset "last" time */
02022       last = mystat.st_mtime;
02023 
02024       /* determine longest node length again */    
02025       longestnode = 0;
02026       vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
02027       while(vp){
02028          j = strlen(vp->name);
02029          if (j > longestnode)
02030             longestnode = j;
02031          vp = vp->next;
02032       }
02033 
02034       vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
02035       while(vp){
02036          j = strlen(vp->name);
02037          if (j > longestnode)
02038             longestnode = j;
02039          vp = vp->next;
02040       }
02041 
02042       myrpt->longestnode = longestnode;
02043    }
02044    val = NULL;
02045    if (ourcfg)
02046       val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
02047    ast_mutex_unlock(&nodelookuplock);
02048    return(val);
02049 }
02050 
02051 /*
02052 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
02053 * If param is passed in non-null, then it will be set to the first character past the match
02054 */
02055 
02056 static int matchkeyword(char *string, char **param, char *keywords[])
02057 {
02058 int   i,ls;
02059    for( i = 0 ; keywords[i] ; i++){
02060       ls = strlen(keywords[i]);
02061       if(!ls){
02062          *param = NULL;
02063          return 0;
02064       }
02065       if(!strncmp(string, keywords[i], ls)){
02066          if(param)
02067             *param = string + ls;
02068          return i + 1; 
02069       }
02070    }
02071    *param = NULL;
02072    return 0;
02073 }
02074 
02075 /*
02076 * Skip characters in string which are in charlist, and return a pointer to the
02077 * first non-matching character
02078 */
02079 
02080 static char *skipchars(char *string, char *charlist)
02081 {
02082 int i;   
02083    while(*string){
02084       for(i = 0; charlist[i] ; i++){
02085          if(*string == charlist[i]){
02086             string++;
02087             break;
02088          }
02089       }
02090       if(!charlist[i])
02091          return string;
02092    }
02093    return string;
02094 }  
02095                
02096 
02097 
02098 static int myatoi(char *str)
02099 {
02100 int   ret;
02101 
02102    if (str == NULL) return -1;
02103    /* leave this %i alone, non-base-10 input is useful here */
02104    if (sscanf(str, "%30i", &ret) != 1) {
02105       return -1;
02106    }
02107 
02108    return ret;
02109 }
02110 
02111 static int mycompar(const void *a, const void *b)
02112 {
02113 char  **x = (char **) a;
02114 char  **y = (char **) b;
02115 int   xoff,yoff;
02116 
02117    if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
02118    if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
02119    return(strcmp((*x) + xoff,(*y) + yoff));
02120 }
02121 
02122 static int topcompar(const void *a, const void *b)
02123 {
02124 struct rpt_topkey *x = (struct rpt_topkey *) a;
02125 struct rpt_topkey *y = (struct rpt_topkey *) b;
02126 
02127    return(x->timesince - y->timesince);
02128 }
02129 
02130 #ifdef   __RPT_NOTCH
02131 
02132 /* rpt filter routine */
02133 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
02134 {
02135 int   i,j;
02136 struct   rptfilter *f;
02137 
02138    for(i = 0; i < len; i++)
02139    {
02140       for(j = 0; j < MAXFILTERS; j++)
02141       {
02142          f = &myrpt->filters[j];
02143          if (!*f->desc) continue;
02144          f->x0 = f->x1; f->x1 = f->x2;
02145               f->x2 = ((float)buf[i]) / f->gain;
02146               f->y0 = f->y1; f->y1 = f->y2;
02147               f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
02148                            + (f->const1 * f->y0) + (f->const2 * f->y1);
02149          buf[i] = (short)f->y2;
02150       }
02151    }
02152 }
02153 
02154 #endif
02155 
02156 
02157 /*
02158  Get the time for the machine's time zone
02159  Note: Asterisk requires a copy of localtime
02160  in the /etc directory for this to work properly.
02161  If /etc/localtime is not present, you will get
02162  GMT time! This is especially important on systems
02163  running embedded linux distributions as they don't usually
02164  have support for locales. 
02165 
02166  If OLD_ASTERISK is defined, then the older localtime_r
02167  function will be used. The /etc/localtime file is not
02168  required in this case. This provides backward compatibility
02169  with Asterisk 1.2 systems.
02170 
02171 */
02172 
02173 #ifdef   NEW_ASTERISK
02174 static void rpt_localtime( time_t * t, struct ast_tm *lt)
02175 {
02176    struct timeval when;
02177 
02178    when.tv_sec = *t;
02179    when.tv_usec = 0;
02180    ast_localtime(&when, lt, NULL);
02181 }
02182 
02183 #else
02184 static void rpt_localtime( time_t * t, struct tm *lt)
02185 {
02186 #ifdef OLD_ASTERISK
02187    localtime_r(t, lt);
02188 #else
02189    ast_localtime(t, lt, NULL);
02190 #endif
02191 }
02192 #endif
02193 
02194 
02195 /* Retrieve an int from a config file */
02196                                                                                 
02197 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
02198 {
02199         char *var;
02200         int ret;
02201    char include_zero = 0;
02202 
02203    if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
02204       min = -min;
02205       include_zero = 1;
02206    }           
02207                                                                      
02208         var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
02209         if(var){
02210                 ret = myatoi(var);
02211       if(include_zero && !ret)
02212          return 0;
02213                 if(ret < min)
02214                         ret = min;
02215                 if(ret > max)
02216                         ret = max;
02217         }
02218         else
02219                 ret = defl;
02220         return ret;
02221 }
02222 
02223 
02224 static void load_rpt_vars(int n,int init)
02225 {
02226 char *this,*val;
02227 int   i,j,longestnode;
02228 struct ast_variable *vp;
02229 struct ast_config *cfg;
02230 char *strs[100];
02231 char s1[256];
02232 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
02233             "ufena","ufdis","atena","atdis",NULL};
02234 
02235    if (option_verbose > 2)
02236       ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
02237          (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
02238    ast_mutex_lock(&rpt_vars[n].lock);
02239    if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
02240 #ifdef   NEW_ASTERISK
02241    cfg = ast_config_load("rpt.conf",config_flags);
02242 #else
02243    cfg = ast_config_load("rpt.conf");
02244 #endif
02245    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
02246       ast_mutex_unlock(&rpt_vars[n].lock);
02247       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
02248       pthread_exit(NULL);
02249    }
02250    rpt_vars[n].cfg = cfg; 
02251    this = rpt_vars[n].name;
02252    memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
02253    if (init)
02254    {
02255       char *cp;
02256       int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
02257 
02258       cp = (char *) &rpt_vars[n].p;
02259       memset(cp + sizeof(rpt_vars[n].p),0,
02260          sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
02261       rpt_vars[n].tele.next = &rpt_vars[n].tele;
02262       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
02263       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
02264       rpt_vars[n].tailmessagen = 0;
02265    }
02266 #ifdef   __RPT_NOTCH
02267    /* zot out filters stuff */
02268    memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
02269 #endif
02270    val = (char *) ast_variable_retrieve(cfg,this,"context");
02271    if (val) rpt_vars[n].p.ourcontext = val;
02272    else rpt_vars[n].p.ourcontext = this;
02273    val = (char *) ast_variable_retrieve(cfg,this,"callerid");
02274    if (val) rpt_vars[n].p.ourcallerid = val;
02275    val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
02276    if (val) rpt_vars[n].p.acctcode = val;
02277    val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
02278    if (val) rpt_vars[n].p.ident = val;
02279    val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
02280    if (val) rpt_vars[n].p.hangtime = atoi(val);
02281       else rpt_vars[n].p.hangtime = HANGTIME;
02282    val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
02283    if (val) rpt_vars[n].p.althangtime = atoi(val);
02284       else rpt_vars[n].p.althangtime = HANGTIME;
02285    val = (char *) ast_variable_retrieve(cfg,this,"totime");
02286    if (val) rpt_vars[n].p.totime = atoi(val);
02287       else rpt_vars[n].p.totime = TOTIME;
02288    val = (char *) ast_variable_retrieve(cfg,this,"voxtimeout");
02289    if (val) rpt_vars[n].p.voxtimeout_ms = atoi(val);
02290       else rpt_vars[n].p.voxtimeout_ms = VOX_TIMEOUT_MS;
02291    val = (char *) ast_variable_retrieve(cfg,this,"voxrecover");
02292    if (val) rpt_vars[n].p.voxrecover_ms = atoi(val);
02293       else rpt_vars[n].p.voxrecover_ms = VOX_RECOVER_MS;
02294    val = (char *) ast_variable_retrieve(cfg,this,"simplexpatchdelay");
02295    if (val) rpt_vars[n].p.simplexpatchdelay = atoi(val);
02296       else rpt_vars[n].p.simplexpatchdelay = SIMPLEX_PATCH_DELAY;
02297    val = (char *) ast_variable_retrieve(cfg,this,"simplexphonedelay");
02298    if (val) rpt_vars[n].p.simplexphonedelay = atoi(val);
02299       else rpt_vars[n].p.simplexphonedelay = SIMPLEX_PHONE_DELAY;
02300    val = (char *) ast_variable_retrieve(cfg,this,"statpost_program");
02301    if (val) rpt_vars[n].p.statpost_program = val;
02302       else rpt_vars[n].p.statpost_program = STATPOST_PROGRAM;
02303    rpt_vars[n].p.statpost_url = 
02304       (char *) ast_variable_retrieve(cfg,this,"statpost_url");
02305    rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);    
02306    rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);     
02307    rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
02308    rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME);   /* Enforce a min max including zero */
02309    rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
02310    val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
02311    if (val) rpt_vars[n].p.tonezone = val;
02312    rpt_vars[n].p.tailmessages[0] = 0;
02313    rpt_vars[n].p.tailmessagemax = 0;
02314    val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
02315    if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
02316    val = (char *) ast_variable_retrieve(cfg,this,"memory");
02317    if (!val) val = MEMORY;
02318    rpt_vars[n].p.memory = val;
02319    val = (char *) ast_variable_retrieve(cfg,this,"macro");
02320    if (!val) val = MACRO;
02321    rpt_vars[n].p.macro = val;
02322    val = (char *) ast_variable_retrieve(cfg,this,"tonemacro");
02323    if (!val) val = TONEMACRO;
02324    rpt_vars[n].p.tonemacro = val;
02325    val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
02326    if (val) rpt_vars[n].p.startupmacro = val;
02327    val = (char *) ast_variable_retrieve(cfg,this,"iobase");
02328    /* do not use atoi() here, we need to be able to have
02329       the input specified in hex or decimal so we use
02330       sscanf with a %i */
02331    if ((!val) || (sscanf(val,"%30i",&rpt_vars[n].p.iobase) != 1))
02332       rpt_vars[n].p.iobase = DEFAULT_IOBASE;
02333    val = (char *) ast_variable_retrieve(cfg,this,"ioport");
02334    rpt_vars[n].p.ioport = val;
02335    val = (char *) ast_variable_retrieve(cfg,this,"functions");
02336    if (!val)
02337       {
02338          val = FUNCTIONS;
02339          rpt_vars[n].p.simple = 1;
02340       } 
02341    rpt_vars[n].p.functions = val;
02342    val =  (char *) ast_variable_retrieve(cfg,this,"link_functions");
02343    if (val) rpt_vars[n].p.link_functions = val;
02344    else 
02345       rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
02346    val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
02347    if (val) rpt_vars[n].p.phone_functions = val;
02348    val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
02349    if (val) rpt_vars[n].p.dphone_functions = val;
02350    val = (char *) ast_variable_retrieve(cfg,this,"alt_functions");
02351    if (val) rpt_vars[n].p.alt_functions = val;
02352    val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
02353    if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
02354       rpt_vars[n].p.funcchar = *val;      
02355    val = (char *) ast_variable_retrieve(cfg,this,"endchar");
02356    if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
02357       rpt_vars[n].p.endchar = *val;    
02358    val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
02359    if (val) rpt_vars[n].p.nobusyout = ast_true(val);
02360    val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
02361    if (val) rpt_vars[n].p.notelemtx = ast_true(val);
02362    val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
02363    if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
02364    val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
02365    if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
02366    val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
02367    if (val) rpt_vars[n].p.linktolink = ast_true(val);
02368    val = (char *) ast_variable_retrieve(cfg,this,"nodes");
02369    if (!val) val = NODES;
02370    rpt_vars[n].p.nodes = val;
02371    val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
02372    if (!val) val = EXTNODES;
02373    rpt_vars[n].p.extnodes = val;
02374    val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
02375    if (!val) val = EXTNODEFILE;
02376    rpt_vars[n].p.extnodefile = val;
02377    val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
02378    if (val) rpt_vars[n].p.archivedir = val;
02379    val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
02380    if (val) rpt_vars[n].p.authlevel = atoi(val); 
02381    else rpt_vars[n].p.authlevel = 0;
02382    val = (char *) ast_variable_retrieve(cfg,this,"parrot");
02383    if (val) rpt_vars[n].p.parrotmode = ast_true(val) * 2;
02384    else rpt_vars[n].p.parrotmode = 0;
02385    val = (char *) ast_variable_retrieve(cfg,this,"parrottime");
02386    if (val) rpt_vars[n].p.parrottime = atoi(val); 
02387    else rpt_vars[n].p.parrottime = PARROTTIME;
02388    val = (char *) ast_variable_retrieve(cfg,this,"rptnode");
02389    rpt_vars[n].p.rptnode = val;
02390    val = (char *) ast_variable_retrieve(cfg,this,"mars");
02391    if (val) rpt_vars[n].p.remote_mars = atoi(val); 
02392    else rpt_vars[n].p.remote_mars = 0;
02393    val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
02394    if (val) rpt_vars[n].p.monminblocks = atol(val); 
02395    else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
02396    val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
02397    if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); 
02398    else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
02399    val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
02400    if (val) rpt_vars[n].p.civaddr = atoi(val); 
02401    else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
02402    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
02403    if (val) rpt_vars[n].p.remotetimeout = atoi(val); 
02404    else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
02405    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
02406    if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); 
02407    else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
02408    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
02409    if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); 
02410    else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
02411 #ifdef   __RPT_NOTCH
02412    val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
02413    if (val) {
02414       i = finddelim(val,strs,MAXFILTERS * 2);
02415       i &= ~1; /* force an even number, rounded down */
02416       if (i >= 2) for(j = 0; j < i; j += 2)
02417       {
02418          rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
02419            &rpt_vars[n].filters[j >> 1].gain,
02420              &rpt_vars[n].filters[j >> 1].const0,
02421             &rpt_vars[n].filters[j >> 1].const1,
02422                 &rpt_vars[n].filters[j >> 1].const2);
02423          sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
02424             strs[j],strs[j + 1]);
02425       }
02426 
02427    }
02428 #endif
02429    val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
02430    if (val) {
02431       memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
02432       i = finddelim(val,strs,3);
02433       if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
02434       if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
02435       if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
02436    }
02437    val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
02438    if (val) {
02439       memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
02440       i = finddelim(val,strs,3);
02441       if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
02442       if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
02443       if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
02444    }
02445    /* retreive the stanza name for the control states if there is one */
02446    val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
02447    rpt_vars[n].p.csstanzaname = val;
02448       
02449    /* retreive the stanza name for the scheduler if there is one */
02450    val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
02451    rpt_vars[n].p.skedstanzaname = val;
02452 
02453    /* retreive the stanza name for the txlimits */
02454    val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
02455    rpt_vars[n].p.txlimitsstanzaname = val;
02456 
02457    longestnode = 0;
02458 
02459    vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
02460       
02461    while(vp){
02462       j = strlen(vp->name);
02463       if (j > longestnode)
02464          longestnode = j;
02465       vp = vp->next;
02466    }
02467 
02468    rpt_vars[n].longestnode = longestnode;
02469       
02470    /*
02471    * For this repeater, Determine the length of the longest function 
02472    */
02473    rpt_vars[n].longestfunc = 0;
02474    vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
02475    while(vp){
02476       j = strlen(vp->name);
02477       if (j > rpt_vars[n].longestfunc)
02478          rpt_vars[n].longestfunc = j;
02479       vp = vp->next;
02480    }
02481    /*
02482    * For this repeater, Determine the length of the longest function 
02483    */
02484    rpt_vars[n].link_longestfunc = 0;
02485    vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
02486    while(vp){
02487       j = strlen(vp->name);
02488       if (j > rpt_vars[n].link_longestfunc)
02489          rpt_vars[n].link_longestfunc = j;
02490       vp = vp->next;
02491    }
02492    rpt_vars[n].phone_longestfunc = 0;
02493    if (rpt_vars[n].p.phone_functions)
02494    {
02495       vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
02496       while(vp){
02497          j = strlen(vp->name);
02498          if (j > rpt_vars[n].phone_longestfunc)
02499             rpt_vars[n].phone_longestfunc = j;
02500          vp = vp->next;
02501       }
02502    }
02503    rpt_vars[n].dphone_longestfunc = 0;
02504    if (rpt_vars[n].p.dphone_functions)
02505    {
02506       vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
02507       while(vp){
02508          j = strlen(vp->name);
02509          if (j > rpt_vars[n].dphone_longestfunc)
02510             rpt_vars[n].dphone_longestfunc = j;
02511          vp = vp->next;
02512       }
02513    }
02514    rpt_vars[n].alt_longestfunc = 0;
02515    if (rpt_vars[n].p.alt_functions)
02516    {
02517       vp = ast_variable_browse(cfg, rpt_vars[n].p.alt_functions);
02518       while(vp){
02519          j = strlen(vp->name);
02520          if (j > rpt_vars[n].alt_longestfunc)
02521             rpt_vars[n].alt_longestfunc = j;
02522          vp = vp->next;
02523       }
02524    }
02525    rpt_vars[n].macro_longest = 1;
02526    vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
02527    while(vp){
02528       j = strlen(vp->name);
02529       if (j > rpt_vars[n].macro_longest)
02530          rpt_vars[n].macro_longest = j;
02531       vp = vp->next;
02532    }
02533    
02534    /* Browse for control states */
02535    if(rpt_vars[n].p.csstanzaname)
02536       vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
02537    else
02538       vp = NULL;
02539    for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
02540       int k,nukw,statenum;
02541       statenum=atoi(vp->name);
02542       strncpy(s1, vp->value, 255);
02543       s1[255] = 0;
02544       nukw  = finddelim(s1,strs,32);
02545       
02546       for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */  
02547          for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
02548             if(!strcmp(strs[k],cs_keywords[j])){
02549                switch(j){
02550                   case 0: /* rptena */
02551                      rpt_vars[n].p.s[statenum].txdisable = 0;
02552                      break;
02553                   case 1: /* rptdis */
02554                      rpt_vars[n].p.s[statenum].txdisable = 1;
02555                      break;
02556          
02557                   case 2: /* apena */
02558                      rpt_vars[n].p.s[statenum].autopatchdisable = 0;
02559                      break;
02560 
02561                   case 3: /* apdis */
02562                      rpt_vars[n].p.s[statenum].autopatchdisable = 1;
02563                      break;
02564 
02565                   case 4: /* lnkena */
02566                      rpt_vars[n].p.s[statenum].linkfundisable = 0;
02567                      break;
02568    
02569                   case 5: /* lnkdis */
02570                      rpt_vars[n].p.s[statenum].linkfundisable = 1;
02571                      break;
02572 
02573                   case 6: /* totena */
02574                      rpt_vars[n].p.s[statenum].totdisable = 0;
02575                      break;
02576                
02577                   case 7: /* totdis */
02578                      rpt_vars[n].p.s[statenum].totdisable = 1;
02579                      break;
02580 
02581                   case 8: /* skena */
02582                      rpt_vars[n].p.s[statenum].schedulerdisable = 0;
02583                      break;
02584 
02585                   case 9: /* skdis */
02586                      rpt_vars[n].p.s[statenum].schedulerdisable = 1;
02587                      break;
02588 
02589                   case 10: /* ufena */
02590                      rpt_vars[n].p.s[statenum].userfundisable = 0;
02591                      break;
02592 
02593                   case 11: /* ufdis */
02594                      rpt_vars[n].p.s[statenum].userfundisable = 1;
02595                      break;
02596 
02597                   case 12: /* atena */
02598                      rpt_vars[n].p.s[statenum].alternatetail = 1;
02599                      break;
02600 
02601                   case 13: /* atdis */
02602                      rpt_vars[n].p.s[statenum].alternatetail = 0;
02603                      break;
02604          
02605                   default:
02606                      ast_log(LOG_WARNING,
02607                         "Unhandled control state keyword %s", cs_keywords[i]);
02608                      break;
02609                }
02610             }
02611          }
02612       }
02613       vp = vp->next;
02614    }
02615    ast_mutex_unlock(&rpt_vars[n].lock);
02616 }
02617 
02618 /*
02619 * Enable or disable debug output at a given level at the console
02620 */
02621                                                                                                                                  
02622 static int rpt_do_debug(int fd, int argc, char *argv[])
02623 {
02624    int newlevel;
02625 
02626         if (argc != 4)
02627                 return RESULT_SHOWUSAGE;
02628         newlevel = myatoi(argv[3]);
02629         if((newlevel < 0) || (newlevel > 7))
02630                 return RESULT_SHOWUSAGE;
02631         if(newlevel)
02632                 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
02633         else
02634                 ast_cli(fd, "app_rpt Debugging disabled\n");
02635 
02636         debug = newlevel;                                                                                                                          
02637         return RESULT_SUCCESS;
02638 }
02639 
02640 /*
02641 * Dump rpt struct debugging onto console
02642 */
02643                                                                                                                                  
02644 static int rpt_do_dump(int fd, int argc, char *argv[])
02645 {
02646    int i;
02647 
02648         if (argc != 3)
02649                 return RESULT_SHOWUSAGE;
02650 
02651    for(i = 0; i < nrpts; i++)
02652    {
02653       if (!strcmp(argv[2],rpt_vars[i].name))
02654       {
02655          rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
02656               ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
02657               return RESULT_SUCCESS;
02658       }
02659    }
02660    return RESULT_FAILURE;
02661 }
02662 
02663 /*
02664 * Dump statistics onto console
02665 */
02666 
02667 static int rpt_do_stats(int fd, int argc, char *argv[])
02668 {
02669    int i,j,numoflinks;
02670    int dailytxtime, dailykerchunks;
02671    time_t now;
02672    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
02673    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
02674    int uptime;
02675    long long totaltxtime;
02676    struct   rpt_link *l;
02677    char *listoflinks[MAX_STAT_LINKS];  
02678    char *lastdtmfcommand,*parrot_ena;
02679    char *tot_state, *ider_state, *patch_state;
02680    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
02681    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
02682    struct rpt *myrpt;
02683 
02684    static char *not_applicable = "N/A";
02685 
02686    if(argc != 3)
02687       return RESULT_SHOWUSAGE;
02688 
02689    tot_state = ider_state = 
02690    patch_state = reverse_patch_state = 
02691    input_signal = not_applicable;
02692    called_number = lastdtmfcommand = NULL;
02693 
02694    time(&now);
02695    for(i = 0; i < nrpts; i++)
02696    {
02697       if (!strcmp(argv[2],rpt_vars[i].name)){
02698          /* Make a copy of all stat variables while locked */
02699          myrpt = &rpt_vars[i];
02700          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02701          uptime = (int)(now - starttime);
02702          dailytxtime = myrpt->dailytxtime;
02703          totaltxtime = myrpt->totaltxtime;
02704          dailykeyups = myrpt->dailykeyups;
02705          totalkeyups = myrpt->totalkeyups;
02706          dailykerchunks = myrpt->dailykerchunks;
02707          totalkerchunks = myrpt->totalkerchunks;
02708          dailyexecdcommands = myrpt->dailyexecdcommands;
02709          totalexecdcommands = myrpt->totalexecdcommands;
02710          timeouts = myrpt->timeouts;
02711 
02712          /* Traverse the list of connected nodes */
02713          reverse_patch_state = "DOWN";
02714          numoflinks = 0;
02715          l = myrpt->links.next;
02716          while(l && (l != &myrpt->links)){
02717             if(numoflinks >= MAX_STAT_LINKS){
02718                ast_log(LOG_NOTICE,
02719                "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
02720                break;
02721             }
02722             if (l->name[0] == '0'){ /* Skip '0' nodes */
02723                reverse_patch_state = "UP";
02724                l = l->next;
02725                continue;
02726             }
02727             listoflinks[numoflinks] = ast_strdup(l->name);
02728             if(listoflinks[numoflinks] == NULL){
02729                break;
02730             }
02731             else{
02732                numoflinks++;
02733             }
02734             l = l->next;
02735          }
02736 
02737          if(myrpt->keyed)
02738             input_signal = "YES";
02739          else
02740             input_signal = "NO";
02741 
02742          if(myrpt->p.parrotmode)
02743             parrot_ena = "ENABLED";
02744          else
02745             parrot_ena = "DISABLED";
02746 
02747          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
02748             sys_ena = "DISABLED";
02749          else
02750             sys_ena = "ENABLED";
02751 
02752          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
02753             tot_ena = "DISABLED";
02754          else
02755             tot_ena = "ENABLED";
02756 
02757          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
02758             link_ena = "DISABLED";
02759          else
02760             link_ena = "ENABLED";
02761 
02762          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
02763             patch_ena = "DISABLED";
02764          else
02765             patch_ena = "ENABLED";
02766 
02767          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
02768             sch_ena = "DISABLED";
02769          else
02770             sch_ena = "ENABLED";
02771 
02772          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
02773             user_funs = "DISABLED";
02774          else
02775             user_funs = "ENABLED";
02776 
02777          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
02778             tail_type = "ALTERNATE";
02779          else
02780             tail_type = "STANDARD";
02781 
02782          if(!myrpt->totimer)
02783             tot_state = "TIMED OUT!";
02784          else if(myrpt->totimer != myrpt->p.totime)
02785             tot_state = "ARMED";
02786          else
02787             tot_state = "RESET";
02788 
02789          if(myrpt->tailid)
02790             ider_state = "QUEUED IN TAIL";
02791          else if(myrpt->mustid)
02792             ider_state = "QUEUED FOR CLEANUP";
02793          else
02794             ider_state = "CLEAN";
02795 
02796          switch(myrpt->callmode){
02797             case 1:
02798                patch_state = "DIALING";
02799                break;
02800             case 2:
02801                patch_state = "CONNECTING";
02802                break;
02803             case 3:
02804                patch_state = "UP";
02805                break;
02806 
02807             case 4:
02808                patch_state = "CALL FAILED";
02809                break;
02810 
02811             default:
02812                patch_state = "DOWN";
02813          }
02814 
02815          if(strlen(myrpt->exten)){
02816             called_number = ast_strdup(myrpt->exten);
02817          }
02818 
02819          if(strlen(myrpt->lastdtmfcommand)){
02820             lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
02821          }
02822          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02823 
02824          ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
02825          ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
02826          ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
02827          ast_cli(fd, "System...........................................: %s\n", sys_ena);
02828          ast_cli(fd, "Parrot Mode......................................: %s\n", parrot_ena);
02829          ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
02830          ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
02831          ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
02832          ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
02833          ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
02834          ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
02835          ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
02836          ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
02837          ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
02838          ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
02839          ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
02840          ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
02841          ast_cli(fd, "Last DTMF command executed.......................: %s\n", 
02842          (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
02843          hours = dailytxtime/3600000;
02844          dailytxtime %= 3600000;
02845          minutes = dailytxtime/60000;
02846          dailytxtime %= 60000;
02847          seconds = dailytxtime/1000;
02848          dailytxtime %= 1000;
02849 
02850          ast_cli(fd, "TX time today....................................: %02d:%02d:%02d.%d\n",
02851             hours, minutes, seconds, dailytxtime);
02852 
02853          hours = (int) totaltxtime/3600000;
02854          totaltxtime %= 3600000;
02855          minutes = (int) totaltxtime/60000;
02856          totaltxtime %= 60000;
02857          seconds = (int)  totaltxtime/1000;
02858          totaltxtime %= 1000;
02859 
02860          ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
02861              hours, minutes, seconds, (int) totaltxtime);
02862 
02863                         hours = uptime/3600;
02864                         uptime %= 3600;
02865                         minutes = uptime/60;
02866                         uptime %= 60;
02867 
02868                         ast_cli(fd, "Uptime...........................................: %02d:%02d:%02d\n",
02869                                 hours, minutes, uptime);
02870 
02871          ast_cli(fd, "Nodes currently connected to us..................: ");
02872                         if(!numoflinks){
02873                          ast_cli(fd,"<NONE>");
02874                         }
02875          else{
02876             for(j = 0 ;j < numoflinks; j++){
02877                ast_cli(fd, "%s", listoflinks[j]);
02878                if(j % 4 == 3){
02879                   ast_cli(fd, "\n");
02880                   ast_cli(fd, "                                                 : ");
02881                }  
02882                else{
02883                   if((numoflinks - 1) - j  > 0)
02884                      ast_cli(fd, ", ");
02885                }
02886             }
02887          }
02888          ast_cli(fd,"\n");
02889 
02890          ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
02891          ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
02892          ast_cli(fd, "Autopatch called number..........................: %s\n",
02893          (called_number && strlen(called_number)) ? called_number : not_applicable);
02894          ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
02895          ast_cli(fd, "User linking commands............................: %s\n", link_ena);
02896          ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
02897 
02898          for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
02899             ast_free(listoflinks[j]);
02900          }
02901          if(called_number){
02902             ast_free(called_number);
02903          }
02904          if(lastdtmfcommand){
02905             ast_free(lastdtmfcommand);
02906          }
02907               return RESULT_SUCCESS;
02908       }
02909    }
02910    return RESULT_FAILURE;
02911 }
02912 
02913 /*
02914 * Link stats function
02915 */
02916 
02917 static int rpt_do_lstats(int fd, int argc, char *argv[])
02918 {
02919    int i,j;
02920    char *connstate;
02921    struct rpt *myrpt;
02922    struct rpt_link *l;
02923    struct rpt_lstat *s,*t;
02924    struct rpt_lstat s_head;
02925    if(argc != 3)
02926       return RESULT_SHOWUSAGE;
02927 
02928    s = NULL;
02929    s_head.next = &s_head;
02930    s_head.prev = &s_head;
02931 
02932    for(i = 0; i < nrpts; i++)
02933    {
02934       if (!strcmp(argv[2],rpt_vars[i].name)){
02935          /* Make a copy of all stat variables while locked */
02936          myrpt = &rpt_vars[i];
02937          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02938          /* Traverse the list of connected nodes */
02939          j = 0;
02940          l = myrpt->links.next;
02941          while(l && (l != &myrpt->links)){
02942             if (l->name[0] == '0'){ /* Skip '0' nodes */
02943                l = l->next;
02944                continue;
02945             }
02946             if((s = (struct rpt_lstat *) ast_malloc(sizeof(struct rpt_lstat))) == NULL){
02947                ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
02948                rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02949                return RESULT_FAILURE;
02950             }
02951             memset(s, 0, sizeof(struct rpt_lstat));
02952             strncpy(s->name, l->name, MAXREMSTR - 1);
02953             if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
02954             else strcpy(s->peer,"(none)");
02955             s->mode = l->mode;
02956             s->outbound = l->outbound;
02957             s->reconnects = l->reconnects;
02958             s->connecttime = l->connecttime;
02959             s->thisconnected = l->thisconnected;
02960             memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
02961             insque((struct qelem *) s, (struct qelem *) s_head.next);
02962             memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
02963             l = l->next;
02964          }
02965          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02966          ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME        CONNECT STATE\n");
02967          ast_cli(fd, "----      ----                ----------  ---------  ------------        -------------\n");
02968 
02969          for(s = s_head.next; s != &s_head; s = s->next){
02970             int hours, minutes, seconds;
02971             long long connecttime = s->connecttime;
02972             char conntime[21];
02973             hours = (int) connecttime/3600000;
02974             connecttime %= 3600000;
02975             minutes = (int) connecttime/60000;
02976             connecttime %= 60000;
02977             seconds = (int)  connecttime/1000;
02978             connecttime %= 1000;
02979             snprintf(conntime, 20, "%02d:%02d:%02d.%d",
02980                hours, minutes, seconds, (int) connecttime);
02981             conntime[20] = 0;
02982             if(s->thisconnected)
02983                connstate  = "ESTABLISHED";
02984             else
02985                connstate = "CONNECTING";
02986             ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
02987                s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
02988          }  
02989          /* destroy our local link queue */
02990          s = s_head.next;
02991          while(s != &s_head){
02992             t = s;
02993             s = s->next;
02994             remque((struct qelem *)t);
02995             ast_free(t);
02996          }        
02997          return RESULT_SUCCESS;
02998       }
02999    }
03000    return RESULT_FAILURE;
03001 }
03002 
03003 /*
03004 * List all nodes connected, directly or indirectly
03005 */
03006 
03007 static int rpt_do_nodes(int fd, int argc, char *argv[])
03008 {
03009    int i,j;
03010    char ns;
03011    char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
03012    struct rpt *myrpt;
03013    if(argc != 3)
03014       return RESULT_SHOWUSAGE;
03015 
03016    for(i = 0; i < nrpts; i++)
03017    {
03018       if (!strcmp(argv[2],rpt_vars[i].name)){
03019          /* Make a copy of all stat variables while locked */
03020          myrpt = &rpt_vars[i];
03021          rpt_mutex_lock(&myrpt->lock); /* LOCK */
03022          __mklinklist(myrpt,NULL,lbuf);
03023          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
03024          /* parse em */
03025          ns = finddelim(lbuf,strs,MAXLINKLIST);
03026          /* sort em */
03027          if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
03028          ast_cli(fd,"\n");
03029          ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
03030          for(j = 0 ;; j++){
03031             if(!strs[j]){
03032                if(!j){
03033                   ast_cli(fd,"<NONE>");
03034                }
03035                break;
03036             }
03037             ast_cli(fd, "%s", strs[j]);
03038             if(j % 8 == 7){
03039                ast_cli(fd, "\n");
03040             }
03041             else{
03042                if(strs[j + 1])
03043                   ast_cli(fd, ", ");
03044             }
03045          }
03046          ast_cli(fd,"\n\n");
03047          return RESULT_SUCCESS;
03048       }
03049    }
03050    return RESULT_FAILURE;
03051 }
03052 
03053 /*
03054 * List all locally configured nodes
03055 */
03056 
03057 static int rpt_do_local_nodes(int fd, int argc, char *argv[])
03058 {
03059 
03060     int i;
03061     ast_cli(fd, "\nNode\n----\n");
03062     for (i=0; i< nrpts; i++)
03063     {
03064         ast_cli(fd, "%s\n", rpt_vars[i].name);        
03065     } /* for i */
03066     ast_cli(fd,"\n");
03067     return RESULT_SUCCESS;
03068 } 
03069 
03070 
03071 /*
03072 * reload vars 
03073 */
03074 
03075 static int rpt_do_reload(int fd, int argc, char *argv[])
03076 {
03077 int   n;
03078 
03079         if (argc > 2) return RESULT_SHOWUSAGE;
03080 
03081    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
03082 
03083    return RESULT_FAILURE;
03084 }
03085 
03086 /*
03087 * restart app_rpt
03088 */
03089                                                                                                                                  
03090 static int rpt_do_restart(int fd, int argc, char *argv[])
03091 {
03092 int   i;
03093 
03094         if (argc > 2) return RESULT_SHOWUSAGE;
03095    for(i = 0; i < nrpts; i++)
03096    {
03097       if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
03098    }
03099    return RESULT_FAILURE;
03100 }
03101 
03102 
03103 /*
03104 * send an app_rpt DTMF function from the CLI
03105 */
03106                                                                                                                                  
03107 static int rpt_do_fun(int fd, int argc, char *argv[])
03108 {
03109    int   i,busy=0;
03110 
03111         if (argc != 4) return RESULT_SHOWUSAGE;
03112 
03113    for(i = 0; i < nrpts; i++){
03114       if(!strcmp(argv[2], rpt_vars[i].name)){
03115          struct rpt *myrpt = &rpt_vars[i];
03116          rpt_mutex_lock(&myrpt->lock);
03117          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
03118             rpt_mutex_unlock(&myrpt->lock);
03119             busy=1;
03120          }
03121          if(!busy){
03122             myrpt->macrotimer = MACROTIME;
03123             strncat(myrpt->macrobuf,argv[3],MAXMACRO - 1);
03124          }
03125          rpt_mutex_unlock(&myrpt->lock);
03126       }
03127    }
03128    if(busy){
03129       ast_cli(fd, "Function decoder busy");
03130    }
03131    return RESULT_FAILURE;
03132 }
03133 /*
03134    the convention is that macros in the data from the rpt() application
03135    are all at the end of the data, separated by the | and start with a *
03136    when put into the macro buffer, the characters have their high bit
03137    set so the macro processor knows they came from the application data
03138    and to use the alt-functions table.
03139    sph:
03140 */
03141 static int rpt_push_alt_macro(struct rpt *myrpt, char *sptr)
03142 {
03143    int   busy=0;
03144 
03145    rpt_mutex_lock(&myrpt->lock);
03146    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(sptr)){
03147       rpt_mutex_unlock(&myrpt->lock);
03148       busy=1;
03149    }
03150    if(!busy){
03151       int x;
03152       if (debug)ast_log(LOG_NOTICE, "rpt_push_alt_macro %s\n",sptr);
03153       myrpt->macrotimer = MACROTIME;
03154       for(x = 0; *(sptr + x); x++)
03155           myrpt->macrobuf[x] = *(sptr + x) | 0x80;
03156       *(sptr + x) = 0;
03157    }
03158    rpt_mutex_unlock(&myrpt->lock);
03159 
03160    if(busy)ast_log(LOG_WARNING, "Function decoder busy on app_rpt command macro.\n");
03161 
03162    return busy;
03163 }
03164 /*
03165    allows us to test rpt() application data commands
03166 */
03167 static int rpt_do_fun1(int fd, int argc, char *argv[])
03168 {
03169    int   i;
03170 
03171     if (argc != 4) return RESULT_SHOWUSAGE;
03172 
03173    for(i = 0; i < nrpts; i++){
03174       if(!strcmp(argv[2], rpt_vars[i].name)){
03175          struct rpt *myrpt = &rpt_vars[i];
03176          rpt_push_alt_macro(myrpt,argv[3]);
03177       }
03178    }
03179    return RESULT_FAILURE;
03180 }
03181 /*
03182 * send an app_rpt **command** from the CLI
03183 */
03184 
03185 static int rpt_do_cmd(int fd, int argc, char *argv[])
03186 {
03187    int i, l;
03188    int busy=0;
03189    int maxActions = sizeof(function_table)/sizeof(struct function_table_tag);
03190 
03191    int thisRpt = -1;
03192    int thisAction = -1;
03193    struct rpt *myrpt = NULL;
03194    if (argc != 6) return RESULT_SHOWUSAGE;
03195    
03196    for(i = 0; i < nrpts; i++)
03197    {
03198       if(!strcmp(argv[2], rpt_vars[i].name))
03199       {
03200          thisRpt = i;
03201          myrpt = &rpt_vars[i];
03202          break;
03203       } /* if !strcmp... */
03204    } /* for i */
03205 
03206    if (thisRpt < 0)
03207    {
03208       ast_cli(fd, "Unknown node number %s.\n", argv[2]);
03209       return RESULT_FAILURE;
03210    } /* if thisRpt < 0 */
03211    
03212    /* Look up the action */
03213    l = strlen(argv[3]);
03214    for(i = 0 ; i < maxActions; i++)
03215    {
03216       if(!strncasecmp(argv[3], function_table[i].action, l))
03217       {
03218          thisAction = i;
03219          break;
03220       } /* if !strncasecmp... */
03221    } /* for i */
03222    
03223    if (thisAction < 0)
03224    {
03225       ast_cli(fd, "Unknown action name %s.\n", argv[3]);
03226       return RESULT_FAILURE;
03227    } /* if thisAction < 0 */
03228 
03229    /* at this point, it looks like all the arguments make sense... */
03230 
03231    rpt_mutex_lock(&myrpt->lock);
03232 
03233    if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE)
03234    {
03235       rpt_vars[thisRpt].cmdAction.state = CMD_STATE_BUSY;
03236       rpt_vars[thisRpt].cmdAction.functionNumber = thisAction;
03237       strncpy(rpt_vars[thisRpt].cmdAction.param, argv[4], MAXDTMF);
03238       strncpy(rpt_vars[thisRpt].cmdAction.digits, argv[5], MAXDTMF);
03239       rpt_vars[thisRpt].cmdAction.command_source = SOURCE_RPT;
03240       rpt_vars[thisRpt].cmdAction.state = CMD_STATE_READY;
03241    } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
03242    else
03243    {
03244       busy = 1;
03245    } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
03246    rpt_mutex_unlock(&myrpt->lock);
03247 
03248    return (busy ? RESULT_FAILURE : RESULT_SUCCESS);
03249 } /* rpt_do_cmd() */
03250 
03251 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
03252 {
03253    int res;
03254 
03255         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
03256                 return res;
03257                                                                                                                                             
03258         while(chan->generatordata) {
03259       if (ast_safe_sleep(chan,1)) return -1;
03260    }
03261 
03262         return 0;
03263 }
03264 
03265 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
03266 {
03267    return play_tone_pair(chan, freq, 0, duration, amplitude);
03268 }
03269 
03270 static int play_silence(struct ast_channel *chan, int duration)
03271 {
03272    return play_tone_pair(chan, 0, 0, duration, 0);
03273 }
03274 
03275 #ifdef   NEW_ASTERISK
03276 
03277 static char *res2cli(int r)
03278 
03279 {
03280    switch (r)
03281    {
03282        case RESULT_SUCCESS:
03283       return(CLI_SUCCESS);
03284        case RESULT_SHOWUSAGE:
03285       return(CLI_SHOWUSAGE);
03286        default:
03287       return(CLI_FAILURE);
03288    }
03289 }
03290 
03291 static char *handle_cli_debug(struct ast_cli_entry *e,
03292    int cmd, struct ast_cli_args *a)
03293 {
03294         switch (cmd) {
03295         case CLI_INIT:
03296                 e->command = "rpt debug level";
03297                 e->usage = debug_usage;
03298                 return NULL;
03299         case CLI_GENERATE:
03300                 return NULL;
03301    }
03302    return res2cli(rpt_do_debug(a->fd,a->argc,a->argv));
03303 }
03304 
03305 static char *handle_cli_dump(struct ast_cli_entry *e,
03306    int cmd, struct ast_cli_args *a)
03307 {
03308         switch (cmd) {
03309         case CLI_INIT:
03310                 e->command = "rpt dump level";
03311                 e->usage = dump_usage;
03312                 return NULL;
03313         case CLI_GENERATE:
03314                 return NULL;
03315    }
03316    return res2cli(rpt_do_dump(a->fd,a->argc,a->argv));
03317 }
03318 
03319 
03320 static char *handle_cli_stats(struct ast_cli_entry *e,
03321    int cmd, struct ast_cli_args *a)
03322 {
03323         switch (cmd) {
03324         case CLI_INIT:
03325                 e->command = "rpt stats";
03326                 e->usage = dump_stats;
03327                 return NULL;
03328         case CLI_GENERATE:
03329                 return NULL;
03330    }
03331    return res2cli(rpt_do_stats(a->fd,a->argc,a->argv));
03332 }
03333 
03334 static char *handle_cli_nodes(struct ast_cli_entry *e,
03335    int cmd, struct ast_cli_args *a)
03336 {
03337         switch (cmd) {
03338         case CLI_INIT:
03339                 e->command = "rpt nodes";
03340                 e->usage = dump_nodes;
03341                 return NULL;
03342         case CLI_GENERATE:
03343                 return NULL;
03344    }
03345    return res2cli(rpt_do_nodes(a->fd,a->argc,a->argv));
03346 }
03347 
03348 static char *handle_cli_local_nodes(struct ast_cli_entry *e,
03349    int cmd, struct ast_cli_args *a)
03350 {
03351         switch (cmd) {
03352         case CLI_INIT:
03353                 e->command = "rpt localnodes";
03354                 e->usage = usage_local_nodes;
03355                 return NULL;
03356         case CLI_GENERATE:
03357                 return NULL;
03358    }
03359    return res2cli(rpt_do_local_nodes(a->fd,a->argc,a->argv));
03360 }
03361 
03362 static char *handle_cli_lstats(struct ast_cli_entry *e,
03363    int cmd, struct ast_cli_args *a)
03364 {
03365         switch (cmd) {
03366         case CLI_INIT:
03367                 e->command = "rpt lstats";
03368                 e->usage = dump_lstats;
03369                 return NULL;
03370         case CLI_GENERATE:
03371                 return NULL;
03372    }
03373    return res2cli(rpt_do_lstats(a->fd,a->argc,a->argv));
03374 }
03375 
03376 static char *handle_cli_reload(struct ast_cli_entry *e,
03377    int cmd, struct ast_cli_args *a)
03378 {
03379         switch (cmd) {
03380         case CLI_INIT:
03381                 e->command = "rpt reload";
03382                 e->usage = reload_usage;
03383                 return NULL;
03384         case CLI_GENERATE:
03385                 return NULL;
03386    }
03387    return res2cli(rpt_do_reload(a->fd,a->argc,a->argv));
03388 }
03389 
03390 static char *handle_cli_restart(struct ast_cli_entry *e,
03391    int cmd, struct ast_cli_args *a)
03392 {
03393         switch (cmd) {
03394         case CLI_INIT:
03395                 e->command = "rpt restart";
03396                 e->usage = restart_usage;
03397                 return NULL;
03398         case CLI_GENERATE:
03399                 return NULL;
03400    }
03401    return res2cli(rpt_do_restart(a->fd,a->argc,a->argv));
03402 }
03403 
03404 static char *handle_cli_fun(struct ast_cli_entry *e,
03405    int cmd, struct ast_cli_args *a)
03406 {
03407         switch (cmd) {
03408         case CLI_INIT:
03409                 e->command = "rpt fun";
03410                 e->usage = fun_usage;
03411                 return NULL;
03412         case CLI_GENERATE:
03413                 return NULL;
03414    }
03415    return res2cli(rpt_do_fun(a->fd,a->argc,a->argv));
03416 }
03417 
03418 static char *handle_cli_fun1(struct ast_cli_entry *e,
03419    int cmd, struct ast_cli_args *a)
03420 {
03421         switch (cmd) {
03422         case CLI_INIT:
03423                 e->command = "rpt fun1";
03424                 e->usage = fun_usage;
03425                 return NULL;
03426         case CLI_GENERATE:
03427                 return NULL;
03428    }
03429    return res2cli(rpt_do_fun1(a->fd,a->argc,a->argv));
03430 }
03431 
03432 static char *handle_cli_cmd(struct ast_cli_entry *e,
03433    int cmd, struct ast_cli_args *a)
03434 {
03435         switch (cmd) {
03436         case CLI_INIT:
03437                 e->command = "rpt cmd";
03438                 e->usage = cmd_usage;
03439                 return NULL;
03440         case CLI_GENERATE:
03441                 return NULL;
03442    }
03443    return res2cli(rpt_do_cmd(a->fd,a->argc,a->argv));
03444 }
03445 
03446 static struct ast_cli_entry rpt_cli[] = {
03447    AST_CLI_DEFINE(handle_cli_debug,"Enable app_rpt debugging"),
03448    AST_CLI_DEFINE(handle_cli_dump,"Dump app_rpt structs for debugging"),
03449    AST_CLI_DEFINE(handle_cli_stats,"Dump node statistics"),
03450    AST_CLI_DEFINE(handle_cli_nodes,"Dump node list"),
03451    AST_CLI_DEFINE(handle_cli_local_nodes, "Dump list of local node numbers"),
03452    AST_CLI_DEFINE(handle_cli_lstats,"Dump link statistics"),
03453    AST_CLI_DEFINE(handle_cli_reload,"Reload app_rpt config"),
03454    AST_CLI_DEFINE(handle_cli_restart,"Restart app_rpt"),
03455    AST_CLI_DEFINE(handle_cli_fun,"Execute a DTMF function"),
03456    AST_CLI_DEFINE(handle_cli_fun1,"Execute a DTMF function"),
03457    AST_CLI_DEFINE(handle_cli_cmd,"Execute a DTMF function")
03458 };
03459 
03460 #endif
03461 
03462 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
03463 {
03464 
03465 static struct morse_bits mbits[] = {
03466       {0, 0}, /* SPACE */
03467       {0, 0}, 
03468       {6, 18},/* " */
03469       {0, 0},
03470       {7, 72},/* $ */
03471       {0, 0},
03472       {0, 0},
03473       {6, 30},/* ' */
03474       {5, 13},/* ( */
03475       {6, 29},/* ) */
03476       {0, 0},
03477       {5, 10},/* + */
03478       {6, 51},/* , */
03479       {6, 33},/* - */
03480       {6, 42},/* . */
03481       {5, 9}, /* / */
03482       {5, 31},/* 0 */
03483       {5, 30},/* 1 */
03484       {5, 28},/* 2 */
03485       {5, 24},/* 3 */
03486       {5, 16},/* 4 */
03487       {5, 0}, /* 5 */
03488       {5, 1}, /* 6 */
03489       {5, 3}, /* 7 */
03490       {5, 7}, /* 8 */
03491       {5, 15},/* 9 */
03492       {6, 7}, /* : */
03493       {6, 21},/* ; */
03494       {0, 0},
03495       {5, 33},/* = */
03496       {0, 0},
03497       {6, 12},/* ? */
03498       {0, 0},
03499          {2, 2}, /* A */
03500       {4, 1}, /* B */
03501       {4, 5}, /* C */
03502       {3, 1}, /* D */
03503       {1, 0}, /* E */
03504       {4, 4}, /* F */
03505       {3, 3}, /* G */
03506       {4, 0}, /* H */
03507       {2, 0}, /* I */
03508       {4, 14},/* J */
03509       {3, 5}, /* K */
03510       {4, 2}, /* L */
03511       {2, 3}, /* M */
03512       {2, 1}, /* N */
03513       {3, 7}, /* O */
03514       {4, 6}, /* P */
03515       {4, 11},/* Q */
03516       {3, 2}, /* R */
03517       {3, 0}, /* S */
03518       {1, 1}, /* T */
03519       {3, 4}, /* U */
03520       {4, 8}, /* V */
03521       {3, 6}, /* W */
03522       {4, 9}, /* X */
03523       {4, 13},/* Y */
03524       {4, 3}  /* Z */
03525    };
03526 
03527 
03528    int dottime;
03529    int dashtime;
03530    int intralettertime;
03531    int interlettertime;
03532    int interwordtime;
03533    int len, ddcomb;
03534    int res;
03535    int c;
03536    int i;
03537    int flags;
03538          
03539    res = 0;
03540    
03541    /* Approximate the dot time from the speed arg. */
03542    
03543    dottime = 900/speed;
03544    
03545    /* Establish timing releationships */
03546    
03547    dashtime = 3 * dottime;
03548    intralettertime = dottime;
03549    interlettertime = dottime * 4 ;
03550    interwordtime = dottime * 7;
03551    
03552    for(;(*string) && (!res); string++){
03553    
03554       c = *string;
03555       
03556       /* Convert lower case to upper case */
03557       
03558       if((c >= 'a') && (c <= 'z'))
03559          c -= 0x20;
03560       
03561       /* Can't deal with any char code greater than Z, skip it */
03562       
03563       if(c  > 'Z')
03564          continue;
03565       
03566       /* If space char, wait the inter word time */
03567                
03568       if(c == ' '){
03569          if(!res)
03570             res = play_silence(chan, interwordtime);
03571          continue;
03572       }
03573       
03574       /* Subtract out control char offset to match our table */
03575       
03576       c -= 0x20;
03577       
03578       /* Get the character data */
03579       
03580       len = mbits[c].len;
03581       ddcomb = mbits[c].ddcomb;
03582       
03583       /* Send the character */
03584       
03585       for(; len ; len--){
03586          if(!res)
03587             res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
03588          if(!res)
03589             res = play_silence(chan, intralettertime);
03590          ddcomb >>= 1;
03591       }
03592       
03593       /* Wait the interletter time */
03594       
03595       if(!res)
03596          res = play_silence(chan, interlettertime - intralettertime);
03597    }
03598    
03599    /* Wait for all the frames to be sent */
03600    
03601    if (!res) 
03602       res = ast_waitstream(chan, "");
03603    ast_stopstream(chan);
03604    
03605    /*
03606    * Wait for the DAHDI driver to physically write the tone blocks to the hardware
03607    */
03608 
03609    for(i = 0; i < 20 ; i++){
03610       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
03611       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
03612       if(flags & DAHDI_IOMUX_WRITEEMPTY)
03613          break;
03614       if( ast_safe_sleep(chan, 50)){
03615          res = -1;
03616          break;
03617       }
03618    }
03619 
03620    
03621    return res;
03622 }
03623 
03624 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
03625 {
03626    char *p,*stringp;
03627    char *tonesubset;
03628    int f1,f2;
03629    int duration;
03630    int amplitude;
03631    int res;
03632    int i;
03633    int flags;
03634    
03635    res = 0;
03636 
03637    if(!tonestring)
03638       return res;
03639    
03640    p = stringp = ast_strdup(tonestring);
03641 
03642    for(;tonestring;){
03643       tonesubset = strsep(&stringp,")");
03644       if(!tonesubset)
03645          break;
03646       if(sscanf(tonesubset,"(%30d,%30d,%30d,%30d", &f1, &f2, &duration, &amplitude) != 4)
03647          break;
03648       res = play_tone_pair(chan, f1, f2, duration, amplitude);
03649       if(res)
03650          break;
03651    }
03652    if(p)
03653       ast_free(p);
03654    if(!res)
03655       res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
03656    
03657    if (!res) 
03658       res = ast_waitstream(chan, "");
03659 
03660    ast_stopstream(chan);
03661 
03662    /*
03663    * Wait for the DAHDI driver to physically write the tone blocks to the hardware
03664    */
03665 
03666    for(i = 0; i < 20 ; i++){
03667       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
03668       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
03669       if(flags & DAHDI_IOMUX_WRITEEMPTY)
03670          break;
03671       if( ast_safe_sleep(chan, 50)){
03672          res = -1;
03673          break;
03674       }
03675    }
03676       
03677    return res;
03678       
03679 }
03680 
03681 static int sayfile(struct ast_channel *mychannel,char *fname)
03682 {
03683 int   res;
03684 
03685    res = ast_streamfile(mychannel, fname, mychannel->language);
03686    if (!res) 
03687       res = ast_waitstream(mychannel, "");
03688    else
03689        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03690    ast_stopstream(mychannel);
03691    return res;
03692 }
03693 
03694 static int saycharstr(struct ast_channel *mychannel,char *str)
03695 {
03696 int   res;
03697 
03698    res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
03699    if (!res) 
03700       res = ast_waitstream(mychannel, "");
03701    else
03702        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03703    ast_stopstream(mychannel);
03704    return res;
03705 }
03706 
03707 static int saynum(struct ast_channel *mychannel, int num)
03708 {
03709    int res;
03710    res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
03711    if(!res)
03712       res = ast_waitstream(mychannel, "");
03713    else
03714       ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03715    ast_stopstream(mychannel);
03716    return res;
03717 }
03718 
03719 /* say a node and nodename. Try to look in dir referred to by nodenames in
03720 config, and see if there's a custom node file to play, and if so, play it */
03721 
03722 static int saynode(struct rpt *myrpt, struct ast_channel *mychannel, char *name)
03723 {
03724 int   res;
03725 char  *val,fname[300];
03726 
03727    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "nodenames");
03728    if (!val) val = NODENAMES;
03729    snprintf(fname,sizeof(fname) - 1,"%s/%s",val,name);
03730    if (ast_fileexists(fname,NULL,mychannel->language) > 0)
03731       return(sayfile(mychannel,fname));
03732    res = sayfile(mychannel,"rpt/node");
03733    if (!res) 
03734       res = ast_say_character_str(mychannel,name,NULL,mychannel->language);
03735    return res;
03736 }
03737 
03738 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
03739 {
03740    int res;
03741    char c;
03742    
03743    static int morsespeed;
03744    static int morsefreq;
03745    static int morseampl;
03746    static int morseidfreq = 0;
03747    static int morseidampl;
03748    static char mcat[] = MORSE;
03749    
03750    res = 0;
03751    
03752    if(!morseidfreq){ /* Get the morse parameters if not already loaded */
03753       morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
03754          morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
03755          morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
03756       morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
03757       morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330); 
03758    }
03759    
03760    /* Is it a file, or a tone sequence? */
03761          
03762    if(entry[0] == '|'){
03763       c = entry[1];
03764       if((c >= 'a')&&(c <= 'z'))
03765          c -= 0x20;
03766    
03767       switch(c){
03768          case 'I': /* Morse ID */
03769             res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
03770             break;
03771          
03772          case 'M': /* Morse Message */
03773             res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
03774             break;
03775          
03776          case 'T': /* Tone sequence */
03777             res = send_tone_telemetry(chan, entry + 2);
03778             break;
03779          default:
03780             res = -1;
03781       }
03782    }
03783    else
03784       res = sayfile(chan, entry); /* File */
03785    return res;
03786 }
03787 
03788 /*
03789 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
03790 *
03791 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
03792 */
03793 
03794 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
03795 {
03796    
03797    int res;
03798    int i;
03799    char *entry;
03800    char *telemetry;
03801    char *telemetry_save;
03802 
03803    res = 0;
03804    telemetry_save = NULL;
03805    entry = NULL;
03806    
03807    /* Retrieve the section name for telemetry from the node section */
03808    telemetry = (char *) ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
03809    if(telemetry ){
03810       telemetry_save = ast_strdup(telemetry);
03811       if(!telemetry_save){
03812          ast_log(LOG_WARNING,"ast_strdup() failed in telem_lookup()\n");
03813          return res;
03814       }
03815       entry = (char *) ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
03816    }
03817    
03818    /* Try to look up the telemetry name */   
03819 
03820    if(!entry){
03821       /* Telemetry name wasn't found in the config file, use the default */
03822       for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
03823          if(!strcasecmp(tele_defs[i].name, name))
03824             entry = tele_defs[i].value;
03825       }
03826    }
03827    if(entry){  
03828       if(strlen(entry))
03829          if (chan) telem_any(myrpt,chan, entry);
03830    }
03831    else{
03832       res = -1;
03833    }
03834    if(telemetry_save)
03835       ast_free(telemetry_save);
03836    return res;
03837 }
03838 
03839 /*
03840 * Retrieve a wait interval
03841 */
03842 
03843 static int get_wait_interval(struct rpt *myrpt, int type)
03844 {
03845         int interval;
03846         char *wait_times;
03847         char *wait_times_save;
03848                                                                                                                   
03849         wait_times_save = NULL;
03850         wait_times = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
03851                                                                                                                   
03852         if(wait_times){
03853                 wait_times_save = ast_strdup(wait_times);
03854                 if(!wait_times_save)
03855          return 0;
03856                 
03857         }
03858                                                                                                                   
03859         switch(type){
03860                 case DLY_TELEM:
03861                         if(wait_times)
03862                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
03863                         else
03864                                 interval = 1000;
03865                         break;
03866                                                                                                                   
03867                 case DLY_ID:
03868                         if(wait_times)
03869                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
03870                         else
03871                                 interval = 500;
03872                         break;
03873                                                                                                                   
03874                 case DLY_UNKEY:
03875                         if(wait_times)
03876                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",50,5000,1000);
03877                         else
03878                                 interval = 1000;
03879                         break;
03880                                                                                                                   
03881                 case DLY_LINKUNKEY:
03882                         if(wait_times)
03883                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "linkunkeywait",500,5000,1000);
03884                         else
03885                                 interval = 1000;
03886                         break;
03887                                                                                                                   
03888                 case DLY_CALLTERM:
03889                         if(wait_times)
03890                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
03891                         else
03892                                 interval = 1500;
03893                         break;
03894                                                                                                                   
03895                 case DLY_COMP:
03896                         if(wait_times)
03897                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "compwait",500,5000,200);
03898                         else
03899                                 interval = 200;
03900                         break;
03901                                                                                                                   
03902                 case DLY_PARROT:
03903                         if(wait_times)
03904                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "parrotwait",500,5000,200);
03905                         else
03906                                 interval = 200;
03907                         break;
03908                                                                                                                   
03909                 default:
03910          interval = 0;
03911          break;
03912         }
03913    if(wait_times_save)
03914             ast_free(wait_times_save);
03915    return interval;
03916 }                                                                                                                  
03917 
03918 
03919 /*
03920 * Wait a configurable interval of time 
03921 */
03922 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
03923 {
03924    int interval;
03925    interval = get_wait_interval(myrpt, type);
03926    if(debug)
03927       ast_log(LOG_NOTICE,"Delay interval = %d\n", interval);
03928    if(interval)
03929       ast_safe_sleep(chan,interval);
03930    if(debug)
03931       ast_log(LOG_NOTICE,"Delay complete\n");
03932    return;
03933 }
03934 
03935 static int split_freq(char *mhz, char *decimals, char *freq);
03936 
03937 static void *rpt_tele_thread(void *this)
03938 {
03939 struct dahdi_confinfo ci;  /* conference info */
03940 int   res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
03941 struct   rpt_tele *mytele = (struct rpt_tele *)this;
03942 struct  rpt_tele *tlist;
03943 struct   rpt *myrpt;
03944 struct   rpt_link *l,*l1,linkbase;
03945 struct   ast_channel *mychannel;
03946 int vmajor, vminor, m;
03947 char *p,*ct,*ct_copy,*ident, *nodename,*cp;
03948 time_t t;
03949 #ifdef   NEW_ASTERISK
03950 struct ast_tm localtm;
03951 #else
03952 struct tm localtm;
03953 #endif
03954 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
03955 int   i,ns,rbimode;
03956 char mhz[MAXREMSTR];
03957 char decimals[MAXREMSTR];
03958 char  mystr[200];
03959 struct dahdi_params par;
03960 
03961 
03962    /* get a pointer to myrpt */
03963    myrpt = mytele->rpt;
03964 
03965    /* Snag copies of a few key myrpt variables */
03966    rpt_mutex_lock(&myrpt->lock);
03967    nodename = ast_strdup(myrpt->name);
03968    if(!nodename)
03969    {
03970        fprintf(stderr,"rpt:Sorry unable strdup nodename\n");
03971        rpt_mutex_lock(&myrpt->lock);
03972        remque((struct qelem *)mytele);
03973        ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03974        rpt_mutex_unlock(&myrpt->lock);
03975        ast_free(mytele);
03976        pthread_exit(NULL);
03977    }
03978 
03979    if (myrpt->p.ident){
03980       ident = ast_strdup(myrpt->p.ident);
03981          if(!ident)
03982       {
03983                  fprintf(stderr,"rpt:Sorry unable strdup ident\n");
03984          rpt_mutex_lock(&myrpt->lock);
03985                   remque((struct qelem *)mytele);
03986                   ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",
03987          __LINE__, mytele->mode); /*@@@@@@@@@@@*/
03988                   rpt_mutex_unlock(&myrpt->lock);
03989          ast_free(nodename);
03990                   ast_free(mytele);
03991                   pthread_exit(NULL);
03992          }
03993    }
03994    else
03995    {
03996       ident = "";
03997    }
03998    rpt_mutex_unlock(&myrpt->lock);
03999       
04000 
04001 
04002    /* allocate a pseudo-channel thru asterisk */
04003    mychannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
04004    if (!mychannel)
04005    {
04006       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
04007       rpt_mutex_lock(&myrpt->lock);
04008       remque((struct qelem *)mytele);
04009       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04010       rpt_mutex_unlock(&myrpt->lock);
04011       ast_free(nodename);
04012       ast_free(ident);
04013       ast_free(mytele);    
04014       pthread_exit(NULL);
04015    }
04016 #ifdef   AST_CDR_FLAG_POST_DISABLED
04017    if (mychannel->cdr) 
04018       ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
04019 #endif
04020    rpt_mutex_lock(&myrpt->lock);
04021    mytele->chan = mychannel;
04022    rpt_mutex_unlock(&myrpt->lock);
04023 
04024    while((mytele->mode != SETREMOTE) && (mytele->mode != UNKEY) &&
04025       (mytele->mode != LINKUNKEY))
04026    {  
04027                 rpt_mutex_lock(&myrpt->lock);
04028       if (!myrpt->active_telem)
04029       {
04030          myrpt->active_telem = mytele;
04031                    rpt_mutex_unlock(&myrpt->lock);
04032          break;
04033       }
04034                 rpt_mutex_unlock(&myrpt->lock);
04035       usleep(100000);
04036    }
04037 
04038    /* make a conference for the tx */
04039    ci.chan = 0;
04040    /* If the telemetry is only intended for a local audience, */
04041    /* only connect the ID audio to the local tx conference so */
04042    /* linked systems can't hear it */
04043    ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
04044       (mytele->mode == TAILMSG) || (mytele->mode == LINKUNKEY) || (mytele->mode == TIMEOUT) || 
04045       (mytele->mode == PARROT) || (mytele->mode == STATS_TIME_LOCAL)) ? 
04046          myrpt->txconf : myrpt->conf);
04047    ci.confmode = DAHDI_CONF_CONFANN;
04048    /* first put the channel on the conference in announce mode */
04049    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04050    {
04051       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04052       rpt_mutex_lock(&myrpt->lock);
04053       myrpt->active_telem = NULL;
04054       remque((struct qelem *)mytele);
04055       rpt_mutex_unlock(&myrpt->lock);
04056       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04057       ast_free(nodename);
04058       ast_free(ident);
04059       ast_free(mytele);    
04060       ast_hangup(mychannel);
04061       pthread_exit(NULL);
04062    }
04063    ast_stopstream(mychannel);
04064    switch(mytele->mode)
04065    {
04066        case ID:
04067        case ID1:
04068       /* wait a bit */
04069       wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
04070       res = telem_any(myrpt,mychannel, ident); 
04071       imdone=1;   
04072       break;
04073       
04074        case TAILMSG:
04075       res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language); 
04076       break;
04077       
04078        case IDTALKOVER:
04079          p = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
04080          if(p)
04081          res = telem_any(myrpt,mychannel, p); 
04082       imdone=1;   
04083          break;
04084             
04085        case PROC:
04086       /* wait a little bit longer */
04087       wait_interval(myrpt, DLY_TELEM, mychannel);
04088       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
04089       if(res < 0){ /* Then default message */
04090          res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
04091       }
04092       break;
04093        case TERM:
04094       /* wait a little bit longer */
04095       wait_interval(myrpt, DLY_CALLTERM, mychannel);
04096       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
04097       if(res < 0){ /* Then default message */
04098          res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
04099       }
04100       break;
04101        case COMPLETE:
04102       /* wait a little bit */
04103       wait_interval(myrpt, DLY_TELEM, mychannel);
04104       res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04105       break;
04106        case MACRO_NOTFOUND:
04107       /* wait a little bit */
04108       wait_interval(myrpt, DLY_TELEM, mychannel);
04109       res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
04110       break;
04111        case MACRO_BUSY:
04112       /* wait a little bit */
04113       wait_interval(myrpt, DLY_TELEM, mychannel);
04114       res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
04115       break;
04116        case UNKEY:
04117       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
04118          imdone = 1;
04119          break;
04120       }
04121          
04122       /*
04123       * Reset the Unkey to CT timer
04124       */
04125 
04126       x = get_wait_interval(myrpt, DLY_UNKEY);
04127       rpt_mutex_lock(&myrpt->lock);
04128       myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
04129       rpt_mutex_unlock(&myrpt->lock);
04130 
04131       /*
04132       * If there's one already queued, don't do another
04133       */
04134 
04135       tlist = myrpt->tele.next;
04136       unkeys_queued = 0;
04137                 if (tlist != &myrpt->tele)
04138                 {
04139                         rpt_mutex_lock(&myrpt->lock);
04140                         while(tlist != &myrpt->tele){
04141                                 if (tlist->mode == UNKEY) unkeys_queued++;
04142                                 tlist = tlist->next;
04143                         }
04144                         rpt_mutex_unlock(&myrpt->lock);
04145       }
04146       if( unkeys_queued > 1){
04147          imdone = 1;
04148          break;
04149       }
04150 
04151       /* Wait for the telemetry timer to expire */
04152       /* Periodically check the timer since it can be re-initialized above */
04153       while(myrpt->unkeytocttimer)
04154       {
04155          int ctint;
04156          if(myrpt->unkeytocttimer > 100)
04157             ctint = 100;
04158          else
04159             ctint = myrpt->unkeytocttimer;
04160          ast_safe_sleep(mychannel, ctint);
04161          rpt_mutex_lock(&myrpt->lock);
04162          if(myrpt->unkeytocttimer < ctint)
04163             myrpt->unkeytocttimer = 0;
04164          else
04165             myrpt->unkeytocttimer -= ctint;
04166          rpt_mutex_unlock(&myrpt->lock);
04167       }
04168    
04169       /*
04170       * Now, the carrier on the rptr rx should be gone. 
04171       * If it re-appeared, then forget about sending the CT
04172       */
04173       if(myrpt->keyed){
04174          imdone = 1;
04175          break;
04176       }
04177       
04178       rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
04179       myrpt->dailykerchunks++;
04180       myrpt->totalkerchunks++;
04181       rpt_mutex_unlock(&myrpt->lock);
04182    
04183       haslink = 0;
04184       hastx = 0;
04185       hasremote = 0;    
04186       l = myrpt->links.next;
04187       if (l != &myrpt->links)
04188       {
04189          rpt_mutex_lock(&myrpt->lock);
04190          while(l != &myrpt->links)
04191          {
04192             if (l->name[0] == '0')
04193             {
04194                l = l->next;
04195                continue;
04196             }
04197             haslink = 1;
04198             if (l->mode) {
04199                hastx++;
04200                if (l->isremote) hasremote++;
04201             }
04202             l = l->next;
04203          }
04204          rpt_mutex_unlock(&myrpt->lock);
04205       }
04206       if (haslink)
04207       {
04208 
04209          res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
04210          if(res)
04211             ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
04212          
04213       
04214          /* if in remote cmd mode, indicate it */
04215          if (myrpt->cmdnode[0])
04216          {
04217             ast_safe_sleep(mychannel,200);
04218             res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
04219             if(res)
04220                ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
04221             ast_stopstream(mychannel);
04222          }
04223       }
04224       else if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
04225          ct_copy = ast_strdup(ct);
04226          if(ct_copy)
04227          {
04228             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04229             ast_free(ct_copy);
04230          }
04231          else
04232             res = -1;
04233          if(res)
04234             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
04235       }  
04236       if (hasremote && (!myrpt->cmdnode[0]))
04237       {
04238          /* set for all to hear */
04239          ci.chan = 0;
04240          ci.confno = myrpt->conf;
04241          ci.confmode = DAHDI_CONF_CONFANN;
04242          /* first put the channel on the conference in announce mode */
04243          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04244          {
04245             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04246             rpt_mutex_lock(&myrpt->lock);
04247             myrpt->active_telem = NULL;
04248             remque((struct qelem *)mytele);
04249             rpt_mutex_unlock(&myrpt->lock);
04250             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04251             ast_free(nodename);
04252             ast_free(ident);
04253             ast_free(mytele);    
04254             ast_hangup(mychannel);
04255             pthread_exit(NULL);
04256          }
04257          if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
04258             ast_safe_sleep(mychannel,200);
04259             ct_copy = ast_strdup(ct);
04260             if(ct_copy)
04261             {
04262                res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04263                ast_free(ct_copy);
04264             }
04265             else
04266                res = -1;
04267       
04268             if(res)
04269                ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
04270          }  
04271       }
04272 #if   defined(_MDC_DECODE_H_) && defined(MDC_SAY_WHEN_DOING_CT)
04273       if (myrpt->lastunit)
04274       {
04275          char mystr[10];
04276 
04277          ast_safe_sleep(mychannel,200);
04278          /* set for all to hear */
04279          ci.chan = 0;
04280          ci.confno = myrpt->txconf;
04281          ci.confmode = DAHDI_CONF_CONFANN;
04282          /* first put the channel on the conference in announce mode */
04283          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04284          {
04285             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04286             rpt_mutex_lock(&myrpt->lock);
04287             myrpt->active_telem = NULL;
04288             remque((struct qelem *)mytele);
04289             rpt_mutex_unlock(&myrpt->lock);
04290             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04291             ast_free(nodename);
04292             ast_free(ident);
04293             ast_free(mytele);    
04294             ast_hangup(mychannel);
04295             pthread_exit(NULL);
04296          }
04297          sprintf(mystr,"%04x",myrpt->lastunit);
04298          myrpt->lastunit = 0;
04299          ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
04300          break;
04301       }
04302 #endif
04303       imdone = 1;
04304       break;
04305        case LINKUNKEY:
04306       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
04307          imdone = 1;
04308          break;
04309       }
04310          
04311       /*
04312       * Reset the Unkey to CT timer
04313       */
04314 
04315       x = get_wait_interval(myrpt, DLY_LINKUNKEY);
04316       mytele->mylink.linkunkeytocttimer = x; /* Must be protected as it is changed below */
04317 
04318       /*
04319       * If there's one already queued, don't do another
04320       */
04321 
04322       tlist = myrpt->tele.next;
04323       unkeys_queued = 0;
04324                 if (tlist != &myrpt->tele)
04325                 {
04326                         rpt_mutex_lock(&myrpt->lock);
04327                         while(tlist != &myrpt->tele){
04328                                 if (tlist->mode == LINKUNKEY) unkeys_queued++;
04329                                 tlist = tlist->next;
04330                         }
04331                         rpt_mutex_unlock(&myrpt->lock);
04332       }
04333       if( unkeys_queued > 1){
04334          imdone = 1;
04335          break;
04336       }
04337 
04338       /* Wait for the telemetry timer to expire */
04339       /* Periodically check the timer since it can be re-initialized above */
04340       while(mytele->mylink.linkunkeytocttimer)
04341       {
04342          int ctint;
04343          if(mytele->mylink.linkunkeytocttimer > 100)
04344             ctint = 100;
04345          else
04346             ctint = mytele->mylink.linkunkeytocttimer;
04347          ast_safe_sleep(mychannel, ctint);
04348          rpt_mutex_lock(&myrpt->lock);
04349          if(mytele->mylink.linkunkeytocttimer < ctint)
04350             mytele->mylink.linkunkeytocttimer = 0;
04351          else
04352             mytele->mylink.linkunkeytocttimer -= ctint;
04353          rpt_mutex_unlock(&myrpt->lock);
04354       }
04355    
04356       if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "linkunkeyct"))){ /* Unlinked Courtesy Tone */
04357          ct_copy = ast_strdup(ct);
04358          if(ct_copy){
04359             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04360             ast_free(ct_copy);
04361          }
04362          else
04363             res = -1;
04364          if(res)
04365             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
04366       }  
04367       imdone = 1;
04368       break;
04369        case REMDISC:
04370       /* wait a little bit */
04371       wait_interval(myrpt, DLY_TELEM, mychannel);
04372       l = myrpt->links.next;
04373       haslink = 0;
04374       /* dont report if a link for this one still on system */
04375       if (l != &myrpt->links)
04376       {
04377          rpt_mutex_lock(&myrpt->lock);
04378          while(l != &myrpt->links)
04379          {
04380             if (l->name[0] == '0')
04381             {
04382                l = l->next;
04383                continue;
04384             }
04385             if (!strcmp(l->name,mytele->mylink.name))
04386             {
04387                haslink = 1;
04388                break;
04389             }
04390             l = l->next;
04391          }
04392          rpt_mutex_unlock(&myrpt->lock);
04393       }
04394       if (haslink)
04395       {
04396          imdone = 1;
04397          break;
04398       }
04399       res = saynode(myrpt,mychannel,mytele->mylink.name);
04400       if (!res) 
04401           res = ast_streamfile(mychannel, ((mytele->mylink.hasconnected) ? 
04402          "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
04403       break;
04404        case REMALREADY:
04405       /* wait a little bit */
04406       wait_interval(myrpt, DLY_TELEM, mychannel);
04407       res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
04408       break;
04409        case REMNOTFOUND:
04410       /* wait a little bit */
04411       wait_interval(myrpt, DLY_TELEM, mychannel);
04412       res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
04413       break;
04414        case REMGO:
04415       /* wait a little bit */
04416       wait_interval(myrpt, DLY_TELEM, mychannel);
04417       res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
04418       break;
04419        case CONNECTED:
04420       /* wait a little bit */
04421       wait_interval(myrpt, DLY_TELEM,  mychannel);
04422       res = saynode(myrpt,mychannel,mytele->mylink.name);
04423       if (!res)
04424           res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
04425       if (!res) 
04426          res = ast_waitstream(mychannel, "");
04427       else
04428           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04429       ast_stopstream(mychannel);
04430       res = ast_streamfile(mychannel, "digits/2", mychannel->language);
04431       if (!res) 
04432          res = ast_waitstream(mychannel, "");
04433       else
04434           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04435       ast_stopstream(mychannel);
04436       res = saynode(myrpt,mychannel,myrpt->name);
04437       imdone = 1;
04438       break;
04439        case CONNFAIL:
04440       res = saynode(myrpt,mychannel,mytele->mylink.name);
04441       if (!res) 
04442           res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
04443       break;
04444        case MEMNOTFOUND:
04445       /* wait a little bit */
04446       wait_interval(myrpt, DLY_TELEM, mychannel);
04447       res = ast_streamfile(mychannel, "rpt/memory_notfound", mychannel->language);
04448       break;
04449        case PLAYBACK:
04450       /* wait a little bit */
04451       wait_interval(myrpt, DLY_TELEM, mychannel);
04452       res = ast_streamfile(mychannel, mytele->param, mychannel->language);
04453       break;
04454        case TOPKEY:
04455       /* wait a little bit */
04456       wait_interval(myrpt, DLY_TELEM, mychannel);
04457       for(i = 0; i < TOPKEYN; i++)
04458       {
04459          if (!myrpt->topkey[i].node[0]) continue;
04460          if ((!myrpt->topkeylong) && (myrpt->topkey[i].keyed)) continue;
04461          res = saynode(myrpt, mychannel,  myrpt->topkey[i].node);
04462          if (!res) res = sayfile(mychannel,(myrpt->topkey[i].keyed) ?
04463             "rpt/keyedfor" : "rpt/unkeyedfor");
04464          if (!res) res = saynum(mychannel,
04465             myrpt->topkey[i].timesince);
04466          if (!res) res = sayfile(mychannel,"rpt/seconds");
04467          if (!myrpt->topkeylong) break;
04468       }
04469       imdone = 1;
04470       break;
04471        case SETREMOTE:
04472       ast_mutex_lock(&myrpt->remlock);
04473       res = 0;
04474       if(!strcmp(myrpt->remoterig, remote_rig_ft897))
04475       {
04476          res = set_ft897(myrpt);
04477       }
04478       else if(!strcmp(myrpt->remoterig, remote_rig_tm271))
04479       {
04480          res = set_tm271(myrpt);
04481       }
04482       else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
04483       {
04484          res = set_ic706(myrpt);
04485       }
04486 #ifdef HAVE_IOPERM
04487       else if(!strcmp(myrpt->remoterig, remote_rig_rbi)||!strcmp(myrpt->remoterig, remote_rig_ppp16))
04488       {
04489          if (ioperm(myrpt->p.iobase,1,1) == -1)
04490          {
04491             rpt_mutex_unlock(&myrpt->lock);
04492             ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
04493             res = -1;
04494          }
04495          else res = setrbi(myrpt);
04496       }
04497 #endif
04498       else if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
04499       {
04500          if (myrpt->iofd >= 0) setdtr(myrpt->iofd,1);
04501          res = setkenwood(myrpt);
04502          if (myrpt->iofd >= 0) setdtr(myrpt->iofd,0);
04503          if (ast_safe_sleep(mychannel,200) == -1)
04504          {
04505             ast_mutex_unlock(&myrpt->remlock);
04506             res = -1;
04507             break;
04508          }
04509          if (myrpt->iofd < 0)
04510          {
04511             i = DAHDI_FLUSH_EVENT;
04512             if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_FLUSH,&i) == -1)
04513             {
04514                ast_mutex_unlock(&myrpt->remlock);
04515                ast_log(LOG_ERROR,"Cant flush events");
04516                res = -1;
04517                break;
04518             }
04519             if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_GET_PARAMS,&par) == -1)
04520             {
04521                ast_mutex_unlock(&myrpt->remlock);
04522                ast_log(LOG_ERROR,"Cant get params");
04523                res = -1;
04524                break;
04525             }
04526             myrpt->remoterx = 
04527                (par.rxisoffhook || (myrpt->tele.next != &myrpt->tele));
04528          }
04529       }
04530 
04531       ast_mutex_unlock(&myrpt->remlock);
04532       if (!res)
04533       {
04534          imdone = 1;
04535          break;
04536       }
04537       /* fall thru to invalid freq */
04538        case INVFREQ:
04539       /* wait a little bit */
04540       wait_interval(myrpt, DLY_TELEM, mychannel);
04541       res = ast_streamfile(mychannel, "rpt/invalid-freq", mychannel->language);
04542       break;
04543        case REMMODE:
04544       cp = 0;
04545       wait_interval(myrpt, DLY_TELEM, mychannel);
04546       switch(myrpt->remmode)
04547       {
04548           case REM_MODE_FM:
04549          saycharstr(mychannel,"FM");
04550          break;
04551           case REM_MODE_USB:
04552          saycharstr(mychannel,"USB");
04553          break;
04554           case REM_MODE_LSB:
04555          saycharstr(mychannel,"LSB");
04556          break;
04557           case REM_MODE_AM:
04558          saycharstr(mychannel,"AM");
04559          break;
04560       }
04561       wait_interval(myrpt, DLY_COMP, mychannel);
04562       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04563       break;
04564        case LOGINREQ:
04565       wait_interval(myrpt, DLY_TELEM, mychannel);
04566       sayfile(mychannel,"rpt/login");
04567       saycharstr(mychannel,myrpt->name);
04568       break;
04569        case REMLOGIN:
04570       wait_interval(myrpt, DLY_TELEM, mychannel);
04571       saycharstr(mychannel,myrpt->loginuser);
04572       saynode(myrpt,mychannel,myrpt->name);
04573       wait_interval(myrpt, DLY_COMP, mychannel);
04574       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04575       break;
04576        case REMXXX:
04577       wait_interval(myrpt, DLY_TELEM, mychannel);
04578       res = 0;
04579       switch(mytele->submode)
04580       {
04581           case 100: /* RX PL Off */
04582          sayfile(mychannel, "rpt/rxpl");
04583          sayfile(mychannel, "rpt/off");
04584          break;
04585           case 101: /* RX PL On */
04586          sayfile(mychannel, "rpt/rxpl");
04587          sayfile(mychannel, "rpt/on");
04588          break;
04589           case 102: /* TX PL Off */
04590          sayfile(mychannel, "rpt/txpl");
04591          sayfile(mychannel, "rpt/off");
04592          break;
04593           case 103: /* TX PL On */
04594          sayfile(mychannel, "rpt/txpl");
04595          sayfile(mychannel, "rpt/on");
04596          break;
04597           case 104: /* Low Power */
04598          sayfile(mychannel, "rpt/lopwr");
04599          break;
04600           case 105: /* Medium Power */
04601          sayfile(mychannel, "rpt/medpwr");
04602          break;
04603           case 106: /* Hi Power */
04604          sayfile(mychannel, "rpt/hipwr");
04605          break;
04606           case 113: /* Scan down slow */
04607          sayfile(mychannel,"rpt/down");
04608          sayfile(mychannel, "rpt/slow");
04609          break;
04610           case 114: /* Scan down quick */
04611          sayfile(mychannel,"rpt/down");
04612          sayfile(mychannel, "rpt/quick");
04613          break;
04614           case 115: /* Scan down fast */
04615          sayfile(mychannel,"rpt/down");
04616          sayfile(mychannel, "rpt/fast");
04617          break;
04618           case 116: /* Scan up slow */
04619          sayfile(mychannel,"rpt/up");
04620          sayfile(mychannel, "rpt/slow");
04621          break;
04622           case 117: /* Scan up quick */
04623          sayfile(mychannel,"rpt/up");
04624          sayfile(mychannel, "rpt/quick");
04625          break;
04626           case 118: /* Scan up fast */
04627          sayfile(mychannel,"rpt/up");
04628          sayfile(mychannel, "rpt/fast");
04629          break;
04630           default:
04631          res = -1;
04632       }
04633       wait_interval(myrpt, DLY_COMP, mychannel);
04634       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04635       break;
04636        case SCAN:
04637       ast_mutex_lock(&myrpt->remlock);
04638       if (myrpt->hfscanstop)
04639       {
04640          myrpt->hfscanstatus = 0;
04641          myrpt->hfscanmode = 0;
04642          myrpt->hfscanstop = 0;
04643          mytele->mode = SCANSTAT;
04644          ast_mutex_unlock(&myrpt->remlock);
04645          if (ast_safe_sleep(mychannel,1000) == -1) break;
04646          sayfile(mychannel, "rpt/stop"); 
04647          imdone = 1;
04648          break;
04649       }
04650       if (myrpt->hfscanstatus > -2) service_scan(myrpt);
04651       i = myrpt->hfscanstatus;
04652       myrpt->hfscanstatus = 0;
04653       if (i) mytele->mode = SCANSTAT;
04654       ast_mutex_unlock(&myrpt->remlock);
04655       if (i < 0) sayfile(mychannel, "rpt/stop"); 
04656       else if (i > 0) saynum(mychannel,i);
04657       imdone = 1;
04658       break;
04659        case TUNE:
04660       ast_mutex_lock(&myrpt->remlock);
04661       if (!strcmp(myrpt->remoterig,remote_rig_ic706))
04662       {
04663          set_mode_ic706(myrpt, REM_MODE_AM);
04664          if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
04665          ast_safe_sleep(mychannel,500);
04666          set_mode_ic706(myrpt, myrpt->remmode);
04667          myrpt->tunerequest = 0;
04668          ast_mutex_unlock(&myrpt->remlock);
04669          imdone = 1;
04670          break;
04671       }
04672       set_mode_ft897(myrpt, REM_MODE_AM);
04673       simple_command_ft897(myrpt, 8);
04674       if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
04675       simple_command_ft897(myrpt, 0x88);
04676       ast_safe_sleep(mychannel,500);
04677       set_mode_ft897(myrpt, myrpt->remmode);
04678       myrpt->tunerequest = 0;
04679       ast_mutex_unlock(&myrpt->remlock);
04680       imdone = 1;
04681       break;
04682        case REMSHORTSTATUS:
04683        case REMLONGSTATUS: 
04684       wait_interval(myrpt, DLY_TELEM, mychannel);
04685       res = saynode(myrpt,mychannel,myrpt->name);
04686       if(!res)
04687          res = sayfile(mychannel,"rpt/frequency");
04688       if(!res)
04689          res = split_freq(mhz, decimals, myrpt->freq);
04690       if (!multimode_capable(myrpt)) decimals[3] = 0;
04691       if(!res){
04692          m = atoi(mhz);
04693          if(m < 100)
04694             res = saynum(mychannel, m);
04695          else
04696             res = saycharstr(mychannel, mhz);
04697       }
04698       if(!res)
04699          res = sayfile(mychannel, "letters/dot");
04700       if(!res)
04701          res = saycharstr(mychannel, decimals);
04702    
04703       if(res)  break;
04704       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
04705          switch(myrpt->offset){
04706    
04707             case REM_MINUS:
04708                res = sayfile(mychannel,"rpt/minus");
04709                break;
04710             
04711             case REM_SIMPLEX:
04712                res = sayfile(mychannel,"rpt/simplex");
04713                break;
04714                
04715             case REM_PLUS:
04716                res = sayfile(mychannel,"rpt/plus");
04717                break;
04718                
04719             default:
04720                break;
04721          }
04722       }
04723       else{ /* Must be USB, LSB, or AM */
04724          switch(myrpt->remmode){
04725 
04726             case REM_MODE_USB:
04727                res = saycharstr(mychannel, "USB");
04728                break;
04729 
04730             case REM_MODE_LSB:
04731                res = saycharstr(mychannel, "LSB");
04732                break;
04733 
04734             case REM_MODE_AM:
04735                res = saycharstr(mychannel, "AM");
04736                break;
04737 
04738 
04739             default:
04740                break;
04741          }
04742       }
04743 
04744       if (res == -1) break;
04745 
04746       if(mytele->mode == REMSHORTSTATUS){ /* Short status? */
04747          wait_interval(myrpt, DLY_COMP, mychannel);
04748          if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04749          break;
04750       }
04751 
04752       if (strcmp(myrpt->remoterig,remote_rig_ic706))
04753       {
04754          switch(myrpt->powerlevel){
04755 
04756             case REM_LOWPWR:
04757                res = sayfile(mychannel,"rpt/lopwr") ;
04758                break;
04759             case REM_MEDPWR:
04760                res = sayfile(mychannel,"rpt/medpwr");
04761                break;
04762             case REM_HIPWR:
04763                res = sayfile(mychannel,"rpt/hipwr"); 
04764                break;
04765             }
04766       }
04767 
04768       rbimode = ((!strncmp(myrpt->remoterig,remote_rig_rbi,3))
04769         || (!strncmp(myrpt->remoterig,remote_rig_ic706,3)));
04770       if (res || (sayfile(mychannel,"rpt/rxpl") == -1)) break;
04771       if (rbimode && (sayfile(mychannel,"rpt/txpl") == -1)) break;
04772       if ((sayfile(mychannel,"rpt/frequency") == -1) ||
04773          (saycharstr(mychannel,myrpt->rxpl) == -1)) break;
04774       if ((!rbimode) && ((sayfile(mychannel,"rpt/txpl") == -1) ||
04775          (sayfile(mychannel,"rpt/frequency") == -1) ||
04776          (saycharstr(mychannel,myrpt->txpl) == -1))) break;
04777       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
04778          if ((sayfile(mychannel,"rpt/rxpl") == -1) ||
04779             (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1) ||
04780             (sayfile(mychannel,"rpt/txpl") == -1) ||
04781             (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1))
04782             {
04783                break;
04784             }
04785       }
04786       wait_interval(myrpt, DLY_COMP, mychannel);
04787       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04788       break;
04789        case STATUS:
04790       /* wait a little bit */
04791       wait_interval(myrpt, DLY_TELEM, mychannel);
04792       hastx = 0;
04793       linkbase.next = &linkbase;
04794       linkbase.prev = &linkbase;
04795       rpt_mutex_lock(&myrpt->lock);
04796       /* make our own list of links */
04797       l = myrpt->links.next;
04798       while(l != &myrpt->links)
04799       {
04800          if (l->name[0] == '0')
04801          {
04802             l = l->next;
04803             continue;
04804          }
04805          l1 = ast_malloc(sizeof(struct rpt_link));
04806          if (!l1)
04807          {
04808             ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
04809             remque((struct qelem *)mytele);
04810             myrpt->active_telem = NULL;
04811             rpt_mutex_unlock(&myrpt->lock);
04812             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04813             ast_free(nodename);
04814             ast_free(ident);
04815             ast_free(mytele);    
04816             ast_hangup(mychannel);
04817             pthread_exit(NULL);
04818          }
04819          memcpy(l1,l,sizeof(struct rpt_link));
04820          l1->next = l1->prev = NULL;
04821          insque((struct qelem *)l1,(struct qelem *)linkbase.next);
04822          l = l->next;
04823       }
04824       rpt_mutex_unlock(&myrpt->lock);
04825       res = saynode(myrpt,mychannel,myrpt->name);
04826       if (myrpt->callmode)
04827       {
04828          hastx = 1;
04829          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
04830          if (!res) 
04831             res = ast_waitstream(mychannel, "");
04832          else
04833              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04834          ast_stopstream(mychannel);
04835       }
04836       l = linkbase.next;
04837       while(l != &linkbase)
04838       {
04839          char *s;
04840 
04841          hastx = 1;
04842          res = saynode(myrpt,mychannel,l->name);
04843          s = "rpt/tranceive";
04844          if (!l->mode) s = "rpt/monitor";
04845          if (!l->thisconnected) s = "rpt/connecting";
04846          res = ast_streamfile(mychannel, s, mychannel->language);
04847          if (!res) 
04848             res = ast_waitstream(mychannel, "");
04849          else
04850             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04851          ast_stopstream(mychannel);
04852          l = l->next;
04853       }        
04854       if (!hastx)
04855       {
04856          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
04857          if (!res) 
04858             res = ast_waitstream(mychannel, "");
04859          else
04860              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04861          ast_stopstream(mychannel);
04862       }
04863       /* destroy our local link queue */
04864       l = linkbase.next;
04865       while(l != &linkbase)
04866       {
04867          l1 = l;
04868          l = l->next;
04869          remque((struct qelem *)l1);
04870          ast_free(l1);
04871       }        
04872       imdone = 1;
04873       break;
04874        case FULLSTATUS:
04875       rpt_mutex_lock(&myrpt->lock);
04876       /* get all the nodes */
04877       __mklinklist(myrpt,NULL,lbuf);
04878       rpt_mutex_unlock(&myrpt->lock);
04879       /* parse em */
04880       ns = finddelim(lbuf,strs,MAXLINKLIST);
04881       /* sort em */
04882       if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
04883       /* wait a little bit */
04884       wait_interval(myrpt, DLY_TELEM, mychannel);
04885       hastx = 0;
04886       res = saynode(myrpt,mychannel,myrpt->name);
04887       if (myrpt->callmode)
04888       {
04889          hastx = 1;
04890          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
04891          if (!res) 
04892             res = ast_waitstream(mychannel, "");
04893          else
04894              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04895          ast_stopstream(mychannel);
04896       }
04897       /* go thru all the nodes in list */
04898       for(i = 0; i < ns; i++)
04899       {
04900          char *s,mode = 'T';
04901 
04902          /* if a mode spec at first, handle it */
04903          if ((*strs[i] < '0') || (*strs[i] > '9'))
04904          {
04905             mode = *strs[i];
04906             strs[i]++;
04907          }
04908 
04909          hastx = 1;
04910          res = saynode(myrpt,mychannel,strs[i]);
04911          s = "rpt/tranceive";
04912          if (mode == 'R') s = "rpt/monitor";
04913          if (mode == 'C') s = "rpt/connecting";
04914          res = ast_streamfile(mychannel, s, mychannel->language);
04915          if (!res) 
04916             res = ast_waitstream(mychannel, "");
04917          else
04918             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04919          ast_stopstream(mychannel);
04920       }        
04921       if (!hastx)
04922       {
04923          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
04924          if (!res) 
04925             res = ast_waitstream(mychannel, "");
04926          else
04927              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04928          ast_stopstream(mychannel);
04929       }
04930       imdone = 1;
04931       break;
04932 
04933        case LASTNODEKEY: /* Identify last node which keyed us up */
04934       rpt_mutex_lock(&myrpt->lock);
04935       if(myrpt->lastnodewhichkeyedusup){
04936          p = ast_strdup(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
04937          if(!p){
04938             ast_log(LOG_WARNING, "ast_strdup failed in telemetery LASTNODEKEY");
04939             imdone = 1;
04940             break;
04941          }
04942       }
04943       else
04944          p = NULL;
04945       rpt_mutex_unlock(&myrpt->lock);
04946       if(!p){
04947          imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
04948          break;
04949       }
04950       wait_interval(myrpt, DLY_TELEM, mychannel);
04951       res = saynode(myrpt,mychannel,p);
04952       ast_free(p);
04953       imdone = 1;
04954       break;      
04955 
04956        case UNAUTHTX: /* Say unauthorized transmit frequency */
04957       wait_interval(myrpt, DLY_TELEM, mychannel);
04958       res = ast_streamfile(mychannel, "rpt/unauthtx", mychannel->language);
04959       if (!res) 
04960          res = ast_waitstream(mychannel, "");
04961       else
04962           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04963       ast_stopstream(mychannel);
04964       imdone = 1;
04965       break;
04966 
04967        case PARROT: /* Repeat stuff */
04968 
04969       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04970       if (ast_fileexists(mystr,NULL,mychannel->language) <= 0)
04971       {
04972          imdone = 1;
04973          myrpt->parrotstate = 0;
04974          break;
04975       }
04976       wait_interval(myrpt, DLY_PARROT, mychannel);
04977       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04978       res = ast_streamfile(mychannel, mystr, mychannel->language);
04979       if (!res) 
04980          res = ast_waitstream(mychannel, "");
04981       else
04982           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04983       ast_stopstream(mychannel);
04984       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04985       strcat(mystr,".wav");
04986       unlink(mystr);       
04987       imdone = 1;
04988       myrpt->parrotstate = 0;
04989       break;
04990 
04991        case TIMEOUT:
04992       res = saynode(myrpt,mychannel,myrpt->name);
04993       if (!res)
04994          res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
04995       break;
04996       
04997        case TIMEOUT_WARNING:
04998       time(&t);
04999       res = saynode(myrpt,mychannel,myrpt->name);
05000       if (!res)
05001          res = ast_streamfile(mychannel, "rpt/timeout-warning", mychannel->language);
05002       if (!res) 
05003          res = ast_waitstream(mychannel, "");
05004       else
05005           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05006       ast_stopstream(mychannel);
05007       if(!res) /* Say number of seconds */
05008          ast_say_number(mychannel, myrpt->p.remotetimeout - 
05009              (t - myrpt->last_activity_time), 
05010             "", mychannel->language, (char *) NULL);
05011       if (!res) 
05012          res = ast_waitstream(mychannel, "");
05013       ast_stopstream(mychannel); 
05014       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
05015       break;
05016 
05017        case ACT_TIMEOUT_WARNING:
05018       time(&t);
05019       res = saynode(myrpt,mychannel,myrpt->name);
05020       if (!res)
05021           res = ast_streamfile(mychannel, "rpt/act-timeout-warning", mychannel->language);
05022       if (!res) 
05023          res = ast_waitstream(mychannel, "");
05024       else
05025           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05026       ast_stopstream(mychannel);
05027       if(!res) /* Say number of seconds */
05028          ast_say_number(mychannel, myrpt->p.remoteinacttimeout - 
05029              (t - myrpt->last_activity_time), 
05030             "", mychannel->language, (char *) NULL);
05031       if (!res) 
05032          res = ast_waitstream(mychannel, "");
05033       ast_stopstream(mychannel); 
05034       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
05035       break;
05036       
05037        case STATS_TIME:
05038             case STATS_TIME_LOCAL:
05039          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05040       t = time(NULL);
05041       rpt_localtime(&t, &localtm);
05042       /* Say the phase of the day is before the time */
05043       if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
05044          p = "rpt/goodmorning";
05045       else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
05046          p = "rpt/goodafternoon";
05047       else
05048          p = "rpt/goodevening";
05049       if (sayfile(mychannel,p) == -1)
05050       {
05051          imdone = 1;
05052          break;
05053       }
05054       /* Say the time is ... */     
05055       if (sayfile(mychannel,"rpt/thetimeis") == -1)
05056       {
05057          imdone = 1;
05058          break;
05059       }
05060       /* Say the time */            
05061          res = ast_say_time(mychannel, t, "", mychannel->language);
05062       if (!res) 
05063          res = ast_waitstream(mychannel, "");
05064       ast_stopstream(mychannel);    
05065       imdone = 1;
05066          break;
05067        case STATS_VERSION:
05068       p = strstr(tdesc, "version"); 
05069       if(!p)
05070          break;   
05071       if(sscanf(p, "version %30d.%30d", &vmajor, &vminor) != 2)
05072          break;
05073          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05074       /* Say "version" */
05075       if (sayfile(mychannel,"rpt/version") == -1)
05076       {
05077          imdone = 1;
05078          break;
05079       }
05080       if(!res) /* Say "X" */
05081          ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
05082       if (!res) 
05083          res = ast_waitstream(mychannel, "");
05084       ast_stopstream(mychannel); 
05085       if (saycharstr(mychannel,".") == -1)
05086       {
05087          imdone = 1;
05088          break;
05089       }
05090       if(!res) /* Say "Y" */
05091          ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
05092       if (!res){
05093          res = ast_waitstream(mychannel, "");
05094          ast_stopstream(mychannel);
05095       }  
05096       else
05097           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05098       imdone = 1;
05099          break;
05100        case ARB_ALPHA:
05101          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05102          if(mytele->param)
05103             saycharstr(mychannel, mytele->param);
05104          imdone = 1;
05105       break;
05106        case REV_PATCH:
05107          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05108          if(mytele->param) {
05109 
05110          /* Parts of this section taken from app_parkandannounce */
05111          char *tpl_working, *tpl_current;
05112          char *tmp[100], *myparm;
05113          int looptemp=0,idx=0, dres = 0;
05114    
05115 
05116          tpl_working = ast_strdup(mytele->param);
05117          myparm = strsep(&tpl_working,",");
05118          tpl_current=strsep(&tpl_working, ":");
05119 
05120          while(tpl_current && looptemp < sizeof(tmp)) {
05121             tmp[looptemp]=tpl_current;
05122             looptemp++;
05123             tpl_current=strsep(&tpl_working,":");
05124          }
05125 
05126          for(idx=0; idx<looptemp; idx++) {
05127             if(!strcmp(tmp[idx], "PARKED")) {
05128                ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
05129             } else if(!strcmp(tmp[idx], "NODE")) {
05130                ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
05131             } else {
05132                dres = ast_streamfile(mychannel, tmp[idx], mychannel->language);
05133                if(!dres) {
05134                   dres = ast_waitstream(mychannel, "");
05135                } else {
05136                   ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[idx], mychannel->name);
05137                   dres = 0;
05138                }
05139             }
05140          }
05141          ast_free(tpl_working);
05142       }
05143          imdone = 1;
05144       break;
05145        case TEST_TONE:
05146       imdone = 1;
05147       if (myrpt->stopgen) break;
05148       myrpt->stopgen = -1;
05149            if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
05150       {
05151          myrpt->stopgen = 0;
05152          break;
05153       }
05154            while(mychannel->generatordata && (myrpt->stopgen <= 0)) {
05155          if (ast_safe_sleep(mychannel,1)) break;
05156             imdone = 1;
05157          }
05158       myrpt->stopgen = 0;
05159       break;
05160        default:
05161          break;
05162    }
05163    if (!imdone)
05164    {
05165       if (!res) 
05166          res = ast_waitstream(mychannel, "");
05167       else {
05168          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05169          res = 0;
05170       }
05171    }
05172    ast_stopstream(mychannel);
05173    rpt_mutex_lock(&myrpt->lock);
05174    if (mytele->mode == TAILMSG)
05175    {
05176       if (!res)
05177       {
05178          myrpt->tailmessagen++;
05179          if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
05180       }
05181       else
05182       {
05183          myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
05184       }
05185    }
05186    remque((struct qelem *)mytele);
05187    myrpt->active_telem = NULL;
05188    rpt_mutex_unlock(&myrpt->lock);
05189    ast_free(nodename);
05190    ast_free(ident);
05191    ast_free(mytele);    
05192    ast_hangup(mychannel);
05193 #ifdef  APP_RPT_LOCK_DEBUG
05194    {
05195       struct lockthread *t;
05196 
05197       sleep(5);
05198       ast_mutex_lock(&locklock);
05199       t = get_lockthread(pthread_self());
05200       if (t) memset(t,0,sizeof(struct lockthread));
05201       ast_mutex_unlock(&locklock);
05202    }        
05203 #endif
05204    pthread_exit(NULL);
05205 }
05206 
05207 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
05208 {
05209 struct rpt_tele *tele;
05210 struct rpt_link *mylink = NULL;
05211 int res;
05212 pthread_attr_t attr;
05213 char *v1, *v2;
05214 
05215    if(debug > 6)
05216       ast_log(LOG_NOTICE,"mode=%i  data=%s\n",mode, (char *)data);
05217 
05218    switch(mode)
05219    {
05220        case UNKEY:
05221       /* if any of the following are defined, go ahead and do it,
05222          otherwise, dont bother */
05223       v1 = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, 
05224          "unlinkedct");
05225       v2 = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, 
05226          "remotect");
05227       if (telem_lookup(myrpt,NULL, myrpt->name, "remotemon") &&
05228         telem_lookup(myrpt,NULL, myrpt->name, "remotetx") &&
05229         telem_lookup(myrpt,NULL, myrpt->name, "cmdmode") &&
05230         (!(v1 && telem_lookup(myrpt,NULL, myrpt->name, v1))) && 
05231         (!(v2 && telem_lookup(myrpt,NULL, myrpt->name, v2)))) return;
05232       break;
05233        case LINKUNKEY:
05234       if (!ast_variable_retrieve(myrpt->cfg, myrpt->name, "linkunkeyct"))
05235          return;
05236       break;
05237        default:
05238       break;
05239    }
05240    tele = ast_malloc(sizeof(struct rpt_tele));
05241    if (!tele)
05242    {
05243       ast_log(LOG_WARNING, "Unable to allocate memory\n");
05244       pthread_exit(NULL);
05245       return;
05246    }
05247    /* zero it out */
05248    memset((char *)tele,0,sizeof(struct rpt_tele));
05249    tele->rpt = myrpt;
05250    tele->mode = mode;
05251    if (mode == PARROT) tele->parrot = (uintptr_t) data;
05252    else mylink = (struct rpt_link *) data;
05253    rpt_mutex_lock(&myrpt->lock);
05254    if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED) ||
05255        (mode == LINKUNKEY)){
05256       memset(&tele->mylink,0,sizeof(struct rpt_link));
05257       if (mylink){
05258          memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
05259       }
05260    }
05261    else if ((mode == ARB_ALPHA) || (mode == REV_PATCH) || (mode == PLAYBACK)) {
05262       strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
05263       tele->param[TELEPARAMSIZE - 1] = 0;
05264    }
05265    if (mode == REMXXX) tele->submode = (intptr_t) data;
05266    insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
05267    rpt_mutex_unlock(&myrpt->lock);
05268         pthread_attr_init(&attr);
05269         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05270    res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
05271    if(res < 0){
05272       rpt_mutex_lock(&myrpt->lock);
05273       remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
05274       rpt_mutex_unlock(&myrpt->lock);  
05275       ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
05276    }
05277    return;
05278 }
05279 
05280 static void *rpt_call(void *this)
05281 {
05282 struct dahdi_confinfo ci;  /* conference info */
05283 struct   rpt *myrpt = (struct rpt *)this;
05284 int   res;
05285 int stopped,congstarted,dialtimer,lastcidx,aborted;
05286 struct ast_channel *mychannel,*genchannel;
05287 
05288    myrpt->mydtmf = 0;
05289    /* allocate a pseudo-channel thru asterisk */
05290    mychannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
05291    if (!mychannel)
05292    {
05293       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
05294       pthread_exit(NULL);
05295    }
05296 #ifdef   AST_CDR_FLAG_POST_DISABLED
05297    if (mychannel->cdr)
05298       ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
05299 #endif
05300    ci.chan = 0;
05301    ci.confno = myrpt->conf; /* use the pseudo conference */
05302 #if   0
05303    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
05304       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
05305 #endif
05306    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
05307    /* first put the channel on the conference */
05308    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05309    {
05310       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05311       ast_hangup(mychannel);
05312       myrpt->callmode = 0;
05313       pthread_exit(NULL);
05314    }
05315    /* allocate a pseudo-channel thru asterisk */
05316    genchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
05317    if (!genchannel)
05318    {
05319       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
05320       ast_hangup(mychannel);
05321       pthread_exit(NULL);
05322    }
05323 #ifdef   AST_CDR_FLAG_POST_DISABLED
05324    if (genchannel->cdr)
05325       ast_set_flag(genchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
05326 #endif
05327    ci.chan = 0;
05328    ci.confno = myrpt->conf;
05329    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
05330       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
05331    /* first put the channel on the conference */
05332    if (ioctl(genchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05333    {
05334       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05335       ast_hangup(mychannel);
05336       ast_hangup(genchannel);
05337       myrpt->callmode = 0;
05338       pthread_exit(NULL);
05339    }
05340    if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
05341    {
05342       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
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(genchannel->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    /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
05357    if ((!myrpt->patchquiet) && (tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_DIALTONE) < 0))
05358    {
05359       ast_log(LOG_WARNING, "Cannot start dialtone\n");
05360       ast_hangup(mychannel);
05361       ast_hangup(genchannel);
05362       myrpt->callmode = 0;
05363       pthread_exit(NULL);
05364    }
05365    stopped = 0;
05366    congstarted = 0;
05367    dialtimer = 0;
05368    lastcidx = 0;
05369    myrpt->calldigittimer = 0;
05370    aborted = 0;
05371 
05372    while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
05373    {
05374       if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
05375          dialtimer = 0;
05376          lastcidx = myrpt->cidx;
05377       }     
05378 
05379       if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){ 
05380           if(debug)
05381             ast_log(LOG_NOTICE, "dialtimer %i > patchdialtime %i\n", dialtimer,myrpt->patchdialtime);
05382          rpt_mutex_lock(&myrpt->lock);
05383          aborted = 1;
05384          myrpt->callmode = 0;
05385          rpt_mutex_unlock(&myrpt->lock);
05386          break;
05387       }
05388    
05389       if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
05390       {
05391          stopped = 1;
05392          /* stop dial tone */
05393          tone_zone_play_tone(genchannel->fds[0],-1);
05394       }
05395       if (myrpt->callmode == 1)
05396       {
05397          if(myrpt->calldigittimer > PATCH_DIALPLAN_TIMEOUT)
05398          {
05399             myrpt->callmode = 2;
05400             break;
05401          }
05402          /* bump timer if active */
05403          if (myrpt->calldigittimer) 
05404             myrpt->calldigittimer += MSWAIT;
05405       }
05406       if (myrpt->callmode == 4)
05407       {
05408          if(!congstarted){
05409             congstarted = 1;
05410             /* start congestion tone */
05411             tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
05412          }
05413       }
05414       res = ast_safe_sleep(mychannel, MSWAIT);
05415       if (res < 0)
05416       {
05417           if(debug)
05418             ast_log(LOG_NOTICE, "ast_safe_sleep=%i\n", res);
05419          ast_hangup(mychannel);
05420          ast_hangup(genchannel);
05421          rpt_mutex_lock(&myrpt->lock);
05422          myrpt->callmode = 0;
05423          rpt_mutex_unlock(&myrpt->lock);
05424          pthread_exit(NULL);
05425       }
05426       dialtimer += MSWAIT;
05427    }
05428    /* stop any tone generation */
05429    tone_zone_play_tone(genchannel->fds[0],-1);
05430    /* end if done */
05431    if (!myrpt->callmode)
05432    {
05433       if(debug)
05434          ast_log(LOG_NOTICE, "callmode==0\n");
05435       ast_hangup(mychannel);
05436       ast_hangup(genchannel);
05437       rpt_mutex_lock(&myrpt->lock);
05438       myrpt->callmode = 0;
05439       myrpt->macropatch=0;
05440       channel_revert(myrpt);
05441       rpt_mutex_unlock(&myrpt->lock);
05442       if((!myrpt->patchquiet) && aborted)
05443          rpt_telemetry(myrpt, TERM, NULL);
05444       pthread_exit(NULL);        
05445    }
05446 
05447    if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
05448       char *name, *loc, *instr;
05449       instr = ast_strdup(myrpt->p.ourcallerid);
05450       if(instr){
05451          ast_callerid_parse(instr, &name, &loc);
05452          if(loc){
05453             if(mychannel->cid.cid_num)
05454                ast_free(mychannel->cid.cid_num);
05455             mychannel->cid.cid_num = ast_strdup(loc);
05456          }
05457          if(name){
05458             if(mychannel->cid.cid_name)
05459                ast_free(mychannel->cid.cid_name);
05460             mychannel->cid.cid_name = ast_strdup(name);
05461          }
05462          ast_free(instr);
05463       }
05464    }
05465 
05466    ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
05467    ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
05468    
05469    if (myrpt->p.acctcode)
05470       ast_cdr_setaccount(mychannel,myrpt->p.acctcode);
05471    mychannel->priority = 1;
05472    ast_channel_undefer_dtmf(mychannel);
05473    if (ast_pbx_start(mychannel) < 0)
05474    {
05475       ast_log(LOG_WARNING, "Unable to start PBX!!\n");
05476       ast_hangup(mychannel);
05477       ast_hangup(genchannel);
05478       rpt_mutex_lock(&myrpt->lock);
05479       myrpt->callmode = 0;
05480       rpt_mutex_unlock(&myrpt->lock);
05481       pthread_exit(NULL);
05482    }
05483    usleep(10000);
05484    rpt_mutex_lock(&myrpt->lock);
05485    myrpt->callmode = 3;
05486    /* set appropriate conference for the pseudo */
05487    ci.chan = 0;
05488    ci.confno = myrpt->conf;
05489    ci.confmode = (myrpt->p.duplex == 2) ? DAHDI_CONF_CONFANNMON :
05490       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
05491    /* first put the channel on the conference in announce mode */
05492    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05493    {
05494       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05495       ast_hangup(mychannel);
05496       ast_hangup(genchannel);
05497       myrpt->callmode = 0;
05498       pthread_exit(NULL);
05499    }
05500    /* get its channel number */
05501    if (ioctl(mychannel->fds[0],DAHDI_CHANNO,&res) == -1)
05502    {
05503       ast_log(LOG_WARNING, "Unable to get autopatch channel number\n");
05504       ast_hangup(mychannel);
05505       myrpt->callmode = 0;
05506       pthread_exit(NULL);
05507    }
05508    ci.chan = 0;
05509    ci.confno = res;
05510    ci.confmode = DAHDI_CONF_MONITOR;
05511    /* put vox channel monitoring on the channel  */
05512    if (ioctl(myrpt->voxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05513    {
05514       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05515       ast_hangup(mychannel);
05516       myrpt->callmode = 0;
05517       pthread_exit(NULL);
05518    }
05519    while(myrpt->callmode)
05520    {
05521       if ((!mychannel->pbx) && (myrpt->callmode != 4))
05522       {
05523           /* If patch is setup for far end disconnect */
05524          if(myrpt->patchfarenddisconnect || (myrpt->p.duplex < 2)){ 
05525             if(debug)ast_log(LOG_NOTICE,"callmode=%i, patchfarenddisconnect=%i, duplex=%i\n",\
05526                   myrpt->callmode,myrpt->patchfarenddisconnect,myrpt->p.duplex);
05527             myrpt->callmode = 0;
05528             myrpt->macropatch=0;
05529             if(!myrpt->patchquiet){
05530                rpt_mutex_unlock(&myrpt->lock);
05531                rpt_telemetry(myrpt, TERM, NULL);
05532                rpt_mutex_lock(&myrpt->lock);
05533             }
05534          }
05535          else{ /* Send congestion until patch is downed by command */
05536             myrpt->callmode = 4;
05537             rpt_mutex_unlock(&myrpt->lock);
05538             /* start congestion tone */
05539             tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
05540             rpt_mutex_lock(&myrpt->lock);
05541          }
05542       }
05543       if (myrpt->mydtmf)
05544       {
05545          struct ast_frame wf = {AST_FRAME_DTMF, } ;
05546          wf.subclass = myrpt->mydtmf;
05547          rpt_mutex_unlock(&myrpt->lock);
05548          ast_queue_frame(mychannel,&wf);
05549 #ifdef   NEW_ASTERISK
05550          ast_senddigit(genchannel,myrpt->mydtmf,0);
05551 #else
05552          ast_senddigit(genchannel,myrpt->mydtmf);
05553 #endif
05554          rpt_mutex_lock(&myrpt->lock);
05555          myrpt->mydtmf = 0;
05556       }
05557       rpt_mutex_unlock(&myrpt->lock);
05558       usleep(MSWAIT * 1000);
05559       rpt_mutex_lock(&myrpt->lock);
05560    }
05561    if(debug)
05562       ast_log(LOG_NOTICE, "exit channel loop\n");
05563    rpt_mutex_unlock(&myrpt->lock);
05564    tone_zone_play_tone(genchannel->fds[0],-1);
05565    if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
05566    ast_hangup(genchannel);
05567    rpt_mutex_lock(&myrpt->lock);
05568    myrpt->callmode = 0;
05569    myrpt->macropatch=0;
05570    channel_revert(myrpt);
05571    rpt_mutex_unlock(&myrpt->lock);
05572    /* set appropriate conference for the pseudo */
05573    ci.chan = 0;
05574    ci.confno = myrpt->conf;
05575    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
05576       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
05577    /* first put the channel on the conference in announce mode */
05578    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05579    {
05580       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05581    }
05582    pthread_exit(NULL);
05583 }
05584 
05585 static void send_link_dtmf(struct rpt *myrpt,char c)
05586 {
05587 char  str[300];
05588 struct   ast_frame wf;
05589 struct   rpt_link *l;
05590 
05591    snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
05592    wf.frametype = AST_FRAME_TEXT;
05593    wf.subclass = 0;
05594    wf.offset = 0;
05595    wf.mallocd = 0;
05596    wf.datalen = strlen(str) + 1;
05597    wf.samples = 0;
05598    l = myrpt->links.next;
05599    /* first, see if our dude is there */
05600    while(l != &myrpt->links)
05601    {
05602       if (l->name[0] == '0') 
05603       {
05604          l = l->next;
05605          continue;
05606       }
05607       /* if we found it, write it and were done */
05608       if (!strcmp(l->name,myrpt->cmdnode))
05609       {
05610          wf.data.ptr = str;
05611          if (l->chan) ast_write(l->chan,&wf);
05612          return;
05613       }
05614       l = l->next;
05615    }
05616    l = myrpt->links.next;
05617    /* if not, give it to everyone */
05618    while(l != &myrpt->links)
05619    {
05620       wf.data.ptr = str;
05621       if (l->chan) ast_write(l->chan,&wf);
05622       l = l->next;
05623    }
05624    return;
05625 }
05626 
05627 static void send_link_keyquery(struct rpt *myrpt)
05628 {
05629 char  str[300];
05630 struct   ast_frame wf;
05631 struct   rpt_link *l;
05632 
05633    rpt_mutex_lock(&myrpt->lock);
05634    memset(myrpt->topkey,0,sizeof(myrpt->topkey));
05635    myrpt->topkeystate = 1;
05636    time(&myrpt->topkeytime);
05637    rpt_mutex_unlock(&myrpt->lock);
05638    snprintf(str, sizeof(str), "K? * %s 0 0", myrpt->name);
05639    wf.frametype = AST_FRAME_TEXT;
05640    wf.subclass = 0;
05641    wf.offset = 0;
05642    wf.mallocd = 0;
05643    wf.datalen = strlen(str) + 1;
05644    wf.samples = 0;
05645    l = myrpt->links.next;
05646    /* give it to everyone */
05647    while(l != &myrpt->links)
05648    {
05649       wf.data.ptr = str;
05650       if (l->chan) ast_write(l->chan,&wf);
05651       l = l->next;
05652    }
05653    return;
05654 }
05655 
05656 /* send newkey request */
05657 
05658 static void send_newkey(struct ast_channel *chan)
05659 {
05660 
05661    /* ast_safe_sleep(chan,10); */
05662    ast_sendtext(chan,newkeystr);
05663    return;
05664 }
05665 
05666 
05667 /* 
05668  * Connect a link 
05669  *
05670  * Return values:
05671  * -2: Attempt to connect to self 
05672  * -1: No such node
05673  *  0: Success
05674  *  1: No match yet
05675  *  2: Already connected to this node
05676  */
05677 
05678 static int connect_link(struct rpt *myrpt, char* node, int mode, int perma)
05679 {
05680    char *val, *s, *s1, *s2, *tele;
05681    char lstr[MAXLINKLIST],*strs[MAXLINKLIST];
05682    char tmp[300], deststr[300] = "",modechange = 0;
05683    char sx[320],*sy;
05684    struct rpt_link *l;
05685    int reconnects = 0;
05686    int i,n;
05687    struct dahdi_confinfo ci;  /* conference info */
05688 
05689    val = node_lookup(myrpt,node);
05690    if (!val){
05691       if(strlen(node) >= myrpt->longestnode)
05692          return -1; /* No such node */
05693       return 1; /* No match yet */
05694    }
05695 
05696    if(!strcmp(myrpt->name,node)) /* Do not allow connections to self */
05697       return -2;
05698       
05699    if(debug > 3){
05700       ast_log(LOG_NOTICE,"Connect attempt to node %s\n", node);
05701       ast_log(LOG_NOTICE,"Mode: %s\n",(mode)?"Transceive":"Monitor");
05702       ast_log(LOG_NOTICE,"Connection type: %s\n",(perma)?"Permalink":"Normal");
05703    }
05704 
05705    strncpy(tmp,val,sizeof(tmp) - 1);
05706    s = tmp;
05707    s1 = strsep(&s,",");
05708    if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
05709    {
05710       sy = strchr(s1,'/');    
05711       *sy = 0;
05712       sprintf(sx,"%s:4569/%s",s1,sy + 1);
05713       s1 = sx;
05714    }
05715    s2 = strsep(&s,",");
05716    rpt_mutex_lock(&myrpt->lock);
05717    l = myrpt->links.next;
05718    /* try to find this one in queue */
05719    while(l != &myrpt->links){
05720       if (l->name[0] == '0') 
05721       {
05722          l = l->next;
05723          continue;
05724       }
05725    /* if found matching string */
05726       if (!strcmp(l->name, node))
05727          break;
05728       l = l->next;
05729    }
05730    /* if found */
05731    if (l != &myrpt->links){ 
05732    /* if already in this mode, just ignore */
05733       if ((l->mode) || (!l->chan)) {
05734          rpt_mutex_unlock(&myrpt->lock);
05735          return 2; /* Already linked */
05736       }
05737       reconnects = l->reconnects;
05738       rpt_mutex_unlock(&myrpt->lock);
05739       if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
05740       l->retries = l->max_retries + 1;
05741       l->disced = 2;
05742       modechange = 1;
05743    } else
05744    {
05745       __mklinklist(myrpt,NULL,lstr);
05746       rpt_mutex_unlock(&myrpt->lock);
05747       n = finddelim(lstr,strs,MAXLINKLIST);
05748       for(i = 0; i < n; i++)
05749       {
05750          if ((*strs[i] < '0') || 
05751              (*strs[i] > '9')) strs[i]++;
05752          if (!strcmp(strs[i],node))
05753          {
05754             return 2; /* Already linked */
05755          }
05756       }
05757    }
05758    strncpy(myrpt->lastlinknode,node,MAXNODESTR - 1);
05759    /* establish call */
05760    l = ast_malloc(sizeof(struct rpt_link));
05761    if (!l)
05762    {
05763       ast_log(LOG_WARNING, "Unable to malloc\n");
05764       return -1;
05765    }
05766    /* zero the silly thing */
05767    memset((char *)l,0,sizeof(struct rpt_link));
05768    l->mode = mode;
05769    l->outbound = 1;
05770    l->thisconnected = 0;
05771    voxinit_link(l,1);
05772    strncpy(l->name, node, MAXNODESTR - 1);
05773    l->isremote = (s && ast_true(s));
05774    if (modechange) l->connected = 1;
05775    l->hasconnected = l->perma = perma;
05776 #ifdef ALLOW_LOCAL_CHANNELS
05777    if ((strncasecmp(s1,"iax2/", 5) == 0) || (strncasecmp(s1, "local/", 6) == 0))
05778          strncpy(deststr, s1, sizeof(deststr));
05779    else
05780            snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
05781 #else
05782    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
05783 #endif
05784    tele = strchr(deststr, '/');
05785    if (!tele){
05786       ast_log(LOG_WARNING,"link3:Dial number (%s) must be in format tech/number\n",deststr);
05787       ast_free(l);
05788       return -1;
05789    }
05790    *tele++ = 0;
05791    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
05792    if (l->chan){
05793       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
05794       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
05795 #ifdef   AST_CDR_FLAG_POST_DISABLED
05796       if (l->chan->cdr)
05797          ast_set_flag(l->chan->cdr,AST_CDR_FLAG_POST_DISABLED);
05798 #endif
05799 #ifndef  NEW_ASTERISK
05800       l->chan->whentohangup = 0;
05801 #endif
05802       l->chan->appl = "Apprpt";
05803       l->chan->data = "(Remote Rx)";
05804       if (debug > 3)
05805          ast_log(LOG_NOTICE, "rpt (remote) initiating call to %s/%s on %s\n",
05806       deststr, tele, l->chan->name);
05807       if(l->chan->cid.cid_num)
05808          ast_free(l->chan->cid.cid_num);
05809       l->chan->cid.cid_num = ast_strdup(myrpt->name);
05810       ast_call(l->chan,tele,999);
05811    }
05812    else {
05813       if(debug > 3) 
05814          ast_log(LOG_NOTICE, "Unable to place call to %s/%s on %s\n",
05815       deststr,tele,l->chan->name);
05816       if (myrpt->p.archivedir)
05817       {
05818          char str[100];
05819          sprintf(str,"LINKFAIL,%s",l->name);
05820          donodelog(myrpt,str);
05821       }
05822       ast_free(l);
05823       return -1;
05824    }
05825    /* allocate a pseudo-channel thru asterisk */
05826    l->pchan = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
05827    if (!l->pchan){
05828       ast_log(LOG_WARNING,"rpt connect: Sorry unable to obtain pseudo channel\n");
05829       ast_hangup(l->chan);
05830       ast_free(l);
05831       return -1;
05832    }
05833    ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
05834    ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
05835 #ifdef   AST_CDR_FLAG_POST_DISABLED
05836    if (l->pchan->cdr)
05837       ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
05838 #endif
05839    /* make a conference for the tx */
05840    ci.chan = 0;
05841    ci.confno = myrpt->conf;
05842    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
05843    /* first put the channel on the conference in proper mode */
05844    if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1)
05845    {
05846       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05847       ast_hangup(l->chan);
05848       ast_hangup(l->pchan);
05849       ast_free(l);
05850       return -1;
05851    }
05852    rpt_mutex_lock(&myrpt->lock);
05853    l->reconnects = reconnects;
05854    /* insert at end of queue */
05855    l->max_retries = MAX_RETRIES;
05856    if (perma)
05857       l->max_retries = MAX_RETRIES_PERM;
05858    if (l->isremote) l->retries = l->max_retries + 1;
05859    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
05860    __kickshort(myrpt);
05861    rpt_mutex_unlock(&myrpt->lock);
05862    if (!l->phonemode) send_newkey(l->chan);
05863    return 0;
05864 }
05865 
05866 
05867 
05868 /*
05869 * Internet linking function 
05870 */
05871 
05872 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
05873 {
05874 
05875    char *val, *s, *s1, *s2;
05876    char tmp[300];
05877    char digitbuf[MAXNODESTR],*strs[MAXLINKLIST];
05878    char mode,perma;
05879    char sx[320],*sy;
05880    struct rpt_link *l;
05881    int i,r;
05882 
05883    if(!param)
05884       return DC_ERROR;
05885       
05886          
05887    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable )
05888       return DC_ERROR;
05889 
05890    strncpy(digitbuf,digits,MAXNODESTR - 1);
05891 
05892    if(debug > 6)
05893       printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
05894       
05895    switch(myatoi(param)){
05896       case 11: /* Perm Link off */
05897       case 1: /* Link off */
05898          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
05899             strcpy(digitbuf,myrpt->lastlinknode);
05900          val = node_lookup(myrpt,digitbuf);
05901          if (!val){
05902             if(strlen(digitbuf) >= myrpt->longestnode)
05903                return DC_ERROR;
05904             break;
05905          }
05906          strncpy(tmp,val,sizeof(tmp) - 1);
05907          s = tmp;
05908          s1 = strsep(&s,",");
05909          if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
05910          {
05911             sy = strchr(s1,'/');    
05912             *sy = 0;
05913             sprintf(sx,"%s:4569/%s",s1,sy + 1);
05914             s1 = sx;
05915          }
05916          s2 = strsep(&s,",");
05917          rpt_mutex_lock(&myrpt->lock);
05918          l = myrpt->links.next;
05919          /* try to find this one in queue */
05920          while(l != &myrpt->links){
05921             if (l->name[0] == '0') 
05922             {
05923                l = l->next;
05924                continue;
05925             }
05926             /* if found matching string */
05927             if (!strcmp(l->name, digitbuf))
05928                break;
05929             l = l->next;
05930          }
05931          if (l != &myrpt->links){ /* if found */
05932             struct   ast_frame wf;
05933 
05934             /* must use perm command on perm link */
05935             if ((myatoi(param) < 10) && 
05936                 (l->max_retries > MAX_RETRIES))
05937             {
05938                rpt_mutex_unlock(&myrpt->lock);
05939                return DC_COMPLETE;
05940             }
05941             strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
05942             l->retries = l->max_retries + 1;
05943             l->disced = 1;
05944             rpt_mutex_unlock(&myrpt->lock);
05945             wf.frametype = AST_FRAME_TEXT;
05946             wf.subclass = 0;
05947             wf.offset = 0;
05948             wf.mallocd = 0;
05949             wf.datalen = strlen(discstr) + 1;
05950             wf.samples = 0;
05951             wf.data.ptr = discstr;
05952             if (l->chan)
05953             {
05954                ast_write(l->chan,&wf);
05955                if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
05956                ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
05957             }
05958             rpt_telemetry(myrpt, COMPLETE, NULL);
05959             return DC_COMPLETE;
05960          }
05961          rpt_mutex_unlock(&myrpt->lock);  
05962          return DC_COMPLETE;
05963       case 2: /* Link Monitor */
05964       case 3: /* Link transceive */
05965       case 12: /* Link Monitor permanent */
05966       case 13: /* Link transceive permanent */
05967          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
05968             strcpy(digitbuf,myrpt->lastlinknode);
05969          /* Attempt connection  */
05970          perma = (atoi(param) > 10) ? 1 : 0;
05971          mode = (atoi(param) & 1) ? 1 : 0;
05972          r = connect_link(myrpt, digitbuf, mode, perma);
05973          switch(r){
05974             case -2: /* Attempt to connect to self */
05975                return DC_COMPLETE; /* Silent error */
05976 
05977             case 0:
05978                rpt_telemetry(myrpt, COMPLETE, NULL);
05979                return DC_COMPLETE;
05980 
05981             case 1:
05982                break;
05983             
05984             case 2:
05985                rpt_telemetry(myrpt, REMALREADY, NULL);
05986                return DC_COMPLETE;
05987             
05988             default:
05989                rpt_telemetry(myrpt, CONNFAIL, NULL);
05990                return DC_COMPLETE;
05991          }
05992          break;
05993 
05994       case 4: /* Enter Command Mode */
05995       
05996          /* if doesnt allow link cmd, or no links active, return */
05997          if (((command_source != SOURCE_RPT) && 
05998             (command_source != SOURCE_PHONE) &&
05999             (command_source != SOURCE_ALT) &&
06000             (command_source != SOURCE_DPHONE)) ||
06001              (myrpt->links.next == &myrpt->links))
06002             return DC_COMPLETE;
06003          
06004          /* if already in cmd mode, or selected self, fughetabahtit */
06005          if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
06006          
06007             rpt_telemetry(myrpt, REMALREADY, NULL);
06008             return DC_COMPLETE;
06009          }
06010          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
06011             strcpy(digitbuf,myrpt->lastlinknode);
06012          /* node must at least exist in list */
06013          val = node_lookup(myrpt,digitbuf);
06014          if (!val){
06015             if(strlen(digitbuf) >= myrpt->longestnode)
06016                return DC_ERROR;
06017             break;
06018          
06019          }
06020          rpt_mutex_lock(&myrpt->lock);
06021          strcpy(myrpt->lastlinknode,digitbuf);
06022          strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
06023          rpt_mutex_unlock(&myrpt->lock);
06024          rpt_telemetry(myrpt, REMGO, NULL);  
06025          return DC_COMPLETE;
06026          
06027       case 5: /* Status */
06028          rpt_telemetry(myrpt, STATUS, NULL);
06029          return DC_COMPLETE;
06030 
06031       case 15: /* Full Status */
06032          rpt_telemetry(myrpt, FULLSTATUS, NULL);
06033          return DC_COMPLETE;
06034          
06035          
06036       case 6: /* All Links Off, including permalinks */
06037                        rpt_mutex_lock(&myrpt->lock);
06038          myrpt->savednodes[0] = 0;
06039                         l = myrpt->links.next;
06040                         /* loop through all links */
06041                         while(l != &myrpt->links){
06042             struct   ast_frame wf;
06043                                 if (l->name[0] == '0') /* Skip any IAXRPT monitoring */
06044                                 {
06045                                         l = l->next;
06046                                         continue;
06047                                 }
06048             /* Make a string of disconnected nodes for possible restoration */
06049             sprintf(tmp,"%c%c%s",(l->mode) ? 'X' : 'M',(l->perma) ? 'P':'T',l->name);
06050             if(strlen(tmp) + strlen(myrpt->savednodes) + 1 < MAXNODESTR){ 
06051                if(myrpt->savednodes[0])
06052                   strcat(myrpt->savednodes, ",");
06053                strcat(myrpt->savednodes, tmp);
06054             }
06055                               l->retries = l->max_retries + 1;
06056                                 l->disced = 2; /* Silently disconnect */
06057                                 rpt_mutex_unlock(&myrpt->lock);
06058             /* ast_log(LOG_NOTICE,"dumping link %s\n",l->name); */
06059                                 
06060                                 wf.frametype = AST_FRAME_TEXT;
06061                                 wf.subclass = 0;
06062                                 wf.offset = 0;
06063                                 wf.mallocd = 0;
06064                                 wf.datalen = strlen(discstr) + 1;
06065                                 wf.samples = 0;
06066                                 wf.data.ptr = discstr;
06067                                 if (l->chan)
06068                                 {
06069                                         ast_write(l->chan,&wf);
06070                                         ast_safe_sleep(l->chan,250); /* It's dead already, why check the return value? */
06071                                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
06072                                 }
06073             rpt_mutex_lock(&myrpt->lock);
06074                                 l = l->next;
06075                         }
06076          rpt_mutex_unlock(&myrpt->lock);
06077          if(debug > 3)
06078             ast_log(LOG_NOTICE,"Nodes disconnected: %s\n",myrpt->savednodes);
06079                         rpt_telemetry(myrpt, COMPLETE, NULL);
06080          return DC_COMPLETE;
06081 
06082       case 7: /* Identify last node which keyed us up */
06083          rpt_telemetry(myrpt, LASTNODEKEY, NULL);
06084          break;
06085 
06086 
06087 #ifdef   _MDC_DECODE_H_
06088       case 8:
06089          myrpt->lastunit = 0xd00d; 
06090          mdc1200_notify(myrpt,NULL,myrpt->lastunit);
06091          mdc1200_send(myrpt,myrpt->lastunit);
06092          break;
06093 #endif
06094 
06095       case 16: /* Restore links disconnected with "disconnect all links" command */
06096          strcpy(tmp, myrpt->savednodes); /* Make a copy */
06097          finddelim(tmp, strs, MAXLINKLIST); /* convert into substrings */
06098          for(i = 0; tmp[0] && strs[i] != NULL && i < MAXLINKLIST; i++){
06099             s1 = strs[i];
06100             mode = (s1[0] == 'X') ? 1 : 0;
06101             perma = (s1[1] == 'P') ? 1 : 0;
06102             connect_link(myrpt, s1 + 2, mode, perma); /* Try to reconnect */
06103          }
06104                         rpt_telemetry(myrpt, COMPLETE, NULL);
06105          break;
06106    
06107       case 200:
06108       case 201:
06109       case 202:
06110       case 203:
06111       case 204:
06112       case 205:
06113       case 206:
06114       case 207:
06115       case 208:
06116       case 209:
06117       case 210:
06118       case 211:
06119       case 212:
06120       case 213:
06121       case 214:
06122       case 215:
06123          if (((myrpt->p.propagate_dtmf) && 
06124               (command_source == SOURCE_LNK)) ||
06125              ((myrpt->p.propagate_phonedtmf) &&
06126             ((command_source == SOURCE_PHONE) ||
06127               (command_source == SOURCE_ALT) ||
06128                 (command_source == SOURCE_DPHONE))))
06129                do_dtmf_local(myrpt,
06130                   remdtmfstr[myatoi(param) - 200]);
06131       default:
06132          return DC_ERROR;
06133          
06134    }
06135    
06136    return DC_INDETERMINATE;
06137 }  
06138 
06139 /*
06140 * Autopatch up
06141 */
06142 
06143 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06144 {
06145    pthread_attr_t attr;
06146    int i, idx, paramlength;
06147    char *lparam;
06148    char *value = NULL;
06149    char *paramlist[20];
06150 
06151    static char *keywords[] = {
06152    "context",
06153    "dialtime",
06154    "farenddisconnect",
06155    "noct",
06156    "quiet",
06157    NULL
06158    };
06159       
06160    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
06161       return DC_ERROR;
06162       
06163    if(debug)
06164       printf("@@@@ Autopatch up\n");
06165 
06166    if(!myrpt->callmode){
06167       /* Set defaults */
06168       myrpt->patchnoct = 0;
06169       myrpt->patchdialtime = 0;
06170       myrpt->patchfarenddisconnect = 0;
06171       myrpt->patchquiet = 0;
06172       strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
06173 
06174       if(param){
06175          /* Process parameter list */
06176          lparam = ast_strdup(param);
06177          if(!lparam){
06178             ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
06179             return DC_ERROR;  
06180          }
06181          paramlength = finddelim(lparam, paramlist, 20);          
06182          for(i = 0; i < paramlength; i++){
06183             idx = matchkeyword(paramlist[i], &value, keywords);
06184             if(value)
06185                value = skipchars(value, "= ");
06186             switch(idx){
06187 
06188                case 1: /* context */
06189                   strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ;
06190                   break;
06191                   
06192                case 2: /* dialtime */
06193                   myrpt->patchdialtime = atoi(value);
06194                   break;
06195 
06196                case 3: /* farenddisconnect */
06197                   myrpt->patchfarenddisconnect = atoi(value);
06198                   break;
06199 
06200                case 4:  /* noct */
06201                   myrpt->patchnoct = atoi(value);
06202                   break;
06203 
06204                case 5: /* quiet */
06205                   myrpt->patchquiet = atoi(value);
06206                   break;
06207                            
06208                default:
06209                   break;
06210             }
06211          }
06212       ast_free(lparam);
06213       }
06214    }
06215                
06216    rpt_mutex_lock(&myrpt->lock);
06217 
06218    /* if on call, force * into current audio stream */
06219    
06220    if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
06221       myrpt->mydtmf = myrpt->p.endchar;
06222    }
06223    if (myrpt->callmode){
06224       rpt_mutex_unlock(&myrpt->lock);
06225       return DC_COMPLETE;
06226    }
06227    myrpt->callmode = 1;
06228    myrpt->cidx = 0;
06229    myrpt->exten[myrpt->cidx] = 0;
06230    rpt_mutex_unlock(&myrpt->lock);
06231    pthread_attr_init(&attr);
06232    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
06233    ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
06234    return DC_COMPLETE;
06235 }
06236 
06237 /*
06238 * Autopatch down
06239 */
06240 
06241 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06242 {
06243    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
06244       return DC_ERROR;
06245    
06246    if(debug)
06247       printf("@@@@ Autopatch down\n");
06248       
06249    rpt_mutex_lock(&myrpt->lock);
06250    
06251    myrpt->macropatch=0;
06252 
06253    if (!myrpt->callmode){
06254       rpt_mutex_unlock(&myrpt->lock);
06255       return DC_COMPLETE;
06256    }
06257    
06258    myrpt->callmode = 0;
06259    channel_revert(myrpt);
06260    rpt_mutex_unlock(&myrpt->lock);
06261    rpt_telemetry(myrpt, TERM, NULL);
06262    return DC_COMPLETE;
06263 }
06264 
06265 /*
06266 * Status
06267 */
06268 
06269 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06270 {
06271 
06272    if (!param)
06273       return DC_ERROR;
06274 
06275    if ((myrpt->p.s[myrpt->p.sysstate_cur].txdisable) || (myrpt->p.s[myrpt->p.sysstate_cur].userfundisable))
06276       return DC_ERROR;
06277 
06278    if(debug)
06279       printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06280    
06281    switch(myatoi(param)){
06282       case 1: /* System ID */
06283          rpt_telemetry(myrpt, ID1, NULL);
06284          return DC_COMPLETE;
06285       case 2: /* System Time */
06286          rpt_telemetry(myrpt, STATS_TIME, NULL);
06287          return DC_COMPLETE;
06288       case 3: /* app_rpt.c version */
06289          rpt_telemetry(myrpt, STATS_VERSION, NULL);
06290          return DC_COMPLETE;
06291       case 11: /* System ID (local only)*/
06292           rpt_telemetry(myrpt, ID , NULL);
06293             return DC_COMPLETE;
06294         case 12: /* System Time (local only)*/
06295             rpt_telemetry(myrpt, STATS_TIME_LOCAL, NULL);
06296             return DC_COMPLETE;
06297       default:
06298          return DC_ERROR;
06299    }
06300    return DC_INDETERMINATE;
06301 }
06302 /*
06303 *  Macro-oni (without Salami)
06304 */
06305 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06306 {
06307 char  *val;
06308 int   i;
06309    if (myrpt->remote)
06310       return DC_ERROR;
06311 
06312    if(debug) 
06313       printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06314    
06315    if(strlen(digitbuf) < 1) /* needs 1 digit */
06316       return DC_INDETERMINATE;
06317          
06318    for(i = 0 ; i < digitbuf[i] ; i++) {
06319       if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06320          return DC_ERROR;
06321    }
06322    
06323    if (*digitbuf == '0') val = myrpt->p.startupmacro;
06324    else val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
06325    /* param was 1 for local buf */
06326    if (!val){
06327                 if (strlen(digitbuf) < myrpt->macro_longest)
06328                         return DC_INDETERMINATE;
06329       rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
06330       return DC_COMPLETE;
06331    }        
06332    rpt_mutex_lock(&myrpt->lock);
06333    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
06334    {
06335       rpt_mutex_unlock(&myrpt->lock);
06336       rpt_telemetry(myrpt, MACRO_BUSY, NULL);
06337       return DC_ERROR;
06338    }
06339    myrpt->macrotimer = MACROTIME;
06340    strncat(myrpt->macrobuf,val,MAXMACRO - 1);
06341    rpt_mutex_unlock(&myrpt->lock);
06342    return DC_COMPLETE;  
06343 }
06344 
06345 /*
06346 *  Playback a recording
06347 */
06348 
06349 static int function_playback(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06350 {
06351 
06352    if (myrpt->remote)
06353       return DC_ERROR;
06354 
06355    if(debug) 
06356       printf("@@@@ playback param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06357    
06358    if (ast_fileexists(param,NULL,myrpt->rxchannel->language) <= 0)
06359       return DC_ERROR;
06360 
06361    rpt_telemetry(myrpt,PLAYBACK,param);
06362    return DC_COMPLETE;
06363 }
06364 
06365 /*
06366 * COP - Control operator
06367 */
06368 
06369 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06370 {
06371    char string[16];
06372    int res;
06373 
06374    int i, r;
06375 
06376    if(!param)
06377       return DC_ERROR;
06378    
06379    switch(myatoi(param)){
06380       case 1: /* System reset */
06381          res = system("killall -9 asterisk");
06382          return DC_COMPLETE;
06383 
06384       case 2:
06385          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 0;
06386          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
06387          return DC_COMPLETE;
06388          
06389       case 3:
06390          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 1;
06391          return DC_COMPLETE;
06392          
06393       case 4: /* test tone on */
06394          if (myrpt->stopgen < 0) 
06395          {
06396             myrpt->stopgen = 1;
06397          }
06398          else 
06399          {
06400             myrpt->stopgen = 0;
06401             rpt_telemetry(myrpt, TEST_TONE, NULL);
06402          }
06403          return DC_COMPLETE;
06404 
06405       case 5: /* Disgorge variables to log for debug purposes */
06406          myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
06407          return DC_COMPLETE;
06408 
06409       case 6: /* Simulate COR being activated (phone only) */
06410          if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
06411          return DC_DOKEY;  
06412 
06413 
06414       case 7: /* Time out timer enable */
06415          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 0;
06416          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTENA");
06417          return DC_COMPLETE;
06418          
06419       case 8: /* Time out timer disable */
06420          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 1;
06421          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTDIS");
06422          return DC_COMPLETE;
06423 
06424                 case 9: /* Autopatch enable */
06425                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 0;
06426                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APENA");
06427                         return DC_COMPLETE;
06428 
06429                 case 10: /* Autopatch disable */
06430                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 1;
06431                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APDIS");
06432                         return DC_COMPLETE;
06433 
06434                 case 11: /* Link Enable */
06435                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 0;
06436                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKENA");
06437                         return DC_COMPLETE;
06438 
06439                 case 12: /* Link Disable */
06440                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 1;
06441                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKDIS");
06442                         return DC_COMPLETE;
06443 
06444       case 13: /* Query System State */
06445          string[0] = string[1] = 'S';
06446          string[2] = myrpt->p.sysstate_cur + '0';
06447          string[3] = '\0';
06448          rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
06449          return DC_COMPLETE;
06450 
06451       case 14: /* Change System State */
06452          if(strlen(digitbuf) == 0)
06453             break;
06454          if((digitbuf[0] < '0') || (digitbuf[0] > '9'))
06455             return DC_ERROR;
06456          myrpt->p.sysstate_cur = digitbuf[0] - '0';
06457                         string[0] = string[1] = 'S';
06458                         string[2] = myrpt->p.sysstate_cur + '0';
06459                         string[3] = '\0';
06460                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
06461                         return DC_COMPLETE;
06462 
06463                 case 15: /* Scheduler Enable */
06464                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 0;
06465                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKENA");
06466                         return DC_COMPLETE;
06467 
06468                 case 16: /* Scheduler Disable */
06469                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 1;
06470                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKDIS");
06471                         return DC_COMPLETE;
06472 
06473                 case 17: /* User functions Enable */
06474                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 0;
06475                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFENA");
06476                         return DC_COMPLETE;
06477 
06478                 case 18: /* User Functions Disable */
06479                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 1;
06480                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFDIS");
06481                         return DC_COMPLETE;
06482 
06483                 case 19: /* Alternate Tail Enable */
06484                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 1;
06485                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATENA");
06486                         return DC_COMPLETE;
06487 
06488                 case 20: /* Alternate Tail Disable */
06489                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 0;
06490                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATDIS");
06491                         return DC_COMPLETE;
06492 
06493                 case 21: /* Parrot Mode Disable */
06494          birdbath(myrpt);
06495          if (myrpt->p.parrotmode < 2)
06496          {
06497             myrpt->p.parrotmode = 0;
06498             rpt_telemetry(myrpt,COMPLETE,NULL);
06499             return DC_COMPLETE;
06500          }
06501          break;
06502 
06503                 case 22: /* Parrot Mode Enable */
06504          birdbath(myrpt);
06505          if (myrpt->p.parrotmode < 2)
06506          {
06507             myrpt->p.parrotmode = 1;
06508             rpt_telemetry(myrpt,COMPLETE,NULL);
06509             return DC_COMPLETE;
06510          }
06511          break;
06512       case 23: /* flush parrot in progress */
06513          birdbath(myrpt);
06514          rpt_telemetry(myrpt,COMPLETE,NULL);
06515          return DC_COMPLETE;
06516       case 24: /* flush all telemetry */
06517          flush_telem(myrpt);
06518          rpt_telemetry(myrpt,COMPLETE,NULL);
06519          return DC_COMPLETE;
06520       case 25: /* request keying info (brief) */
06521          send_link_keyquery(myrpt);
06522          myrpt->topkeylong = 0;
06523          rpt_telemetry(myrpt,COMPLETE,NULL);
06524          return DC_COMPLETE;
06525       case 26: /* request keying info (full) */
06526          send_link_keyquery(myrpt);
06527          myrpt->topkeylong = 1;
06528          rpt_telemetry(myrpt,COMPLETE,NULL);
06529          return DC_COMPLETE;
06530 
06531       case 30: /* recall memory location on programmable radio */
06532 
06533          if(strlen(digitbuf) < 2) /* needs 2 digits */
06534             break;
06535          
06536          for(i = 0 ; i < 2 ; i++){
06537             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06538                return DC_ERROR;
06539          }
06540        
06541          r = retreive_memory(myrpt, digitbuf);
06542          if (r < 0){
06543             rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
06544             return DC_COMPLETE;
06545          }
06546          if (r > 0){
06547             return DC_ERROR;
06548          }
06549          if (setrem(myrpt) == -1) return DC_ERROR;
06550          return DC_COMPLETE;  
06551 
06552       case 31: 
06553           /* set channel. note that it's going to change channel 
06554              then confirm on the new channel! */
06555          if(strlen(digitbuf) < 2) /* needs 2 digits */
06556             break;
06557          
06558          for(i = 0 ; i < 2 ; i++){
06559             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06560                return DC_ERROR;
06561          }
06562          channel_steer(myrpt,digitbuf);
06563          return DC_COMPLETE;  
06564 
06565       case 32: /* Touch Tone Pad Test */
06566          i = strlen(digitbuf);
06567          if(!i){
06568             if(debug > 3)
06569             ast_log(LOG_NOTICE,"Padtest entered");
06570             myrpt->inpadtest = 1;
06571          }
06572          else{
06573             if(debug > 3)
06574                ast_log(LOG_NOTICE,"Padtest len= %d digits=%s",i,digitbuf);
06575             if(digitbuf[i-1] != myrpt->p.endchar)
06576                break;
06577             rpt_telemetry(myrpt, ARB_ALPHA, digitbuf);
06578             myrpt->inpadtest = 0;
06579             if(debug > 3)
06580                ast_log(LOG_NOTICE,"Padtest exited");
06581             return DC_COMPLETE;
06582          }
06583    }  
06584    return DC_INDETERMINATE;
06585 }
06586 /*
06587 * Collect digits one by one until something matches
06588 */
06589 static int collect_function_digits(struct rpt *myrpt, char *digits, 
06590    int command_source, struct rpt_link *mylink)
06591 {
06592    int i,rv;
06593    char *stringp,*action,*param,*functiondigits;
06594    char function_table_name[30] = "";
06595    char workstring[200];
06596    
06597    struct ast_variable *vp;
06598    
06599    if (debug > 6) ast_log(LOG_NOTICE,"digits=%s  source=%d\n",digits, command_source);
06600 
06601    //if(debug) 
06602    // printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
06603    
06604    if (command_source == SOURCE_DPHONE) {
06605       if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
06606       strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1);
06607       }
06608    else if (command_source == SOURCE_ALT) {
06609       if (!myrpt->p.alt_functions) return DC_INDETERMINATE;
06610       strncpy(function_table_name, myrpt->p.alt_functions, sizeof(function_table_name) - 1);
06611       }
06612    else if (command_source == SOURCE_PHONE) {
06613       if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
06614       strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1);
06615       }
06616    else if (command_source == SOURCE_LNK)
06617       strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1);
06618    else
06619       strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1);
06620     /* find context for function table in rpt.conf file */
06621    vp = ast_variable_browse(myrpt->cfg, function_table_name);
06622    while(vp) {
06623       if(!strncasecmp(vp->name, digits, strlen(vp->name)))
06624          break;
06625       vp = vp->next;
06626    }  
06627    /* if function context not found */
06628    if(!vp) {
06629       int n;
06630 
06631       n = myrpt->longestfunc;
06632       if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
06633       else 
06634       if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
06635       else 
06636       if (command_source == SOURCE_ALT) n = myrpt->alt_longestfunc;
06637       else 
06638       if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
06639       
06640       if(strlen(digits) >= n)
06641          return DC_ERROR;
06642       else
06643          return DC_INDETERMINATE;
06644    }  
06645    /* Found a match, retrieve value part and parse */
06646    strncpy(workstring, vp->value, sizeof(workstring) - 1 );
06647    stringp = workstring;
06648    action = strsep(&stringp, ",");
06649    param = stringp;
06650    if(debug)
06651       printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
06652    /* Look up the action */
06653    for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
06654       if(!strncasecmp(action, function_table[i].action, strlen(action)))
06655          break;
06656    }
06657    if(debug)
06658       printf("@@@@ table index i = %d\n",i);
06659    if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
06660       /* Error, action not in table */
06661       return DC_ERROR;
06662    }
06663    if(function_table[i].function == NULL){
06664       /* Error, function undefined */
06665       if(debug)
06666          printf("@@@@ NULL for action: %s\n",action);
06667       return DC_ERROR;
06668    }
06669    functiondigits = digits + strlen(vp->name);
06670    rv=(*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
06671    if (debug > 6) ast_log(LOG_NOTICE,"rv=%i\n",rv);
06672    return(rv);
06673 }
06674 
06675 
06676 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
06677    char *str)
06678 {
06679 /* XXX ATTENTION: if you change the size of these arrays you MUST
06680  * change the limits in corresponding sscanf() calls below. */
06681 char  tmp[512],tmp1[512],cmd[300] = "",dest[300],src[300],c;
06682 int   i,seq, res, ts;
06683 struct rpt_link *l;
06684 struct   ast_frame wf;
06685 
06686    wf.frametype = AST_FRAME_TEXT;
06687    wf.subclass = 0;
06688    wf.offset = 0;
06689    wf.mallocd = 0;
06690    wf.datalen = strlen(str) + 1;
06691    wf.samples = 0;
06692    /* put string in our buffer */
06693    strncpy(tmp,str,sizeof(tmp) - 1);
06694 
06695         if (!strcmp(tmp,discstr))
06696         {
06697                 mylink->disced = 1;
06698       mylink->retries = mylink->max_retries + 1;
06699                 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
06700                 return;
06701         }
06702         if (!strcmp(tmp,newkeystr))
06703         {
06704       mylink->newkey = 1;
06705                 return;
06706         }
06707    if (tmp[0] == 'L')
06708    {
06709       rpt_mutex_lock(&myrpt->lock);
06710       strcpy(mylink->linklist,tmp + 2);
06711       time(&mylink->linklistreceived);
06712       rpt_mutex_unlock(&myrpt->lock);
06713       if (debug > 6) ast_log(LOG_NOTICE,"@@@@ node %s received node list %s from node %s\n",
06714          myrpt->name,tmp,mylink->name);
06715       return;
06716    }
06717    if (tmp[0] == 'K')
06718    {
06719       if (sscanf(tmp, "%299s %299s %299s %30d %30d", cmd, dest, src, &seq, &ts) != 5)
06720       {
06721          ast_log(LOG_WARNING, "Unable to parse keying string %s\n",str);
06722          return;
06723       }
06724       if (dest[0] == '0')
06725       {
06726          strcpy(dest,myrpt->name);
06727       }     
06728       /* if not for me, redistribute to all links */
06729       if (strcmp(dest,myrpt->name))
06730       {
06731          l = myrpt->links.next;
06732          /* see if this is one in list */
06733          while(l != &myrpt->links)
06734          {
06735             if (l->name[0] == '0') 
06736             {
06737                l = l->next;
06738                continue;
06739             }
06740             /* dont send back from where it came */
06741             if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06742             {
06743                l = l->next;
06744                continue;
06745             }
06746             /* if it is, send it and we're done */
06747             if (!strcmp(l->name,dest))
06748             {
06749                /* send, but not to src */
06750                if (strcmp(l->name,src)) {
06751                   wf.data.ptr = str;
06752                   if (l->chan) ast_write(l->chan,&wf);
06753                }
06754                return;
06755             }
06756             l = l->next;
06757          }
06758       }
06759       /* if not for me, or is broadcast, redistribute to all links */
06760       if ((strcmp(dest,myrpt->name)) || (dest[0] == '*'))
06761       {
06762          l = myrpt->links.next;
06763          /* otherwise, send it to all of em */
06764          while(l != &myrpt->links)
06765          {
06766             if (l->name[0] == '0') 
06767             {
06768                l = l->next;
06769                continue;
06770             }
06771             /* dont send back from where it came */
06772             if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06773             {
06774                l = l->next;
06775                continue;
06776             }
06777             /* send, but not to src */
06778             if (strcmp(l->name,src)) {
06779                wf.data.ptr = str;
06780                if (l->chan) ast_write(l->chan,&wf); 
06781             }
06782             l = l->next;
06783          }
06784       }
06785       /* if not for me, end here */
06786       if (strcmp(dest,myrpt->name) && (dest[0] != '*')) return;
06787       if (cmd[1] == '?')
06788       {
06789          time_t now;
06790          int n = 0;
06791 
06792          time(&now);
06793          if (myrpt->lastkeyedtime)
06794          {
06795             n = (int)(now - myrpt->lastkeyedtime);
06796          }
06797          sprintf(tmp1,"K %s %s %d %d",src,myrpt->name,myrpt->keyed,n);
06798          wf.data.ptr = tmp1;
06799          wf.datalen = strlen(tmp1) + 1;
06800          if (mylink->chan) ast_write(mylink->chan,&wf); 
06801          return;
06802       }
06803       if (myrpt->topkeystate != 1) return;
06804       rpt_mutex_lock(&myrpt->lock);
06805       for(i = 0; i < TOPKEYN; i++)
06806       {
06807          if (!strcmp(myrpt->topkey[i].node,src)) break;
06808       }
06809       if (i >= TOPKEYN)
06810       {
06811          for(i = 0; i < TOPKEYN; i++)
06812          {
06813             if (!myrpt->topkey[i].node[0]) break;
06814          }
06815       }
06816       if (i < TOPKEYN)
06817       {
06818          strncpy(myrpt->topkey[i].node,src,TOPKEYMAXSTR - 1);
06819          myrpt->topkey[i].timesince = ts;
06820          myrpt->topkey[i].keyed = seq;
06821       }
06822       rpt_mutex_unlock(&myrpt->lock);
06823       return;
06824    }
06825    if (tmp[0] == 'I')
06826    {
06827       /* XXX WARNING: be very careful with the limits on the folowing
06828        * sscanf() call, make sure they match the values defined above */
06829       if (sscanf(tmp,"%299s %299s %30x",cmd,src,&seq) != 3)
06830       {
06831          ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
06832          return;
06833       }
06834       mdc1200_notify(myrpt,src,seq);
06835       strcpy(dest,"*");
06836    }
06837    else
06838    {
06839       /* XXX WARNING: be very careful with the limits on the folowing
06840        * sscanf() call, make sure they match the values defined above */
06841       if (sscanf(tmp,"%299s %299s %299s %30d %1c",cmd,dest,src,&seq,&c) != 5)
06842       {
06843          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
06844          return;
06845       }
06846       if (strcmp(cmd,"D"))
06847       {
06848          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
06849          return;
06850       }
06851    }
06852    if (dest[0] == '0')
06853    {
06854       strcpy(dest,myrpt->name);
06855    }     
06856 
06857    /* if not for me, redistribute to all links */
06858    if (strcmp(dest,myrpt->name))
06859    {
06860       l = myrpt->links.next;
06861       /* see if this is one in list */
06862       while(l != &myrpt->links)
06863       {
06864          if (l->name[0] == '0') 
06865          {
06866             l = l->next;
06867             continue;
06868          }
06869          /* dont send back from where it came */
06870          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06871          {
06872             l = l->next;
06873             continue;
06874          }
06875          /* if it is, send it and we're done */
06876          if (!strcmp(l->name,dest))
06877          {
06878             /* send, but not to src */
06879             if (strcmp(l->name,src)) {
06880                wf.data.ptr = str;
06881                if (l->chan) ast_write(l->chan,&wf);
06882             }
06883             return;
06884          }
06885          l = l->next;
06886       }
06887       l = myrpt->links.next;
06888       /* otherwise, send it to all of em */
06889       while(l != &myrpt->links)
06890       {
06891          if (l->name[0] == '0') 
06892          {
06893             l = l->next;
06894             continue;
06895          }
06896          /* dont send back from where it came */
06897          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06898          {
06899             l = l->next;
06900             continue;
06901          }
06902          /* send, but not to src */
06903          if (strcmp(l->name,src)) {
06904             wf.data.ptr = str;
06905             if (l->chan) ast_write(l->chan,&wf); 
06906          }
06907          l = l->next;
06908       }
06909       return;
06910    }
06911    if (myrpt->p.archivedir)
06912    {
06913       char dtmfstr[100];
06914 
06915       sprintf(dtmfstr,"DTMF,%s,%c",mylink->name,c);
06916       donodelog(myrpt,dtmfstr);
06917    }
06918    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
06919    if (!c) return;
06920    rpt_mutex_lock(&myrpt->lock);
06921    if (c == myrpt->p.endchar) myrpt->stopgen = 1;
06922    if (myrpt->callmode == 1)
06923    {
06924       myrpt->exten[myrpt->cidx++] = c;
06925       myrpt->exten[myrpt->cidx] = 0;
06926       /* if this exists */
06927       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
06928       {
06929          /* if this really it, end now */
06930          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
06931             myrpt->exten,1,NULL)) 
06932          {
06933             myrpt->callmode = 2;
06934             if(!myrpt->patchquiet)
06935             {
06936                rpt_mutex_unlock(&myrpt->lock);
06937                rpt_telemetry(myrpt,PROC,NULL); 
06938                rpt_mutex_lock(&myrpt->lock);
06939             }
06940          }
06941          else /* othewise, reset timer */
06942          {
06943             myrpt->calldigittimer = 1;
06944          }
06945       }
06946       /* if can continue, do so */
06947       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
06948       {
06949          /* call has failed, inform user */
06950          myrpt->callmode = 4;
06951       }
06952    }
06953    if ((!myrpt->inpadtest) &&(c == myrpt->p.funcchar))
06954    {
06955       myrpt->rem_dtmfidx = 0;
06956       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
06957       time(&myrpt->rem_dtmf_time);
06958       rpt_mutex_unlock(&myrpt->lock);
06959       return;
06960    } 
06961    else if (myrpt->rem_dtmfidx < 0)
06962    {
06963       if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
06964       {
06965          myrpt->mydtmf = c;
06966       }
06967       if (myrpt->p.propagate_dtmf) do_dtmf_local(myrpt,c);
06968       if (myrpt->p.propagate_phonedtmf) do_dtmf_phone(myrpt,mylink,c);
06969       rpt_mutex_unlock(&myrpt->lock);
06970       return;
06971    }
06972    else if (((myrpt->inpadtest) || (c != myrpt->p.endchar)) && (myrpt->rem_dtmfidx >= 0))
06973    {
06974       time(&myrpt->rem_dtmf_time);
06975       if (myrpt->rem_dtmfidx < MAXDTMF)
06976       {
06977          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
06978          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
06979          
06980          rpt_mutex_unlock(&myrpt->lock);
06981          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
06982          res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
06983          rpt_mutex_lock(&myrpt->lock);
06984          
06985          switch(res){
06986 
06987             case DC_INDETERMINATE:
06988                break;
06989             
06990             case DC_REQ_FLUSH:
06991                myrpt->rem_dtmfidx = 0;
06992                myrpt->rem_dtmfbuf[0] = 0;
06993                break;
06994             
06995             
06996             case DC_COMPLETE:
06997             case DC_COMPLETEQUIET:
06998                myrpt->totalexecdcommands++;
06999                myrpt->dailyexecdcommands++;
07000                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
07001                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
07002                myrpt->rem_dtmfbuf[0] = 0;
07003                myrpt->rem_dtmfidx = -1;
07004                myrpt->rem_dtmf_time = 0;
07005                break;
07006             
07007             case DC_ERROR:
07008             default:
07009                myrpt->rem_dtmfbuf[0] = 0;
07010                myrpt->rem_dtmfidx = -1;
07011                myrpt->rem_dtmf_time = 0;
07012                break;
07013          }
07014       }
07015 
07016    }
07017    rpt_mutex_unlock(&myrpt->lock);
07018    return;
07019 }
07020 
07021 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
07022    char c)
07023 {
07024 
07025 char  cmd[300];
07026 int   res;
07027 
07028    if (myrpt->p.archivedir)
07029    {
07030       char str[100];
07031 
07032       sprintf(str,"DTMF(P),%s,%c",mylink->name,c);
07033       donodelog(myrpt,str);
07034    }
07035    rpt_mutex_lock(&myrpt->lock);
07036 
07037    if (mylink->phonemode == 3) /*If in simplex dumb phone mode */
07038    {
07039       if(c == myrpt->p.endchar) /* If end char */
07040       {
07041          mylink->lastrealrx = 0; /* Keying state = off */
07042          rpt_mutex_unlock(&myrpt->lock);
07043          return;
07044       }
07045 
07046       if(c == myrpt->p.funcchar) /* If lead-in char */
07047       {
07048          mylink->lastrealrx = !mylink->lastrealrx; /* Toggle keying state */
07049          rpt_mutex_unlock(&myrpt->lock);
07050          return;
07051       }
07052    }
07053    else
07054    {
07055       if (c == myrpt->p.endchar)
07056       {
07057          if (mylink->lastrx)
07058          {
07059             mylink->lastrealrx = 0;
07060             rpt_mutex_unlock(&myrpt->lock);
07061             return;
07062          }
07063          myrpt->stopgen = 1;
07064          if (myrpt->cmdnode[0])
07065          {
07066             myrpt->cmdnode[0] = 0;
07067             myrpt->dtmfidx = -1;
07068             myrpt->dtmfbuf[0] = 0;
07069             rpt_mutex_unlock(&myrpt->lock);
07070             rpt_telemetry(myrpt,COMPLETE,NULL);
07071             return;
07072          }
07073       }
07074    }
07075    if (myrpt->cmdnode[0])
07076    {
07077       rpt_mutex_unlock(&myrpt->lock);
07078       send_link_dtmf(myrpt,c);
07079       return;
07080    }
07081    if (myrpt->callmode == 1)
07082    {
07083       myrpt->exten[myrpt->cidx++] = c;
07084       myrpt->exten[myrpt->cidx] = 0;
07085       /* if this exists */
07086       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
07087       {
07088          /* if this really it, end now */
07089          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
07090             myrpt->exten,1,NULL)) 
07091          {
07092             myrpt->callmode = 2;
07093             if(!myrpt->patchquiet)
07094             {
07095                rpt_mutex_unlock(&myrpt->lock);
07096                rpt_telemetry(myrpt,PROC,NULL); 
07097                rpt_mutex_lock(&myrpt->lock);
07098             }
07099          }
07100          else /* othewise, reset timer */
07101          {
07102             myrpt->calldigittimer = 1;
07103          }
07104       }
07105       /* if can continue, do so */
07106       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
07107       {
07108          /* call has failed, inform user */
07109          myrpt->callmode = 4;
07110       }
07111    }
07112    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
07113    {
07114       myrpt->mydtmf = c;
07115    }
07116    if ((!myrpt->inpadtest) && (c == myrpt->p.funcchar))
07117    {
07118       myrpt->rem_dtmfidx = 0;
07119       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
07120       time(&myrpt->rem_dtmf_time);
07121       rpt_mutex_unlock(&myrpt->lock);
07122       return;
07123    } 
07124    else if (((myrpt->inpadtest) || (c != myrpt->p.endchar)) && (myrpt->rem_dtmfidx >= 0))
07125    {
07126       time(&myrpt->rem_dtmf_time);
07127       if (myrpt->rem_dtmfidx < MAXDTMF)
07128       {
07129          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
07130          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
07131          
07132          rpt_mutex_unlock(&myrpt->lock);
07133          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
07134          switch(mylink->phonemode)
07135          {
07136              case 1:
07137             res = collect_function_digits(myrpt, cmd, 
07138                SOURCE_PHONE, mylink);
07139             break;
07140              case 2:
07141             res = collect_function_digits(myrpt, cmd, 
07142                SOURCE_DPHONE,mylink);
07143             break;
07144              case 4:
07145             res = collect_function_digits(myrpt, cmd, 
07146                SOURCE_ALT,mylink);
07147             break;
07148              default:
07149             res = collect_function_digits(myrpt, cmd, 
07150                SOURCE_LNK, mylink);
07151             break;
07152          }
07153 
07154          rpt_mutex_lock(&myrpt->lock);
07155          
07156          switch(res){
07157 
07158             case DC_INDETERMINATE:
07159                break;
07160             
07161             case DC_DOKEY:
07162                mylink->lastrealrx = 1;
07163                break;
07164             
07165             case DC_REQ_FLUSH:
07166                myrpt->rem_dtmfidx = 0;
07167                myrpt->rem_dtmfbuf[0] = 0;
07168                break;
07169             
07170             
07171             case DC_COMPLETE:
07172             case DC_COMPLETEQUIET:
07173                myrpt->totalexecdcommands++;
07174                myrpt->dailyexecdcommands++;
07175                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
07176                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
07177                myrpt->rem_dtmfbuf[0] = 0;
07178                myrpt->rem_dtmfidx = -1;
07179                myrpt->rem_dtmf_time = 0;
07180                break;
07181             
07182             case DC_ERROR:
07183             default:
07184                myrpt->rem_dtmfbuf[0] = 0;
07185                myrpt->rem_dtmfidx = -1;
07186                myrpt->rem_dtmf_time = 0;
07187                break;
07188          }
07189       }
07190 
07191    }
07192    rpt_mutex_unlock(&myrpt->lock);
07193    return;
07194 }
07195 
07196 /* Doug Hall RBI-1 serial data definitions:
07197  *
07198  * Byte 0: Expansion external outputs 
07199  * Byte 1: 
07200  * Bits 0-3 are BAND as follows:
07201  * Bits 4-5 are POWER bits as follows:
07202  *    00 - Low Power
07203  *    01 - Hi Power
07204  *    02 - Med Power
07205  * Bits 6-7 are always set
07206  * Byte 2:
07207  * Bits 0-3 MHZ in BCD format
07208  * Bits 4-5 are offset as follows:
07209  *    00 - minus
07210  *    01 - plus
07211  *    02 - simplex
07212  *    03 - minus minus (whatever that is)
07213  * Bit 6 is the 0/5 KHZ bit
07214  * Bit 7 is always set
07215  * Byte 3:
07216  * Bits 0-3 are 10 KHZ in BCD format
07217  * Bits 4-7 are 100 KHZ in BCD format
07218  * Byte 4: PL Tone code and encode/decode enable bits
07219  * Bits 0-5 are PL tone code (comspec binary codes)
07220  * Bit 6 is encode enable/disable
07221  * Bit 7 is decode enable/disable
07222  */
07223 
07224 /* take the frequency from the 10 mhz digits (and up) and convert it
07225    to a band number */
07226 
07227 static int rbi_mhztoband(char *str)
07228 {
07229 int   i;
07230 
07231    i = atoi(str) / 10; /* get the 10's of mhz */
07232    switch(i)
07233    {
07234        case 2:
07235       return 10;
07236        case 5:
07237       return 11;
07238        case 14:
07239       return 2;
07240        case 22:
07241       return 3;
07242        case 44:
07243       return 4;
07244        case 124:
07245       return 0;
07246        case 125:
07247       return 1;
07248        case 126:
07249       return 8;
07250        case 127:
07251       return 5;
07252        case 128:
07253       return 6;
07254        case 129:
07255       return 7;
07256        default:
07257       break;
07258    }
07259    return -1;
07260 }
07261 
07262 /* take a PL frequency and turn it into a code */
07263 static int rbi_pltocode(char *str)
07264 {
07265 int i;
07266 char *s;
07267 
07268    s = strchr(str,'.');
07269    i = 0;
07270    if (s) i = atoi(s + 1);
07271    i += atoi(str) * 10;
07272    switch(i)
07273    {
07274        case 670:
07275       return 0;
07276        case 719:
07277       return 1;
07278        case 744:
07279       return 2;
07280        case 770:
07281       return 3;
07282        case 797:
07283       return 4;
07284        case 825:
07285       return 5;
07286        case 854:
07287       return 6;
07288        case 885:
07289       return 7;
07290        case 915:
07291       return 8;
07292        case 948:
07293       return 9;
07294        case 974:
07295       return 10;
07296        case 1000:
07297       return 11;
07298        case 1035:
07299       return 12;
07300        case 1072:
07301       return 13;
07302        case 1109:
07303       return 14;
07304        case 1148:
07305       return 15;
07306        case 1188:
07307       return 16;
07308        case 1230:
07309       return 17;
07310        case 1273:
07311       return 18;
07312        case 1318:
07313       return 19;
07314        case 1365:
07315       return 20;
07316        case 1413:
07317       return 21;
07318        case 1462:
07319       return 22;
07320        case 1514:
07321       return 23;
07322        case 1567:
07323       return 24;
07324        case 1622:
07325       return 25;
07326        case 1679:
07327       return 26;
07328        case 1738:
07329       return 27;
07330        case 1799:
07331       return 28;
07332        case 1862:
07333       return 29;
07334        case 1928:
07335       return 30;
07336        case 2035:
07337       return 31;
07338        case 2107:
07339       return 32;
07340        case 2181:
07341       return 33;
07342        case 2257:
07343       return 34;
07344        case 2336:
07345       return 35;
07346        case 2418:
07347       return 36;
07348        case 2503:
07349       return 37;
07350    }
07351    return -1;
07352 }
07353 
07354 /*
07355 * Shift out a formatted serial bit stream
07356 */
07357 
07358 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
07359     {
07360 #ifdef __i386__
07361     int i,j;
07362     unsigned char od,d;
07363     static volatile long long delayvar;
07364 
07365     for(i = 0 ; i < 5 ; i++){
07366         od = *data++; 
07367         for(j = 0 ; j < 8 ; j++){
07368             d = od & 1;
07369             outb(d,myrpt->p.iobase);
07370        /* >= 15 us */
07371        for(delayvar = 1; delayvar < 15000; delayvar++); 
07372             od >>= 1;
07373             outb(d | 2,myrpt->p.iobase);
07374        /* >= 30 us */
07375        for(delayvar = 1; delayvar < 30000; delayvar++); 
07376             outb(d,myrpt->p.iobase);
07377        /* >= 10 us */
07378        for(delayvar = 1; delayvar < 10000; delayvar++); 
07379             }
07380         }
07381    /* >= 50 us */
07382         for(delayvar = 1; delayvar < 50000; delayvar++); 
07383 #endif
07384     }
07385 
07386 static void rbi_out(struct rpt *myrpt,unsigned char *data)
07387 {
07388 struct dahdi_radio_param r;
07389 
07390    memset(&r,0,sizeof(struct dahdi_radio_param));
07391    r.radpar = DAHDI_RADPAR_REMMODE;
07392    r.data = DAHDI_RADPAR_REM_RBI1;
07393    /* if setparam ioctl fails, its probably not a pciradio card */
07394    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
07395    {
07396       rbi_out_parallel(myrpt,data);
07397       return;
07398    }
07399    r.radpar = DAHDI_RADPAR_REMCOMMAND;
07400    memcpy(&r.data,data,5);
07401    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
07402    {
07403       ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->dahdirxchannel->name);
07404       return;
07405    }
07406 }
07407 
07408 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, 
07409    unsigned char *rxbuf, int rxmaxbytes, int asciiflag)
07410 {
07411    int i,j,idx,oldmode,olddata;
07412    struct dahdi_radio_param prm;
07413    char c;
07414 
07415     if(debug) {
07416        ast_log(LOG_NOTICE, "ioport=%s  iofd=0x%x\n",myrpt->p.ioport,myrpt->iofd);
07417       printf("String output was:\n");
07418       for(i = 0; i < txbytes; i++)
07419          printf("%02X ", (unsigned char ) txbuf[i]);
07420       printf("\n");
07421    }
07422 
07423    if (myrpt->iofd >= 0)  /* if to do out a serial port */
07424    {
07425       if (write(myrpt->iofd,txbuf,txbytes) != txbytes)
07426       {
07427          return -1;
07428       }
07429       if ((!rxmaxbytes) || (rxbuf == NULL)) 
07430       {
07431          return(0);
07432       }
07433       memset(rxbuf,0,rxmaxbytes);
07434       for(i = 0; i < rxmaxbytes; i++)
07435       {
07436          j = read(myrpt->iofd,&c,1);
07437          if (j < 1) 
07438          {
07439             return(i);
07440          }
07441          rxbuf[i] = c;
07442          if (asciiflag & 1)
07443          {
07444             rxbuf[i + 1] = 0;
07445             if (c == '\r') break;
07446          }
07447       }              
07448       if(debug) {
07449          printf("String returned was:\n");
07450          for(j = 0; j < i; j++)
07451             printf("%02X ", (unsigned char ) rxbuf[j]);
07452          printf("\n");
07453       }
07454       return(i);
07455    }
07456 
07457    /* if not a DAHDI channel, cant use pciradio stuff */
07458    if (myrpt->rxchannel != myrpt->dahdirxchannel) return -1;   
07459 
07460    prm.radpar = DAHDI_RADPAR_UIOMODE;
07461    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
07462    oldmode = prm.data;
07463    prm.radpar = DAHDI_RADPAR_UIODATA;
07464    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
07465    olddata = prm.data;
07466         prm.radpar = DAHDI_RADPAR_REMMODE;
07467         if (asciiflag & 1)  prm.data = DAHDI_RADPAR_REM_SERIAL_ASCII;
07468         else prm.data = DAHDI_RADPAR_REM_SERIAL;
07469    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07470    if (asciiflag & 2)
07471    {
07472       i = DAHDI_ONHOOK;
07473       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
07474       usleep(100000);
07475    }
07476         prm.radpar = DAHDI_RADPAR_REMCOMMAND;
07477         prm.data = rxmaxbytes;
07478         memcpy(prm.buf,txbuf,txbytes);
07479         prm.index = txbytes;
07480    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07481         if (rxbuf)
07482         {
07483                 *rxbuf = 0;
07484                 memcpy(rxbuf,prm.buf,prm.index);
07485         }
07486    idx = prm.index;
07487         prm.radpar = DAHDI_RADPAR_REMMODE;
07488         prm.data = DAHDI_RADPAR_REM_NONE;
07489    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07490    if (asciiflag & 2)
07491    {
07492       i = DAHDI_OFFHOOK;
07493       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
07494    }
07495    prm.radpar = DAHDI_RADPAR_UIOMODE;
07496    prm.data = oldmode;
07497    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07498    prm.radpar = DAHDI_RADPAR_UIODATA;
07499    prm.data = olddata;
07500    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07501         return(idx);
07502 }
07503 
07504 static int civ_cmd(struct rpt *myrpt,unsigned char *cmd, int cmdlen)
07505 {
07506 unsigned char rxbuf[100];
07507 int   i,rv ;
07508 
07509    rv = serial_remote_io(myrpt,cmd,cmdlen,rxbuf,cmdlen + 6,0);
07510    if (rv == -1) return(-1);
07511    if (rv != (cmdlen + 6)) return(1);
07512    for(i = 0; i < 6; i++)
07513       if (rxbuf[i] != cmd[i]) return(1);
07514    if (rxbuf[cmdlen] != 0xfe) return(1);
07515    if (rxbuf[cmdlen + 1] != 0xfe) return(1);
07516    if (rxbuf[cmdlen + 4] != 0xfb) return(1);
07517    if (rxbuf[cmdlen + 5] != 0xfd) return(1);
07518    return(0);
07519 }
07520 
07521 static int sendkenwood(struct rpt *myrpt,char *txstr, char *rxstr)
07522 {
07523 int   i;
07524 
07525 ast_log(LOG_NOTICE,"Sent to kenwood: %s\n",txstr);
07526    if (debug) printf("Send to kenwood: %s\n",txstr);
07527    i = serial_remote_io(myrpt, (unsigned char *)txstr, strlen(txstr), 
07528       (unsigned char *)rxstr,RAD_SERIAL_BUFLEN - 1,3);
07529    if (i < 0) return -1;
07530    if ((i > 0) && (rxstr[i - 1] == '\r'))
07531       rxstr[i-- - 1] = 0;
07532    if (debug) printf("Got from kenwood: %s\n",rxstr);
07533 ast_log(LOG_NOTICE,"Got from kenwood: %s\n",rxstr);
07534    return(i);
07535 }
07536 
07537 /* take a PL frequency and turn it into a code */
07538 static int kenwood_pltocode(char *str)
07539 {
07540 int i;
07541 char *s;
07542 
07543    s = strchr(str,'.');
07544    i = 0;
07545    if (s) i = atoi(s + 1);
07546    i += atoi(str) * 10;
07547    switch(i)
07548    {
07549        case 670:
07550       return 1;
07551        case 719:
07552       return 3;
07553        case 744:
07554       return 4;
07555        case 770:
07556       return 5;
07557        case 797:
07558       return 6;
07559        case 825:
07560       return 7;
07561        case 854:
07562       return 8;
07563        case 885:
07564       return 9;
07565        case 915:
07566       return 10;
07567        case 948:
07568       return 11;
07569        case 974:
07570       return 12;
07571        case 1000:
07572       return 13;
07573        case 1035:
07574       return 14;
07575        case 1072:
07576       return 15;
07577        case 1109:
07578       return 16;
07579        case 1148:
07580       return 17;
07581        case 1188:
07582       return 18;
07583        case 1230:
07584       return 19;
07585        case 1273:
07586       return 20;
07587        case 1318:
07588       return 21;
07589        case 1365:
07590       return 22;
07591        case 1413:
07592       return 23;
07593        case 1462:
07594       return 24;
07595        case 1514:
07596       return 25;
07597        case 1567:
07598       return 26;
07599        case 1622:
07600       return 27;
07601        case 1679:
07602       return 28;
07603        case 1738:
07604       return 29;
07605        case 1799:
07606       return 30;
07607        case 1862:
07608       return 31;
07609        case 1928:
07610       return 32;
07611        case 2035:
07612       return 33;
07613        case 2107:
07614       return 34;
07615        case 2181:
07616       return 35;
07617        case 2257:
07618       return 36;
07619        case 2336:
07620       return 37;
07621        case 2418:
07622       return 38;
07623        case 2503:
07624       return 39;
07625    }
07626    return -1;
07627 }
07628 
07629 static int sendrxkenwood(struct rpt *myrpt, char *txstr, char *rxstr, 
07630    char *cmpstr)
07631 {
07632 int   i,j;
07633 
07634    for(i = 0;i < KENWOOD_RETRIES;i++)
07635    {
07636       j = sendkenwood(myrpt,txstr,rxstr);
07637       if (j < 0) return(j);
07638       if (j == 0) continue;
07639       if (!strncmp(rxstr,cmpstr,strlen(cmpstr))) return(0);
07640    }
07641    return(-1);
07642 }     
07643 
07644 static int setkenwood(struct rpt *myrpt)
07645 {
07646 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
07647 char mhz[MAXREMSTR],offset[20],band,decimals[MAXREMSTR],band1,band2;
07648 int myrxpl;
07649    
07650 int offsets[] = {0,2,1};
07651 int powers[] = {2,1,0};
07652 
07653    if (sendrxkenwood(myrpt,"VMC 0,0\r",rxstr,"VMC") < 0) return -1;
07654    split_freq(mhz, decimals, myrpt->freq);
07655    if (atoi(mhz) > 400)
07656    {
07657       band = '6';
07658       band1 = '1';
07659       band2 = '5';
07660       strcpy(offset,"005000000");
07661    }
07662    else
07663    {
07664       band = '2';
07665       band1 = '0';
07666       band2 = '2';
07667       strcpy(offset,"000600000");
07668    }
07669    strcpy(freq,"000000");
07670    strncpy(freq,decimals,strlen(decimals));
07671    myrxpl = myrpt->rxplon;
07672    if (IS_XPMR(myrpt)) myrxpl = 0;
07673    sprintf(txstr,"VW %c,%05d%s,0,%d,0,%d,%d,,%02d,,%02d,%s\r",
07674       band,atoi(mhz),freq,offsets[(int)myrpt->offset],
07675       (myrpt->txplon != 0),myrxpl,
07676       kenwood_pltocode(myrpt->txpl),kenwood_pltocode(myrpt->rxpl),
07677       offset);
07678    if (sendrxkenwood(myrpt,txstr,rxstr,"VW") < 0) return -1;
07679    sprintf(txstr,"RBN %c\r",band2);
07680    if (sendrxkenwood(myrpt,txstr,rxstr,"RBN") < 0) return -1;
07681    sprintf(txstr,"PC %c,%d\r",band1,powers[(int)myrpt->powerlevel]);
07682    if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
07683    return 0;
07684 }
07685 
07686 static int set_tm271(struct rpt *myrpt)
07687 {
07688 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
07689 char mhz[MAXREMSTR],decimals[MAXREMSTR];
07690    
07691 int offsets[] = {0,2,1};
07692 int powers[] = {2,1,0};
07693 
07694    split_freq(mhz, decimals, myrpt->freq);
07695    strcpy(freq,"000000");
07696    strncpy(freq,decimals,strlen(decimals));
07697 
07698    sprintf(txstr,"VF %04d%s,4,%d,0,%d,0,0,%d,%d,000,00600000,0,0\r",
07699       atoi(mhz),freq,offsets[(int)myrpt->offset],
07700       (myrpt->txplon != 0),kenwood_pltocode(myrpt->txpl),
07701       kenwood_pltocode(myrpt->rxpl));
07702 
07703    if (sendrxkenwood(myrpt,txstr,rxstr,"VF") < 0) return -1;
07704    if (sendrxkenwood(myrpt,"VM 0\r",rxstr,"VM") < 0) return -1;
07705    sprintf(txstr,"PC %d\r",powers[(int)myrpt->powerlevel]);
07706    if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
07707    return 0;
07708 }
07709 
07710 static int setrbi(struct rpt *myrpt)
07711 {
07712 char tmp[MAXREMSTR] = "",*s;
07713 unsigned char rbicmd[5];
07714 int   band,txoffset = 0,txpower = 0,rxpl;
07715 
07716    /* must be a remote system */
07717    if (!myrpt->remoterig) return(0);
07718    if (!myrpt->remoterig[0]) return(0);
07719    /* must have rbi hardware */
07720    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
07721    if (setrbi_check(myrpt) == -1) return(-1);
07722    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07723    s = strchr(tmp,'.');
07724    /* if no decimal, is invalid */
07725    
07726    if (s == NULL){
07727       if(debug)
07728          printf("@@@@ Frequency needs a decimal\n");
07729       return -1;
07730    }
07731    
07732    *s++ = 0;
07733    if (strlen(tmp) < 2){
07734       if(debug)
07735          printf("@@@@ Bad MHz digits: %s\n", tmp);
07736       return -1;
07737    }
07738     
07739    if (strlen(s) < 3){
07740       if(debug)
07741          printf("@@@@ Bad KHz digits: %s\n", s);
07742       return -1;
07743    }
07744 
07745    if ((s[2] != '0') && (s[2] != '5')){
07746       if(debug)
07747          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
07748       return -1;
07749    }
07750     
07751    band = rbi_mhztoband(tmp);
07752    if (band == -1){
07753       if(debug)
07754          printf("@@@@ Bad Band: %s\n", tmp);
07755       return -1;
07756    }
07757    
07758    rxpl = rbi_pltocode(myrpt->rxpl);
07759    
07760    if (rxpl == -1){
07761       if(debug)
07762          printf("@@@@ Bad TX PL: %s\n", myrpt->rxpl);
07763       return -1;
07764    }
07765 
07766    
07767    switch(myrpt->offset)
07768    {
07769        case REM_MINUS:
07770       txoffset = 0;
07771       break;
07772        case REM_PLUS:
07773       txoffset = 0x10;
07774       break;
07775        case REM_SIMPLEX:
07776       txoffset = 0x20;
07777       break;
07778    }
07779    switch(myrpt->powerlevel)
07780    {
07781        case REM_LOWPWR:
07782       txpower = 0;
07783       break;
07784        case REM_MEDPWR:
07785       txpower = 0x20;
07786       break;
07787        case REM_HIPWR:
07788       txpower = 0x10;
07789       break;
07790    }
07791    rbicmd[0] = 0;
07792    rbicmd[1] = band | txpower | 0xc0;
07793    rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
07794    if (s[2] == '5') rbicmd[2] |= 0x40;
07795    rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
07796    rbicmd[4] = rxpl;
07797    if (myrpt->txplon) rbicmd[4] |= 0x40;
07798    if (myrpt->rxplon) rbicmd[4] |= 0x80;
07799    rbi_out(myrpt,rbicmd);
07800    return 0;
07801 }
07802 
07803 static int setrtx(struct rpt *myrpt)
07804 {
07805 char tmp[MAXREMSTR] = "",*s,rigstr[200],pwr,res = 0;
07806 int   band,txoffset = 0,txpower = 0,rxpl,txpl;
07807 float ofac;
07808 double txfreq;
07809 
07810    /* must be a remote system */
07811    if (!myrpt->remoterig) return(0);
07812    if (!myrpt->remoterig[0]) return(0);
07813    /* must have rtx hardware */
07814    if (!ISRIG_RTX(myrpt->remoterig)) return(0);
07815    /* must be a usbradio interface type */
07816    if (!IS_XPMR(myrpt)) return(0);
07817    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07818    s = strchr(tmp,'.');
07819    /* if no decimal, is invalid */
07820    
07821    if(debug)printf("setrtx() %s %s\n",myrpt->name,myrpt->remoterig);
07822 
07823    if (s == NULL){
07824       if(debug)
07825          printf("@@@@ Frequency needs a decimal\n");
07826       return -1;
07827    }
07828    *s++ = 0;
07829    if (strlen(tmp) < 2){
07830       if(debug)
07831          printf("@@@@ Bad MHz digits: %s\n", tmp);
07832       return -1;
07833    }
07834     
07835    if (strlen(s) < 3){
07836       if(debug)
07837          printf("@@@@ Bad KHz digits: %s\n", s);
07838       return -1;
07839    }
07840 
07841    if ((s[2] != '0') && (s[2] != '5')){
07842       if(debug)
07843          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
07844       return -1;
07845    }
07846     
07847    band = rbi_mhztoband(tmp);
07848    if (band == -1){
07849       if(debug)
07850          printf("@@@@ Bad Band: %s\n", tmp);
07851       return -1;
07852    }
07853    
07854    rxpl = rbi_pltocode(myrpt->rxpl);
07855    
07856    if (rxpl == -1){
07857       if(debug)
07858          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
07859       return -1;
07860    }
07861 
07862    txpl = rbi_pltocode(myrpt->txpl);
07863    
07864    if (txpl == -1){
07865       if(debug)
07866          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
07867       return -1;
07868    }
07869    
07870    switch(myrpt->offset)
07871    {
07872        case REM_MINUS:
07873       txoffset = 0;
07874       break;
07875        case REM_PLUS:
07876       txoffset = 0x10;
07877       break;
07878        case REM_SIMPLEX:
07879       txoffset = 0x20;
07880       break;
07881    }
07882    switch(myrpt->powerlevel)
07883    {
07884        case REM_LOWPWR:
07885       txpower = 0;
07886       break;
07887        case REM_MEDPWR:
07888       txpower = 0x20;
07889       break;
07890        case REM_HIPWR:
07891       txpower = 0x10;
07892       break;
07893    }
07894 
07895    res = setrtx_check(myrpt);
07896    if (res < 0) return res;
07897    ofac = 0.0;
07898    if (myrpt->offset == REM_MINUS) ofac = -1.0;
07899    if (myrpt->offset == REM_PLUS) ofac = 1.0;
07900 
07901    if (!strcmp(myrpt->remoterig,remote_rig_rtx450))
07902       txfreq = atof(myrpt->freq) +  (ofac * 5.0);
07903    else
07904       txfreq = atof(myrpt->freq) +  (ofac * 0.6);
07905 
07906    pwr = 'L';
07907    if (myrpt->powerlevel == REM_HIPWR) pwr = 'H';
07908    if (!res)
07909    {
07910       sprintf(rigstr,"SETFREQ %s %f %s %s %c",myrpt->freq,txfreq,
07911          (myrpt->rxplon) ? myrpt->rxpl : "0.0",
07912          (myrpt->txplon) ? myrpt->txpl : "0.0",pwr);
07913       send_usb_txt(myrpt,rigstr);
07914       rpt_telemetry(myrpt,COMPLETE,NULL);
07915       res = 0;
07916    }
07917    return 0;
07918 }
07919 #if 0
07920 /*
07921    sets current signaling code for xpmr routines
07922    under development for new radios.
07923 */
07924 static int setxpmr(struct rpt *myrpt)
07925 {
07926    char rigstr[200];
07927    int rxpl,txpl;
07928 
07929    /* must be a remote system */
07930    if (!myrpt->remoterig) return(0);
07931    if (!myrpt->remoterig[0]) return(0);
07932    /* must not have rtx hardware */
07933    if (ISRIG_RTX(myrpt->remoterig)) return(0);
07934    /* must be a usbradio interface type */
07935    if (!IS_XPMR(myrpt)) return(0);
07936    
07937    if(debug)printf("setxpmr() %s %s\n",myrpt->name,myrpt->remoterig );
07938 
07939    rxpl = rbi_pltocode(myrpt->rxpl);
07940    
07941    if (rxpl == -1){
07942       if(debug)
07943          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
07944       return -1;
07945    }
07946 
07947    txpl = rbi_pltocode(myrpt->txpl);
07948    if (txpl == -1){
07949       if(debug)
07950          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
07951       return -1;
07952    }
07953    sprintf(rigstr,"SETFREQ 0.0 0.0 %s %s L",
07954       (myrpt->rxplon) ? myrpt->rxpl : "0.0",
07955       (myrpt->txplon) ? myrpt->txpl : "0.0");
07956    send_usb_txt(myrpt,rigstr);
07957    return 0;
07958 }
07959 #endif
07960 
07961 static int setrbi_check(struct rpt *myrpt)
07962 {
07963 char tmp[MAXREMSTR] = "",*s;
07964 int   band,txpl;
07965 
07966    /* must be a remote system */
07967    if (!myrpt->remote) return(0);
07968    /* must have rbi hardware */
07969    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
07970    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07971    s = strchr(tmp,'.');
07972    /* if no decimal, is invalid */
07973    
07974    if (s == NULL){
07975       if(debug)
07976          printf("@@@@ Frequency needs a decimal\n");
07977       return -1;
07978    }
07979    
07980    *s++ = 0;
07981    if (strlen(tmp) < 2){
07982       if(debug)
07983          printf("@@@@ Bad MHz digits: %s\n", tmp);
07984       return -1;
07985    }
07986     
07987    if (strlen(s) < 3){
07988       if(debug)
07989          printf("@@@@ Bad KHz digits: %s\n", s);
07990       return -1;
07991    }
07992 
07993    if ((s[2] != '0') && (s[2] != '5')){
07994       if(debug)
07995          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
07996       return -1;
07997    }
07998     
07999    band = rbi_mhztoband(tmp);
08000    if (band == -1){
08001       if(debug)
08002          printf("@@@@ Bad Band: %s\n", tmp);
08003       return -1;
08004    }
08005    
08006    txpl = rbi_pltocode(myrpt->txpl);
08007    
08008    if (txpl == -1){
08009       if(debug)
08010          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
08011       return -1;
08012    }
08013    return 0;
08014 }
08015 
08016 static int setrtx_check(struct rpt *myrpt)
08017 {
08018 char tmp[MAXREMSTR] = "",*s;
08019 int   band,txpl,rxpl;
08020 
08021    /* must be a remote system */
08022    if (!myrpt->remote) return(0);
08023    /* must have rbi hardware */
08024    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
08025    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
08026    s = strchr(tmp,'.');
08027    /* if no decimal, is invalid */
08028    
08029    if (s == NULL){
08030       if(debug)
08031          printf("@@@@ Frequency needs a decimal\n");
08032       return -1;
08033    }
08034    
08035    *s++ = 0;
08036    if (strlen(tmp) < 2){
08037       if(debug)
08038          printf("@@@@ Bad MHz digits: %s\n", tmp);
08039       return -1;
08040    }
08041     
08042    if (strlen(s) < 3){
08043       if(debug)
08044          printf("@@@@ Bad KHz digits: %s\n", s);
08045       return -1;
08046    }
08047 
08048    if ((s[2] != '0') && (s[2] != '5')){
08049       if(debug)
08050          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
08051       return -1;
08052    }
08053     
08054    band = rbi_mhztoband(tmp);
08055    if (band == -1){
08056       if(debug)
08057          printf("@@@@ Bad Band: %s\n", tmp);
08058       return -1;
08059    }
08060    
08061    txpl = rbi_pltocode(myrpt->txpl);
08062    
08063    if (txpl == -1){
08064       if(debug)
08065          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
08066       return -1;
08067    }
08068 
08069    rxpl = rbi_pltocode(myrpt->rxpl);
08070    
08071    if (rxpl == -1){
08072       if(debug)
08073          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
08074       return -1;
08075    }
08076    return 0;
08077 }
08078 
08079 static int check_freq_kenwood(int m, int d, int *defmode)
08080 {
08081    int dflmd = REM_MODE_FM;
08082 
08083    if (m == 144){ /* 2 meters */
08084       if(d < 10100)
08085          return -1;
08086    }
08087    else if((m >= 145) && (m < 148)){
08088       ;
08089    }
08090    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08091       ;
08092    }
08093    else
08094       return -1;
08095    
08096    if(defmode)
08097       *defmode = dflmd; 
08098 
08099 
08100    return 0;
08101 }
08102 
08103 
08104 static int check_freq_tm271(int m, int d, int *defmode)
08105 {
08106    int dflmd = REM_MODE_FM;
08107 
08108    if (m == 144){ /* 2 meters */
08109       if(d < 10100)
08110          return -1;
08111    }
08112    else if((m >= 145) && (m < 148)){
08113       ;
08114    }
08115       return -1;
08116    
08117    if(defmode)
08118       *defmode = dflmd; 
08119 
08120 
08121    return 0;
08122 }
08123 
08124 
08125 /* Check for valid rbi frequency */
08126 /* Hard coded limits now, configurable later, maybe? */
08127 
08128 static int check_freq_rbi(int m, int d, int *defmode)
08129 {
08130    int dflmd = REM_MODE_FM;
08131 
08132    if(m == 50){ /* 6 meters */
08133       if(d < 10100)
08134          return -1;
08135    }
08136    else if((m >= 51) && ( m < 54)){
08137                 ;
08138    }
08139    else if(m == 144){ /* 2 meters */
08140       if(d < 10100)
08141          return -1;
08142    }
08143    else if((m >= 145) && (m < 148)){
08144       ;
08145    }
08146    else if((m >= 222) && (m < 225)){ /* 1.25 meters */
08147       ;
08148    }
08149    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08150       ;
08151    }
08152    else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
08153       ;
08154    }
08155    else
08156       return -1;
08157    
08158    if(defmode)
08159       *defmode = dflmd; 
08160 
08161 
08162    return 0;
08163 }
08164 
08165 /* Check for valid rtx frequency */
08166 /* Hard coded limits now, configurable later, maybe? */
08167 
08168 static int check_freq_rtx(int m, int d, int *defmode, struct rpt *myrpt)
08169 {
08170    int dflmd = REM_MODE_FM;
08171 
08172    if (!strcmp(myrpt->remoterig,remote_rig_rtx150))
08173    {
08174 
08175       if(m == 144){ /* 2 meters */
08176          if(d < 10100)
08177             return -1;
08178       }
08179       else if((m >= 145) && (m < 148)){
08180          ;
08181       }
08182       else
08183          return -1;
08184    }
08185    else 
08186    {
08187       if((m >= 430) && (m < 450)){ /* 70 centimeters */
08188          ;
08189       }
08190       else
08191          return -1;
08192    }
08193    if(defmode)
08194       *defmode = dflmd; 
08195 
08196 
08197    return 0;
08198 }
08199 
08200 /*
08201  * Convert decimals of frequency to int
08202  */
08203 
08204 static int decimals2int(char *fraction)
08205 {
08206    int i;
08207    char len = strlen(fraction);
08208    int multiplier = 100000;
08209    int res = 0;
08210 
08211    if(!len)
08212       return 0;
08213    for( i = 0 ; i < len ; i++, multiplier /= 10)
08214       res += (fraction[i] - '0') * multiplier;
08215    return res;
08216 }
08217 
08218 
08219 /*
08220 * Split frequency into mhz and decimals
08221 */
08222  
08223 static int split_freq(char *mhz, char *decimals, char *freq)
08224 {
08225    char freq_copy[MAXREMSTR];
08226    char *decp;
08227 
08228    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
08229    if(decp){
08230       *decp++ = 0;
08231       strncpy(mhz, freq_copy, MAXREMSTR);
08232       strcpy(decimals, "00000");
08233       strncpy(decimals, decp, strlen(decp));
08234       decimals[5] = 0;
08235       return 0;
08236    }
08237    else
08238       return -1;
08239 
08240 }
08241    
08242 /*
08243 * Split ctcss frequency into hertz and decimal
08244 */
08245  
08246 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
08247 {
08248    char freq_copy[MAXREMSTR];
08249    char *decp;
08250 
08251    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
08252    if(decp){
08253       *decp++ = 0;
08254       strncpy(hertz, freq_copy, MAXREMSTR);
08255       strncpy(decimal, decp, strlen(decp));
08256       decimal[strlen(decp)] = '\0';
08257       return 0;
08258    }
08259    else
08260       return -1;
08261 }
08262 
08263 
08264 
08265 /*
08266 * FT-897 I/O handlers
08267 */
08268 
08269 /* Check to see that the frequency is valid */
08270 /* Hard coded limits now, configurable later, maybe? */
08271 
08272 
08273 static int check_freq_ft897(int m, int d, int *defmode)
08274 {
08275    int dflmd = REM_MODE_FM;
08276 
08277    if(m == 1){ /* 160 meters */
08278       dflmd =  REM_MODE_LSB; 
08279       if(d < 80000)
08280          return -1;
08281    }
08282    else if(m == 3){ /* 80 meters */
08283       dflmd = REM_MODE_LSB;
08284       if(d < 50000)
08285          return -1;
08286    }
08287    else if(m == 7){ /* 40 meters */
08288       dflmd = REM_MODE_LSB;
08289       if(d > 30000)
08290          return -1;
08291    }
08292    else if(m == 14){ /* 20 meters */
08293       dflmd = REM_MODE_USB;
08294       if(d > 35000)
08295          return -1;
08296    }
08297    else if(m == 18){ /* 17 meters */
08298       dflmd = REM_MODE_USB;
08299       if((d < 6800) || (d > 16800))
08300          return -1;
08301    }
08302    else if(m == 21){ /* 15 meters */
08303       dflmd = REM_MODE_USB;
08304       if((d < 20000) || (d > 45000))
08305          return -1;
08306    }
08307    else if(m == 24){ /* 12 meters */
08308       dflmd = REM_MODE_USB;
08309       if((d < 89000) || (d > 99000))
08310          return -1;
08311    }
08312    else if(m == 28){ /* 10 meters */
08313       dflmd = REM_MODE_USB;
08314    }
08315    else if(m == 29){ 
08316       if(d >= 51000)
08317          dflmd = REM_MODE_FM;
08318       else
08319          dflmd = REM_MODE_USB;
08320       if(d > 70000)
08321          return -1;
08322    }
08323    else if(m == 50){ /* 6 meters */
08324       if(d >= 30000)
08325          dflmd = REM_MODE_FM;
08326       else
08327          dflmd = REM_MODE_USB;
08328 
08329    }
08330    else if((m >= 51) && ( m < 54)){
08331       dflmd = REM_MODE_FM;
08332    }
08333    else if(m == 144){ /* 2 meters */
08334       if(d >= 30000)
08335          dflmd = REM_MODE_FM;
08336       else
08337          dflmd = REM_MODE_USB;
08338    }
08339    else if((m >= 145) && (m < 148)){
08340       dflmd = REM_MODE_FM;
08341    }
08342    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08343       if(m  < 438)
08344          dflmd = REM_MODE_USB;
08345       else
08346          dflmd = REM_MODE_FM;
08347       ;
08348    }
08349    else
08350       return -1;
08351 
08352    if(defmode)
08353       *defmode = dflmd;
08354 
08355    return 0;
08356 }
08357 
08358 /*
08359 * Set a new frequency for the FT897
08360 */
08361 
08362 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
08363 {
08364    unsigned char cmdstr[5];
08365    int fd,m,d;
08366    char mhz[MAXREMSTR];
08367    char decimals[MAXREMSTR];
08368 
08369    fd = 0;
08370    if(debug) 
08371       printf("New frequency: %s\n",newfreq);
08372 
08373    if(split_freq(mhz, decimals, newfreq))
08374       return -1; 
08375 
08376    m = atoi(mhz);
08377    d = atoi(decimals);
08378 
08379    /* The FT-897 likes packed BCD frequencies */
08380 
08381    cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10);        /* 100MHz 10Mhz */
08382    cmdstr[1] = ((m % 10) << 4) + (d / 10000);         /* 1MHz 100KHz */
08383    cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100);  /* 10KHz 1KHz */
08384    cmdstr[3] = (((d % 100)/10) << 4) + (d % 10);         /* 100Hz 10Hz */
08385    cmdstr[4] = 0x01;                /* command */
08386 
08387    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08388 
08389 }
08390 
08391 /* ft-897 simple commands */
08392 
08393 static int simple_command_ft897(struct rpt *myrpt, char command)
08394 {
08395    unsigned char cmdstr[5];
08396    
08397    memset(cmdstr, 0, 5);
08398 
08399    cmdstr[4] = command; 
08400 
08401    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08402 
08403 }
08404 
08405 /* ft-897 offset */
08406 
08407 static int set_offset_ft897(struct rpt *myrpt, char offset)
08408 {
08409    unsigned char cmdstr[5];
08410    
08411    memset(cmdstr, 0, 5);
08412 
08413    switch(offset){
08414       case  REM_SIMPLEX:
08415          cmdstr[0] = 0x89;
08416          break;
08417 
08418       case  REM_MINUS:
08419          cmdstr[0] = 0x09;
08420          break;
08421       
08422       case  REM_PLUS:
08423          cmdstr[0] = 0x49;
08424          break;   
08425 
08426       default:
08427          return -1;
08428    }
08429 
08430    cmdstr[4] = 0x09; 
08431 
08432    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08433 }
08434 
08435 /* ft-897 mode */
08436 
08437 static int set_mode_ft897(struct rpt *myrpt, char newmode)
08438 {
08439    unsigned char cmdstr[5];
08440    
08441    memset(cmdstr, 0, 5);
08442    
08443    switch(newmode){
08444       case  REM_MODE_FM:
08445          cmdstr[0] = 0x08;
08446          break;
08447 
08448       case  REM_MODE_USB:
08449          cmdstr[0] = 0x01;
08450          break;
08451 
08452       case  REM_MODE_LSB:
08453          cmdstr[0] = 0x00;
08454          break;
08455 
08456       case  REM_MODE_AM:
08457          cmdstr[0] = 0x04;
08458          break;
08459       
08460       default:
08461          return -1;
08462    }
08463    cmdstr[4] = 0x07; 
08464 
08465    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08466 }
08467 
08468 /* Set tone encode and decode modes */
08469 
08470 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
08471 {
08472    unsigned char cmdstr[5];
08473    
08474    memset(cmdstr, 0, 5);
08475    
08476    if(rxplon && txplon)
08477       cmdstr[0] = 0x2A; /* Encode and Decode */
08478    else if (!rxplon && txplon)
08479       cmdstr[0] = 0x4A; /* Encode only */
08480    else if (rxplon && !txplon)
08481       cmdstr[0] = 0x3A; /* Encode only */
08482    else
08483       cmdstr[0] = 0x8A; /* OFF */
08484 
08485    cmdstr[4] = 0x0A; 
08486 
08487    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08488 }
08489 
08490 
08491 /* Set transmit and receive ctcss tone frequencies */
08492 
08493 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
08494 {
08495    unsigned char cmdstr[5];
08496    char hertz[MAXREMSTR],decimal[MAXREMSTR];
08497    int h,d; 
08498 
08499    memset(cmdstr, 0, 5);
08500 
08501    if(split_ctcss_freq(hertz, decimal, txtone))
08502       return -1; 
08503 
08504    h = atoi(hertz);
08505    d = atoi(decimal);
08506    
08507    cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
08508    cmdstr[1] = ((h % 10) << 4) + (d % 10);
08509    
08510    if(rxtone){
08511    
08512       if(split_ctcss_freq(hertz, decimal, rxtone))
08513          return -1; 
08514 
08515       h = atoi(hertz);
08516       d = atoi(decimal);
08517    
08518       cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
08519       cmdstr[3] = ((h % 10) << 4) + (d % 10);
08520    }
08521    cmdstr[4] = 0x0B; 
08522 
08523    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08524 }  
08525 
08526 
08527 
08528 static int set_ft897(struct rpt *myrpt)
08529 {
08530    int res;
08531    
08532    if(debug)
08533       printf("@@@@ lock on\n");
08534 
08535    res = simple_command_ft897(myrpt, 0x00);  /* LOCK on */  
08536 
08537    if(debug)
08538       printf("@@@@ ptt off\n");
08539 
08540    if(!res)
08541       res = simple_command_ft897(myrpt, 0x88);     /* PTT off */
08542 
08543    if(debug)
08544       printf("Modulation mode\n");
08545 
08546    if(!res)
08547       res = set_mode_ft897(myrpt, myrpt->remmode);    /* Modulation mode */
08548 
08549    if(debug)
08550       printf("Split off\n");
08551 
08552    if(!res)
08553       simple_command_ft897(myrpt, 0x82);        /* Split off */
08554 
08555    if(debug)
08556       printf("Frequency\n");
08557 
08558    if(!res)
08559       res = set_freq_ft897(myrpt, myrpt->freq);    /* Frequency */
08560    if((myrpt->remmode == REM_MODE_FM)){
08561       if(debug)
08562          printf("Offset\n");
08563       if(!res)
08564          res = set_offset_ft897(myrpt, myrpt->offset);   /* Offset if FM */
08565       if((!res)&&(myrpt->rxplon || myrpt->txplon)){
08566          if(debug)
08567             printf("CTCSS tone freqs.\n");
08568          res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
08569       }
08570       if(!res){
08571          if(debug)
08572             printf("CTCSS mode\n");
08573          res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
08574       }
08575    }
08576    if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
08577       if(debug)
08578          printf("Clarifier off\n");
08579       simple_command_ft897(myrpt, 0x85);        /* Clarifier off if LSB or USB */
08580    }
08581    return res;
08582 }
08583 
08584 static int closerem_ft897(struct rpt *myrpt)
08585 {
08586    simple_command_ft897(myrpt, 0x88); /* PTT off */
08587    return 0;
08588 }  
08589 
08590 /*
08591 * Bump frequency up or down by a small amount 
08592 * Return 0 if the new frequnecy is valid, or -1 if invalid
08593 * Interval is in Hz, resolution is 10Hz 
08594 */
08595 
08596 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
08597 {
08598    int m,d;
08599    char mhz[MAXREMSTR], decimals[MAXREMSTR];
08600 
08601    if(debug)
08602       printf("Before bump: %s\n", myrpt->freq);
08603 
08604    if(split_freq(mhz, decimals, myrpt->freq))
08605       return -1;
08606    
08607    m = atoi(mhz);
08608    d = atoi(decimals);
08609 
08610    d += (interval / 10); /* 10Hz resolution */
08611    if(d < 0){
08612       m--;
08613       d += 100000;
08614    }
08615    else if(d >= 100000){
08616       m++;
08617       d -= 100000;
08618    }
08619 
08620    if(check_freq_ft897(m, d, NULL)){
08621       if(debug)
08622          printf("Bump freq invalid\n");
08623       return -1;
08624    }
08625 
08626    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
08627 
08628    if(debug)
08629       printf("After bump: %s\n", myrpt->freq);
08630 
08631    return set_freq_ft897(myrpt, myrpt->freq);   
08632 }
08633 
08634 
08635 
08636 /*
08637 * IC-706 I/O handlers
08638 */
08639 
08640 /* Check to see that the frequency is valid */
08641 /* returns 0 if frequency is valid          */
08642 
08643 static int check_freq_ic706(int m, int d, int *defmode, char mars)
08644 {
08645    int dflmd = REM_MODE_FM;
08646    int rv=0;
08647 
08648    if(debug > 6)
08649       ast_log(LOG_NOTICE,"(%i,%i,%i,%i)\n",m,d,*defmode,mars);
08650 
08651    /* first test for standard amateur radio bands */
08652 
08653    if(m == 1){                /* 160 meters */
08654       dflmd =  REM_MODE_LSB; 
08655       if(d < 80000)rv=-1;
08656    }
08657    else if(m == 3){           /* 80 meters */
08658       dflmd = REM_MODE_LSB;
08659       if(d < 50000)rv=-1;
08660    }
08661    else if(m == 7){           /* 40 meters */
08662       dflmd = REM_MODE_LSB;
08663       if(d > 30000)rv=-1;
08664    }
08665    else if(m == 14){             /* 20 meters */
08666       dflmd = REM_MODE_USB;
08667       if(d > 35000)rv=-1;
08668    }
08669    else if(m == 18){                      /* 17 meters */
08670       dflmd = REM_MODE_USB;
08671       if((d < 6800) || (d > 16800))rv=-1;
08672    }
08673    else if(m == 21){ /* 15 meters */
08674       dflmd = REM_MODE_USB;
08675       if((d < 20000) || (d > 45000))rv=-1;
08676    }
08677    else if(m == 24){ /* 12 meters */
08678       dflmd = REM_MODE_USB;
08679       if((d < 89000) || (d > 99000))rv=-1;
08680    }
08681    else if(m == 28){                      /* 10 meters */
08682       dflmd = REM_MODE_USB;
08683    }
08684    else if(m == 29){ 
08685       if(d >= 51000)
08686          dflmd = REM_MODE_FM;
08687       else
08688          dflmd = REM_MODE_USB;
08689       if(d > 70000)rv=-1;
08690    }
08691    else if(m == 50){                      /* 6 meters */
08692       if(d >= 30000)
08693          dflmd = REM_MODE_FM;
08694       else
08695          dflmd = REM_MODE_USB;
08696    }
08697    else if((m >= 51) && ( m < 54)){
08698       dflmd = REM_MODE_FM;
08699    }
08700    else if(m == 144){ /* 2 meters */
08701       if(d >= 30000)
08702          dflmd = REM_MODE_FM;
08703       else
08704          dflmd = REM_MODE_USB;
08705    }
08706    else if((m >= 145) && (m < 148)){
08707       dflmd = REM_MODE_FM;
08708    }
08709    else if((m >= 430) && (m < 450)){         /* 70 centimeters */
08710       if(m  < 438)
08711          dflmd = REM_MODE_USB;
08712       else
08713          dflmd = REM_MODE_FM;
08714    }
08715 
08716    /* check expanded coverage */
08717    if(mars && rv<0){
08718       if((m >= 450) && (m < 470)){        /* LMR */
08719          dflmd = REM_MODE_FM;
08720          rv=0;
08721       }
08722       else if((m >= 148) && (m < 174)){      /* LMR */
08723          dflmd = REM_MODE_FM;
08724          rv=0;
08725       }
08726       else if((m >= 138) && (m < 144)){      /* VHF-AM AIRCRAFT */
08727          dflmd = REM_MODE_AM;
08728          rv=0;
08729       }
08730       else if((m >= 108) && (m < 138)){      /* VHF-AM AIRCRAFT */
08731          dflmd = REM_MODE_AM;
08732          rv=0;
08733       }
08734       else if( (m==0 && d>=55000) || (m==1 && d<=75000) ){  /* AM BCB*/
08735          dflmd = REM_MODE_AM;
08736          rv=0;
08737       }
08738       else if( (m == 1 && d>75000) || (m>1 && m<30) ){      /* HF SWL*/
08739          dflmd = REM_MODE_AM;
08740          rv=0;
08741       }
08742    }
08743 
08744    if(defmode)
08745       *defmode = dflmd;
08746 
08747    if(debug > 1)
08748       ast_log(LOG_NOTICE,"(%i,%i,%i,%i) returning %i\n",m,d,*defmode,mars,rv);
08749 
08750    return rv;
08751 }
08752 
08753 /* take a PL frequency and turn it into a code */
08754 static int ic706_pltocode(char *str)
08755 {
08756    int i;
08757    char *s;
08758    int rv=-1;
08759 
08760    s = strchr(str,'.');
08761    i = 0;
08762    if (s) i = atoi(s + 1);
08763    i += atoi(str) * 10;
08764    switch(i)
08765    {
08766        case 670:
08767          rv=0;
08768        case 693:
08769          rv=1;
08770        case 719:
08771          rv=2;
08772        case 744:
08773          rv=3;
08774        case 770:
08775          rv=4;
08776        case 797:
08777          rv=5;
08778        case 825:
08779          rv=6;
08780        case 854:
08781          rv=7;
08782        case 885:
08783          rv=8;
08784        case 915:
08785          rv=9;
08786        case 948:
08787          rv=10;
08788        case 974:
08789          rv=11;
08790        case 1000:
08791          rv=12;
08792        case 1035:
08793          rv=13;
08794        case 1072:
08795          rv=14;
08796        case 1109:
08797          rv=15;
08798        case 1148:
08799          rv=16;
08800        case 1188:
08801          rv=17;
08802        case 1230:
08803          rv=18;
08804        case 1273:
08805          rv=19;
08806        case 1318:
08807          rv=20;
08808        case 1365:
08809          rv=21;
08810        case 1413:
08811          rv=22;
08812        case 1462:
08813          rv=23;
08814        case 1514:
08815          rv=24;
08816        case 1567:
08817          rv=25;
08818        case 1598:
08819          rv=26;
08820        case 1622:
08821          rv=27;
08822        case 1655:
08823          rv=28;      
08824        case 1679:
08825          rv=29;
08826        case 1713:
08827          rv=30;
08828        case 1738:
08829          rv=31;
08830        case 1773:
08831          rv=32;
08832        case 1799:
08833          rv=33;
08834         case 1835:
08835          rv=34;
08836        case 1862:
08837          rv=35;
08838        case 1899:
08839          rv=36;
08840        case 1928:
08841          rv=37;
08842        case 1966:
08843          rv=38;
08844        case 1995:
08845          rv=39;
08846        case 2035:
08847          rv=40;
08848        case 2065:
08849          rv=41;
08850        case 2107:
08851          rv=42;
08852        case 2181:
08853          rv=43;
08854        case 2257:
08855          rv=44;
08856        case 2291:
08857          rv=45;
08858        case 2336:
08859          rv=46;
08860        case 2418:
08861          rv=47;
08862        case 2503:
08863          rv=48;
08864        case 2541:
08865          rv=49;
08866    }
08867    if(debug > 1)
08868       ast_log(LOG_NOTICE,"%i  rv=%i\n",i, rv);
08869 
08870    return rv;
08871 }
08872 
08873 /* ic-706 simple commands */
08874 
08875 static int simple_command_ic706(struct rpt *myrpt, char command, char subcommand)
08876 {
08877    unsigned char cmdstr[10];
08878    
08879    cmdstr[0] = cmdstr[1] = 0xfe;
08880    cmdstr[2] = myrpt->p.civaddr;
08881    cmdstr[3] = 0xe0;
08882    cmdstr[4] = command;
08883    cmdstr[5] = subcommand;
08884    cmdstr[6] = 0xfd;
08885 
08886    return(civ_cmd(myrpt,cmdstr,7));
08887 }
08888 
08889 /*
08890 * Set a new frequency for the ic706
08891 */
08892 
08893 static int set_freq_ic706(struct rpt *myrpt, char *newfreq)
08894 {
08895    unsigned char cmdstr[20];
08896    char mhz[MAXREMSTR], decimals[MAXREMSTR];
08897    int fd,m,d;
08898 
08899    fd = 0;
08900    if(debug) 
08901       ast_log(LOG_NOTICE,"newfreq:%s\n",newfreq);        
08902 
08903    if(split_freq(mhz, decimals, newfreq))
08904       return -1; 
08905 
08906    m = atoi(mhz);
08907    d = atoi(decimals);
08908 
08909    /* The ic-706 likes packed BCD frequencies */
08910 
08911    cmdstr[0] = cmdstr[1] = 0xfe;
08912    cmdstr[2] = myrpt->p.civaddr;
08913    cmdstr[3] = 0xe0;
08914    cmdstr[4] = 5;
08915    cmdstr[5] = ((d % 10) << 4);
08916    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
08917    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
08918    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
08919    cmdstr[9] = (m / 100);
08920    cmdstr[10] = 0xfd;
08921 
08922    return(civ_cmd(myrpt,cmdstr,11));
08923 }
08924 
08925 /* ic-706 offset */
08926 
08927 static int set_offset_ic706(struct rpt *myrpt, char offset)
08928 {
08929    unsigned char c;
08930 
08931    if(debug > 6)
08932       ast_log(LOG_NOTICE,"offset=%i\n",offset);
08933 
08934    switch(offset){
08935       case  REM_SIMPLEX:
08936          c = 0x10;
08937          break;
08938 
08939       case  REM_MINUS:
08940          c = 0x11;
08941          break;
08942       
08943       case  REM_PLUS:
08944          c = 0x12;
08945          break;   
08946 
08947       default:
08948          return -1;
08949    }
08950 
08951    return simple_command_ic706(myrpt,0x0f,c);
08952 
08953 }
08954 
08955 /* ic-706 mode */
08956 
08957 static int set_mode_ic706(struct rpt *myrpt, char newmode)
08958 {
08959    unsigned char c;
08960    
08961    if(debug > 6)
08962       ast_log(LOG_NOTICE,"newmode=%i\n",newmode);
08963 
08964    switch(newmode){
08965       case  REM_MODE_FM:
08966          c = 5;
08967          break;
08968 
08969       case  REM_MODE_USB:
08970          c = 1;
08971          break;
08972 
08973       case  REM_MODE_LSB:
08974          c = 0;
08975          break;
08976 
08977       case  REM_MODE_AM:
08978          c = 2;
08979          break;
08980       
08981       default:
08982          return -1;
08983    }
08984    return simple_command_ic706(myrpt,6,c);
08985 }
08986 
08987 /* Set tone encode and decode modes */
08988 
08989 static int set_ctcss_mode_ic706(struct rpt *myrpt, char txplon, char rxplon)
08990 {
08991    unsigned char cmdstr[10];
08992    int rv;
08993 
08994    if(debug > 6)
08995       ast_log(LOG_NOTICE,"txplon=%i  rxplon=%i \n",txplon,rxplon);
08996 
08997    cmdstr[0] = cmdstr[1] = 0xfe;
08998    cmdstr[2] = myrpt->p.civaddr;
08999    cmdstr[3] = 0xe0;
09000    cmdstr[4] = 0x16;
09001    cmdstr[5] = 0x42;
09002    cmdstr[6] = (txplon != 0);
09003    cmdstr[7] = 0xfd;
09004 
09005    rv = civ_cmd(myrpt,cmdstr,8);
09006    if (rv) return(-1);
09007 
09008    cmdstr[0] = cmdstr[1] = 0xfe;
09009    cmdstr[2] = myrpt->p.civaddr;
09010    cmdstr[3] = 0xe0;
09011    cmdstr[4] = 0x16;
09012    cmdstr[5] = 0x43;
09013    cmdstr[6] = (rxplon != 0);
09014    cmdstr[7] = 0xfd;
09015 
09016    return(civ_cmd(myrpt,cmdstr,8));
09017 }
09018 
09019 #if 0
09020 /* Set transmit and receive ctcss tone frequencies */
09021 
09022 static int set_ctcss_freq_ic706(struct rpt *myrpt, char *txtone, char *rxtone)
09023 {
09024    unsigned char cmdstr[10];
09025    char hertz[MAXREMSTR],decimal[MAXREMSTR];
09026    int h,d,rv;
09027 
09028    memset(cmdstr, 0, 5);
09029 
09030    if(debug > 6)
09031       ast_log(LOG_NOTICE,"txtone=%s  rxtone=%s \n",txtone,rxtone);
09032 
09033    if(split_ctcss_freq(hertz, decimal, txtone))
09034       return -1; 
09035 
09036    h = atoi(hertz);
09037    d = atoi(decimal);
09038    
09039    cmdstr[0] = cmdstr[1] = 0xfe;
09040    cmdstr[2] = myrpt->p.civaddr;
09041    cmdstr[3] = 0xe0;
09042    cmdstr[4] = 0x1b;
09043    cmdstr[5] = 0;
09044    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
09045    cmdstr[7] = ((h % 10) << 4) + (d % 10);
09046    cmdstr[8] = 0xfd;
09047 
09048    rv = civ_cmd(myrpt,cmdstr,9);
09049    if (rv) return(-1);
09050 
09051    if (!rxtone) return(0);
09052 
09053    if(split_ctcss_freq(hertz, decimal, rxtone))
09054       return -1; 
09055 
09056    h = atoi(hertz);
09057    d = atoi(decimal);
09058 
09059    cmdstr[0] = cmdstr[1] = 0xfe;
09060    cmdstr[2] = myrpt->p.civaddr;
09061    cmdstr[3] = 0xe0;
09062    cmdstr[4] = 0x1b;
09063    cmdstr[5] = 1;
09064    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
09065    cmdstr[7] = ((h % 10) << 4) + (d % 10);
09066    cmdstr[8] = 0xfd;
09067    return(civ_cmd(myrpt,cmdstr,9));
09068 }  
09069 #endif
09070 
09071 static int vfo_ic706(struct rpt *myrpt)
09072 {
09073    unsigned char cmdstr[10];
09074    
09075    cmdstr[0] = cmdstr[1] = 0xfe;
09076    cmdstr[2] = myrpt->p.civaddr;
09077    cmdstr[3] = 0xe0;
09078    cmdstr[4] = 7;
09079    cmdstr[5] = 0xfd;
09080 
09081    return(civ_cmd(myrpt,cmdstr,6));
09082 }
09083 
09084 static int mem2vfo_ic706(struct rpt *myrpt)
09085 {
09086    unsigned char cmdstr[10];
09087    
09088    cmdstr[0] = cmdstr[1] = 0xfe;
09089    cmdstr[2] = myrpt->p.civaddr;
09090    cmdstr[3] = 0xe0;
09091    cmdstr[4] = 0x0a;
09092    cmdstr[5] = 0xfd;
09093 
09094    return(civ_cmd(myrpt,cmdstr,6));
09095 }
09096 
09097 static int select_mem_ic706(struct rpt *myrpt, int slot)
09098 {
09099    unsigned char cmdstr[10];
09100    
09101    cmdstr[0] = cmdstr[1] = 0xfe;
09102    cmdstr[2] = myrpt->p.civaddr;
09103    cmdstr[3] = 0xe0;
09104    cmdstr[4] = 8;
09105    cmdstr[5] = 0;
09106    cmdstr[6] = ((slot / 10) << 4) + (slot % 10);
09107    cmdstr[7] = 0xfd;
09108 
09109    return(civ_cmd(myrpt,cmdstr,8));
09110 }
09111 
09112 static int set_ic706(struct rpt *myrpt)
09113 {
09114    int res = 0,i;
09115    
09116    if(debug)ast_log(LOG_NOTICE, "Set to VFO A iobase=%i\n",myrpt->p.iobase);
09117 
09118    if (!res)
09119       res = simple_command_ic706(myrpt,7,0);
09120 
09121    if((myrpt->remmode == REM_MODE_FM))
09122    {
09123       i = ic706_pltocode(myrpt->rxpl);
09124       if (i == -1) return -1;
09125       if(debug)
09126          printf("Select memory number\n");
09127       if (!res)
09128          res = select_mem_ic706(myrpt,i + IC706_PL_MEMORY_OFFSET);
09129       if(debug)
09130          printf("Transfer memory to VFO\n");
09131       if (!res)
09132          res = mem2vfo_ic706(myrpt);
09133    }
09134       
09135    if(debug)
09136       printf("Set to VFO\n");
09137 
09138    if (!res)
09139       res = vfo_ic706(myrpt);
09140 
09141    if(debug)
09142       printf("Modulation mode\n");
09143 
09144    if (!res)
09145       res = set_mode_ic706(myrpt, myrpt->remmode);    /* Modulation mode */
09146 
09147    if(debug)
09148       printf("Split off\n");
09149 
09150    if(!res)
09151       simple_command_ic706(myrpt, 0x82,0);         /* Split off */
09152 
09153    if(debug)
09154       printf("Frequency\n");
09155 
09156    if(!res)
09157       res = set_freq_ic706(myrpt, myrpt->freq);    /* Frequency */
09158    if((myrpt->remmode == REM_MODE_FM)){
09159       if(debug)
09160          printf("Offset\n");
09161       if(!res)
09162          res = set_offset_ic706(myrpt, myrpt->offset);   /* Offset if FM */
09163       if(!res){
09164          if(debug)
09165             printf("CTCSS mode\n");
09166          res = set_ctcss_mode_ic706(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
09167       }
09168    }
09169    return res;
09170 }
09171 
09172 /*
09173 * Bump frequency up or down by a small amount 
09174 * Return 0 if the new frequnecy is valid, or -1 if invalid
09175 * Interval is in Hz, resolution is 10Hz 
09176 */
09177 
09178 static int multimode_bump_freq_ic706(struct rpt *myrpt, int interval)
09179 {
09180    int m,d;
09181    char mhz[MAXREMSTR], decimals[MAXREMSTR];
09182    unsigned char cmdstr[20];
09183 
09184    if(debug)
09185       printf("Before bump: %s\n", myrpt->freq);
09186 
09187    if(split_freq(mhz, decimals, myrpt->freq))
09188       return -1;
09189    
09190    m = atoi(mhz);
09191    d = atoi(decimals);
09192 
09193    d += (interval / 10); /* 10Hz resolution */
09194    if(d < 0){
09195       m--;
09196       d += 100000;
09197    }
09198    else if(d >= 100000){
09199       m++;
09200       d -= 100000;
09201    }
09202 
09203    if(check_freq_ic706(m, d, NULL,myrpt->p.remote_mars)){
09204       if(debug)
09205          printf("Bump freq invalid\n");
09206       return -1;
09207    }
09208 
09209    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
09210 
09211    if(debug)
09212       printf("After bump: %s\n", myrpt->freq);
09213 
09214    /* The ic-706 likes packed BCD frequencies */
09215 
09216    cmdstr[0] = cmdstr[1] = 0xfe;
09217    cmdstr[2] = myrpt->p.civaddr;
09218    cmdstr[3] = 0xe0;
09219    cmdstr[4] = 0;
09220    cmdstr[5] = ((d % 10) << 4);
09221    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
09222    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
09223    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
09224    cmdstr[9] = (m / 100);
09225    cmdstr[10] = 0xfd;
09226 
09227    return(serial_remote_io(myrpt,cmdstr,11,NULL,0,0));
09228 }
09229 
09230 
09231 
09232 /*
09233 * Dispatch to correct I/O handler 
09234 */
09235 static int setrem(struct rpt *myrpt)
09236 {
09237 char  str[300];
09238 char  *offsets[] = {"SIMPLEX","MINUS","PLUS"};
09239 char  *powerlevels[] = {"LOW","MEDIUM","HIGH"};
09240 char  *modes[] = {"FM","USB","LSB","AM"};
09241 int   res = -1;
09242 
09243 #if   0
09244 printf("FREQ,%s,%s,%s,%s,%s,%s,%d,%d\n",myrpt->freq,
09245    modes[(int)myrpt->remmode],
09246    myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
09247    powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
09248    myrpt->rxplon);
09249 #endif
09250    if (myrpt->p.archivedir)
09251    {
09252       sprintf(str,"FREQ,%s,%s,%s,%s,%s,%s,%d,%d",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       donodelog(myrpt,str);
09258    }
09259    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09260    {
09261       rpt_telemetry(myrpt,SETREMOTE,NULL);
09262       res = 0;
09263    }
09264    if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09265    {
09266       rpt_telemetry(myrpt,SETREMOTE,NULL);
09267       res = 0;
09268    }
09269    if(!strcmp(myrpt->remoterig, remote_rig_tm271))
09270    {
09271       rpt_telemetry(myrpt,SETREMOTE,NULL);
09272       res = 0;
09273    }
09274    else if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09275    {
09276       res = setrbi_check(myrpt);
09277       if (!res)
09278       {
09279          rpt_telemetry(myrpt,SETREMOTE,NULL);
09280          res = 0;
09281       }
09282    }
09283    else if(ISRIG_RTX(myrpt->remoterig))
09284    {
09285       setrtx(myrpt);
09286       res = 0;
09287    }
09288    else if(!strcmp(myrpt->remoterig, remote_rig_kenwood)) {
09289       rpt_telemetry(myrpt,SETREMOTE,NULL);
09290       res = 0;
09291    }
09292    else
09293       res = 0;
09294 
09295    if (res < 0) ast_log(LOG_ERROR,"Unable to send remote command on node %s\n",myrpt->name);
09296 
09297    return res;
09298 }
09299 
09300 static int closerem(struct rpt *myrpt)
09301 {
09302    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09303       return closerem_ft897(myrpt);
09304    else
09305       return 0;
09306 }
09307 
09308 /*
09309 * Dispatch to correct RX frequency checker
09310 */
09311 
09312 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
09313 {
09314    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09315       return check_freq_ft897(m, d, defmode);
09316    else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09317       return check_freq_ic706(m, d, defmode,myrpt->p.remote_mars);
09318    else if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09319       return check_freq_rbi(m, d, defmode);
09320    else if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
09321       return check_freq_kenwood(m, d, defmode);
09322    else if(!strcmp(myrpt->remoterig, remote_rig_tm271))
09323       return check_freq_tm271(m, d, defmode);
09324    else if(ISRIG_RTX(myrpt->remoterig))
09325       return check_freq_rtx(m, d, defmode, myrpt);
09326    else
09327       return -1;
09328 }
09329 
09330 /*
09331  * Check TX frequency before transmitting
09332    rv=1 if tx frequency in ok.
09333 */
09334 
09335 static char check_tx_freq(struct rpt *myrpt)
09336 {
09337    int i,rv=0;
09338    int radio_mhz, radio_decimals, ulimit_mhz, ulimit_decimals, llimit_mhz, llimit_decimals;
09339    char radio_mhz_char[MAXREMSTR];
09340    char radio_decimals_char[MAXREMSTR];
09341    char limit_mhz_char[MAXREMSTR];
09342    char limit_decimals_char[MAXREMSTR];
09343    char limits[256];
09344    char *limit_ranges[40];
09345    struct ast_variable *limitlist;
09346    
09347    if(debug > 3){
09348       ast_log(LOG_NOTICE, "myrpt->freq = %s\n", myrpt->freq);
09349    }
09350 
09351    /* Must have user logged in and tx_limits defined */
09352 
09353    if(!myrpt->p.txlimitsstanzaname || !myrpt->loginuser[0] || !myrpt->loginlevel[0]){
09354       if(debug > 3){
09355          ast_log(LOG_NOTICE, "No tx band table defined, or no user logged in. rv=1\n");
09356       }
09357       rv=1;
09358       return 1; /* Assume it's ok otherwise */
09359    }
09360 
09361    /* Retrieve the band table for the loginlevel */
09362    limitlist = ast_variable_browse(myrpt->cfg, myrpt->p.txlimitsstanzaname);
09363 
09364    if(!limitlist){
09365       ast_log(LOG_WARNING, "No entries in %s band table stanza. rv=0\n", myrpt->p.txlimitsstanzaname);
09366       rv=0;
09367       return 0;
09368    }
09369 
09370    split_freq(radio_mhz_char, radio_decimals_char, myrpt->freq);
09371    radio_mhz = atoi(radio_mhz_char);
09372    radio_decimals = decimals2int(radio_decimals_char);
09373 
09374    if(debug > 3){
09375       ast_log(LOG_NOTICE, "Login User = %s, login level = %s\n", myrpt->loginuser, myrpt->loginlevel);
09376    }
09377 
09378    /* Find our entry */
09379 
09380    for(;limitlist; limitlist=limitlist->next){
09381       if(!strcmp(limitlist->name, myrpt->loginlevel))
09382          break;
09383    }
09384 
09385    if(!limitlist){
09386       ast_log(LOG_WARNING, "Can't find %s entry in band table stanza %s. rv=0\n", myrpt->loginlevel, myrpt->p.txlimitsstanzaname);
09387       rv=0;
09388        return 0;
09389    }
09390    
09391    if(debug > 3){
09392       ast_log(LOG_NOTICE, "Auth: %s = %s\n", limitlist->name, limitlist->value);
09393    }
09394 
09395    /* Parse the limits */
09396 
09397    strncpy(limits, limitlist->value, 256);
09398    limits[255] = 0;
09399    finddelim(limits, limit_ranges, 40);
09400    for(i = 0; i < 40 && limit_ranges[i] ; i++){
09401       char range[40];
09402       char *r,*s;
09403       strncpy(range, limit_ranges[i], 40);
09404       range[39] = 0;
09405         if(debug > 3) 
09406          ast_log(LOG_NOTICE, "Check %s within %s\n", myrpt->freq, range);
09407    
09408       r = strchr(range, '-');
09409       if(!r){
09410          ast_log(LOG_WARNING, "Malformed range in %s tx band table entry. rv=0\n", limitlist->name);
09411          rv=0;
09412          break;
09413       }
09414       *r++ = 0;
09415       s = eatwhite(range);
09416       r = eatwhite(r);
09417       split_freq(limit_mhz_char, limit_decimals_char, s);
09418       llimit_mhz = atoi(limit_mhz_char);
09419       llimit_decimals = decimals2int(limit_decimals_char);
09420       split_freq(limit_mhz_char, limit_decimals_char, r);
09421       ulimit_mhz = atoi(limit_mhz_char);
09422       ulimit_decimals = decimals2int(limit_decimals_char);
09423          
09424       if((radio_mhz >= llimit_mhz) && (radio_mhz <= ulimit_mhz)){
09425          if(radio_mhz == llimit_mhz){ /* CASE 1: TX freq is in llimit mhz portion of band */
09426             if(radio_decimals >= llimit_decimals){ /* Cannot be below llimit decimals */
09427                if(llimit_mhz == ulimit_mhz){ /* If bandwidth < 1Mhz, check ulimit decimals */
09428                   if(radio_decimals <= ulimit_decimals){
09429                      rv=1;
09430                      break;
09431                   }
09432                   else{
09433                      if(debug > 3)
09434                         ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 1\n");
09435                      rv=0;
09436                      break;
09437                   }
09438                }
09439                else{
09440                   rv=1;
09441                   break;
09442                }
09443             }
09444             else{ /* Is below llimit decimals */
09445                if(debug > 3)
09446                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 2\n");
09447                rv=0;
09448                break;
09449             }
09450          }
09451          else if(radio_mhz == ulimit_mhz){ /* CASE 2: TX freq not in llimit mhz portion of band */
09452             if(radio_decimals <= ulimit_decimals){
09453                if(debug > 3)
09454                   ast_log(LOG_NOTICE, "radio_decimals <= ulimit_decimals\n");
09455                rv=1;
09456                break;
09457             }
09458             else{ /* Is above ulimit decimals */
09459                if(debug > 3)
09460                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 3\n");
09461                rv=0;
09462                break;
09463             }
09464          }
09465          else /* CASE 3: TX freq within a multi-Mhz band and ok */
09466             if(debug > 3)
09467                   ast_log(LOG_NOTICE, "Valid TX freq within a multi-Mhz band and ok.\n");
09468             rv=1;
09469             break;
09470       }
09471    }
09472    if(debug > 3)  
09473       ast_log(LOG_NOTICE, "rv=%i\n",rv);
09474 
09475    return rv;
09476 }
09477 
09478 
09479 /*
09480 * Dispatch to correct frequency bumping function
09481 */
09482 
09483 static int multimode_bump_freq(struct rpt *myrpt, int interval)
09484 {
09485    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09486       return multimode_bump_freq_ft897(myrpt, interval);
09487    else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09488       return multimode_bump_freq_ic706(myrpt, interval);
09489    else
09490       return -1;
09491 }
09492 
09493 
09494 /*
09495 * Queue announcment that scan has been stopped 
09496 */
09497 
09498 static void stop_scan(struct rpt *myrpt)
09499 {
09500    myrpt->hfscanstop = 1;
09501    rpt_telemetry(myrpt,SCAN,0);
09502 }
09503 
09504 /*
09505 * This is called periodically when in scan mode
09506 */
09507 
09508 
09509 static int service_scan(struct rpt *myrpt)
09510 {
09511    int res, interval;
09512    char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
09513 
09514    switch(myrpt->hfscanmode){
09515 
09516       case HF_SCAN_DOWN_SLOW:
09517          interval = -10; /* 100Hz /sec */
09518          break;
09519 
09520       case HF_SCAN_DOWN_QUICK:
09521          interval = -50; /* 500Hz /sec */
09522          break;
09523 
09524       case HF_SCAN_DOWN_FAST:
09525          interval = -200; /* 2KHz /sec */
09526          break;
09527 
09528       case HF_SCAN_UP_SLOW:
09529          interval = 10; /* 100Hz /sec */
09530          break;
09531 
09532       case HF_SCAN_UP_QUICK:
09533          interval = 50; /* 500 Hz/sec */
09534          break;
09535 
09536       case HF_SCAN_UP_FAST:
09537          interval = 200; /* 2KHz /sec */
09538          break;
09539 
09540       default:
09541          myrpt->hfscanmode = 0; /* Huh? */
09542          return -1;
09543    }
09544 
09545    res = split_freq(mhz, decimals, myrpt->freq);
09546       
09547    if(!res){
09548       k100 =decimals[0];
09549       k10 = decimals[1];
09550       res = multimode_bump_freq(myrpt, interval);
09551    }
09552 
09553    if(!res)
09554       res = split_freq(mhz, decimals, myrpt->freq);
09555 
09556 
09557    if(res){
09558       myrpt->hfscanmode = 0;
09559       myrpt->hfscanstatus = -2;
09560       return -1;
09561    }
09562 
09563    /* Announce 10KHz boundaries */
09564    if(k10 != decimals[1]){
09565       int myhund = (interval < 0) ? k100 : decimals[0];
09566       int myten = (interval < 0) ? k10 : decimals[1];
09567       myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
09568    } else myrpt->hfscanstatus = 0;
09569    return res;
09570 
09571 }
09572 /*
09573    retrieve memory setting and set radio
09574 */
09575 static int get_mem_set(struct rpt *myrpt, char *digitbuf)
09576 {
09577    int res=0;
09578    if(debug)ast_log(LOG_NOTICE," digitbuf=%s\n", digitbuf);
09579    res = retreive_memory(myrpt, digitbuf);
09580    if(!res)res=setrem(myrpt); 
09581    if(debug)ast_log(LOG_NOTICE," freq=%s  res=%i\n", myrpt->freq, res);
09582    return res;
09583 }
09584 /*
09585    steer the radio selected channel to either one programmed into the radio
09586    or if the radio is VFO agile, to an rpt.conf memory location.
09587 */
09588 static int channel_steer(struct rpt *myrpt, char *data)
09589 {
09590    int res=0;
09591 
09592    if(debug)ast_log(LOG_NOTICE,"remoterig=%s, data=%s\n",myrpt->remoterig,data);
09593    if (!myrpt->remoterig) return(0);
09594    if(data<=0)
09595    {
09596       res=-1;
09597    }
09598    else
09599    {
09600       myrpt->nowchan=strtod(data,NULL);
09601       if(!strcmp(myrpt->remoterig, remote_rig_ppp16))
09602       {
09603          char string[16];
09604          sprintf(string,"SETCHAN %d ",myrpt->nowchan);
09605          send_usb_txt(myrpt,string);   
09606       }
09607       else
09608       {
09609          if(get_mem_set(myrpt, data))res=-1;
09610       }
09611    }
09612    if(debug)ast_log(LOG_NOTICE,"nowchan=%i  res=%i\n",myrpt->nowchan, res);
09613    return res;
09614 }
09615 /*
09616 */
09617 static int channel_revert(struct rpt *myrpt)
09618 {
09619    int res=0;
09620    if(debug)ast_log(LOG_NOTICE,"remoterig=%s, nowchan=%02d, waschan=%02d\n",myrpt->remoterig,myrpt->nowchan,myrpt->waschan);
09621    if (!myrpt->remoterig) return(0);
09622    if(myrpt->nowchan!=myrpt->waschan)
09623    {
09624       char data[8];
09625         if(debug)ast_log(LOG_NOTICE,"reverting.\n");
09626       sprintf(data,"%02d",myrpt->waschan);
09627       myrpt->nowchan=myrpt->waschan;
09628       channel_steer(myrpt,data);
09629       res=1;
09630    }
09631    return(res);
09632 }
09633 /*
09634 * Remote base function
09635 */
09636 
09637 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
09638 {
09639    char *s,*s1,*s2;
09640    int i,j,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode=0;
09641    intptr_t p;
09642    char multimode = 0;
09643    char oc,*cp,*cp1,*cp2;
09644    char tmp[20], freq[20] = "", savestr[20] = "";
09645    char mhz[MAXREMSTR], decimals[MAXREMSTR];
09646 
09647     if(debug > 6) {
09648       ast_log(LOG_NOTICE,"%s param=%s digitbuf=%s source=%i\n",myrpt->name,param,digitbuf,command_source);
09649    }
09650 
09651    if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
09652       return DC_ERROR;
09653       
09654    p = myatoi(param);
09655 
09656    if ((p != 99) && (p != 5) && (p != 140) && myrpt->p.authlevel && 
09657       (!myrpt->loginlevel[0])) return DC_ERROR;
09658    multimode = multimode_capable(myrpt);
09659 
09660    switch(p){
09661 
09662       case 1:  /* retrieve memory */
09663          if(strlen(digitbuf) < 2) /* needs 2 digits */
09664             break;
09665          
09666          for(i = 0 ; i < 2 ; i++){
09667             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09668                return DC_ERROR;
09669          }
09670          r=get_mem_set(myrpt, digitbuf);
09671          if (r < 0){
09672             rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
09673             return DC_COMPLETE;
09674          }
09675          else if (r > 0){
09676             return DC_ERROR;
09677          }
09678          return DC_COMPLETE;  
09679          
09680       case 2:  /* set freq and offset */
09681       
09682          
09683             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
09684             if(digitbuf[i] == '*'){
09685                j++;
09686                continue;
09687             }
09688             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09689                goto invalid_freq;
09690             else{
09691                if(j == 0)
09692                   l++; /* # of digits before first * */
09693                if(j == 1)
09694                   k++; /* # of digits after first * */
09695             }
09696          }
09697       
09698          i = strlen(digitbuf) - 1;
09699          if(multimode){
09700             if((j > 2) || (l > 3) || (k > 6))
09701                goto invalid_freq; /* &^@#! */
09702          }
09703          else{
09704             if((j > 2) || (l > 4) || (k > 3))
09705                goto invalid_freq; /* &^@#! */
09706          }
09707 
09708          /* Wait for M+*K+* */
09709 
09710          if(j < 2)
09711             break; /* Not yet */
09712 
09713          /* We have a frequency */
09714 
09715          strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
09716          
09717          s = tmp;
09718          s1 = strsep(&s, "*"); /* Pick off MHz */
09719          s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
09720          ls2 = strlen(s2); 
09721          
09722          switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
09723             case 1:
09724                ht = 0;
09725                k = 100 * atoi(s2);
09726                break;
09727             
09728             case 2:
09729                ht = 0;
09730                k = 10 * atoi(s2);
09731                break;
09732                
09733             case 3:
09734                if(!multimode){
09735                   if((s2[2] != '0')&&(s2[2] != '5'))
09736                      goto invalid_freq;
09737                }
09738                ht = 0;
09739                k = atoi(s2);
09740                   break;
09741             case 4:
09742                k = atoi(s2)/10;
09743                ht = 10 * (atoi(s2+(ls2-1)));
09744                break;
09745 
09746             case 5:
09747                k = atoi(s2)/100;
09748                ht = (atoi(s2+(ls2-2)));
09749                break;
09750                
09751             default:
09752                goto invalid_freq;
09753          }
09754 
09755          /* Check frequency for validity and establish a default mode */
09756          
09757          snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
09758 
09759          if(debug)
09760             ast_log(LOG_NOTICE, "New frequency: %s\n", freq);
09761    
09762          split_freq(mhz, decimals, freq);
09763          m = atoi(mhz);
09764          d = atoi(decimals);
09765 
09766          if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
09767                  goto invalid_freq;
09768 
09769 
09770          if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
09771             break; /* Not yet */
09772 
09773 
09774          offset = REM_SIMPLEX; /* Assume simplex */
09775 
09776          if(defmode == REM_MODE_FM){
09777             oc = *s; /* Pick off offset */
09778          
09779             if (oc){
09780                switch(oc){
09781                   case '1':
09782                      offset = REM_MINUS;
09783                      break;
09784                   
09785                   case '2':
09786                      offset = REM_SIMPLEX;
09787                   break;
09788                   
09789                   case '3':
09790                      offset = REM_PLUS;
09791                      break;
09792                   
09793                   default:
09794                      goto invalid_freq;
09795                } 
09796             } 
09797          }  
09798          offsave = myrpt->offset;
09799          modesave = myrpt->remmode;
09800          strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
09801          strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
09802          myrpt->offset = offset;
09803          myrpt->remmode = defmode;
09804 
09805          if (setrem(myrpt) == -1){
09806             myrpt->offset = offsave;
09807             myrpt->remmode = modesave;
09808             strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
09809             goto invalid_freq;
09810          }
09811 
09812          return DC_COMPLETE;
09813 
09814 invalid_freq:
09815          rpt_telemetry(myrpt,INVFREQ,NULL);
09816          return DC_ERROR; 
09817       
09818       case 3: /* set rx PL tone */
09819             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
09820             if(digitbuf[i] == '*'){
09821                j++;
09822                continue;
09823             }
09824             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09825                return DC_ERROR;
09826             else{
09827                if(j)
09828                   l++;
09829                else
09830                   k++;
09831             }
09832          }
09833          if((j > 1) || (k > 3) || (l > 1))
09834             return DC_ERROR; /* &$@^! */
09835          i = strlen(digitbuf) - 1;
09836          if((j != 1) || (k < 2)|| (l != 1))
09837             break; /* Not yet */
09838          if(debug)
09839             printf("PL digits entered %s\n", digitbuf);
09840             
09841          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
09842          /* see if we have at least 1 */
09843          s = strchr(tmp,'*');
09844          if(s)
09845             *s = '.';
09846          strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
09847          strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
09848          if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09849          {
09850             strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
09851          }
09852          if (setrem(myrpt) == -1){
09853             strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
09854             return DC_ERROR;
09855          }
09856          return DC_COMPLETE;
09857       
09858       case 4: /* set tx PL tone */
09859          /* cant set tx tone on RBI (rx tone does both) */
09860          if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09861             return DC_ERROR;
09862          /*  eventually for the ic706 instead of just throwing the exception
09863             we can check if we are in encode only mode and allow the tx
09864             ctcss code to be changed. but at least the warning message is
09865             issued for now.
09866          */
09867          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09868          {
09869             if(debug)
09870                ast_log(LOG_WARNING,"Setting IC706 Tx CTCSS Code Not Supported. Set Rx Code for both.\n");
09871             return DC_ERROR;
09872          }
09873          for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
09874             if(digitbuf[i] == '*'){
09875                j++;
09876                continue;
09877             }
09878             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09879                return DC_ERROR;
09880             else{
09881                if(j)
09882                   l++;
09883                else
09884                   k++;
09885             }
09886          }
09887          if((j > 1) || (k > 3) || (l > 1))
09888             return DC_ERROR; /* &$@^! */
09889          i = strlen(digitbuf) - 1;
09890          if((j != 1) || (k < 2)|| (l != 1))
09891             break; /* Not yet */
09892          if(debug)
09893             printf("PL digits entered %s\n", digitbuf);
09894             
09895          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
09896          /* see if we have at least 1 */
09897          s = strchr(tmp,'*');
09898          if(s)
09899             *s = '.';
09900          strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1);
09901          strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
09902          
09903          if (setrem(myrpt) == -1){
09904             strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
09905             return DC_ERROR;
09906          }
09907          return DC_COMPLETE;
09908       
09909 
09910       case 6: /* MODE (FM,USB,LSB,AM) */
09911          if(strlen(digitbuf) < 1)
09912             break;
09913 
09914          if(!multimode)
09915             return DC_ERROR; /* Multimode radios only */
09916 
09917          switch(*digitbuf){
09918             case '1':
09919                split_freq(mhz, decimals, myrpt->freq); 
09920                m=atoi(mhz);
09921                if(m < 29) /* No FM allowed below 29MHz! */
09922                   return DC_ERROR;
09923                myrpt->remmode = REM_MODE_FM;
09924                
09925                rpt_telemetry(myrpt,REMMODE,NULL);
09926                break;
09927 
09928             case '2':
09929                myrpt->remmode = REM_MODE_USB;
09930                rpt_telemetry(myrpt,REMMODE,NULL);
09931                break;   
09932 
09933             case '3':
09934                myrpt->remmode = REM_MODE_LSB;
09935                rpt_telemetry(myrpt,REMMODE,NULL);
09936                break;
09937             
09938             case '4':
09939                myrpt->remmode = REM_MODE_AM;
09940                rpt_telemetry(myrpt,REMMODE,NULL);
09941                break;
09942       
09943             default:
09944                return DC_ERROR;
09945          }
09946 
09947          if(setrem(myrpt))
09948             return DC_ERROR;
09949          return DC_COMPLETEQUIET;
09950       case 99:
09951          /* cant log in when logged in */
09952          if (myrpt->loginlevel[0]) 
09953             return DC_ERROR;
09954          *myrpt->loginuser = 0;
09955          myrpt->loginlevel[0] = 0;
09956          cp = ast_strdup(param);
09957          cp1 = strchr(cp,',');
09958          ast_mutex_lock(&myrpt->lock);
09959          if (cp1) 
09960          {
09961             *cp1 = 0;
09962             cp2 = strchr(cp1 + 1,',');
09963             if (cp2) 
09964             {
09965                *cp2 = 0;
09966                strncpy(myrpt->loginlevel,cp2 + 1,
09967                   sizeof(myrpt->loginlevel) - 1);
09968             }
09969             strncpy(myrpt->loginuser,cp1 + 1,sizeof(myrpt->loginuser));
09970             ast_mutex_unlock(&myrpt->lock);
09971             if (myrpt->p.archivedir)
09972             {
09973                char str[100];
09974 
09975                sprintf(str,"LOGIN,%s,%s",
09976                    myrpt->loginuser,myrpt->loginlevel);
09977                donodelog(myrpt,str);
09978             }
09979             if (debug) 
09980                printf("loginuser %s level %s\n",myrpt->loginuser,myrpt->loginlevel);
09981             rpt_telemetry(myrpt,REMLOGIN,NULL);
09982          }
09983          ast_free(cp);
09984          return DC_COMPLETEQUIET;
09985       case 100: /* RX PL Off */
09986          myrpt->rxplon = 0;
09987          setrem(myrpt);
09988          rpt_telemetry(myrpt,REMXXX,(void *)p);
09989          return DC_COMPLETEQUIET;
09990       case 101: /* RX PL On */
09991          myrpt->rxplon = 1;
09992          setrem(myrpt);
09993          rpt_telemetry(myrpt,REMXXX,(void *)p);
09994          return DC_COMPLETEQUIET;
09995       case 102: /* TX PL Off */
09996          myrpt->txplon = 0;
09997          setrem(myrpt);
09998          rpt_telemetry(myrpt,REMXXX,(void *)p);
09999          return DC_COMPLETEQUIET;
10000       case 103: /* TX PL On */
10001          myrpt->txplon = 1;
10002          setrem(myrpt);
10003          rpt_telemetry(myrpt,REMXXX,(void *)p);
10004          return DC_COMPLETEQUIET;
10005       case 104: /* Low Power */
10006          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10007             return DC_ERROR;
10008          myrpt->powerlevel = REM_LOWPWR;
10009          setrem(myrpt);
10010          rpt_telemetry(myrpt,REMXXX,(void *)p);
10011          return DC_COMPLETEQUIET;
10012       case 105: /* Medium Power */
10013          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10014             return DC_ERROR;
10015          if (ISRIG_RTX(myrpt->remoterig)) return DC_ERROR;
10016          myrpt->powerlevel = REM_MEDPWR;
10017          setrem(myrpt);
10018          rpt_telemetry(myrpt,REMXXX,(void *)p);
10019          return DC_COMPLETEQUIET;
10020       case 106: /* Hi Power */
10021          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10022             return DC_ERROR;
10023          myrpt->powerlevel = REM_HIPWR;
10024          setrem(myrpt);
10025          rpt_telemetry(myrpt,REMXXX,(void *)p);
10026          return DC_COMPLETEQUIET;
10027       case 107: /* Bump down 20Hz */
10028          multimode_bump_freq(myrpt, -20);
10029          return DC_COMPLETE;
10030       case 108: /* Bump down 100Hz */
10031          multimode_bump_freq(myrpt, -100);
10032          return DC_COMPLETE;
10033       case 109: /* Bump down 500Hz */
10034          multimode_bump_freq(myrpt, -500);
10035          return DC_COMPLETE;
10036       case 110: /* Bump up 20Hz */
10037          multimode_bump_freq(myrpt, 20);
10038          return DC_COMPLETE;
10039       case 111: /* Bump up 100Hz */
10040          multimode_bump_freq(myrpt, 100);
10041          return DC_COMPLETE;
10042       case 112: /* Bump up 500Hz */
10043          multimode_bump_freq(myrpt, 500);
10044          return DC_COMPLETE;
10045       case 113: /* Scan down slow */
10046          myrpt->scantimer = REM_SCANTIME;
10047          myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
10048          rpt_telemetry(myrpt,REMXXX,(void *)p);
10049          return DC_COMPLETEQUIET;
10050       case 114: /* Scan down quick */
10051          myrpt->scantimer = REM_SCANTIME;
10052          myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
10053          rpt_telemetry(myrpt,REMXXX,(void *)p);
10054          return DC_COMPLETEQUIET;
10055       case 115: /* Scan down fast */
10056          myrpt->scantimer = REM_SCANTIME;
10057          myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
10058          rpt_telemetry(myrpt,REMXXX,(void *)p);
10059          return DC_COMPLETEQUIET;
10060       case 116: /* Scan up slow */
10061          myrpt->scantimer = REM_SCANTIME;
10062          myrpt->hfscanmode = HF_SCAN_UP_SLOW;
10063          rpt_telemetry(myrpt,REMXXX,(void *)p);
10064          return DC_COMPLETEQUIET;
10065       case 117: /* Scan up quick */
10066          myrpt->scantimer = REM_SCANTIME;
10067          myrpt->hfscanmode = HF_SCAN_UP_QUICK;
10068          rpt_telemetry(myrpt,REMXXX,(void *)p);
10069          return DC_COMPLETEQUIET;
10070       case 118: /* Scan up fast */
10071          myrpt->scantimer = REM_SCANTIME;
10072          myrpt->hfscanmode = HF_SCAN_UP_FAST;
10073          rpt_telemetry(myrpt,REMXXX,(void *)p);
10074          return DC_COMPLETEQUIET;
10075       case 119: /* Tune Request */
10076          if(debug > 3)
10077             ast_log(LOG_NOTICE,"TUNE REQUEST\n");
10078          /* if not currently going, and valid to do */
10079          if((!myrpt->tunerequest) && 
10080              ((!strcmp(myrpt->remoterig, remote_rig_ft897) || 
10081             !strcmp(myrpt->remoterig, remote_rig_ic706)) )) { 
10082             myrpt->remotetx = 0;
10083             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
10084             myrpt->tunerequest = 1;
10085             rpt_telemetry(myrpt,TUNE,NULL);
10086             return DC_COMPLETEQUIET;
10087          }
10088          return DC_ERROR;        
10089       case 5: /* Long Status */
10090          rpt_telemetry(myrpt,REMLONGSTATUS,NULL);
10091          return DC_COMPLETEQUIET;
10092       case 140: /* Short Status */
10093          rpt_telemetry(myrpt,REMSHORTSTATUS,NULL);
10094          return DC_COMPLETEQUIET;
10095       case 200:
10096       case 201:
10097       case 202:
10098       case 203:
10099       case 204:
10100       case 205:
10101       case 206:
10102       case 207:
10103       case 208:
10104       case 209:
10105       case 210:
10106       case 211:
10107       case 212:
10108       case 213:
10109       case 214:
10110       case 215:
10111          do_dtmf_local(myrpt,remdtmfstr[p - 200]);
10112          return DC_COMPLETEQUIET;
10113       default:
10114          break;
10115    }
10116    return DC_INDETERMINATE;
10117 }
10118 
10119 
10120 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode)
10121 {
10122 time_t   now;
10123 int   ret,res = 0,src;
10124 
10125    if(debug > 6)
10126       ast_log(LOG_NOTICE,"c=%c  phonemode=%i  dtmfidx=%i\n",c,phonemode,myrpt->dtmfidx);
10127 
10128    time(&myrpt->last_activity_time);
10129    /* Stop scan mode if in scan mode */
10130    if(myrpt->hfscanmode){
10131       stop_scan(myrpt);
10132       return 0;
10133    }
10134 
10135    time(&now);
10136    /* if timed-out */
10137    if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
10138    {
10139       myrpt->dtmfidx = -1;
10140       myrpt->dtmfbuf[0] = 0;
10141       myrpt->dtmf_time_rem = 0;
10142    }
10143    /* if decode not active */
10144    if (myrpt->dtmfidx == -1)
10145    {
10146       /* if not lead-in digit, dont worry */
10147       if (c != myrpt->p.funcchar)
10148       {
10149          if (!myrpt->p.propagate_dtmf)
10150          {
10151             rpt_mutex_lock(&myrpt->lock);
10152             do_dtmf_local(myrpt,c);
10153             rpt_mutex_unlock(&myrpt->lock);
10154          }
10155          return 0;
10156       }
10157       myrpt->dtmfidx = 0;
10158       myrpt->dtmfbuf[0] = 0;
10159       myrpt->dtmf_time_rem = now;
10160       return 0;
10161    }
10162    /* if too many in buffer, start over */
10163    if (myrpt->dtmfidx >= MAXDTMF)
10164    {
10165       myrpt->dtmfidx = 0;
10166       myrpt->dtmfbuf[0] = 0;
10167       myrpt->dtmf_time_rem = now;
10168    }
10169    if (c == myrpt->p.funcchar)
10170    {
10171       /* if star at beginning, or 2 together, erase buffer */
10172       if ((myrpt->dtmfidx < 1) || 
10173          (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
10174       {
10175          myrpt->dtmfidx = 0;
10176          myrpt->dtmfbuf[0] = 0;
10177          myrpt->dtmf_time_rem = now;
10178          return 0;
10179       }
10180    }
10181    myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
10182    myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10183    myrpt->dtmf_time_rem = now;
10184    
10185    
10186    src = SOURCE_RMT;
10187    if (phonemode == 2) src = SOURCE_DPHONE;
10188    else if (phonemode) src = SOURCE_PHONE;
10189    else if (phonemode == 4) src = SOURCE_ALT;
10190    ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
10191    
10192    switch(ret){
10193    
10194       case DC_INDETERMINATE:
10195          res = 0;
10196          break;
10197             
10198       case DC_DOKEY:
10199          if (keyed) *keyed = 1;
10200          res = 0;
10201          break;
10202             
10203       case DC_REQ_FLUSH:
10204          myrpt->dtmfidx = 0;
10205          myrpt->dtmfbuf[0] = 0;
10206          res = 0;
10207          break;
10208             
10209             
10210       case DC_COMPLETE:
10211          res = 1;
10212       case DC_COMPLETEQUIET:
10213          myrpt->totalexecdcommands++;
10214          myrpt->dailyexecdcommands++;
10215          strncpy(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF-1);
10216          myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
10217          myrpt->dtmfbuf[0] = 0;
10218          myrpt->dtmfidx = -1;
10219          myrpt->dtmf_time_rem = 0;
10220          break;
10221             
10222       case DC_ERROR:
10223       default:
10224          myrpt->dtmfbuf[0] = 0;
10225          myrpt->dtmfidx = -1;
10226          myrpt->dtmf_time_rem = 0;
10227          res = 0;
10228          break;
10229    }
10230 
10231    return res;
10232 }
10233 
10234 static int handle_remote_data(struct rpt *myrpt, char *str)
10235 {
10236 /* XXX ATTENTION: if you change the size of these arrays you MUST
10237  * change the limits in corresponding sscanf() calls below. */
10238 char  tmp[300],cmd[300],dest[300],src[300],c;
10239 int   seq,res;
10240 
10241    /* put string in our buffer */
10242    strncpy(tmp,str,sizeof(tmp) - 1);
10243    if (!strcmp(tmp,discstr)) return 0;
10244         if (!strcmp(tmp,newkeystr))
10245         {
10246       myrpt->newkey = 1;
10247                 return 0;
10248         }
10249 
10250 #ifndef  DO_NOT_NOTIFY_MDC1200_ON_REMOTE_BASES
10251    if (tmp[0] == 'I')
10252    {
10253       /* XXX WARNING: be very careful with the limits on the folowing
10254        * sscanf() call, make sure they match the values defined above */
10255       if (sscanf(tmp,"%299s %299s %30x",cmd,src,&seq) != 3)
10256       {
10257          ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
10258          return 0;
10259       }
10260       mdc1200_notify(myrpt,src,seq);
10261       return 0;
10262    }
10263 #endif
10264    /* XXX WARNING: be very careful with the limits on the folowing
10265     * sscanf() call, make sure they match the values defined above */
10266    if (sscanf(tmp,"%299s %299s %299s %30d %1c",cmd,dest,src,&seq,&c) != 5)
10267    {
10268       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
10269       return 0;
10270    }
10271    if (strcmp(cmd,"D"))
10272    {
10273       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
10274       return 0;
10275    }
10276    /* if not for me, ignore */
10277    if (strcmp(dest,myrpt->name)) return 0;
10278    if (myrpt->p.archivedir)
10279    {
10280       char dtmfstr[100];
10281 
10282       sprintf(dtmfstr,"DTMF,%c",c);
10283       donodelog(myrpt,dtmfstr);
10284    }
10285    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
10286    if (!c) return(0);
10287    res = handle_remote_dtmf_digit(myrpt,c, NULL, 0);
10288    if (res != 1)
10289       return res;
10290    rpt_telemetry(myrpt,COMPLETE,NULL);
10291    return 0;
10292 }
10293 
10294 static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode)
10295 {
10296 int   res;
10297 
10298 
10299    if(phonemode == 3) /* simplex phonemode, funcchar key/unkey toggle */
10300    {
10301       if (keyed && *keyed && ((c == myrpt->p.funcchar) || (c == myrpt->p.endchar)))
10302       {
10303          *keyed = 0; /* UNKEY */
10304          return 0;
10305       }
10306       else if (keyed && !*keyed && (c = myrpt->p.funcchar))
10307       {
10308          *keyed = 1; /* KEY */
10309          return 0;
10310       }
10311    }
10312    else /* endchar unkey */
10313    {
10314 
10315       if (keyed && *keyed && (c == myrpt->p.endchar))
10316       {
10317          *keyed = 0;
10318          return DC_INDETERMINATE;
10319       }
10320    }
10321    if (myrpt->p.archivedir)
10322    {
10323       char str[100];
10324 
10325       sprintf(str,"DTMF(P),%c",c);
10326       donodelog(myrpt,str);
10327    }
10328    res = handle_remote_dtmf_digit(myrpt,c,keyed, phonemode);
10329    if (res != 1)
10330       return res;
10331    rpt_telemetry(myrpt,COMPLETE,NULL);
10332    return 0;
10333 }
10334 
10335 static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
10336 {
10337    char *val, *s, *s1, *s2, *tele;
10338    char tmp[300], deststr[300] = "";
10339    char sx[320],*sy;
10340 
10341 
10342    val = node_lookup(myrpt,l->name);
10343    if (!val)
10344    {
10345       fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
10346       return -1;
10347    }
10348 
10349    rpt_mutex_lock(&myrpt->lock);
10350    /* remove from queue */
10351    remque((struct qelem *) l);
10352    rpt_mutex_unlock(&myrpt->lock);
10353    strncpy(tmp,val,sizeof(tmp) - 1);
10354    s = tmp;
10355    s1 = strsep(&s,",");
10356    if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
10357    {
10358       sy = strchr(s1,'/');    
10359       *sy = 0;
10360       sprintf(sx,"%s:4569/%s",s1,sy + 1);
10361       s1 = sx;
10362    }
10363    s2 = strsep(&s,",");
10364    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
10365    tele = strchr(deststr, '/');
10366    if (!tele) {
10367       fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
10368       return -1;
10369    }
10370    *tele++ = 0;
10371    l->elaptime = 0;
10372    l->connecttime = 0;
10373    l->thisconnected = 0;
10374    l->newkey = 0;
10375    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
10376    if (l->chan){
10377       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
10378       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
10379 #ifndef  NEW_ASTERISK
10380       l->chan->whentohangup = 0;
10381 #endif
10382       l->chan->appl = "Apprpt";
10383       l->chan->data = "(Remote Rx)";
10384       if (option_verbose > 2)
10385          ast_verbose(VERBOSE_PREFIX_3 "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
10386             deststr, tele, l->chan->name);
10387       if(l->chan->cid.cid_num)
10388          ast_free(l->chan->cid.cid_num);
10389       l->chan->cid.cid_num = ast_strdup(myrpt->name);
10390                 ast_call(l->chan,tele,999); 
10391 
10392    }
10393    else 
10394    {
10395       if (option_verbose > 2)
10396          ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
10397             deststr,tele,l->chan->name);
10398       return -1;
10399    }
10400    rpt_mutex_lock(&myrpt->lock);
10401    /* put back in queue */
10402    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
10403    rpt_mutex_unlock(&myrpt->lock);
10404    ast_log(LOG_WARNING,"Reconnect Attempt to %s in process\n",l->name);
10405    if (!l->phonemode) send_newkey(l->chan);
10406    return 0;
10407 }
10408 
10409 /* 0 return=continue, 1 return = break, -1 return = error */
10410 static void local_dtmf_helper(struct rpt *myrpt,char c_in)
10411 {
10412 int   res;
10413 pthread_attr_t attr;
10414 char  cmd[MAXDTMF+1] = "",c;
10415 
10416 
10417    c = c_in & 0x7f;
10418    if (myrpt->p.archivedir)
10419    {
10420       char str[100];
10421 
10422       sprintf(str,"DTMF,MAIN,%c",c);
10423       donodelog(myrpt,str);
10424    }
10425    if (c == myrpt->p.endchar)
10426    {
10427    /* if in simple mode, kill autopatch */
10428       if (myrpt->p.simple && myrpt->callmode)
10429       {   
10430          if(debug)
10431             ast_log(LOG_WARNING, "simple mode autopatch kill\n");
10432          rpt_mutex_lock(&myrpt->lock);
10433          myrpt->callmode = 0;
10434          myrpt->macropatch=0;
10435          channel_revert(myrpt);
10436          rpt_mutex_unlock(&myrpt->lock);
10437          rpt_telemetry(myrpt,TERM,NULL);
10438          return;
10439       }
10440       rpt_mutex_lock(&myrpt->lock);
10441       myrpt->stopgen = 1;
10442       if (myrpt->cmdnode[0])
10443       {
10444          myrpt->cmdnode[0] = 0;
10445          myrpt->dtmfidx = -1;
10446          myrpt->dtmfbuf[0] = 0;
10447          rpt_mutex_unlock(&myrpt->lock);
10448          rpt_telemetry(myrpt,COMPLETE,NULL);
10449          return;
10450       } 
10451       else if(!myrpt->inpadtest)
10452                 {
10453                         rpt_mutex_unlock(&myrpt->lock);
10454                         if (myrpt->p.propagate_phonedtmf)
10455                                do_dtmf_phone(myrpt,NULL,c);
10456          return;
10457                 }
10458       else
10459          rpt_mutex_unlock(&myrpt->lock);
10460    }
10461    rpt_mutex_lock(&myrpt->lock);
10462    if (myrpt->cmdnode[0])
10463    {
10464       rpt_mutex_unlock(&myrpt->lock);
10465       send_link_dtmf(myrpt,c);
10466       return;
10467    }
10468    if (!myrpt->p.simple)
10469    {
10470       if ((!myrpt->inpadtest)&&(c == myrpt->p.funcchar))
10471       {
10472          myrpt->dtmfidx = 0;
10473          myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10474          rpt_mutex_unlock(&myrpt->lock);
10475          time(&myrpt->dtmf_time);
10476          return;
10477       } 
10478       else if (((myrpt->inpadtest)||(c != myrpt->p.endchar)) && (myrpt->dtmfidx >= 0))
10479       {
10480          time(&myrpt->dtmf_time);
10481          
10482          if (myrpt->dtmfidx < MAXDTMF)
10483          {
10484             int src;
10485 
10486             myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
10487             myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10488             
10489             strncpy(cmd, myrpt->dtmfbuf, sizeof(cmd) - 1);
10490             
10491             rpt_mutex_unlock(&myrpt->lock);
10492             src = SOURCE_RPT;
10493             if (c_in & 0x80) src = SOURCE_ALT;
10494             res = collect_function_digits(myrpt, cmd, src, NULL);
10495             rpt_mutex_lock(&myrpt->lock);
10496             switch(res){
10497                 case DC_INDETERMINATE:
10498                break;
10499                 case DC_REQ_FLUSH:
10500                myrpt->dtmfidx = 0;
10501                myrpt->dtmfbuf[0] = 0;
10502                break;
10503                 case DC_COMPLETE:
10504                 case DC_COMPLETEQUIET:
10505                myrpt->totalexecdcommands++;
10506                myrpt->dailyexecdcommands++;
10507                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
10508                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
10509                myrpt->dtmfbuf[0] = 0;
10510                myrpt->dtmfidx = -1;
10511                myrpt->dtmf_time = 0;
10512                break;
10513 
10514                 case DC_ERROR:
10515                 default:
10516                myrpt->dtmfbuf[0] = 0;
10517                myrpt->dtmfidx = -1;
10518                myrpt->dtmf_time = 0;
10519                break;
10520             }
10521             if(res != DC_INDETERMINATE) {
10522                rpt_mutex_unlock(&myrpt->lock);
10523                return;
10524             }
10525          } 
10526       }
10527    }
10528    else /* if simple */
10529    {
10530       if ((!myrpt->callmode) && (c == myrpt->p.funcchar))
10531       {
10532          myrpt->callmode = 1;
10533          myrpt->patchnoct = 0;
10534          myrpt->patchquiet = 0;
10535          myrpt->patchfarenddisconnect = 0;
10536          myrpt->patchdialtime = 0;
10537          strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
10538          myrpt->cidx = 0;
10539          myrpt->exten[myrpt->cidx] = 0;
10540          rpt_mutex_unlock(&myrpt->lock);
10541               pthread_attr_init(&attr);
10542               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10543          ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
10544          return;
10545       }
10546    }
10547    if (myrpt->callmode == 1)
10548    {
10549       myrpt->exten[myrpt->cidx++] = c;
10550       myrpt->exten[myrpt->cidx] = 0;
10551       /* if this exists */
10552       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
10553       {
10554          /* if this really it, end now */
10555          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
10556             myrpt->exten,1,NULL)) 
10557          {
10558             myrpt->callmode = 2;
10559             rpt_mutex_unlock(&myrpt->lock);
10560             if(!myrpt->patchquiet)
10561                rpt_telemetry(myrpt,PROC,NULL); 
10562             return;
10563          }
10564          else /* othewise, reset timer */
10565          {
10566             myrpt->calldigittimer = 1;
10567          }
10568       }
10569       /* if can continue, do so */
10570       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
10571       {
10572          /* call has failed, inform user */
10573          myrpt->callmode = 4;
10574       }
10575       rpt_mutex_unlock(&myrpt->lock);
10576       return;
10577    }
10578    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
10579    {
10580       myrpt->mydtmf = c;
10581    }
10582    rpt_mutex_unlock(&myrpt->lock);
10583    if ((myrpt->dtmfidx < 0) && myrpt->p.propagate_phonedtmf)
10584       do_dtmf_phone(myrpt,NULL,c);
10585    return;
10586 }
10587 
10588 
10589 /* place an ID event in the telemetry queue */
10590 
10591 static void queue_id(struct rpt *myrpt)
10592 {
10593    if(myrpt->p.idtime){ /* ID time must be non-zero */
10594       myrpt->mustid = myrpt->tailid = 0;
10595       myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
10596       rpt_mutex_unlock(&myrpt->lock);
10597       rpt_telemetry(myrpt,ID,NULL);
10598       rpt_mutex_lock(&myrpt->lock);
10599    }
10600 }
10601 
10602 /* Scheduler */
10603 /* must be called locked */
10604 
10605 static void do_scheduler(struct rpt *myrpt)
10606 {
10607    int i,res;
10608 
10609 #ifdef   NEW_ASTERISK
10610    struct ast_tm tmnow;
10611 #else
10612    struct tm tmnow;
10613 #endif
10614    struct ast_variable *skedlist;
10615    char *strs[5],*vp,*val,value[100];
10616 
10617    memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
10618    
10619    if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
10620       ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
10621 
10622    /* Try to get close to a 1 second resolution */
10623    
10624    if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
10625       return;
10626 
10627    rpt_localtime(&myrpt->curtv.tv_sec, &tmnow);
10628 
10629    /* If midnight, then reset all daily statistics */
10630    
10631    if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
10632       myrpt->dailykeyups = 0;
10633       myrpt->dailytxtime = 0;
10634       myrpt->dailykerchunks = 0;
10635       myrpt->dailyexecdcommands = 0;
10636    }
10637 
10638    if(tmnow.tm_sec != 0)
10639       return;
10640 
10641    /* Code below only executes once per minute */
10642 
10643 
10644    /* Don't schedule if remote */
10645 
10646         if (myrpt->remote)
10647                 return;
10648 
10649    /* Don't schedule if disabled */
10650 
10651         if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable){
10652       if(debug > 6)
10653          ast_log(LOG_NOTICE, "Scheduler disabled\n");
10654       return;
10655    }
10656 
10657    if(!myrpt->p.skedstanzaname){ /* No stanza means we do nothing */
10658       if(debug > 6)
10659          ast_log(LOG_NOTICE,"No stanza for scheduler in rpt.conf\n");
10660       return;
10661    }
10662 
10663     /* get pointer to linked list of scheduler entries */
10664     skedlist = ast_variable_browse(myrpt->cfg, myrpt->p.skedstanzaname);
10665 
10666    if(debug > 6){
10667       ast_log(LOG_NOTICE, "Time now: %02d:%02d %02d %02d %02d\n",
10668          tmnow.tm_hour,tmnow.tm_min,tmnow.tm_mday,tmnow.tm_mon + 1, tmnow.tm_wday); 
10669    }
10670    /* walk the list */
10671    for(; skedlist; skedlist = skedlist->next){
10672       if(debug > 6)
10673          ast_log(LOG_NOTICE, "Scheduler entry %s = %s being considered\n",skedlist->name, skedlist->value);
10674       strncpy(value,skedlist->value,99);
10675       value[99] = 0;
10676       /* point to the substrings for minute, hour, dom, month, and dow */
10677       for( i = 0, vp = value ; i < 5; i++){
10678          if(!*vp)
10679             break;
10680          while((*vp == ' ') || (*vp == 0x09)) /* get rid of any leading white space */
10681             vp++;
10682          strs[i] = vp; /* save pointer to beginning of substring */
10683          while((*vp != ' ') && (*vp != 0x09) && (*vp != 0)) /* skip over substring */
10684             vp++;
10685          if(*vp)
10686             *vp++ = 0; /* mark end of substring */
10687       }
10688       if(debug > 6)
10689          ast_log(LOG_NOTICE, "i = %d, min = %s, hour = %s, mday=%s, mon=%s, wday=%s\n",i,
10690             strs[0], strs[1], strs[2], strs[3], strs[4]); 
10691       if(i == 5){
10692          if((*strs[0] != '*')&&(atoi(strs[0]) != tmnow.tm_min))
10693             continue;
10694          if((*strs[1] != '*')&&(atoi(strs[1]) != tmnow.tm_hour))
10695             continue;
10696          if((*strs[2] != '*')&&(atoi(strs[2]) != tmnow.tm_mday))
10697             continue;
10698          if((*strs[3] != '*')&&(atoi(strs[3]) != tmnow.tm_mon + 1))
10699             continue;
10700          if(atoi(strs[4]) == 7)
10701             strs[4] = "0";
10702          if((*strs[4] != '*')&&(atoi(strs[4]) != tmnow.tm_wday))
10703             continue;
10704          if(debug)
10705             ast_log(LOG_NOTICE, "Executing scheduler entry %s = %s\n", skedlist->name, skedlist->value);
10706          if(atoi(skedlist->name) == 0)
10707             return; /* Zero is reserved for the startup macro */
10708          val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, skedlist->name);
10709          if (!val){
10710             ast_log(LOG_WARNING,"Scheduler could not find macro %s\n",skedlist->name);
10711             return; /* Macro not found */
10712          }
10713          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)){
10714             ast_log(LOG_WARNING, "Scheduler could not execute macro %s: Macro buffer full\n",
10715                skedlist->name);
10716             return; /* Macro buffer full */
10717          }
10718          myrpt->macrotimer = MACROTIME;
10719          strncat(myrpt->macrobuf,val,MAXMACRO - 1);
10720       }
10721       else{
10722          ast_log(LOG_WARNING,"Malformed scheduler entry in rpt.conf: %s = %s\n",
10723             skedlist->name, skedlist->value);
10724       }
10725    }
10726 
10727 }
10728 
10729 /* single thread with one file (request) to dial */
10730 static void *rpt(void *this)
10731 {
10732 struct   rpt *myrpt = (struct rpt *)this;
10733 char *tele,*idtalkover,c,myfirst,*p;
10734 int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued;
10735 int tailmessagequeued,ctqueued,dtmfed,lastmyrx,localmsgqueued;
10736 struct ast_channel *who;
10737 struct dahdi_confinfo ci;  /* conference info */
10738 time_t   t;
10739 struct rpt_link *l,*m;
10740 struct rpt_tele *telem;
10741 char tmpstr[300],lstr[MAXLINKLIST];
10742 
10743 
10744    if (myrpt->p.archivedir) mkdir(myrpt->p.archivedir,0600);
10745    sprintf(tmpstr,"%s/%s",myrpt->p.archivedir,myrpt->name);
10746    mkdir(tmpstr,0600);
10747    rpt_mutex_lock(&myrpt->lock);
10748 
10749    telem = myrpt->tele.next;
10750    while(telem != &myrpt->tele)
10751    {
10752       ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
10753       telem = telem->next;
10754    }
10755    rpt_mutex_unlock(&myrpt->lock);
10756    /* find our index, and load the vars initially */
10757    for(i = 0; i < nrpts; i++)
10758    {
10759       if (&rpt_vars[i] == myrpt)
10760       {
10761          load_rpt_vars(i,0);
10762          break;
10763       }
10764    }
10765 
10766    rpt_mutex_lock(&myrpt->lock);
10767    while(myrpt->xlink)
10768    {
10769       myrpt->xlink = 3;
10770       rpt_mutex_unlock(&myrpt->lock);
10771       usleep(100000);
10772       rpt_mutex_lock(&myrpt->lock);
10773    }
10774 #ifdef HAVE_IOPERM
10775    if ((!strcmp(myrpt->remoterig, remote_rig_rbi)) &&
10776      (ioperm(myrpt->p.iobase,1,1) == -1))
10777    {
10778       rpt_mutex_unlock(&myrpt->lock);
10779       ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
10780       myrpt->rpt_thread = AST_PTHREADT_STOP;
10781       pthread_exit(NULL);
10782    }
10783 #endif
10784    strncpy(tmpstr,myrpt->rxchanname,sizeof(tmpstr) - 1);
10785    tele = strchr(tmpstr,'/');
10786    if (!tele)
10787    {
10788       fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
10789       rpt_mutex_unlock(&myrpt->lock);
10790       myrpt->rpt_thread = AST_PTHREADT_STOP;
10791       pthread_exit(NULL);
10792    }
10793    *tele++ = 0;
10794    myrpt->rxchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
10795    myrpt->dahdirxchannel = NULL;
10796    if (!strcasecmp(tmpstr,"DAHDI"))
10797       myrpt->dahdirxchannel = myrpt->rxchannel;
10798    if (myrpt->rxchannel)
10799    {
10800       if (myrpt->rxchannel->_state == AST_STATE_BUSY)
10801       {
10802          fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
10803          rpt_mutex_unlock(&myrpt->lock);
10804          ast_hangup(myrpt->rxchannel);
10805          myrpt->rpt_thread = AST_PTHREADT_STOP;
10806          pthread_exit(NULL);
10807       }
10808       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10809       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10810 #ifdef   AST_CDR_FLAG_POST_DISABLED
10811       if (myrpt->rxchannel->cdr)
10812          ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10813 #endif
10814 #ifndef  NEW_ASTERISK
10815       myrpt->rxchannel->whentohangup = 0;
10816 #endif
10817       myrpt->rxchannel->appl = "Apprpt";
10818       myrpt->rxchannel->data = "(Repeater Rx)";
10819       if (option_verbose > 2)
10820          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
10821             tmpstr,tele,myrpt->rxchannel->name);
10822       ast_call(myrpt->rxchannel,tele,999);
10823       if (myrpt->rxchannel->_state != AST_STATE_UP)
10824       {
10825          rpt_mutex_unlock(&myrpt->lock);
10826          ast_hangup(myrpt->rxchannel);
10827          myrpt->rpt_thread = AST_PTHREADT_STOP;
10828          pthread_exit(NULL);
10829       }
10830    }
10831    else
10832    {
10833       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
10834       rpt_mutex_unlock(&myrpt->lock);
10835       myrpt->rpt_thread = AST_PTHREADT_STOP;
10836       pthread_exit(NULL);
10837    }
10838    myrpt->dahditxchannel = NULL;
10839    if (myrpt->txchanname)
10840    {
10841       strncpy(tmpstr,myrpt->txchanname,sizeof(tmpstr) - 1);
10842       tele = strchr(tmpstr,'/');
10843       if (!tele)
10844       {
10845          fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
10846          rpt_mutex_unlock(&myrpt->lock);
10847          ast_hangup(myrpt->rxchannel);
10848          myrpt->rpt_thread = AST_PTHREADT_STOP;
10849          pthread_exit(NULL);
10850       }
10851       *tele++ = 0;
10852       myrpt->txchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
10853       if (!strcasecmp(tmpstr,"DAHDI"))
10854          myrpt->dahditxchannel = myrpt->txchannel;
10855       if (myrpt->txchannel)
10856       {
10857          if (myrpt->txchannel->_state == AST_STATE_BUSY)
10858          {
10859             fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
10860             rpt_mutex_unlock(&myrpt->lock);
10861             ast_hangup(myrpt->txchannel);
10862             ast_hangup(myrpt->rxchannel);
10863             myrpt->rpt_thread = AST_PTHREADT_STOP;
10864             pthread_exit(NULL);
10865          }        
10866          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
10867          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
10868 #ifdef   AST_CDR_FLAG_POST_DISABLED
10869          if (myrpt->txchannel->cdr)
10870             ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10871 #endif
10872 #ifndef  NEW_ASTERISK
10873          myrpt->txchannel->whentohangup = 0;
10874 #endif
10875          myrpt->txchannel->appl = "Apprpt";
10876          myrpt->txchannel->data = "(Repeater Tx)";
10877          if (option_verbose > 2)
10878             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
10879                tmpstr,tele,myrpt->txchannel->name);
10880          ast_call(myrpt->txchannel,tele,999);
10881          if (myrpt->rxchannel->_state != AST_STATE_UP)
10882          {
10883             rpt_mutex_unlock(&myrpt->lock);
10884             ast_hangup(myrpt->rxchannel);
10885             ast_hangup(myrpt->txchannel);
10886             myrpt->rpt_thread = AST_PTHREADT_STOP;
10887             pthread_exit(NULL);
10888          }
10889       }
10890       else
10891       {
10892          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
10893          rpt_mutex_unlock(&myrpt->lock);
10894          ast_hangup(myrpt->rxchannel);
10895          myrpt->rpt_thread = AST_PTHREADT_STOP;
10896          pthread_exit(NULL);
10897       }
10898    }
10899    else
10900    {
10901       myrpt->txchannel = myrpt->rxchannel;
10902       if (!strncasecmp(myrpt->rxchanname,"DAHDI",3))
10903          myrpt->dahditxchannel = myrpt->txchannel;
10904    }
10905    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
10906    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
10907    /* allocate a pseudo-channel thru asterisk */
10908    myrpt->pchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
10909    if (!myrpt->pchannel)
10910    {
10911       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10912       rpt_mutex_unlock(&myrpt->lock);
10913       if (myrpt->txchannel != myrpt->rxchannel) 
10914          ast_hangup(myrpt->txchannel);
10915       ast_hangup(myrpt->rxchannel);
10916       myrpt->rpt_thread = AST_PTHREADT_STOP;
10917       pthread_exit(NULL);
10918    }
10919 #ifdef   AST_CDR_FLAG_POST_DISABLED
10920    if (myrpt->pchannel->cdr)
10921       ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10922 #endif
10923    if (!myrpt->dahdirxchannel) myrpt->dahdirxchannel = myrpt->pchannel;
10924    if (!myrpt->dahditxchannel)
10925    {
10926       /* allocate a pseudo-channel thru asterisk */
10927       myrpt->dahditxchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
10928       if (!myrpt->dahditxchannel)
10929       {
10930          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10931          rpt_mutex_unlock(&myrpt->lock);
10932          if (myrpt->txchannel != myrpt->rxchannel) 
10933             ast_hangup(myrpt->txchannel);
10934          ast_hangup(myrpt->rxchannel);
10935          myrpt->rpt_thread = AST_PTHREADT_STOP;
10936          pthread_exit(NULL);
10937       }
10938       ast_set_read_format(myrpt->dahditxchannel,AST_FORMAT_SLINEAR);
10939       ast_set_write_format(myrpt->dahditxchannel,AST_FORMAT_SLINEAR);
10940 #ifdef   AST_CDR_FLAG_POST_DISABLED
10941       if (myrpt->dahditxchannel->cdr)
10942          ast_set_flag(myrpt->dahditxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10943 #endif
10944    }
10945    /* allocate a pseudo-channel thru asterisk */
10946    myrpt->monchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
10947    if (!myrpt->monchannel)
10948    {
10949       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10950       rpt_mutex_unlock(&myrpt->lock);
10951       if (myrpt->txchannel != myrpt->rxchannel) 
10952          ast_hangup(myrpt->txchannel);
10953       ast_hangup(myrpt->rxchannel);
10954       myrpt->rpt_thread = AST_PTHREADT_STOP;
10955       pthread_exit(NULL);
10956    }
10957    ast_set_read_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
10958    ast_set_write_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
10959 #ifdef   AST_CDR_FLAG_POST_DISABLED
10960    if (myrpt->monchannel->cdr)
10961       ast_set_flag(myrpt->monchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10962 #endif
10963    /* make a conference for the tx */
10964    ci.chan = 0;
10965    ci.confno = -1; /* make a new conf */
10966    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER;
10967    /* first put the channel on the conference in proper mode */
10968    if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
10969    {
10970       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10971       rpt_mutex_unlock(&myrpt->lock);
10972       ast_hangup(myrpt->pchannel);
10973       ast_hangup(myrpt->monchannel);
10974       if (myrpt->txchannel != myrpt->rxchannel) 
10975          ast_hangup(myrpt->txchannel);
10976       ast_hangup(myrpt->rxchannel);
10977       myrpt->rpt_thread = AST_PTHREADT_STOP;
10978       pthread_exit(NULL);
10979    }
10980    /* save tx conference number */
10981    myrpt->txconf = ci.confno;
10982    /* make a conference for the pseudo */
10983    ci.chan = 0;
10984    ci.confno = -1; /* make a new conf */
10985    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
10986       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
10987    /* first put the channel on the conference in announce mode */
10988    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
10989    {
10990       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10991       rpt_mutex_unlock(&myrpt->lock);
10992       ast_hangup(myrpt->pchannel);
10993       ast_hangup(myrpt->monchannel);
10994       if (myrpt->txchannel != myrpt->rxchannel) 
10995          ast_hangup(myrpt->txchannel);
10996       ast_hangup(myrpt->rxchannel);
10997       myrpt->rpt_thread = AST_PTHREADT_STOP;
10998       pthread_exit(NULL);
10999    }
11000    /* save pseudo channel conference number */
11001    myrpt->conf = ci.confno;
11002    /* make a conference for the pseudo */
11003    ci.chan = 0;
11004    if ((strstr(myrpt->txchannel->name,"pseudo") == NULL) &&
11005       (myrpt->dahditxchannel == myrpt->txchannel))
11006    {
11007       /* get tx channel's port number */
11008       if (ioctl(myrpt->txchannel->fds[0],DAHDI_CHANNO,&ci.confno) == -1)
11009       {
11010          ast_log(LOG_WARNING, "Unable to set tx channel's chan number\n");
11011          rpt_mutex_unlock(&myrpt->lock);
11012          ast_hangup(myrpt->pchannel);
11013          ast_hangup(myrpt->monchannel);
11014          if (myrpt->txchannel != myrpt->rxchannel) 
11015             ast_hangup(myrpt->txchannel);
11016          ast_hangup(myrpt->rxchannel);
11017          myrpt->rpt_thread = AST_PTHREADT_STOP;
11018          pthread_exit(NULL);
11019       }
11020       ci.confmode = DAHDI_CONF_MONITORTX;
11021    }
11022    else
11023    {
11024       ci.confno = myrpt->txconf;
11025       ci.confmode = DAHDI_CONF_CONFANNMON;
11026    }
11027    /* first put the channel on the conference in announce mode */
11028    if (ioctl(myrpt->monchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11029    {
11030       ast_log(LOG_WARNING, "Unable to set conference mode for monitor\n");
11031       rpt_mutex_unlock(&myrpt->lock);
11032       ast_hangup(myrpt->pchannel);
11033       ast_hangup(myrpt->monchannel);
11034       if (myrpt->txchannel != myrpt->rxchannel) 
11035          ast_hangup(myrpt->txchannel);
11036       ast_hangup(myrpt->rxchannel);
11037       myrpt->rpt_thread = AST_PTHREADT_STOP;
11038       pthread_exit(NULL);
11039    }
11040    /* allocate a pseudo-channel thru asterisk */
11041    myrpt->parrotchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
11042    if (!myrpt->parrotchannel)
11043    {
11044       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11045       rpt_mutex_unlock(&myrpt->lock);
11046       if (myrpt->txchannel != myrpt->rxchannel) 
11047          ast_hangup(myrpt->txchannel);
11048       ast_hangup(myrpt->rxchannel);
11049       myrpt->rpt_thread = AST_PTHREADT_STOP;
11050       pthread_exit(NULL);
11051    }
11052    ast_set_read_format(myrpt->parrotchannel,AST_FORMAT_SLINEAR);
11053    ast_set_write_format(myrpt->parrotchannel,AST_FORMAT_SLINEAR);
11054 #ifdef   AST_CDR_FLAG_POST_DISABLED
11055    if (myrpt->parrotchannel->cdr)
11056       ast_set_flag(myrpt->parrotchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11057 #endif
11058    /* allocate a pseudo-channel thru asterisk */
11059    myrpt->voxchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
11060    if (!myrpt->voxchannel)
11061    {
11062       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11063       rpt_mutex_unlock(&myrpt->lock);
11064       if (myrpt->txchannel != myrpt->rxchannel) 
11065          ast_hangup(myrpt->txchannel);
11066       ast_hangup(myrpt->rxchannel);
11067       myrpt->rpt_thread = AST_PTHREADT_STOP;
11068       pthread_exit(NULL);
11069    }
11070    ast_set_read_format(myrpt->voxchannel,AST_FORMAT_SLINEAR);
11071    ast_set_write_format(myrpt->voxchannel,AST_FORMAT_SLINEAR);
11072 #ifdef   AST_CDR_FLAG_POST_DISABLED
11073    if (myrpt->voxchannel->cdr)
11074       ast_set_flag(myrpt->voxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11075 #endif
11076    /* allocate a pseudo-channel thru asterisk */
11077    myrpt->txpchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
11078    if (!myrpt->txpchannel)
11079    {
11080       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11081       rpt_mutex_unlock(&myrpt->lock);
11082       ast_hangup(myrpt->pchannel);
11083       ast_hangup(myrpt->monchannel);
11084       if (myrpt->txchannel != myrpt->rxchannel) 
11085          ast_hangup(myrpt->txchannel);
11086       ast_hangup(myrpt->rxchannel);
11087       myrpt->rpt_thread = AST_PTHREADT_STOP;
11088       pthread_exit(NULL);
11089    }
11090 #ifdef   AST_CDR_FLAG_POST_DISABLED
11091    if (myrpt->txpchannel->cdr)
11092       ast_set_flag(myrpt->txpchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11093 #endif
11094    /* make a conference for the tx */
11095    ci.chan = 0;
11096    ci.confno = myrpt->txconf;
11097    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER ;
11098    /* first put the channel on the conference in proper mode */
11099    if (ioctl(myrpt->txpchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11100    {
11101       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
11102       rpt_mutex_unlock(&myrpt->lock);
11103       ast_hangup(myrpt->txpchannel);
11104       ast_hangup(myrpt->monchannel);
11105       if (myrpt->txchannel != myrpt->rxchannel) 
11106          ast_hangup(myrpt->txchannel);
11107       ast_hangup(myrpt->rxchannel);
11108       myrpt->rpt_thread = AST_PTHREADT_STOP;
11109       pthread_exit(NULL);
11110    }
11111    /* if serial io port, open it */
11112    myrpt->iofd = -1;
11113    if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt,myrpt->p.ioport)) == -1))
11114    {
11115       ast_log(LOG_ERROR, "Unable to open %s\n",myrpt->p.ioport);
11116       rpt_mutex_unlock(&myrpt->lock);
11117       ast_hangup(myrpt->pchannel);
11118       if (myrpt->txchannel != myrpt->rxchannel) 
11119          ast_hangup(myrpt->txchannel);
11120       ast_hangup(myrpt->rxchannel);
11121       pthread_exit(NULL);
11122    }
11123    /* Now, the idea here is to copy from the physical rx channel buffer
11124       into the pseudo tx buffer, and from the pseudo rx buffer into the 
11125       tx channel buffer */
11126    myrpt->links.next = &myrpt->links;
11127    myrpt->links.prev = &myrpt->links;
11128    myrpt->tailtimer = 0;
11129    myrpt->totimer = 0;
11130    myrpt->tmsgtimer = myrpt->p.tailmessagetime;
11131    myrpt->idtimer = myrpt->p.politeid;
11132    myrpt->mustid = myrpt->tailid = 0;
11133    myrpt->callmode = 0;
11134    myrpt->tounkeyed = 0;
11135    myrpt->tonotify = 0;
11136    myrpt->retxtimer = 0;
11137    myrpt->rerxtimer = 0;
11138    myrpt->skedtimer = 0;
11139    myrpt->tailevent = 0;
11140    lasttx = 0;
11141    myrpt->keyed = 0;
11142    myrpt->txkeyed = 0;
11143    time(&myrpt->lastkeyedtime);
11144    myrpt->lastkeyedtime -= RPT_LOCKOUT_SECS;
11145    time(&myrpt->lasttxkeyedtime);
11146    myrpt->lasttxkeyedtime -= RPT_LOCKOUT_SECS;
11147    idtalkover = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
11148    myrpt->dtmfidx = -1;
11149    myrpt->dtmfbuf[0] = 0;
11150    myrpt->rem_dtmfidx = -1;
11151    myrpt->rem_dtmfbuf[0] = 0;
11152    myrpt->dtmf_time = 0;
11153    myrpt->rem_dtmf_time = 0;
11154    myrpt->inpadtest = 0;
11155    myrpt->disgorgetime = 0;
11156    myrpt->lastnodewhichkeyedusup[0] = '\0';
11157    myrpt->dailytxtime = 0;
11158    myrpt->totaltxtime = 0;
11159    myrpt->dailykeyups = 0;
11160    myrpt->totalkeyups = 0;
11161    myrpt->dailykerchunks = 0;
11162    myrpt->totalkerchunks = 0;
11163    myrpt->dailyexecdcommands = 0;
11164    myrpt->totalexecdcommands = 0;
11165    myrpt->timeouts = 0;
11166    myrpt->exten[0] = '\0';
11167    myrpt->lastdtmfcommand[0] = '\0';
11168    voxinit_rpt(myrpt,1);
11169    myrpt->wasvox = 0;
11170    if (myrpt->p.startupmacro)
11171    {
11172       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
11173    }
11174    rpt_mutex_unlock(&myrpt->lock);
11175    val = 1;
11176    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
11177    val = 1;
11178    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
11179    if (myrpt->p.archivedir) donodelog(myrpt,"STARTUP");
11180    dtmfed = 0;
11181    if (myrpt->remoterig && !ISRIG_RTX(myrpt->remoterig)) setrem(myrpt);
11182    lastmyrx = 0;
11183    myfirst = 0;
11184    while (ms >= 0)
11185    {
11186       struct ast_frame *f,*f1,*f2;
11187       struct ast_channel *cs[300],*cs1[300];
11188       int totx=0,elap=0,n,x,toexit=0;
11189 
11190       /* DEBUG Dump */
11191       if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){
11192          struct rpt_link *dl;
11193          struct rpt_tele *dt;
11194 
11195          myrpt->disgorgetime = 0;
11196          ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n");
11197          ast_log(LOG_NOTICE,"totx = %d\n",totx);
11198          ast_log(LOG_NOTICE,"remrx = %d\n",remrx);
11199          ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx);
11200          ast_log(LOG_NOTICE,"elap = %d\n",elap);
11201          ast_log(LOG_NOTICE,"toexit = %d\n",toexit);
11202 
11203          ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed);
11204          ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx);
11205          ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode);
11206          ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
11207          ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed);
11208          ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify);
11209          ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
11210          ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
11211          ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
11212          ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
11213 
11214          dl = myrpt->links.next;
11215                   while(dl != &myrpt->links){
11216             ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",dl->name);
11217             ast_log(LOG_NOTICE,"        link->lasttx %d\n",dl->lasttx);
11218             ast_log(LOG_NOTICE,"        link->lastrx %d\n",dl->lastrx);
11219             ast_log(LOG_NOTICE,"        link->connected %d\n",dl->connected);
11220             ast_log(LOG_NOTICE,"        link->hasconnected %d\n",dl->hasconnected);
11221             ast_log(LOG_NOTICE,"        link->outbound %d\n",dl->outbound);
11222             ast_log(LOG_NOTICE,"        link->disced %d\n",dl->disced);
11223             ast_log(LOG_NOTICE,"        link->killme %d\n",dl->killme);
11224             ast_log(LOG_NOTICE,"        link->disctime %ld\n",dl->disctime);
11225             ast_log(LOG_NOTICE,"        link->retrytimer %ld\n",dl->retrytimer);
11226             ast_log(LOG_NOTICE,"        link->retries = %d\n",dl->retries);
11227             ast_log(LOG_NOTICE,"        link->reconnects = %d\n",dl->reconnects);
11228             ast_log(LOG_NOTICE,"        link->newkey = %d\n",dl->newkey);
11229                            dl = dl->next;
11230                   }
11231                                                                                                                                
11232          dt = myrpt->tele.next;
11233          if(dt != &myrpt->tele)
11234             ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n");
11235                   while(dt != &myrpt->tele){
11236             ast_log(LOG_NOTICE,"        Telemetry mode: %d\n",dt->mode);
11237                            dt = dt->next;
11238                   }
11239          ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n");
11240 
11241       }  
11242 
11243 
11244       if (myrpt->reload)
11245       {
11246          struct rpt_tele *inner_telem;
11247 
11248          rpt_mutex_lock(&myrpt->lock);
11249          inner_telem = myrpt->tele.next;
11250          while(inner_telem != &myrpt->tele)
11251          {
11252             ast_softhangup(inner_telem->chan,AST_SOFTHANGUP_DEV);
11253             inner_telem = inner_telem->next;
11254          }
11255          myrpt->reload = 0;
11256          rpt_mutex_unlock(&myrpt->lock);
11257          usleep(10000);
11258          /* find our index, and load the vars */
11259          for(i = 0; i < nrpts; i++)
11260          {
11261             if (&rpt_vars[i] == myrpt)
11262             {
11263                load_rpt_vars(i,0);
11264                break;
11265             }
11266          }
11267       }
11268 
11269       rpt_mutex_lock(&myrpt->lock);
11270       if (ast_check_hangup(myrpt->rxchannel)) break;
11271       if (ast_check_hangup(myrpt->txchannel)) break;
11272       if (ast_check_hangup(myrpt->pchannel)) break;
11273       if (ast_check_hangup(myrpt->monchannel)) break;
11274       if (myrpt->parrotchannel && 
11275          ast_check_hangup(myrpt->parrotchannel)) break;
11276       if (myrpt->voxchannel && 
11277          ast_check_hangup(myrpt->voxchannel)) break;
11278       if (ast_check_hangup(myrpt->txpchannel)) break;
11279       if (myrpt->dahditxchannel && ast_check_hangup(myrpt->dahditxchannel)) break;
11280 
11281       /* Set local tx with keyed */
11282       myrpt->localtx = myrpt->keyed;
11283       /* If someone's connected, and they're transmitting from their end to us, set remrx true */
11284       l = myrpt->links.next;
11285       remrx = 0;
11286       while(l != &myrpt->links)
11287       {
11288          if (l->lastrx){
11289             remrx = 1;
11290             if(l->name[0] != '0') /* Ignore '0' nodes */
11291                strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
11292          }
11293          l = l->next;
11294       }
11295       /* Create a "must_id" flag for the cleanup ID */      
11296       if(myrpt->p.idtime) /* ID time must be non-zero */
11297          myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
11298       /* Build a fresh totx from myrpt->keyed and autopatch activated */
11299       /* If full duplex, add local tx to totx */
11300       if (myrpt->p.duplex > 1) 
11301       {
11302          totx = myrpt->callmode;
11303          totx = totx || myrpt->localtx;
11304       }
11305       else
11306       {
11307          int myrx = myrpt->localtx || remrx || (!myrpt->callmode);
11308 
11309          if (lastmyrx != myrx)
11310          {
11311             voxinit_rpt(myrpt,!myrx);
11312             lastmyrx = myrx;
11313          }
11314          totx = 0;
11315          if (myrpt->callmode && (myrpt->voxtotimer <= 0))
11316          {
11317             if (myrpt->voxtostate)
11318             {
11319                myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
11320                myrpt->voxtostate = 0;
11321             }           
11322             else
11323             {
11324                myrpt->voxtotimer = myrpt->p.voxrecover_ms;
11325                myrpt->voxtostate = 1;
11326             }
11327          }
11328          if (!myrpt->voxtostate)
11329             totx = myrpt->callmode && myrpt->wasvox;
11330       }
11331       /* Traverse the telemetry list to see what's queued */
11332       identqueued = 0;
11333       localmsgqueued = 0;
11334       othertelemqueued = 0;
11335       tailmessagequeued = 0;
11336       ctqueued = 0;
11337       telem = myrpt->tele.next;
11338       while(telem != &myrpt->tele)
11339       {
11340          if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
11341             identqueued = 1; /* Identification telemetry */
11342          }
11343          else if(telem->mode == TAILMSG)
11344          {
11345             tailmessagequeued = 1; /* Tail message telemetry */
11346          }
11347          else if(telem->mode == STATS_TIME_LOCAL) 
11348          {
11349             localmsgqueued = 1; /* Local message */
11350          }
11351          else
11352          {
11353             if ((telem->mode != UNKEY) && (telem->mode != LINKUNKEY))
11354                othertelemqueued = 1;  /* Other telemetry */
11355             else
11356                ctqueued = 1; /* Courtesy tone telemetry */
11357          }
11358          telem = telem->next;
11359       }
11360    
11361       /* Add in any "other" telemetry, unless specified otherwise */
11362       if (!myrpt->p.notelemtx) totx = totx || othertelemqueued;
11363       /* Update external (to links) transmitter PTT state with everything but */
11364       /* ID, CT, local messages, and tailmessage telemetry */
11365       myrpt->exttx = totx;
11366       totx = totx || myrpt->dtmf_local_timer;
11367       /* If half or 3/4 duplex, add localtx to external link tx */
11368       if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
11369       /* Add in ID telemetry to local transmitter */
11370       totx = totx || remrx;
11371       /* If 3/4 or full duplex, add in ident, CT telemetry, and local messages */
11372       if (myrpt->p.duplex > 0)
11373          totx = totx || identqueued || ctqueued || localmsgqueued;
11374       /* If full duplex, add local dtmf stuff active */
11375       if (myrpt->p.duplex > 1) 
11376       {
11377          totx = totx || (myrpt->dtmfidx > -1) ||
11378             myrpt->cmdnode[0];
11379       }
11380       /* add in parrot stuff */
11381       totx = totx || (myrpt->parrotstate > 1);
11382       /* Reset time out timer variables if there is no activity */
11383       if (!totx) 
11384       {
11385          myrpt->totimer = myrpt->p.totime;
11386          myrpt->tounkeyed = 0;
11387          myrpt->tonotify = 0;
11388       }
11389       else{
11390          myrpt->tailtimer = myrpt->p.s[myrpt->p.sysstate_cur].alternatetail ?
11391             myrpt->p.althangtime : /* Initialize tail timer */
11392             myrpt->p.hangtime;
11393       }
11394       /* Disable the local transmitter if we are timed out */
11395       totx = totx && myrpt->totimer;
11396       /* if timed-out and not said already, say it */
11397       if ((!myrpt->totimer) && (!myrpt->tonotify))
11398       {
11399          myrpt->tonotify = 1;
11400          myrpt->timeouts++;
11401          rpt_mutex_unlock(&myrpt->lock);
11402          rpt_telemetry(myrpt,TIMEOUT,NULL);
11403          rpt_mutex_lock(&myrpt->lock);
11404       }
11405 
11406       /* If unkey and re-key, reset time out timer */
11407       if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
11408       {
11409          myrpt->tounkeyed = 1;
11410       }
11411       if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
11412       {
11413          myrpt->totimer = myrpt->p.totime;
11414          myrpt->tounkeyed = 0;
11415          myrpt->tonotify = 0;
11416          rpt_mutex_unlock(&myrpt->lock);
11417          continue;
11418       }
11419       /* if timed-out and in circuit busy after call */
11420       if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
11421       {
11422           if(debug)
11423             ast_log(LOG_NOTICE, "timed-out and in circuit busy after call\n");
11424          myrpt->callmode = 0;
11425          myrpt->macropatch=0;
11426          channel_revert(myrpt);
11427       }
11428       /* get rid of tail if timed out */
11429       if (!myrpt->totimer) myrpt->tailtimer = 0;
11430       /* if not timed-out, add in tail */
11431       if (myrpt->totimer) totx = totx || myrpt->tailtimer;
11432       /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
11433       /* If tail message, kill the message if someone keys up over it */ 
11434       if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
11435          int hasid = 0,hastalkover = 0;
11436 
11437          telem = myrpt->tele.next;
11438          while(telem != &myrpt->tele){
11439             if(telem->mode == ID){
11440                if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
11441                hasid = 1;
11442             }
11443             if(telem->mode == TAILMSG){
11444                                         if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
11445                                 }
11446             if (telem->mode == IDTALKOVER) hastalkover = 1;
11447             telem = telem->next;
11448          }
11449          rpt_mutex_unlock(&myrpt->lock);
11450          if (hasid && (!hastalkover)) rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
11451          rpt_mutex_lock(&myrpt->lock);
11452       }
11453       /* Try to be polite */
11454       /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
11455       /* If within 30 seconds of the time to ID, try do it in the tail */
11456       /* else if at ID time limit, do it right over the top of them */
11457       /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
11458       if(myrpt->mustid && (!myrpt->idtimer))
11459          queue_id(myrpt);
11460 
11461       if ((myrpt->p.idtime && totx && (!myrpt->exttx) &&
11462           (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) /* ID time must be non-zero */ 
11463          {
11464             myrpt->tailid = 1;
11465          }
11466 
11467       /* If tail timer expires, then check for tail messages */
11468 
11469       if(myrpt->tailevent){
11470          myrpt->tailevent = 0;
11471          if(myrpt->tailid){
11472             totx = 1;
11473             queue_id(myrpt);
11474          }
11475          else if ((myrpt->p.tailmessages[0]) &&
11476             (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
11477                totx = 1;
11478                myrpt->tmsgtimer = myrpt->p.tailmessagetime; 
11479                rpt_mutex_unlock(&myrpt->lock);
11480                rpt_telemetry(myrpt, TAILMSG, NULL);
11481                rpt_mutex_lock(&myrpt->lock);
11482          }  
11483       }
11484 
11485       /* Main TX control */
11486 
11487       /* let telemetry transmit anyway (regardless of timeout) */
11488       if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
11489       totx = totx && !myrpt->p.s[myrpt->p.sysstate_cur].txdisable;
11490       myrpt->txrealkeyed = totx;
11491       totx = totx || (!AST_LIST_EMPTY(&myrpt->txq));
11492       if (totx && (!lasttx))
11493       {
11494          char mydate[100],myfname[100];
11495          time_t myt;
11496 
11497          if (myrpt->monstream) ast_closestream(myrpt->monstream);
11498          if (myrpt->p.archivedir)
11499          {
11500             long blocksleft;
11501 
11502             time(&myt);
11503             strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
11504                localtime(&myt));
11505             sprintf(myfname,"%s/%s/%s",myrpt->p.archivedir,
11506                myrpt->name,mydate);
11507             myrpt->monstream = ast_writefile(myfname,"wav49",
11508                "app_rpt Air Archive",O_CREAT | O_APPEND,0,0600);
11509             if (myrpt->p.monminblocks)
11510             {
11511                blocksleft = diskavail(myrpt);
11512                if (blocksleft >= myrpt->p.monminblocks)
11513                   donodelog(myrpt,"TXKEY,MAIN");
11514             } else donodelog(myrpt,"TXKEY,MAIN");
11515          }
11516          lasttx = 1;
11517          myrpt->txkeyed = 1;
11518          time(&myrpt->lasttxkeyedtime);
11519          myrpt->dailykeyups++;
11520          myrpt->totalkeyups++;
11521          rpt_mutex_unlock(&myrpt->lock);
11522          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
11523          rpt_mutex_lock(&myrpt->lock);
11524       }
11525       if ((!totx) && lasttx)
11526       {
11527          if (myrpt->monstream) ast_closestream(myrpt->monstream);
11528          myrpt->monstream = NULL;
11529 
11530          lasttx = 0;
11531          myrpt->txkeyed = 0;
11532          time(&myrpt->lasttxkeyedtime);
11533          rpt_mutex_unlock(&myrpt->lock);
11534          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
11535          rpt_mutex_lock(&myrpt->lock);
11536          donodelog(myrpt,"TXUNKEY,MAIN");
11537       }
11538       time(&t);
11539       /* if DTMF timeout */
11540       if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t))
11541       {
11542          myrpt->inpadtest = 0;
11543          myrpt->dtmfidx = -1;
11544          myrpt->dtmfbuf[0] = 0;
11545       }        
11546       /* if remote DTMF timeout */
11547       if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
11548       {
11549          myrpt->inpadtest = 0;
11550          myrpt->rem_dtmfidx = -1;
11551          myrpt->rem_dtmfbuf[0] = 0;
11552       }  
11553 
11554       if (myrpt->exttx && myrpt->parrotchannel && 
11555          myrpt->p.parrotmode && (!myrpt->parrotstate))
11556       {
11557          char myfname[300];
11558 
11559          ci.confno = myrpt->conf;
11560          ci.confmode = DAHDI_CONF_CONFANNMON;
11561          ci.chan = 0;
11562 
11563          /* first put the channel on the conference in announce mode */
11564          if (ioctl(myrpt->parrotchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11565          {
11566             ast_log(LOG_WARNING, "Unable to set conference mode for parrot\n");
11567             break;
11568          }
11569 
11570          sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
11571          strcat(myfname,".wav");
11572          unlink(myfname);        
11573          sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
11574          myrpt->parrotstate = 1;
11575          myrpt->parrottimer = myrpt->p.parrottime;
11576          if (myrpt->parrotstream) 
11577             ast_closestream(myrpt->parrotstream);
11578          myrpt->parrotstream = NULL;
11579          myrpt->parrotstream = ast_writefile(myfname,"wav",
11580             "app_rpt Parrot",O_CREAT | O_TRUNC,0,0600);
11581       }
11582 
11583       /* Reconnect */
11584    
11585       l = myrpt->links.next;
11586       while(l != &myrpt->links)
11587       {
11588          if (l->killme)
11589          {
11590             /* remove from queue */
11591             remque((struct qelem *) l);
11592             if (!strcmp(myrpt->cmdnode,l->name))
11593                myrpt->cmdnode[0] = 0;
11594             rpt_mutex_unlock(&myrpt->lock);
11595             /* hang-up on call to device */
11596             if (l->chan) ast_hangup(l->chan);
11597             ast_hangup(l->pchan);
11598             ast_free(l);
11599             rpt_mutex_lock(&myrpt->lock);
11600             /* re-start link traversal */
11601             l = myrpt->links.next;
11602             continue;
11603          }
11604          l = l->next;
11605       }
11606       n = 0;
11607       cs[n++] = myrpt->rxchannel;
11608       cs[n++] = myrpt->pchannel;
11609       cs[n++] = myrpt->monchannel;
11610       if (myrpt->parrotchannel) cs[n++] = myrpt->parrotchannel;
11611       if (myrpt->voxchannel) cs[n++] = myrpt->voxchannel;
11612       cs[n++] = myrpt->txpchannel;
11613       if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
11614       if (myrpt->dahditxchannel != myrpt->txchannel)
11615          cs[n++] = myrpt->dahditxchannel;
11616       l = myrpt->links.next;
11617       while(l != &myrpt->links)
11618       {
11619          if ((!l->killme) && (!l->disctime) && l->chan)
11620          {
11621             cs[n++] = l->chan;
11622             cs[n++] = l->pchan;
11623          }
11624          l = l->next;
11625       }
11626       if ((myrpt->topkeystate == 1) && 
11627           ((t - myrpt->topkeytime) > TOPKEYWAIT))
11628       {
11629          myrpt->topkeystate = 2;
11630          qsort(myrpt->topkey,TOPKEYN,sizeof(struct rpt_topkey),
11631             topcompar);
11632       }
11633       rpt_mutex_unlock(&myrpt->lock);
11634 
11635       if (myrpt->topkeystate == 2)
11636       {
11637          rpt_telemetry(myrpt,TOPKEY,NULL);
11638          myrpt->topkeystate = 3;
11639       }
11640       ms = MSWAIT;
11641       for(x = 0; x < n; x++)
11642       {
11643          int s = -(-x - myrpt->scram - 1) % n;
11644          cs1[x] = cs[s];
11645       }
11646       myrpt->scram++;
11647       who = ast_waitfor_n(cs1,n,&ms);
11648       if (who == NULL) ms = 0;
11649       elap = MSWAIT - ms;
11650       rpt_mutex_lock(&myrpt->lock);
11651       l = myrpt->links.next;
11652       while(l != &myrpt->links)
11653       {
11654          int myrx;
11655 
11656          if (l->voxtotimer) l->voxtotimer -= elap;
11657          if (l->voxtotimer < 0) l->voxtotimer = 0;
11658 
11659          if (l->lasttx != l->lasttx1)
11660          {
11661             voxinit_link(l,!l->lasttx);
11662             l->lasttx1 = l->lasttx;
11663          }
11664          myrx = l->lastrealrx;
11665          if ((l->phonemode) && (l->phonevox))
11666          {
11667             myrx = myrx || (!AST_LIST_EMPTY(&l->rxq));
11668             if (l->voxtotimer <= 0)
11669             {
11670                if (l->voxtostate)
11671                {
11672                   l->voxtotimer = myrpt->p.voxtimeout_ms;
11673                   l->voxtostate = 0;
11674                }           
11675                else
11676                {
11677                   l->voxtotimer = myrpt->p.voxrecover_ms;
11678                   l->voxtostate = 1;
11679                }
11680             }
11681             if (!l->voxtostate)
11682                myrx = myrx || l->wasvox ;
11683          }
11684          l->lastrx = myrx;
11685          if (l->linklisttimer)
11686          {
11687             l->linklisttimer -= elap;
11688             if (l->linklisttimer < 0) l->linklisttimer = 0;
11689          }
11690          if ((!l->linklisttimer) && (l->name[0] != '0') && (!l->isremote))
11691          {
11692             struct   ast_frame lf;
11693 
11694             memset(&lf,0,sizeof(lf));
11695             lf.frametype = AST_FRAME_TEXT;
11696             lf.subclass = 0;
11697             lf.offset = 0;
11698             lf.mallocd = 0;
11699             lf.samples = 0;
11700             l->linklisttimer = LINKLISTTIME;
11701             strcpy(lstr,"L ");
11702             __mklinklist(myrpt,l,lstr + 2);
11703             if (l->chan)
11704             {
11705                lf.datalen = strlen(lstr) + 1;
11706                lf.data.ptr = lstr;
11707                ast_write(l->chan,&lf);
11708                if (debug > 6) ast_log(LOG_NOTICE,
11709                   "@@@@ node %s sent node string %s to node %s\n",
11710                      myrpt->name,lstr,l->name);
11711             }
11712          }
11713          if (l->newkey)
11714          {
11715             if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
11716             {
11717                l->retxtimer = 0;
11718                if (l->chan && l->phonemode == 0) 
11719                {
11720                   if (l->lasttx)
11721                      ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
11722                   else
11723                      ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
11724                }
11725             }
11726             if ((l->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 5))
11727             {
11728                if (debug == 7) printf("@@@@ rx un-key\n");
11729                l->lastrealrx = 0;
11730                l->rerxtimer = 0;
11731                if (l->lastrx1)
11732                {
11733                   if (myrpt->p.archivedir)
11734                   {
11735                      char str[100];
11736    
11737                      sprintf(str,"RXUNKEY(T),%s",l->name);
11738                      donodelog(myrpt,str);
11739                   }
11740                   if(myrpt->p.duplex) 
11741                      rpt_telemetry(myrpt,LINKUNKEY,l);
11742                   l->lastrx1 = 0;
11743                }
11744             }
11745          }
11746          if (l->disctime) /* Disconnect timer active on a channel ? */
11747          {
11748             l->disctime -= elap;
11749             if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
11750                l->disctime = 0; /* Yep */
11751          }
11752 
11753          if (l->retrytimer)
11754          {
11755             l->retrytimer -= elap;
11756             if (l->retrytimer < 0) l->retrytimer = 0;
11757          }
11758 
11759          /* Tally connect time */
11760          l->connecttime += elap;
11761 
11762          /* ignore non-timing channels */
11763          if (l->elaptime < 0)
11764          {
11765             l = l->next;
11766             continue;
11767          }
11768          l->elaptime += elap;
11769          /* if connection has taken too long */
11770          if ((l->elaptime > MAXCONNECTTIME) && 
11771             ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
11772          {
11773             l->elaptime = 0;
11774             rpt_mutex_unlock(&myrpt->lock);
11775             if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
11776             rpt_mutex_lock(&myrpt->lock);
11777             break;
11778          }
11779          if ((!l->chan) && (!l->retrytimer) && l->outbound && 
11780             (l->retries++ < l->max_retries) && (l->hasconnected))
11781          {
11782             if (l->chan) ast_hangup(l->chan);
11783             l->chan = 0;
11784             rpt_mutex_unlock(&myrpt->lock);
11785             if ((l->name[0] != '0') && (!l->isremote))
11786             {
11787                if (attempt_reconnect(myrpt,l) == -1)
11788                {
11789                   l->retrytimer = RETRY_TIMER_MS;
11790                } 
11791             }
11792             else 
11793             {
11794                l->retrytimer = l->max_retries + 1;
11795             }
11796 
11797             rpt_mutex_lock(&myrpt->lock);
11798             break;
11799          }
11800          if ((!l->chan) && (!l->retrytimer) && l->outbound &&
11801             (l->retries >= l->max_retries))
11802          {
11803             /* remove from queue */
11804             remque((struct qelem *) l);
11805             if (!strcmp(myrpt->cmdnode,l->name))
11806                myrpt->cmdnode[0] = 0;
11807             rpt_mutex_unlock(&myrpt->lock);
11808             if (l->name[0] != '0')
11809             {
11810                if (!l->hasconnected)
11811                   rpt_telemetry(myrpt,CONNFAIL,l);
11812                else rpt_telemetry(myrpt,REMDISC,l);
11813             }
11814             if (myrpt->p.archivedir)
11815             {
11816                char str[100];
11817 
11818                if (!l->hasconnected)
11819                   sprintf(str,"LINKFAIL,%s",l->name);
11820                else
11821                   sprintf(str,"LINKDISC,%s",l->name);
11822                donodelog(myrpt,str);
11823             }
11824             /* hang-up on call to device */
11825             ast_hangup(l->pchan);
11826             ast_free(l);
11827                                 rpt_mutex_lock(&myrpt->lock);
11828             break;
11829          }
11830             if ((!l->chan) && (!l->disctime) && (!l->outbound))
11831             {
11832             if(debug)ast_log(LOG_NOTICE, "LINKDISC AA\n");
11833                 /* remove from queue */
11834                 remque((struct qelem *) l);
11835             if(myrpt->links.next==&myrpt->links)channel_revert(myrpt);
11836                 if (!strcmp(myrpt->cmdnode,l->name))myrpt->cmdnode[0] = 0;
11837                 rpt_mutex_unlock(&myrpt->lock);
11838             if (l->name[0] != '0') 
11839             {
11840                   rpt_telemetry(myrpt,REMDISC,l);
11841             }
11842             if (myrpt->p.archivedir)
11843             {
11844                char str[100];
11845                sprintf(str,"LINKDISC,%s",l->name);
11846                donodelog(myrpt,str);
11847             }
11848                 /* hang-up on call to device */
11849                 ast_hangup(l->pchan);
11850                 ast_free(l);
11851                 rpt_mutex_lock(&myrpt->lock);
11852                 break;
11853             }
11854          l = l->next;
11855       }
11856       if (myrpt->linkposttimer)
11857       {
11858          myrpt->linkposttimer -= elap;
11859          if (myrpt->linkposttimer < 0) myrpt->linkposttimer = 0;
11860       }
11861       if (myrpt->linkposttimer <= 0)
11862       {
11863          int nstr;
11864          char lst,*str;
11865          time_t now;
11866 
11867          myrpt->linkposttimer = LINKPOSTTIME;
11868          nstr = 0;
11869          for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
11870          {
11871             /* if is not a real link, ignore it */
11872             if (l->name[0] == '0') continue;
11873             nstr += strlen(l->name) + 1;
11874          }
11875          str = ast_malloc(nstr + 256);
11876          if (!str)
11877          {
11878             ast_log(LOG_NOTICE,"Cannot ast_malloc()\n");
11879             break;
11880          }
11881          nstr = 0;
11882          strcpy(str,"nodes=");
11883          for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
11884          {
11885             /* if is not a real link, ignore it */
11886             if (l->name[0] == '0') continue;
11887             lst = 'T';
11888             if (!l->mode) lst = 'R';
11889             if (!l->thisconnected) lst = 'C';
11890             if (nstr) strcat(str,",");
11891             sprintf(str + strlen(str),"%c%s",lst,l->name);
11892             nstr = 1;
11893          }
11894                   p = strstr(tdesc, "version");
11895                   if(p){
11896             int vmajor,vminor;
11897             if(sscanf(p, "version %30d.%30d", &vmajor, &vminor) == 2)
11898                sprintf(str + strlen(str),"&apprptvers=%d.%d",vmajor,vminor);
11899          }
11900          time(&now);
11901          sprintf(str + strlen(str),"&apprptuptime=%d",(int)(now-starttime));
11902          sprintf(str + strlen(str),
11903          "&totalkerchunks=%d&totalkeyups=%d&totaltxtime=%d&timeouts=%d&totalexecdcommands=%d",
11904          myrpt->totalkerchunks,myrpt->totalkeyups,(int) myrpt->totaltxtime/1000,
11905          myrpt->timeouts,myrpt->totalexecdcommands);
11906          rpt_mutex_unlock(&myrpt->lock);
11907          statpost(myrpt,str);
11908          rpt_mutex_lock(&myrpt->lock);
11909          ast_free(str);
11910       }
11911       if (myrpt->keyposttimer)
11912       {
11913          myrpt->keyposttimer -= elap;
11914          if (myrpt->keyposttimer < 0) myrpt->keyposttimer = 0;
11915       }
11916       if (myrpt->keyposttimer <= 0)
11917       {
11918          char str[100];
11919          int diff = 0;
11920          time_t now;
11921 
11922          myrpt->keyposttimer = KEYPOSTTIME;
11923          time(&now);
11924          if (myrpt->lastkeyedtime)
11925          {
11926             diff = (int)(now - myrpt->lastkeyedtime);
11927          }
11928          sprintf(str,"keyed=%d&keytime=%d",myrpt->keyed,diff);
11929          rpt_mutex_unlock(&myrpt->lock);
11930          statpost(myrpt,str);
11931          rpt_mutex_lock(&myrpt->lock);
11932       }
11933       if(totx){
11934          myrpt->dailytxtime += elap;
11935          myrpt->totaltxtime += elap;
11936       }
11937       i = myrpt->tailtimer;
11938       if (myrpt->tailtimer) myrpt->tailtimer -= elap;
11939       if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
11940       if((i) && (myrpt->tailtimer == 0))
11941          myrpt->tailevent = 1;
11942       if ((!myrpt->p.s[myrpt->p.sysstate_cur].totdisable) && myrpt->totimer) myrpt->totimer -= elap;
11943       if (myrpt->totimer < 0) myrpt->totimer = 0;
11944       if (myrpt->idtimer) myrpt->idtimer -= elap;
11945       if (myrpt->idtimer < 0) myrpt->idtimer = 0;
11946       if (myrpt->tmsgtimer) myrpt->tmsgtimer -= elap;
11947       if (myrpt->tmsgtimer < 0) myrpt->tmsgtimer = 0;
11948       if (myrpt->voxtotimer) myrpt->voxtotimer -= elap;
11949       if (myrpt->voxtotimer < 0) myrpt->voxtotimer = 0;
11950       if (myrpt->exttx)
11951       {
11952          myrpt->parrottimer = myrpt->p.parrottime;
11953       }
11954       else
11955       {
11956          if (myrpt->parrottimer) myrpt->parrottimer -= elap;
11957          if (myrpt->parrottimer < 0) myrpt->parrottimer = 0;
11958       }
11959       /* do macro timers */
11960       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
11961       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
11962       /* do local dtmf timer */
11963       if (myrpt->dtmf_local_timer)
11964       {
11965          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
11966          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
11967       }
11968       do_dtmf_local(myrpt,0);
11969       /* Execute scheduler appx. every 2 tenths of a second */
11970       if (myrpt->skedtimer <= 0){
11971          myrpt->skedtimer = 200;
11972          do_scheduler(myrpt);
11973       }
11974       else
11975          myrpt->skedtimer -=elap;
11976       if (!ms) 
11977       {
11978          rpt_mutex_unlock(&myrpt->lock);
11979          continue;
11980       }
11981       if (myrpt->p.parrotmode && (myrpt->parrotstate == 1) &&
11982          (myrpt->parrottimer <= 0))
11983       {
11984 
11985          ci.confno = 0;
11986          ci.confmode = 0;
11987          ci.chan = 0;
11988 
11989          /* first put the channel on the conference in announce mode */
11990          if (ioctl(myrpt->parrotchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11991          {
11992             ast_log(LOG_WARNING, "Unable to set conference mode for parrot\n");
11993             break;
11994          }
11995          if (myrpt->parrotstream) 
11996             ast_closestream(myrpt->parrotstream);
11997          myrpt->parrotstream = NULL;
11998          myrpt->parrotstate = 2;
11999          rpt_telemetry(myrpt,PARROT,(void *) ((intptr_t)myrpt->parrotcnt++)); 
12000       }        
12001       if (myrpt->cmdAction.state == CMD_STATE_READY)
12002       { /* there is a command waiting to be processed */
12003          int status;
12004          myrpt->cmdAction.state = CMD_STATE_EXECUTING;
12005          // lose the lock
12006          rpt_mutex_unlock(&myrpt->lock);
12007          // do the function
12008          status = (*function_table[myrpt->cmdAction.functionNumber].function)(myrpt,myrpt->cmdAction.param, myrpt->cmdAction.digits, myrpt->cmdAction.command_source, NULL);
12009          // get the lock again
12010          rpt_mutex_lock(&myrpt->lock);
12011          myrpt->cmdAction.state = CMD_STATE_IDLE;
12012       } /* if myrpt->cmdAction.state == CMD_STATE_READY */
12013       
12014       c = myrpt->macrobuf[0];
12015       time(&t);
12016       if (c && (!myrpt->macrotimer) && 
12017          starttime && (t > (starttime + START_DELAY)))
12018       {
12019          char cin = c & 0x7f;
12020          myrpt->macrotimer = MACROTIME;
12021          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
12022          if ((cin == 'p') || (cin == 'P'))
12023             myrpt->macrotimer = MACROPTIME;
12024          rpt_mutex_unlock(&myrpt->lock);
12025          if (myrpt->p.archivedir)
12026          {
12027             char str[100];
12028 
12029             sprintf(str,"DTMF(M),MAIN,%c",cin);
12030             donodelog(myrpt,str);
12031          }
12032          local_dtmf_helper(myrpt,c);
12033       } else rpt_mutex_unlock(&myrpt->lock);
12034       if (who == myrpt->rxchannel) /* if it was a read from rx */
12035       {
12036          int ismuted;
12037 
12038          f = ast_read(myrpt->rxchannel);
12039          if (!f)
12040          {
12041             if (debug) printf("@@@@ rpt:Hung Up\n");
12042             break;
12043          }
12044          if (f->frametype == AST_FRAME_VOICE)
12045          {
12046 #ifdef   _MDC_DECODE_H_
12047             unsigned char ubuf[2560];
12048             short *sp;
12049             int n;
12050 #endif
12051 
12052             if ((!myrpt->localtx) && (!myrpt->p.linktolink)) {
12053                memset(f->data.ptr,0,f->datalen);
12054             }
12055 
12056 #ifdef   _MDC_DECODE_H_
12057             sp = (short *) f->data;
12058             /* convert block to unsigned char */
12059             for(n = 0; n < f->datalen / 2; n++)
12060             {
12061                ubuf[n] = (*sp++ >> 8) + 128;
12062             }
12063             n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
12064             if (n == 1)
12065             {
12066                   unsigned char op,arg;
12067                   unsigned short unitID;
12068 
12069                   mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
12070                   if (debug > 2)
12071                   {
12072                      ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
12073                      ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
12074                         op & 255,arg & 255,unitID);
12075                   }
12076                   if ((op == 1) && (arg == 0))
12077                   {
12078                      myrpt->lastunit = unitID;
12079                      mdc1200_notify(myrpt,NULL,myrpt->lastunit);
12080                      mdc1200_send(myrpt,myrpt->lastunit);
12081                   }
12082             }
12083             if ((debug > 2) && (i == 2))
12084             {
12085                unsigned char op,arg,ex1,ex2,ex3,ex4;
12086                unsigned short unitID;
12087 
12088                mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
12089                   &ex1,&ex2,&ex3,&ex4);
12090                ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
12091                ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
12092                   op & 255,arg & 255,unitID);
12093                ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
12094                   ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
12095             }
12096 #endif
12097 #ifdef   __RPT_NOTCH
12098             /* apply inbound filters, if any */
12099             rpt_filter(myrpt,f->data,f->datalen / 2);
12100 #endif
12101             if (ioctl(myrpt->dahdirxchannel->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
12102             {
12103                ismuted = 0;
12104             }
12105             if (dtmfed) ismuted = 1;
12106             dtmfed = 0;
12107             if (ismuted)
12108             {
12109                memset(f->data.ptr,0,f->datalen);
12110                if (myrpt->lastf1)
12111                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12112                if (myrpt->lastf2)
12113                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12114             } 
12115             if (f) f2 = ast_frdup(f);
12116             else f2 = NULL;
12117             f1 = myrpt->lastf2;
12118             myrpt->lastf2 = myrpt->lastf1;
12119             myrpt->lastf1 = f2;
12120             if (ismuted)
12121             {
12122                if (myrpt->lastf1)
12123                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12124                if (myrpt->lastf2)
12125                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12126             }
12127             if (f1)
12128             {
12129                ast_write(myrpt->pchannel,f1);
12130                ast_frfree(f1);
12131             }
12132          }
12133 #ifndef  OLD_ASTERISK
12134          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
12135          {
12136             if (myrpt->lastf1)
12137                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12138             if (myrpt->lastf2)
12139                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12140             dtmfed = 1;
12141          }
12142 #endif
12143          else if (f->frametype == AST_FRAME_DTMF)
12144          {
12145             c = (char) f->subclass; /* get DTMF char */
12146             ast_frfree(f);
12147             if (myrpt->lastf1)
12148                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12149             if (myrpt->lastf2)
12150                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12151             dtmfed = 1;
12152             if (!myrpt->keyed) continue;
12153             c = func_xlat(myrpt,c,&myrpt->p.inxlat);
12154             if (c) local_dtmf_helper(myrpt,c);
12155             continue;
12156          }                 
12157          else if (f->frametype == AST_FRAME_CONTROL)
12158          {
12159             if (f->subclass == AST_CONTROL_HANGUP)
12160             {
12161                if (debug) printf("@@@@ rpt:Hung Up\n");
12162                ast_frfree(f);
12163                break;
12164             }
12165             /* if RX key */
12166             if (f->subclass == AST_CONTROL_RADIO_KEY)
12167             {
12168                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink)) 
12169                {
12170                   if (debug == 7) printf("@@@@ rx key\n");
12171                   myrpt->keyed = 1;
12172                   time(&myrpt->lastkeyedtime);
12173                   myrpt->keyposttimer = KEYPOSTSHORTTIME;
12174                }
12175                if (myrpt->p.archivedir)
12176                {
12177                   donodelog(myrpt,"RXKEY,MAIN");
12178                }
12179                if (f->datalen && f->data.ptr)
12180                {
12181                   char busy = 0;
12182 
12183                   if (debug) ast_log(LOG_NOTICE,"Got PL %s on node %s\n",(char *)f->data.ptr,myrpt->name);
12184                   // ctcss code autopatch initiate
12185                   if (strstr((char *)f->data.ptr,"/M/")&& !myrpt->macropatch)
12186                   {
12187                       char value[16];
12188                      strcat(value,"*6");
12189                      myrpt->macropatch=1;
12190                      rpt_mutex_lock(&myrpt->lock);
12191                      if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(value)){
12192                         rpt_mutex_unlock(&myrpt->lock);
12193                         busy=1;
12194                      }
12195                      if(!busy){
12196                         myrpt->macrotimer = MACROTIME;
12197                         strncat(myrpt->macrobuf,value,MAXMACRO - 1);
12198                         if (!busy) strcpy(myrpt->lasttone,(char*)f->data.ptr);
12199                      }
12200                      rpt_mutex_unlock(&myrpt->lock);
12201                   }
12202                   else if (strcmp((char *)f->data.ptr,myrpt->lasttone))
12203                   {
12204                      char *value = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.tonemacro, (char *)f->data.ptr);
12205                      if (value)
12206                      {
12207                         if (debug) ast_log(LOG_NOTICE,"Tone %s doing %s on node %s\n",(char *) f->data.ptr,value,myrpt->name);
12208                         rpt_mutex_lock(&myrpt->lock);
12209                         if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(value)){
12210                            rpt_mutex_unlock(&myrpt->lock);
12211                            busy=1;
12212                         }
12213                         if(!busy){
12214                            myrpt->macrotimer = MACROTIME;
12215                            strncat(myrpt->macrobuf,value,MAXMACRO - 1);
12216                         }
12217                         rpt_mutex_unlock(&myrpt->lock);
12218                      }
12219                      if (!busy) strcpy(myrpt->lasttone,(char*)f->data.ptr);
12220                   }
12221                } else myrpt->lasttone[0] = 0;
12222             }
12223             /* if RX un-key */
12224             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
12225             {
12226                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
12227                {
12228                   if (debug == 7) printf("@@@@ rx un-key\n");
12229                   if(myrpt->p.duplex && myrpt->keyed) {
12230                      rpt_telemetry(myrpt,UNKEY,NULL);
12231                   }
12232                }
12233                myrpt->keyed = 0;
12234                time(&myrpt->lastkeyedtime);
12235                myrpt->keyposttimer = KEYPOSTSHORTTIME;
12236                if (myrpt->p.archivedir)
12237                {
12238                   donodelog(myrpt,"RXUNKEY,MAIN");
12239                }
12240             }
12241          }
12242          ast_frfree(f);
12243          continue;
12244       }
12245       if (who == myrpt->pchannel) /* if it was a read from pseudo */
12246       {
12247          f = ast_read(myrpt->pchannel);
12248          if (!f)
12249          {
12250             if (debug) printf("@@@@ rpt:Hung Up\n");
12251             break;
12252          }
12253          if (f->frametype == AST_FRAME_VOICE)
12254          {
12255             ast_write(myrpt->txpchannel,f);
12256          }
12257          if (f->frametype == AST_FRAME_CONTROL)
12258          {
12259             if (f->subclass == AST_CONTROL_HANGUP)
12260             {
12261                if (debug) printf("@@@@ rpt:Hung Up\n");
12262                ast_frfree(f);
12263                break;
12264             }
12265          }
12266          ast_frfree(f);
12267          continue;
12268       }
12269       if (who == myrpt->txchannel) /* if it was a read from tx */
12270       {
12271          f = ast_read(myrpt->txchannel);
12272          if (!f)
12273          {
12274             if (debug) printf("@@@@ rpt:Hung Up\n");
12275             break;
12276          }
12277          if (f->frametype == AST_FRAME_CONTROL)
12278          {
12279             if (f->subclass == AST_CONTROL_HANGUP)
12280             {
12281                if (debug) printf("@@@@ rpt:Hung Up\n");
12282                ast_frfree(f);
12283                break;
12284             }
12285          }
12286          ast_frfree(f);
12287          continue;
12288       }
12289       if (who == myrpt->dahditxchannel) /* if it was a read from pseudo-tx */
12290       {
12291          f = ast_read(myrpt->dahditxchannel);
12292          if (!f)
12293          {
12294             if (debug) printf("@@@@ rpt:Hung Up\n");
12295             break;
12296          }
12297          if (f->frametype == AST_FRAME_VOICE)
12298          {
12299             struct ast_frame *vframe;
12300 
12301             if (myrpt->p.duplex < 2)
12302             {
12303                if (myrpt->txrealkeyed) 
12304                {
12305                   if ((!myfirst) && myrpt->callmode)
12306                   {
12307                       x = 0;
12308                       AST_LIST_TRAVERSE(&myrpt->txq, vframe,
12309                      frame_list) x++;
12310                       for(;x < myrpt->p.simplexpatchdelay; x++)
12311                       {
12312                         vframe = ast_frdup(f);
12313                         memset(vframe->data.ptr,0,vframe->datalen);
12314                         AST_LIST_INSERT_TAIL(&myrpt->txq,vframe,frame_list);
12315                       }
12316                       myfirst = 1;
12317                   }
12318                   vframe = ast_frdup(f);
12319                   AST_LIST_INSERT_TAIL(&myrpt->txq,
12320                      vframe,frame_list);
12321                } else myfirst = 0;
12322                x = 0;
12323                AST_LIST_TRAVERSE(&myrpt->txq, vframe,
12324                   frame_list) x++;
12325                if (!x)
12326                {
12327                   memset(f->data.ptr,0,f->datalen);
12328                }
12329                else
12330                {
12331                   ast_frfree(f);
12332                   f = AST_LIST_REMOVE_HEAD(&myrpt->txq,
12333                      frame_list);
12334                }
12335             }
12336             else
12337             {
12338                while((vframe = AST_LIST_REMOVE_HEAD(&myrpt->txq,
12339                   frame_list))) ast_frfree(vframe);
12340             }
12341             ast_write(myrpt->txchannel,f);
12342          }
12343          if (f->frametype == AST_FRAME_CONTROL)
12344          {
12345             if (f->subclass == AST_CONTROL_HANGUP)
12346             {
12347                if (debug) printf("@@@@ rpt:Hung Up\n");
12348                ast_frfree(f);
12349                break;
12350             }
12351          }
12352          ast_frfree(f);
12353          continue;
12354       }
12355       toexit = 0;
12356       rpt_mutex_lock(&myrpt->lock);
12357       l = myrpt->links.next;
12358       while(l != &myrpt->links)
12359       {
12360          int remnomute;
12361          struct timeval now;
12362 
12363          if (l->disctime)
12364          {
12365             l = l->next;
12366             continue;
12367          }
12368 
12369          remrx = 0;
12370          /* see if any other links are receiving */
12371          m = myrpt->links.next;
12372          while(m != &myrpt->links)
12373          {
12374             /* if not us, count it */
12375             if ((m != l) && (m->lastrx)) remrx = 1;
12376             m = m->next;
12377          }
12378          rpt_mutex_unlock(&myrpt->lock);
12379          now = ast_tvnow();
12380          if ((who == l->chan) || (!l->lastlinktv.tv_sec) ||
12381             (ast_tvdiff_ms(now,l->lastlinktv) >= 19))
12382          {
12383             l->lastlinktv = now;
12384             remnomute = myrpt->localtx && 
12385                 (!(myrpt->cmdnode[0] || 
12386                (myrpt->dtmfidx > -1)));
12387             totx = (((l->isremote) ? (remnomute) : 
12388                myrpt->exttx) || remrx) && l->mode;
12389             if (l->phonemode == 0 && l->chan && (l->lasttx != totx))
12390             {
12391                if (totx)
12392                {
12393                   ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
12394                }
12395                else
12396                {
12397                   ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
12398                }
12399                if (myrpt->p.archivedir)
12400                {
12401                   char str[100];
12402 
12403                   if (totx)
12404                      sprintf(str,"TXKEY,%s",l->name);
12405                   else
12406                      sprintf(str,"TXUNKEY,%s",l->name);
12407                   donodelog(myrpt,str);
12408                }
12409             }
12410             l->lasttx = totx;
12411          }
12412          rpt_mutex_lock(&myrpt->lock);
12413          if (who == l->chan) /* if it was a read from rx */
12414          {
12415             rpt_mutex_unlock(&myrpt->lock);
12416             f = ast_read(l->chan);
12417             if (!f)
12418             {
12419                rpt_mutex_lock(&myrpt->lock);
12420                __kickshort(myrpt);
12421                rpt_mutex_unlock(&myrpt->lock);
12422                if ((!l->disced) && (!l->outbound))
12423                {
12424                   if ((l->name[0] == '0') || l->isremote)
12425                      l->disctime = 1;
12426                   else
12427                      l->disctime = DISC_TIME;
12428                   rpt_mutex_lock(&myrpt->lock);
12429                   ast_hangup(l->chan);
12430                   l->chan = 0;
12431                   break;
12432                }
12433 
12434                if (l->retrytimer) 
12435                {
12436                   ast_hangup(l->chan);
12437                   l->chan = 0;
12438                   rpt_mutex_lock(&myrpt->lock);
12439                   break; 
12440                }
12441                if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
12442                {
12443                   rpt_mutex_lock(&myrpt->lock);
12444                   if (l->chan) ast_hangup(l->chan);
12445                   l->chan = 0;
12446                   l->hasconnected = 1;
12447                   l->retrytimer = RETRY_TIMER_MS;
12448                   l->elaptime = 0;
12449                   l->connecttime = 0;
12450                   l->thisconnected = 0;
12451                   break;
12452                }
12453                rpt_mutex_lock(&myrpt->lock);
12454                /* remove from queue */
12455                remque((struct qelem *) l);
12456                if (!strcmp(myrpt->cmdnode,l->name))
12457                   myrpt->cmdnode[0] = 0;
12458                __kickshort(myrpt);
12459                rpt_mutex_unlock(&myrpt->lock);
12460                if (!l->hasconnected)
12461                   rpt_telemetry(myrpt,CONNFAIL,l);
12462                else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
12463                if (myrpt->p.archivedir)
12464                {
12465                   char str[100];
12466 
12467                   if (!l->hasconnected)
12468                      sprintf(str,"LINKFAIL,%s",l->name);
12469                   else
12470                      sprintf(str,"LINKDISC,%s",l->name);
12471                   donodelog(myrpt,str);
12472                }
12473                if (l->lastf1) ast_frfree(l->lastf1);
12474                l->lastf1 = NULL;
12475                if (l->lastf2) ast_frfree(l->lastf2);
12476                l->lastf2 = NULL;
12477                /* hang-up on call to device */
12478                ast_hangup(l->chan);
12479                ast_hangup(l->pchan);
12480                ast_free(l);
12481                rpt_mutex_lock(&myrpt->lock);
12482                break;
12483             }
12484             if (f->frametype == AST_FRAME_VOICE)
12485             {
12486                int ismuted,n1;
12487 
12488                if ((l->phonemode) && (l->phonevox))
12489                {
12490                   n1 = dovox(&l->vox,
12491                      f->data.ptr,f->datalen / 2);
12492                   if (n1 != l->wasvox)
12493                   {
12494                      if (debug)ast_log(LOG_DEBUG,"Link Node %s, vox %d\n",l->name,n1);
12495                      l->wasvox = n1;
12496                      l->voxtostate = 0;
12497                      if (n1) l->voxtotimer = myrpt->p.voxtimeout_ms;
12498                      else l->voxtotimer = 0;
12499                   }
12500                   if (l->lastrealrx || n1)
12501                   {
12502                      if (!myfirst)
12503                      {
12504                          x = 0;
12505                          AST_LIST_TRAVERSE(&l->rxq, f1,
12506                         frame_list) x++;
12507                          for(;x < myrpt->p.simplexphonedelay; x++)
12508                         {
12509                            f1 = ast_frdup(f);
12510                            memset(f1->data.ptr,0,f1->datalen);
12511                            AST_LIST_INSERT_TAIL(&l->rxq,
12512                               f1,frame_list);
12513                          }
12514                          myfirst = 1;
12515                      }
12516                      f1 = ast_frdup(f);
12517                      AST_LIST_INSERT_TAIL(&l->rxq,f1,frame_list);
12518                   } else myfirst = 0; 
12519                   x = 0;
12520                   AST_LIST_TRAVERSE(&l->rxq, f1,frame_list) x++;
12521                   if (!x)
12522                   {
12523                      memset(f->data.ptr,0,f->datalen);
12524                   }
12525                   else
12526                   {
12527                      ast_frfree(f);
12528                      f = AST_LIST_REMOVE_HEAD(&l->rxq,frame_list);
12529                   }
12530                   if (ioctl(l->chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
12531                   {
12532                      ismuted = 0;
12533                   }
12534                   /* if not receiving, zero-out audio */
12535                   ismuted |= (!l->lastrx);
12536                   if (l->dtmfed && l->phonemode) ismuted = 1;
12537                   l->dtmfed = 0;
12538                   if (ismuted)
12539                   {
12540                      memset(f->data.ptr,0,f->datalen);
12541                      if (l->lastf1)
12542                         memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12543                      if (l->lastf2)
12544                         memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12545                   } 
12546                   if (f) f2 = ast_frdup(f);
12547                   else f2 = NULL;
12548                   f1 = l->lastf2;
12549                   l->lastf2 = l->lastf1;
12550                   l->lastf1 = f2;
12551                   if (ismuted)
12552                   {
12553                      if (l->lastf1)
12554                         memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12555                      if (l->lastf2)
12556                         memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12557                   }
12558                   if (f1)
12559                   {
12560                      ast_write(l->pchan,f1);
12561                      ast_frfree(f1);
12562                   }
12563                }
12564                else
12565                {
12566                   if (!l->lastrx)
12567                      memset(f->data.ptr,0,f->datalen);
12568                   ast_write(l->pchan,f);
12569                }
12570             }
12571 #ifndef  OLD_ASTERISK
12572             else if (f->frametype == AST_FRAME_DTMF_BEGIN)
12573             {
12574                if (l->lastf1)
12575                   memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12576                if (l->lastf2)
12577                   memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12578                l->dtmfed = 1;
12579             }
12580 #endif
12581             if (f->frametype == AST_FRAME_TEXT)
12582             {
12583                handle_link_data(myrpt,l,f->data.ptr);
12584             }
12585             if (f->frametype == AST_FRAME_DTMF)
12586             {
12587                if (l->lastf1)
12588                   memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12589                if (l->lastf2)
12590                   memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12591                l->dtmfed = 1;
12592                handle_link_phone_dtmf(myrpt,l,f->subclass);
12593             }
12594             if (f->frametype == AST_FRAME_CONTROL)
12595             {
12596                if (f->subclass == AST_CONTROL_ANSWER)
12597                {
12598                   char lconnected = l->connected;
12599 
12600                   __kickshort(myrpt);
12601                   l->connected = 1;
12602                   l->hasconnected = 1;
12603                   l->thisconnected = 1;
12604                   l->elaptime = -1;
12605                   if (!l->phonemode) send_newkey(l->chan);
12606                   if (!l->isremote) l->retries = 0;
12607                   if (!lconnected) 
12608                   {
12609                      rpt_telemetry(myrpt,CONNECTED,l);
12610                      if (myrpt->p.archivedir)
12611                      {
12612                         char str[100];
12613 
12614                         if (l->mode)
12615                            sprintf(str,"LINKTRX,%s",l->name);
12616                         else
12617                            sprintf(str,"LINKMONITOR,%s",l->name);
12618                         donodelog(myrpt,str);
12619                      }
12620                   }     
12621                   else
12622                      l->reconnects++;
12623                }
12624                /* if RX key */
12625                if (f->subclass == AST_CONTROL_RADIO_KEY)
12626                {
12627                   if (debug == 7 ) printf("@@@@ rx key\n");
12628                   l->lastrealrx = 1;
12629                   l->rerxtimer = 0;
12630                   if (!l->lastrx1)
12631                   {
12632                      if (myrpt->p.archivedir)
12633                      {
12634                         char str[100];
12635 
12636                         sprintf(str,"RXKEY,%s",l->name);
12637                         donodelog(myrpt,str);
12638                      }
12639                      l->lastrx1 = 1;
12640                   }
12641                }
12642                /* if RX un-key */
12643                if (f->subclass == AST_CONTROL_RADIO_UNKEY)
12644                {
12645                   if (debug == 7) printf("@@@@ rx un-key\n");
12646                   l->lastrealrx = 0;
12647                   l->rerxtimer = 0;
12648                   if (l->lastrx1)
12649                   {
12650                      if (myrpt->p.archivedir)
12651                      {
12652                         char str[100];
12653 
12654                         sprintf(str,"RXUNKEY,%s",l->name);
12655                         donodelog(myrpt,str);
12656                      }
12657                      l->lastrx1 = 0;
12658                      if(myrpt->p.duplex) 
12659                         rpt_telemetry(myrpt,LINKUNKEY,l);
12660                   }
12661                }
12662                if (f->subclass == AST_CONTROL_HANGUP)
12663                {
12664                   ast_frfree(f);
12665                   rpt_mutex_lock(&myrpt->lock);
12666                   __kickshort(myrpt);
12667                   rpt_mutex_unlock(&myrpt->lock);
12668                   if ((!l->outbound) && (!l->disced))
12669                   {
12670                      if ((l->name[0] == '0') || l->isremote)
12671                         l->disctime = 1;
12672                      else
12673                         l->disctime = DISC_TIME;
12674                      rpt_mutex_lock(&myrpt->lock);
12675                      ast_hangup(l->chan);
12676                      l->chan = 0;
12677                      break;
12678                   }
12679                   if (l->retrytimer) 
12680                   {
12681                      if (l->chan) ast_hangup(l->chan);
12682                      l->chan = 0;
12683                      rpt_mutex_lock(&myrpt->lock);
12684                      break;
12685                   }
12686                   if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
12687                   {
12688                      rpt_mutex_lock(&myrpt->lock);
12689                      if (l->chan) ast_hangup(l->chan);
12690                      l->chan = 0;
12691                      l->hasconnected = 1;
12692                      l->elaptime = 0;
12693                      l->retrytimer = RETRY_TIMER_MS;
12694                      l->connecttime = 0;
12695                      l->thisconnected = 0;
12696                      break;
12697                   }
12698                   rpt_mutex_lock(&myrpt->lock);
12699                   /* remove from queue */
12700                   remque((struct qelem *) l);
12701                   if (!strcmp(myrpt->cmdnode,l->name))
12702                      myrpt->cmdnode[0] = 0;
12703                   __kickshort(myrpt);
12704                   rpt_mutex_unlock(&myrpt->lock);
12705                   if (!l->hasconnected)
12706                      rpt_telemetry(myrpt,CONNFAIL,l);
12707                   else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
12708                   if (myrpt->p.archivedir)
12709                   {
12710                      char str[100];
12711 
12712                      if (!l->hasconnected)
12713                         sprintf(str,"LINKFAIL,%s",l->name);
12714                      else
12715                         sprintf(str,"LINKDISC,%s",l->name);
12716                      donodelog(myrpt,str);
12717                   }
12718                   if (l->lastf1) ast_frfree(l->lastf1);
12719                   l->lastf1 = NULL;
12720                   if (l->lastf2) ast_frfree(l->lastf2);
12721                   l->lastf2 = NULL;
12722                   /* hang-up on call to device */
12723                   ast_hangup(l->chan);
12724                   ast_hangup(l->pchan);
12725                   ast_free(l);
12726                   rpt_mutex_lock(&myrpt->lock);
12727                   break;
12728                }
12729             }
12730             ast_frfree(f);
12731             rpt_mutex_lock(&myrpt->lock);
12732             break;
12733          }
12734          if (who == l->pchan) 
12735          {
12736             rpt_mutex_unlock(&myrpt->lock);
12737             f = ast_read(l->pchan);
12738             if (!f)
12739             {
12740                if (debug) printf("@@@@ rpt:Hung Up\n");
12741                toexit = 1;
12742                rpt_mutex_lock(&myrpt->lock);
12743                break;
12744             }
12745             if (f->frametype == AST_FRAME_VOICE)
12746             {
12747                if (l->chan) ast_write(l->chan,f);
12748             }
12749             if (f->frametype == AST_FRAME_CONTROL)
12750             {
12751                if (f->subclass == AST_CONTROL_HANGUP)
12752                {
12753                   if (debug) printf("@@@@ rpt:Hung Up\n");
12754                   ast_frfree(f);
12755                   toexit = 1;
12756                   rpt_mutex_lock(&myrpt->lock);
12757                   break;
12758                }
12759             }
12760             ast_frfree(f);
12761             rpt_mutex_lock(&myrpt->lock);
12762             break;
12763          }
12764          l = l->next;
12765       }
12766       rpt_mutex_unlock(&myrpt->lock);
12767       if (toexit) break;
12768       if (who == myrpt->monchannel) 
12769       {
12770          f = ast_read(myrpt->monchannel);
12771          if (!f)
12772          {
12773             if (debug) printf("@@@@ rpt:Hung Up\n");
12774             break;
12775          }
12776          if (f->frametype == AST_FRAME_VOICE)
12777          {
12778             if (myrpt->monstream) 
12779                ast_writestream(myrpt->monstream,f);
12780          }
12781          if (f->frametype == AST_FRAME_CONTROL)
12782          {
12783             if (f->subclass == AST_CONTROL_HANGUP)
12784             {
12785                if (debug) printf("@@@@ rpt:Hung Up\n");
12786                ast_frfree(f);
12787                break;
12788             }
12789          }
12790          ast_frfree(f);
12791          continue;
12792       }
12793       if (myrpt->parrotchannel && (who == myrpt->parrotchannel))
12794       {
12795          f = ast_read(myrpt->parrotchannel);
12796          if (!f)
12797          {
12798             if (debug) printf("@@@@ rpt:Hung Up\n");
12799             break;
12800          }
12801          if (!myrpt->p.parrotmode)
12802          {
12803             char myfname[300];
12804 
12805             if (myrpt->parrotstream)
12806             {
12807                ast_closestream(myrpt->parrotstream);
12808                myrpt->parrotstream = 0;
12809             }
12810             sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
12811             strcat(myfname,".wav");
12812             unlink(myfname);        
12813          } else if (f->frametype == AST_FRAME_VOICE)
12814          {
12815             if (myrpt->parrotstream) 
12816                ast_writestream(myrpt->parrotstream,f);
12817          }
12818          if (f->frametype == AST_FRAME_CONTROL)
12819          {
12820             if (f->subclass == AST_CONTROL_HANGUP)
12821             {
12822                if (debug) printf("@@@@ rpt:Hung Up\n");
12823                ast_frfree(f);
12824                break;
12825             }
12826          }
12827          ast_frfree(f);
12828          continue;
12829       }
12830       if (myrpt->voxchannel && (who == myrpt->voxchannel))
12831       {
12832          f = ast_read(myrpt->voxchannel);
12833          if (!f)
12834          {
12835             if (debug) printf("@@@@ rpt:Hung Up\n");
12836             break;
12837          }
12838          if (f->frametype == AST_FRAME_VOICE)
12839          {
12840             n = dovox(&myrpt->vox,f->data.ptr,f->datalen / 2);
12841             if (n != myrpt->wasvox)
12842             {
12843                if (debug) ast_log(LOG_DEBUG,"Node %s, vox %d\n",myrpt->name,n);
12844                myrpt->wasvox = n;
12845                myrpt->voxtostate = 0;
12846                if (n) myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
12847                else myrpt->voxtotimer = 0;
12848             }
12849          }
12850          if (f->frametype == AST_FRAME_CONTROL)
12851          {
12852             if (f->subclass == AST_CONTROL_HANGUP)
12853             {
12854                if (debug) printf("@@@@ rpt:Hung Up\n");
12855                ast_frfree(f);
12856                break;
12857             }
12858          }
12859          ast_frfree(f);
12860          continue;
12861       }
12862       if (who == myrpt->txpchannel) /* if it was a read from remote tx */
12863       {
12864          f = ast_read(myrpt->txpchannel);
12865          if (!f)
12866          {
12867             if (debug) printf("@@@@ rpt:Hung Up\n");
12868             break;
12869          }
12870          if (f->frametype == AST_FRAME_CONTROL)
12871          {
12872             if (f->subclass == AST_CONTROL_HANGUP)
12873             {
12874                if (debug) printf("@@@@ rpt:Hung Up\n");
12875                ast_frfree(f);
12876                break;
12877             }
12878          }
12879          ast_frfree(f);
12880          continue;
12881       }
12882    }
12883    usleep(100000);
12884    ast_hangup(myrpt->pchannel);
12885    ast_hangup(myrpt->monchannel);
12886    if (myrpt->parrotchannel) ast_hangup(myrpt->parrotchannel);
12887    myrpt->parrotstate = 0;
12888    if (myrpt->voxchannel) ast_hangup(myrpt->voxchannel);
12889    ast_hangup(myrpt->txpchannel);
12890    if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
12891    if (myrpt->dahditxchannel != myrpt->txchannel) ast_hangup(myrpt->dahditxchannel);
12892    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
12893    myrpt->lastf1 = NULL;
12894    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
12895    myrpt->lastf2 = NULL;
12896    ast_hangup(myrpt->rxchannel);
12897    rpt_mutex_lock(&myrpt->lock);
12898    l = myrpt->links.next;
12899    while(l != &myrpt->links)
12900    {
12901       struct rpt_link *ll = l;
12902       /* remove from queue */
12903       remque((struct qelem *) l);
12904       /* hang-up on call to device */
12905       if (l->chan) ast_hangup(l->chan);
12906       ast_hangup(l->pchan);
12907       l = l->next;
12908       ast_free(ll);
12909    }
12910    if (myrpt->xlink  == 1) myrpt->xlink = 2;
12911    rpt_mutex_unlock(&myrpt->lock);
12912    if (debug) printf("@@@@ rpt:Hung up channel\n");
12913    myrpt->rpt_thread = AST_PTHREADT_STOP;
12914    pthread_exit(NULL); 
12915    return NULL;
12916 }
12917 
12918    
12919 static void *rpt_master(void *ignore)
12920 {
12921 int   i,n;
12922 pthread_attr_t attr;
12923 struct ast_config *cfg;
12924 char *this,*val;
12925 
12926    /* init nodelog queue */
12927    nodelog.next = nodelog.prev = &nodelog;
12928    /* go thru all the specified repeaters */
12929    this = NULL;
12930    n = 0;
12931 #ifndef OLD_ASTERISK
12932    /* wait until asterisk starts */
12933         while(!ast_test_flag(&ast_options,AST_OPT_FLAG_FULLY_BOOTED))
12934                 usleep(250000);
12935 #endif
12936 #ifdef   NEW_ASTERISK
12937    rpt_vars[n].cfg = ast_config_load("rpt.conf",config_flags);
12938 #else
12939    rpt_vars[n].cfg = ast_config_load("rpt.conf");
12940 #endif
12941    cfg = rpt_vars[n].cfg;
12942    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
12943       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
12944       pthread_exit(NULL);
12945    }
12946    while((this = ast_category_browse(cfg,this)) != NULL)
12947    {
12948       for(i = 0 ; i < strlen(this) ; i++){
12949          if((this[i] < '0') || (this[i] > '9'))
12950             break;
12951       }
12952       if(i != strlen(this)) continue; /* Not a node defn */
12953       memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
12954       rpt_vars[n].name = ast_strdup(this);
12955       val = (char *) ast_variable_retrieve(cfg,this,"rxchannel");
12956       if (val) rpt_vars[n].rxchanname = ast_strdup(val);
12957       val = (char *) ast_variable_retrieve(cfg,this,"txchannel");
12958       if (val) rpt_vars[n].txchanname = ast_strdup(val);
12959       rpt_vars[n].remote = 0;
12960       rpt_vars[n].remoterig = "";
12961       val = (char *) ast_variable_retrieve(cfg,this,"remote");
12962       if (val) 
12963       {
12964          rpt_vars[n].remoterig = ast_strdup(val);
12965          rpt_vars[n].remote = 1;
12966       }
12967       val = (char *) ast_variable_retrieve(cfg,this,"radiotype");
12968       if (val) rpt_vars[n].remoterig = ast_strdup(val);
12969       ast_mutex_init(&rpt_vars[n].lock);
12970       ast_mutex_init(&rpt_vars[n].remlock);
12971       ast_mutex_init(&rpt_vars[n].statpost_lock);
12972       rpt_vars[n].tele.next = &rpt_vars[n].tele;
12973       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
12974       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
12975       rpt_vars[n].tailmessagen = 0;
12976 #ifdef   _MDC_DECODE_H_
12977       rpt_vars[n].mdc = mdc_decoder_new(8000);
12978 #endif
12979       n++;
12980    }
12981    nrpts = n;
12982    ast_config_destroy(cfg);
12983 
12984    /* start em all */
12985    for(i = 0; i < n; i++)
12986    {
12987       load_rpt_vars(i,1);
12988 
12989       /* if is a remote, dont start one for it */
12990       if (rpt_vars[i].remote)
12991       {
12992          if(retreive_memory(&rpt_vars[i],"init")){ /* Try to retreive initial memory channel */
12993             if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx450))
12994                strncpy(rpt_vars[i].freq, "446.500", sizeof(rpt_vars[i].freq) - 1);
12995             else
12996                strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
12997             strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
12998 
12999             strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
13000             rpt_vars[i].remmode = REM_MODE_FM;
13001             rpt_vars[i].offset = REM_SIMPLEX;
13002             rpt_vars[i].powerlevel = REM_LOWPWR;
13003          }
13004          continue;
13005       }
13006       else /* is a normal repeater */
13007       {
13008           rpt_vars[i].p.memory = rpt_vars[i].name;
13009          if(retreive_memory(&rpt_vars[i],"radiofreq")){ /* Try to retreive initial memory channel */
13010             if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx450))
13011                strncpy(rpt_vars[i].freq, "446.500", sizeof(rpt_vars[i].freq) - 1);
13012             else if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx150))
13013                strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
13014             strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
13015 
13016             strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
13017             rpt_vars[i].remmode = REM_MODE_FM;
13018             rpt_vars[i].offset = REM_SIMPLEX;
13019             rpt_vars[i].powerlevel = REM_LOWPWR;
13020          }
13021          ast_log(LOG_NOTICE,"Normal Repeater Init  %s  %s  %s\n",rpt_vars[i].name, rpt_vars[i].remoterig, rpt_vars[i].freq);
13022       }
13023       if (!rpt_vars[i].p.ident)
13024       {
13025          ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
13026          ast_config_destroy(cfg);
13027          pthread_exit(NULL);
13028       }
13029            pthread_attr_init(&attr);
13030            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13031       ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
13032    }
13033    usleep(500000);
13034    time(&starttime);
13035    for(;;)
13036    {
13037       /* Now monitor each thread, and restart it if necessary */
13038       for(i = 0; i < n; i++)
13039       { 
13040          int rv;
13041          if (rpt_vars[i].remote) continue;
13042          if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP) 
13043             rv = -1;
13044          else
13045             rv = pthread_kill(rpt_vars[i].rpt_thread,0);
13046          if (rv)
13047          {
13048             if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15)
13049             {
13050                if(rpt_vars[i].threadrestarts >= 5)
13051                {
13052                   ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n");
13053                   exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
13054                }
13055                else
13056                {
13057                   ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name);
13058                   rpt_vars[i].threadrestarts++;
13059                }
13060             }
13061             else
13062                rpt_vars[i].threadrestarts = 0;
13063 
13064             rpt_vars[i].lastthreadrestarttime = time(NULL);
13065                  pthread_attr_init(&attr);
13066                  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13067             ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
13068             /* if (!rpt_vars[i].xlink) */
13069                ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
13070          }
13071 
13072       }
13073       for(;;)
13074       {
13075          struct nodelog *nodep;
13076          char *space,datestr[100],fname[300];
13077          int fd;
13078 
13079          ast_mutex_lock(&nodeloglock);
13080          nodep = nodelog.next;
13081          if(nodep == &nodelog) /* if nothing in queue */
13082          {
13083             ast_mutex_unlock(&nodeloglock);
13084             break;
13085          }
13086          remque((struct qelem *)nodep);
13087          ast_mutex_unlock(&nodeloglock);
13088          space = strchr(nodep->str,' ');
13089          if (!space) 
13090          {
13091             ast_free(nodep);
13092             continue;
13093          }
13094          *space = 0;
13095          strftime(datestr,sizeof(datestr) - 1,"%Y%m%d",
13096             localtime(&nodep->timestamp));
13097          sprintf(fname,"%s/%s/%s.txt",nodep->archivedir,
13098             nodep->str,datestr);
13099          fd = open(fname,O_WRONLY | O_CREAT | O_APPEND,0600);
13100          if (fd == -1)
13101          {
13102             ast_log(LOG_ERROR,"Cannot open node log file %s for write",space + 1);
13103             ast_free(nodep);
13104             continue;
13105          }
13106          if (write(fd,space + 1,strlen(space + 1)) !=
13107             strlen(space + 1))
13108          {
13109             ast_log(LOG_ERROR,"Cannot write node log file %s for write",space + 1);
13110             ast_free(nodep);
13111             continue;
13112          }
13113          close(fd);
13114          ast_free(nodep);
13115       }
13116       sleep(2);
13117    }
13118    ast_config_destroy(cfg);
13119    pthread_exit(NULL);
13120 }
13121 
13122 static int rpt_exec(struct ast_channel *chan, void *data)
13123 {
13124    int res=-1,i,rem_totx,rem_rx,remkeyed,n,phone_mode = 0;
13125    int iskenwood_pci4,authtold,authreq,setting,notremming,reming;
13126    int ismuted,dtmfed,phone_vox = 0;
13127 #ifdef   OLD_ASTERISK
13128    struct localuser *u;
13129 #endif
13130    char tmp[256], keyed = 0,keyed1 = 0;
13131    char *options,*stringp,*tele,c,*altp,*memp;
13132    char sx[320],*sy;
13133    struct   rpt *myrpt;
13134    struct ast_frame *f,*f1,*f2;
13135    struct ast_channel *who;
13136    struct ast_channel *cs[20];
13137    struct   rpt_link *l;
13138    struct dahdi_confinfo ci;  /* conference info */
13139    struct dahdi_params par;
13140    int ms,elap,nullfd;
13141    time_t t,last_timeout_warning;
13142    struct   dahdi_radio_param z;
13143    struct rpt_tele *telem;
13144    int   numlinks;
13145 
13146    nullfd = open("/dev/null",O_RDWR);
13147    if (ast_strlen_zero(data)) {
13148       ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
13149       return -1;
13150    }
13151 
13152    strncpy(tmp, (char *)data, sizeof(tmp)-1);
13153    time(&t);
13154    /* if time has externally shifted negative, screw it */
13155    if (t < starttime) t = starttime + START_DELAY;
13156    if ((!starttime) || (t < (starttime + START_DELAY)))
13157    {
13158       ast_log(LOG_NOTICE,"Node %s rejecting call: too soon!\n",tmp);
13159       ast_safe_sleep(chan,3000);
13160       return -1;
13161    }
13162 
13163    ast_log(LOG_NOTICE,"parsing argument=%s \n",tmp);
13164 
13165    altp=strstr(tmp, "|*");
13166    if(altp){
13167       altp[0]=0;
13168       altp++;
13169     }
13170 
13171    memp=strstr(tmp, "|M");
13172    if(memp){
13173       memp[0]=0;
13174       memp+=2;
13175     }
13176 
13177    stringp=tmp;
13178    strsep(&stringp, "|");
13179    options = stringp;
13180 
13181    ast_log(LOG_NOTICE,"options=%s \n",options);
13182    if(memp>0)ast_log(LOG_NOTICE,"memp=%s \n",memp);
13183    if(altp>0)ast_log(LOG_NOTICE,"altp=%s \n",altp);
13184 
13185    myrpt = NULL;
13186    /* see if we can find our specified one */
13187    for(i = 0; i < nrpts; i++)
13188    {
13189       /* if name matches, assign it and exit loop */
13190       if (!strcmp(tmp,rpt_vars[i].name))
13191       {
13192          myrpt = &rpt_vars[i];
13193          break;
13194       }
13195    }
13196 
13197    pbx_builtin_setvar_helper(chan, "RPT_STAT_ERR", "");
13198 
13199    if (myrpt == NULL)
13200    {
13201       pbx_builtin_setvar_helper(chan, "RPT_STAT_ERR", "NODE_NOT_FOUND");
13202       ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
13203       return (priority_jump(NULL,chan));
13204    }
13205 
13206    numlinks=linkcount(myrpt);
13207 
13208    if(options && *options == 'q')
13209    {
13210       char buf2[128];
13211 
13212       if(myrpt->keyed)
13213          pbx_builtin_setvar_helper(chan, "RPT_STAT_RXKEYED", "1");
13214       else
13215          pbx_builtin_setvar_helper(chan, "RPT_STAT_RXKEYED", "0");   
13216 
13217       if(myrpt->txkeyed)
13218          pbx_builtin_setvar_helper(chan, "RPT_STAT_TXKEYED", "1");
13219       else
13220          pbx_builtin_setvar_helper(chan, "RPT_STAT_TXKEYED", "0");   
13221 
13222       snprintf(buf2,sizeof(buf2),"%s=%i", "RPT_STAT_XLINK", myrpt->xlink);
13223       pbx_builtin_setvar(chan, buf2);
13224       snprintf(buf2,sizeof(buf2),"%s=%i", "RPT_STAT_LINKS", numlinks);
13225       pbx_builtin_setvar(chan, buf2);
13226       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_WASCHAN", myrpt->waschan);
13227       pbx_builtin_setvar(chan, buf2);
13228       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_NOWCHAN", myrpt->nowchan);
13229       pbx_builtin_setvar(chan, buf2);
13230       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_DUPLEX", myrpt->p.duplex);
13231       pbx_builtin_setvar(chan, buf2);
13232       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_PARROT", myrpt->p.parrotmode);
13233       pbx_builtin_setvar(chan, buf2);
13234       //snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_PHONEVOX", myrpt->phonevox);
13235       //pbx_builtin_setvar(chan, buf2);
13236       //snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_CONNECTED", myrpt->connected);
13237       //pbx_builtin_setvar(chan, buf2);
13238       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_CALLMODE", myrpt->callmode);
13239       pbx_builtin_setvar(chan, buf2);
13240       snprintf(buf2,sizeof(buf2),"%s=%s", "RPT_STAT_LASTTONE", myrpt->lasttone);
13241       pbx_builtin_setvar(chan, buf2);
13242 
13243       return priority_jump(myrpt,chan);
13244    }
13245 
13246    if(options && *options == 'o')
13247    {
13248       return(channel_revert(myrpt));
13249    }
13250 
13251    #if 0
13252    if((altp)&&(*options == 'Z'))
13253    {
13254       rpt_push_alt_macro(myrpt,altp);
13255       return 0;
13256    }
13257    #endif
13258 
13259 
13260    /* if not phone access, must be an IAX connection */
13261    if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R') || (*options == 'S')))
13262    {
13263       int val;
13264 
13265       pbx_builtin_setvar_helper(chan, "RPT_STAT_BUSY", "0");
13266        
13267       myrpt->bargechan=0;
13268       if(options && strstr(options, "f")>0)
13269       {
13270          myrpt->bargechan=1;     
13271       }
13272 
13273       if(memp>0)
13274       {
13275          char radiochan;
13276          radiochan=strtod(data,NULL);
13277          // if(myrpt->nowchan!=0 && radiochan!=myrpt->nowchan && !myrpt->bargechan)
13278 
13279          if(numlinks>0 && radiochan!=myrpt->nowchan && !myrpt->bargechan)
13280          {
13281             pbx_builtin_setvar_helper(chan, "RPT_STAT_BUSY", "1");
13282             ast_log(LOG_NOTICE, "Radio Channel Busy.\n");
13283             return (priority_jump(myrpt,chan));
13284          }
13285          else if(radiochan!=myrpt->nowchan || myrpt->bargechan)
13286          {
13287             channel_steer(myrpt,memp); 
13288          }
13289       }
13290       if(altp)rpt_push_alt_macro(myrpt,altp);
13291       phone_mode = 1;
13292       if (*options == 'D') phone_mode = 2;
13293       if (*options == 'S') phone_mode = 3;
13294       ast_set_callerid(chan,"0","app_rpt user","0");
13295       val = 1;
13296       ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
13297       if ((*(options + 1) == 'V') || (*(options + 1) == 'v')) phone_vox = 1;
13298    }
13299    else
13300    {
13301 #ifdef ALLOW_LOCAL_CHANNELS
13302            /* Check to insure the connection is IAX2 or Local*/
13303            if ( (strncmp(chan->name,"IAX2",4)) && (strncmp(chan->name,"Local",5)) ) {
13304                ast_log(LOG_WARNING, "We only accept links via IAX2 or Local!!\n");
13305                return -1;
13306            }
13307 #else
13308       if (strncmp(chan->name,"IAX2",4))
13309       {
13310          ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
13311          return -1;
13312       }
13313 #endif
13314            if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable){ /* Do not allow incoming radio connections if disabled */
13315                  ast_log(LOG_NOTICE, "Connect attempt to node %s  with tx disabled", myrpt->name);
13316                   return -1;
13317          }  
13318    }
13319    if (options && (*options == 'R'))
13320    {
13321       /* Parts of this section taken from app_parkandannounce */
13322       char *return_context;
13323       int length, m, lot, timeout = 0;
13324       char buffer[256],*template;
13325       char *working, *context, *exten, *priority;
13326       char *s,*orig_s;
13327 
13328       rpt_mutex_lock(&myrpt->lock);
13329       m = myrpt->callmode;
13330       rpt_mutex_unlock(&myrpt->lock);
13331 
13332       if ((!myrpt->p.nobusyout) && m)
13333       {
13334          if (chan->_state != AST_STATE_UP)
13335          {
13336             ast_indicate(chan,AST_CONTROL_BUSY);
13337          }
13338          while(ast_safe_sleep(chan,10000) != -1);
13339          return -1;
13340       }
13341 
13342       if (chan->_state != AST_STATE_UP)
13343       {
13344          ast_answer(chan);
13345          if (!phone_mode) send_newkey(chan);
13346       }
13347 
13348       length=strlen(options)+2;
13349       orig_s=ast_malloc(length);
13350       if(!orig_s) {
13351          ast_log(LOG_WARNING, "Out of memory\n");
13352          return -1;
13353       }
13354       s=orig_s;
13355       strncpy(s,options,length);
13356 
13357       template=strsep(&s,"|");
13358       if(!template) {
13359          ast_log(LOG_WARNING, "An announce template must be defined\n");
13360          ast_free(orig_s);
13361          return -1;
13362       } 
13363   
13364       if(s) {
13365          timeout = atoi(strsep(&s, "|"));
13366          timeout *= 1000;
13367       }
13368    
13369       return_context = s;
13370   
13371       if(return_context != NULL) {
13372          /* set the return context. Code borrowed from the Goto builtin */
13373     
13374          working = return_context;
13375          context = strsep(&working, "|");
13376          exten = strsep(&working, "|");
13377          if(!exten) {
13378             /* Only a priority in this one */
13379             priority = context;
13380             exten = NULL;
13381             context = NULL;
13382          } else {
13383             priority = strsep(&working, "|");
13384             if(!priority) {
13385                /* Only an extension and priority in this one */
13386                priority = exten;
13387                exten = context;
13388                context = NULL;
13389          }
13390       }
13391       if(atoi(priority) < 0) {
13392          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
13393          ast_free(orig_s);
13394          return -1;
13395       }
13396       /* At this point we have a priority and maybe an extension and a context */
13397       chan->priority = atoi(priority);
13398 #ifdef OLD_ASTERISK
13399       if(exten && strcasecmp(exten, "BYEXTENSION"))
13400 #else
13401       if(exten)
13402 #endif
13403          strncpy(chan->exten, exten, sizeof(chan->exten)-1);
13404       if(context)
13405          strncpy(chan->context, context, sizeof(chan->context)-1);
13406       } else {  /* increment the priority by default*/
13407          chan->priority++;
13408       }
13409 
13410       if(option_verbose > 2) {
13411          ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
13412          if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
13413             ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
13414          }
13415       }
13416   
13417       /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
13418       before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
13419 
13420       ast_masq_park_call(chan, NULL, timeout, &lot);
13421 
13422       if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
13423 
13424       snprintf(buffer, sizeof(buffer) - 1, "%d,%s", lot, template + 1);
13425 
13426       rpt_telemetry(myrpt,REV_PATCH,buffer);
13427 
13428       ast_free(orig_s);
13429 
13430       return 0;
13431 
13432    }
13433 
13434    if (!options)
13435    {
13436         struct ast_hostent ahp;
13437         struct hostent *hp;
13438         struct in_addr ia;
13439         char hisip[100],nodeip[100],*val, *s, *s1, *s2, *s3, *b,*b1;
13440 
13441       /* look at callerid to see what node this comes from */
13442       if (!chan->cid.cid_num) /* if doesn't have caller id */
13443       {
13444          ast_log(LOG_WARNING, "Does not have callerid on %s\n",tmp);
13445          return -1;
13446       }
13447       /* get his IP from IAX2 module */
13448       memset(hisip,0,sizeof(hisip));
13449 #ifdef ALLOW_LOCAL_CHANNELS
13450         /* set IP address if this is a local connection*/
13451         if (strncmp(chan->name,"Local",5)==0) {
13452             strcpy(hisip,"127.0.0.1");
13453         } else {
13454          pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
13455       }
13456 #else
13457       pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
13458 #endif
13459 
13460       if (!hisip[0])
13461       {
13462          ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
13463          return -1;
13464       }
13465       
13466       ast_callerid_parse(chan->cid.cid_num,&b,&b1);
13467       ast_shrink_phone_number(b1);
13468       if (!strcmp(myrpt->name,b1))
13469       {
13470          ast_log(LOG_WARNING, "Trying to link to self!!\n");
13471          return -1;
13472       }
13473 
13474       if (*b1 < '1')
13475       {
13476          ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n",b1);
13477          return -1;
13478       }
13479 
13480 
13481       /* look for his reported node string */
13482       val = node_lookup(myrpt,b1);
13483       if (!val)
13484       {
13485          ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
13486          return -1;
13487       }
13488       strncpy(tmp,val,sizeof(tmp) - 1);
13489       s = tmp;
13490       s1 = strsep(&s,",");
13491       if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
13492       {
13493          sy = strchr(s1,'/');    
13494          *sy = 0;
13495          sprintf(sx,"%s:4569/%s",s1,sy + 1);
13496          s1 = sx;
13497       }
13498       s2 = strsep(&s,",");
13499       if (!s2)
13500       {
13501          ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n",b1);
13502          return -1;
13503       }
13504                 if (strcmp(s2,"NONE")) {
13505          hp = ast_gethostbyname(s2, &ahp);
13506          if (!hp)
13507          {
13508             ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s2);
13509             return -1;
13510          }
13511          memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
13512 #ifdef   OLD_ASTERISK
13513          ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
13514 #else
13515          strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
13516 #endif
13517          s3 = strchr(hisip,':');
13518          if (s3) *s3 = 0;
13519          if (strcmp(hisip,nodeip))
13520          {
13521             s3 = strchr(s1,'@');
13522             if (s3) s1 = s3 + 1;
13523             s3 = strchr(s1,'/');
13524             if (s3) *s3 = 0;
13525             s3 = strchr(s1,':');
13526             if (s3) *s3 = 0;
13527             hp = ast_gethostbyname(s1, &ahp);
13528             if (!hp)
13529             {
13530                ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s1);
13531                return -1;
13532             }
13533             memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
13534 #ifdef   OLD_ASTERISK
13535             ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
13536 #else
13537             strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
13538 #endif
13539             if (strcmp(hisip,nodeip))
13540             {
13541                ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip);
13542                return -1;
13543             }
13544          }
13545       }
13546    }
13547 
13548    /* if is not a remote */
13549    if (!myrpt->remote)
13550    {
13551       char *b,*b1;
13552       int reconnects = 0;
13553 
13554       rpt_mutex_lock(&myrpt->lock);
13555       i = myrpt->xlink;
13556       rpt_mutex_unlock(&myrpt->lock);
13557       if (i)
13558       {
13559          ast_log(LOG_WARNING, "Cannot connect to node %s, system busy\n",myrpt->name);
13560          return -1;
13561       }
13562       /* look at callerid to see what node this comes from */
13563       if (!chan->cid.cid_num) /* if doesn't have caller id */
13564       {
13565          ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
13566          return -1;
13567       }
13568 
13569       ast_callerid_parse(chan->cid.cid_num,&b,&b1);
13570       ast_shrink_phone_number(b1);
13571       if (!strcmp(myrpt->name,b1))
13572       {
13573          ast_log(LOG_WARNING, "Trying to link to self!!\n");
13574          return -1;
13575       }
13576       rpt_mutex_lock(&myrpt->lock);
13577       l = myrpt->links.next;
13578       /* try to find this one in queue */
13579       while(l != &myrpt->links)
13580       {
13581          if (l->name[0] == '0') 
13582          {
13583             l = l->next;
13584             continue;
13585          }
13586          /* if found matching string */
13587          if (!strcmp(l->name,b1)) break;
13588          l = l->next;
13589       }
13590       /* if found */
13591       if (l != &myrpt->links) 
13592       {
13593          l->killme = 1;
13594          l->retries = l->max_retries + 1;
13595          l->disced = 2;
13596          reconnects = l->reconnects;
13597          reconnects++;
13598                         rpt_mutex_unlock(&myrpt->lock);
13599          usleep(500000);   
13600       } else 
13601          rpt_mutex_unlock(&myrpt->lock);
13602       /* establish call in tranceive mode */
13603       l = ast_malloc(sizeof(struct rpt_link));
13604       if (!l)
13605       {
13606          ast_log(LOG_WARNING, "Unable to malloc\n");
13607          pthread_exit(NULL);
13608       }
13609       /* zero the silly thing */
13610       memset((char *)l,0,sizeof(struct rpt_link));
13611       l->mode = 1;
13612       strncpy(l->name,b1,MAXNODESTR - 1);
13613       l->isremote = 0;
13614       l->chan = chan;
13615       l->connected = 1;
13616       l->thisconnected = 1;
13617       l->hasconnected = 1;
13618       l->reconnects = reconnects;
13619       l->phonemode = phone_mode;
13620       l->phonevox = phone_vox;
13621       l->lastf1 = NULL;
13622       l->lastf2 = NULL;
13623       l->dtmfed = 0;
13624       voxinit_link(l,1);
13625       ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
13626       ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
13627       /* allocate a pseudo-channel thru asterisk */
13628       l->pchan = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
13629       if (!l->pchan)
13630       {
13631          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
13632          pthread_exit(NULL);
13633       }
13634       ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
13635       ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
13636 #ifdef   AST_CDR_FLAG_POST_DISABLED
13637       if (l->pchan->cdr)
13638          ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
13639 #endif
13640       /* make a conference for the tx */
13641       ci.chan = 0;
13642       ci.confno = myrpt->conf;
13643       ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
13644       /* first put the channel on the conference in proper mode */
13645       if (ioctl(l->pchan->fds[0],DAHDI_SETCONF,&ci) == -1)
13646       {
13647          ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
13648          pthread_exit(NULL);
13649       }
13650       rpt_mutex_lock(&myrpt->lock);
13651       if ((phone_mode == 2) && (!phone_vox)) l->lastrealrx = 1;
13652       l->max_retries = MAX_RETRIES;
13653       /* insert at end of queue */
13654       insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
13655       __kickshort(myrpt);
13656       rpt_mutex_unlock(&myrpt->lock);
13657       if (chan->_state != AST_STATE_UP) {
13658          ast_answer(chan);
13659          if (!phone_mode) send_newkey(chan);
13660       }
13661       if (myrpt->p.archivedir)
13662       {
13663          char str[100];
13664 
13665          if (l->phonemode)
13666             sprintf(str,"LINK(P),%s",l->name);
13667          else
13668             sprintf(str,"LINK,%s",l->name);
13669          donodelog(myrpt,str);
13670       }
13671       if (!phone_mode) send_newkey(chan);
13672       return 0;
13673    }
13674    /* well, then it is a remote */
13675    rpt_mutex_lock(&myrpt->lock);
13676    /* if remote, error if anyone else already linked */
13677    if (myrpt->remoteon)
13678    {
13679       rpt_mutex_unlock(&myrpt->lock);
13680       usleep(500000);
13681       if (myrpt->remoteon)
13682       {
13683          ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
13684 #ifdef   AST_CDR_FLAG_POST_DISABLED
13685          if (chan->cdr)
13686             ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13687 #endif
13688          return -1;
13689       }     
13690       rpt_mutex_lock(&myrpt->lock);
13691    }
13692    if (myrpt->p.rptnode)
13693    {
13694       char killedit = 0;
13695       time_t now;
13696 
13697       time(&now);
13698       for(i = 0; i < nrpts; i++)
13699       {
13700          if (!strcasecmp(rpt_vars[i].name,myrpt->p.rptnode))
13701          {
13702             if ((rpt_vars[i].links.next != &rpt_vars[i].links) ||
13703                rpt_vars[i].keyed ||
13704                 ((rpt_vars[i].lastkeyedtime + RPT_LOCKOUT_SECS) > now) ||
13705                  rpt_vars[i].txkeyed ||
13706                   ((rpt_vars[i].lasttxkeyedtime + RPT_LOCKOUT_SECS) > now))
13707             {
13708                rpt_mutex_unlock(&myrpt->lock);
13709                ast_log(LOG_WARNING, "Trying to use busy link (repeater node %s) on %s\n",rpt_vars[i].name,tmp);
13710 #ifdef   AST_CDR_FLAG_POST_DISABLED
13711                if (chan->cdr)
13712                   ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13713 #endif
13714                return -1;
13715             }
13716             while(rpt_vars[i].xlink != 3)
13717             {
13718                if (!killedit)
13719                {
13720                   ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
13721                   rpt_vars[i].xlink = 1;
13722                   killedit = 1;
13723                }
13724                rpt_mutex_unlock(&myrpt->lock);
13725                if (ast_safe_sleep(chan,500) == -1)
13726                {
13727 #ifdef   AST_CDR_FLAG_POST_DISABLED
13728                   if (chan->cdr)
13729                      ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13730 #endif
13731                   return -1;
13732                }
13733                rpt_mutex_lock(&myrpt->lock);
13734             }
13735             break;
13736          }
13737       }
13738    }
13739 
13740 #ifdef HAVE_IOPERM
13741    if ( (!strcmp(myrpt->remoterig, remote_rig_rbi)||!strcmp(myrpt->remoterig, remote_rig_ppp16)) &&
13742      (ioperm(myrpt->p.iobase,1,1) == -1))
13743    {
13744       rpt_mutex_unlock(&myrpt->lock);
13745       ast_log(LOG_WARNING, "Can't get io permission on IO port %x hex\n",myrpt->p.iobase);
13746       return -1;
13747    }
13748 #endif
13749    myrpt->remoteon = 1;
13750 #ifdef   OLD_ASTERISK
13751    LOCAL_USER_ADD(u);
13752 #endif
13753    rpt_mutex_unlock(&myrpt->lock);
13754    /* find our index, and load the vars initially */
13755    for(i = 0; i < nrpts; i++)
13756    {
13757       if (&rpt_vars[i] == myrpt)
13758       {
13759          load_rpt_vars(i,0);
13760          break;
13761       }
13762    }
13763    rpt_mutex_lock(&myrpt->lock);
13764    tele = strchr(myrpt->rxchanname,'/');
13765    if (!tele)
13766    {
13767       fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
13768       rpt_mutex_unlock(&myrpt->lock);
13769       pthread_exit(NULL);
13770    }
13771    *tele++ = 0;
13772    myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele,NULL);
13773    myrpt->dahdirxchannel = NULL;
13774    if (!strcasecmp(myrpt->rxchanname,"DAHDI"))
13775       myrpt->dahdirxchannel = myrpt->rxchannel;
13776    if (myrpt->rxchannel)
13777    {
13778       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
13779       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
13780 #ifdef   AST_CDR_FLAG_POST_DISABLED
13781       if (myrpt->rxchannel->cdr)
13782          ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13783 #endif
13784 #ifndef  NEW_ASTERISK
13785       myrpt->rxchannel->whentohangup = 0;
13786 #endif
13787       myrpt->rxchannel->appl = "Apprpt";
13788       myrpt->rxchannel->data = "(Link Rx)";
13789       if (option_verbose > 2)
13790          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
13791             myrpt->rxchanname,tele,myrpt->rxchannel->name);
13792       rpt_mutex_unlock(&myrpt->lock);
13793       ast_call(myrpt->rxchannel,tele,999);
13794       rpt_mutex_lock(&myrpt->lock);
13795    }
13796    else
13797    {
13798       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
13799       rpt_mutex_unlock(&myrpt->lock);
13800       pthread_exit(NULL);
13801    }
13802    *--tele = '/';
13803    myrpt->dahditxchannel = NULL;
13804    if (myrpt->txchanname)
13805    {
13806       tele = strchr(myrpt->txchanname,'/');
13807       if (!tele)
13808       {
13809          fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
13810          rpt_mutex_unlock(&myrpt->lock);
13811          ast_hangup(myrpt->rxchannel);
13812          pthread_exit(NULL);
13813       }
13814       *tele++ = 0;
13815       myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele,NULL);
13816       if (!strncasecmp(myrpt->txchanname,"DAHDI",3))
13817          myrpt->dahditxchannel = myrpt->txchannel;
13818       if (myrpt->txchannel)
13819       {
13820          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
13821          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
13822 #ifdef   AST_CDR_FLAG_POST_DISABLED
13823          if (myrpt->txchannel->cdr)
13824             ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13825 #endif
13826 #ifndef  NEW_ASTERISK
13827          myrpt->txchannel->whentohangup = 0;
13828 #endif
13829          myrpt->txchannel->appl = "Apprpt";
13830          myrpt->txchannel->data = "(Link Tx)";
13831          if (option_verbose > 2)
13832             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
13833                myrpt->txchanname,tele,myrpt->txchannel->name);
13834          rpt_mutex_unlock(&myrpt->lock);
13835          ast_call(myrpt->txchannel,tele,999);
13836          rpt_mutex_lock(&myrpt->lock);
13837       }
13838       else
13839       {
13840          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
13841          rpt_mutex_unlock(&myrpt->lock);
13842          ast_hangup(myrpt->rxchannel);
13843          pthread_exit(NULL);
13844       }
13845       *--tele = '/';
13846    }
13847    else
13848    {
13849       myrpt->txchannel = myrpt->rxchannel;
13850       if (!strncasecmp(myrpt->rxchanname,"DAHDI",3))
13851          myrpt->dahditxchannel = myrpt->rxchannel;
13852    }
13853    /* allocate a pseudo-channel thru asterisk */
13854    myrpt->pchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
13855    if (!myrpt->pchannel)
13856    {
13857       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
13858       rpt_mutex_unlock(&myrpt->lock);
13859       if (myrpt->txchannel != myrpt->rxchannel) 
13860          ast_hangup(myrpt->txchannel);
13861       ast_hangup(myrpt->rxchannel);
13862       pthread_exit(NULL);
13863    }
13864    ast_set_read_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
13865    ast_set_write_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
13866 #ifdef   AST_CDR_FLAG_POST_DISABLED
13867    if (myrpt->pchannel->cdr)
13868       ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13869 #endif
13870    if (!myrpt->dahdirxchannel) myrpt->dahdirxchannel = myrpt->pchannel;
13871    if (!myrpt->dahditxchannel) myrpt->dahditxchannel = myrpt->pchannel;
13872    /* make a conference for the pseudo */
13873    ci.chan = 0;
13874    ci.confno = -1; /* make a new conf */
13875    ci.confmode = DAHDI_CONF_CONFANNMON ;
13876    /* first put the channel on the conference in announce/monitor mode */
13877    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
13878    {
13879       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
13880       rpt_mutex_unlock(&myrpt->lock);
13881       ast_hangup(myrpt->pchannel);
13882       if (myrpt->txchannel != myrpt->rxchannel) 
13883          ast_hangup(myrpt->txchannel);
13884       ast_hangup(myrpt->rxchannel);
13885       pthread_exit(NULL);
13886    }
13887    /* save pseudo channel conference number */
13888    myrpt->conf = myrpt->txconf = ci.confno;
13889    /* if serial io port, open it */
13890    myrpt->iofd = -1;
13891    if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt,myrpt->p.ioport)) == -1))
13892    {
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    iskenwood_pci4 = 0;
13901    memset(&z,0,sizeof(z));
13902    if ((myrpt->iofd < 1) && (myrpt->txchannel == myrpt->dahditxchannel))
13903    {
13904       z.radpar = DAHDI_RADPAR_REMMODE;
13905       z.data = DAHDI_RADPAR_REM_NONE;
13906       res = ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z);
13907       /* if PCIRADIO and kenwood selected */
13908       if ((!res) && (!strcmp(myrpt->remoterig,remote_rig_kenwood)))
13909       {
13910          z.radpar = DAHDI_RADPAR_UIOMODE;
13911          z.data = 1;
13912          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13913          {
13914             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
13915             return -1;
13916          }
13917          z.radpar = DAHDI_RADPAR_UIODATA;
13918          z.data = 3;
13919          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13920          {
13921             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
13922             return -1;
13923          }
13924          i = DAHDI_OFFHOOK;
13925          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i) == -1)
13926          {
13927             ast_log(LOG_ERROR,"Cannot set hook\n");
13928             return -1;
13929          }
13930          iskenwood_pci4 = 1;
13931       }
13932    }
13933    if (myrpt->txchannel == myrpt->dahditxchannel)
13934    {
13935       i = DAHDI_ONHOOK;
13936       ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i);
13937       /* if PCIRADIO and Yaesu ft897/ICOM IC-706 selected */
13938       if ((myrpt->iofd < 1) && (!res) &&
13939          ((!strcmp(myrpt->remoterig,remote_rig_ft897)) ||
13940             (!strcmp(myrpt->remoterig,remote_rig_ic706)) ||
13941                (!strcmp(myrpt->remoterig,remote_rig_tm271))))
13942       {
13943          z.radpar = DAHDI_RADPAR_UIOMODE;
13944          z.data = 1;
13945          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13946          {
13947             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
13948             return -1;
13949          }
13950          z.radpar = DAHDI_RADPAR_UIODATA;
13951          z.data = 3;
13952          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13953          {
13954             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
13955             return -1;
13956          }
13957       }
13958    }
13959    myrpt->remoterx = 0;
13960    myrpt->remotetx = 0;
13961    myrpt->retxtimer = 0;
13962    myrpt->rerxtimer = 0;
13963    myrpt->remoteon = 1;
13964    myrpt->dtmfidx = -1;
13965    myrpt->dtmfbuf[0] = 0;
13966    myrpt->dtmf_time_rem = 0;
13967    myrpt->hfscanmode = 0;
13968    myrpt->hfscanstatus = 0;
13969    if (myrpt->p.startupmacro)
13970    {
13971       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
13972    }
13973    time(&myrpt->start_time);
13974    myrpt->last_activity_time = myrpt->start_time;
13975    last_timeout_warning = 0;
13976    myrpt->reload = 0;
13977    myrpt->tele.next = &myrpt->tele;
13978    myrpt->tele.prev = &myrpt->tele;
13979    myrpt->newkey = 0;
13980    rpt_mutex_unlock(&myrpt->lock);
13981    ast_set_write_format(chan, AST_FORMAT_SLINEAR);
13982    ast_set_read_format(chan, AST_FORMAT_SLINEAR);
13983    rem_rx = 0;
13984    remkeyed = 0;
13985    /* if we are on 2w loop and are a remote, turn EC on */
13986    if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
13987    {
13988       i = 128;
13989       ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_ECHOCANCEL,&i);
13990    }
13991    if (chan->_state != AST_STATE_UP) {
13992       ast_answer(chan);
13993       if (!phone_mode) send_newkey(chan);
13994    }
13995 
13996    if (myrpt->rxchannel == myrpt->dahdirxchannel)
13997    {
13998       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_GET_PARAMS,&par) != -1)
13999       {
14000          if (par.rxisoffhook)
14001          {
14002             ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14003             myrpt->remoterx = 1;
14004             remkeyed = 1;
14005          }
14006       }
14007    }
14008    if (myrpt->p.archivedir)
14009    {
14010       char mycmd[100],mydate[100],*b,*b1;
14011       time_t myt;
14012       long blocksleft;
14013 
14014 
14015       mkdir(myrpt->p.archivedir,0600);
14016       sprintf(mycmd,"%s/%s",myrpt->p.archivedir,myrpt->name);
14017       mkdir(mycmd,0600);
14018       time(&myt);
14019       strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
14020          localtime(&myt));
14021       sprintf(mycmd,"mixmonitor start %s %s/%s/%s.wav49 a",chan->name,
14022          myrpt->p.archivedir,myrpt->name,mydate);
14023       if (myrpt->p.monminblocks)
14024       {
14025          blocksleft = diskavail(myrpt);
14026          if (myrpt->p.remotetimeout)
14027          {
14028             blocksleft -= (myrpt->p.remotetimeout *
14029                MONITOR_DISK_BLOCKS_PER_MINUTE) / 60;
14030          }
14031          if (blocksleft >= myrpt->p.monminblocks)
14032             ast_cli_command(nullfd,mycmd);
14033       } else ast_cli_command(nullfd,mycmd);
14034       /* look at callerid to see what node this comes from */
14035       if (!chan->cid.cid_num) /* if doesn't have caller id */
14036       {
14037          b1 = "0";
14038       } else {
14039          ast_callerid_parse(chan->cid.cid_num,&b,&b1);
14040          ast_shrink_phone_number(b1);
14041       }
14042       sprintf(mycmd,"CONNECT,%s",b1);
14043       donodelog(myrpt,mycmd);
14044    }
14045    myrpt->loginuser[0] = 0;
14046    myrpt->loginlevel[0] = 0;
14047    myrpt->authtelltimer = 0;
14048    myrpt->authtimer = 0;
14049    authtold = 0;
14050    authreq = 0;
14051    if (myrpt->p.authlevel > 1) authreq = 1;
14052    setrem(myrpt); 
14053    n = 0;
14054    dtmfed = 0;
14055    cs[n++] = chan;
14056    cs[n++] = myrpt->rxchannel;
14057    cs[n++] = myrpt->pchannel;
14058    if (myrpt->rxchannel != myrpt->txchannel)
14059       cs[n++] = myrpt->txchannel;
14060    if (!phone_mode) send_newkey(chan);
14061    /* start un-locked */
14062    for(;;) 
14063    {
14064       if (ast_check_hangup(chan)) break;
14065       if (ast_check_hangup(myrpt->rxchannel)) break;
14066       notremming = 0;
14067       setting = 0;
14068       reming = 0;
14069       telem = myrpt->tele.next;
14070       while(telem != &myrpt->tele)
14071       {
14072          if (telem->mode == SETREMOTE) setting = 1;
14073          if ((telem->mode == SETREMOTE) ||
14074              (telem->mode == SCAN) ||
14075             (telem->mode == TUNE))  reming = 1;
14076          else notremming = 1;
14077          telem = telem->next;
14078       }
14079       if (myrpt->reload)
14080       {
14081          myrpt->reload = 0;
14082          /* find our index, and load the vars */
14083          for(i = 0; i < nrpts; i++)
14084          {
14085             if (&rpt_vars[i] == myrpt)
14086             {
14087                load_rpt_vars(i,0);
14088                break;
14089             }
14090          }
14091       }
14092       time(&t);
14093       if (myrpt->p.remotetimeout)
14094       { 
14095          time_t r;
14096 
14097          r = (t - myrpt->start_time);
14098          if (r >= myrpt->p.remotetimeout)
14099          {
14100             saynode(myrpt,chan,myrpt->name);
14101             sayfile(chan,"rpt/timeout");
14102             ast_safe_sleep(chan,1000);
14103             break;
14104          }
14105          if ((myrpt->p.remotetimeoutwarning) && 
14106              (r >= (myrpt->p.remotetimeout -
14107             myrpt->p.remotetimeoutwarning)) &&
14108                 (r <= (myrpt->p.remotetimeout - 
14109                   myrpt->p.remotetimeoutwarningfreq)))
14110          {
14111             if (myrpt->p.remotetimeoutwarningfreq)
14112             {
14113                 if ((t - last_timeout_warning) >=
14114                myrpt->p.remotetimeoutwarningfreq)
14115                 {
14116                time(&last_timeout_warning);
14117                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
14118                 }
14119             }
14120             else
14121             {
14122                 if (!last_timeout_warning)
14123                 {
14124                time(&last_timeout_warning);
14125                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
14126                 }
14127             }
14128          }
14129       }
14130       if (myrpt->p.remoteinacttimeout && myrpt->last_activity_time)
14131       { 
14132          time_t r;
14133 
14134          r = (t - myrpt->last_activity_time);
14135          if (r >= myrpt->p.remoteinacttimeout)
14136          {
14137             saynode(myrpt,chan,myrpt->name);
14138             ast_safe_sleep(chan,1000);
14139             break;
14140          }
14141          if ((myrpt->p.remotetimeoutwarning) && 
14142              (r >= (myrpt->p.remoteinacttimeout -
14143             myrpt->p.remotetimeoutwarning)) &&
14144                 (r <= (myrpt->p.remoteinacttimeout - 
14145                   myrpt->p.remotetimeoutwarningfreq)))
14146          {
14147             if (myrpt->p.remotetimeoutwarningfreq)
14148             {
14149                 if ((t - last_timeout_warning) >=
14150                myrpt->p.remotetimeoutwarningfreq)
14151                 {
14152                time(&last_timeout_warning);
14153                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
14154                 }
14155             }
14156             else
14157             {
14158                 if (!last_timeout_warning)
14159                 {
14160                time(&last_timeout_warning);
14161                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
14162                 }
14163             }
14164          }
14165       }
14166       ms = MSWAIT;
14167       who = ast_waitfor_n(cs,n,&ms);
14168       if (who == NULL) ms = 0;
14169       elap = MSWAIT - ms;
14170       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
14171       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
14172       if (!ms) continue;
14173       /* do local dtmf timer */
14174       if (myrpt->dtmf_local_timer)
14175       {
14176          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
14177          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
14178       }
14179       rpt_mutex_lock(&myrpt->lock);
14180       do_dtmf_local(myrpt,0);
14181       rpt_mutex_unlock(&myrpt->lock);
14182       //
14183       rem_totx =  myrpt->dtmf_local_timer && (!phone_mode);
14184       rem_totx |= keyed && (!myrpt->tunerequest);
14185       rem_rx = (remkeyed && (!setting)) || (myrpt->tele.next != &myrpt->tele);
14186       if(!strcmp(myrpt->remoterig, remote_rig_ic706))
14187          rem_totx |= myrpt->tunerequest;
14188       //
14189        if((debug > 6) && rem_totx) {
14190          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);
14191       }
14192       if (keyed && (!keyed1))
14193       {
14194          keyed1 = 1;
14195       }
14196 
14197       if (!keyed && (keyed1))
14198       {
14199          time_t myt;
14200 
14201          keyed1 = 0;
14202          time(&myt);
14203          /* if login necessary, and not too soon */
14204          if ((myrpt->p.authlevel) && 
14205              (!myrpt->loginlevel[0]) &&
14206             (myt > (t + 3)))
14207          {
14208             authreq = 1;
14209             authtold = 0;
14210             myrpt->authtelltimer = AUTHTELLTIME - AUTHTXTIME;
14211          }
14212       }
14213 
14214       if (rem_rx && (!myrpt->remoterx))
14215       {
14216          myrpt->remoterx = 1;
14217          ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14218       }
14219       if ((!rem_rx) && (myrpt->remoterx))
14220       {
14221          myrpt->remoterx = 0;
14222          ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
14223       }
14224       /* if auth requested, and not authed yet */
14225       if (authreq && (!myrpt->loginlevel[0]))
14226       {
14227          if ((!authtold) && ((myrpt->authtelltimer += elap)
14228              >= AUTHTELLTIME))
14229          {
14230             authtold = 1;
14231             rpt_telemetry(myrpt,LOGINREQ,NULL);
14232          }
14233          if ((myrpt->authtimer += elap) >= AUTHLOGOUTTIME)
14234          {
14235             break; /* if not logged in, hang up after a time */
14236          }
14237       }
14238       if (myrpt->newkey)
14239       {
14240          if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
14241          {
14242             myrpt->retxtimer = 0;
14243             if ((myrpt->remoterx) && (!myrpt->remotetx))
14244                ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14245             else
14246                ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
14247          }
14248 
14249          if ((myrpt->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 2))
14250          {
14251             keyed = 0;
14252             myrpt->rerxtimer = 0;
14253          }
14254       }
14255       if (rem_totx && (!myrpt->remotetx))
14256       {
14257          /* if not authed, and needed, do not transmit */
14258          if ((!myrpt->p.authlevel) || myrpt->loginlevel[0])
14259          {
14260             if(debug > 6)
14261                ast_log(LOG_NOTICE,"Handle rem_totx=%i.  dtmf_local_timer=%i  tunerequest=%i\n",rem_totx,myrpt->dtmf_local_timer,myrpt->tunerequest);
14262 
14263             myrpt->remotetx = 1;
14264             /* asdf maw ??? is this really what you want? Doesn't it always get executed? */
14265             if((myrpt->remtxfreqok = check_tx_freq(myrpt)))
14266             {
14267                time(&myrpt->last_activity_time);
14268                if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14269                {
14270                   z.radpar = DAHDI_RADPAR_UIODATA;
14271                   z.data = 1;
14272                   if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14273                   {
14274                      ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14275                      return -1;
14276                   }
14277                }
14278                else
14279                {
14280                   ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
14281                }
14282                if (myrpt->p.archivedir) donodelog(myrpt,"TXKEY");
14283             }
14284          }
14285       }
14286       if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
14287       {
14288          myrpt->remotetx = 0;
14289          if(!myrpt->remtxfreqok){
14290             rpt_telemetry(myrpt,UNAUTHTX,NULL);
14291          }
14292          if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14293          {
14294             z.radpar = DAHDI_RADPAR_UIODATA;
14295             z.data = 3;
14296             if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14297             {
14298                ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14299                return -1;
14300             }
14301          }
14302          else
14303          {
14304             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
14305          }
14306          if (myrpt->p.archivedir) donodelog(myrpt,"TXUNKEY");
14307       }
14308       if (myrpt->hfscanmode){
14309          myrpt->scantimer -= elap;
14310          if(myrpt->scantimer <= 0){
14311             if (!reming)
14312             {
14313                myrpt->scantimer = REM_SCANTIME;
14314                rpt_telemetry(myrpt,SCAN,0);
14315             } else myrpt->scantimer = 1;
14316          }
14317       }
14318       rpt_mutex_lock(&myrpt->lock);
14319       c = myrpt->macrobuf[0];
14320       if (c && (!myrpt->macrotimer))
14321       {
14322          myrpt->macrotimer = MACROTIME;
14323          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
14324          if ((c == 'p') || (c == 'P'))
14325             myrpt->macrotimer = MACROPTIME;
14326          rpt_mutex_unlock(&myrpt->lock);
14327          if (myrpt->p.archivedir)
14328          {
14329             char str[100];
14330                sprintf(str,"DTMF(M),%c",c);
14331             donodelog(myrpt,str);
14332          }
14333          if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
14334          continue;
14335       } else rpt_mutex_unlock(&myrpt->lock);
14336       if (who == chan) /* if it was a read from incomming */
14337       {
14338          f = ast_read(chan);
14339          if (!f)
14340          {
14341             if (debug) printf("@@@@ link:Hung Up\n");
14342             break;
14343          }
14344          if (f->frametype == AST_FRAME_VOICE)
14345          {
14346             if (ioctl(chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
14347             {
14348                ismuted = 0;
14349             }
14350             /* if not transmitting, zero-out audio */
14351             ismuted |= (!myrpt->remotetx);
14352             if (dtmfed && phone_mode) ismuted = 1;
14353             dtmfed = 0;
14354             if (ismuted)
14355             {
14356                memset(f->data.ptr,0,f->datalen);
14357                if (myrpt->lastf1)
14358                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14359                if (myrpt->lastf2)
14360                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14361             } 
14362             if (f) f2 = ast_frdup(f);
14363             else f2 = NULL;
14364             f1 = myrpt->lastf2;
14365             myrpt->lastf2 = myrpt->lastf1;
14366             myrpt->lastf1 = f2;
14367             if (ismuted)
14368             {
14369                if (myrpt->lastf1)
14370                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14371                if (myrpt->lastf2)
14372                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14373             }
14374             if (f1)
14375             {
14376                if (phone_mode)
14377                   ast_write(myrpt->txchannel,f1);
14378                else
14379                   ast_write(myrpt->txchannel,f);
14380                ast_frfree(f1);
14381             }
14382          }
14383 #ifndef  OLD_ASTERISK
14384          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
14385          {
14386             if (myrpt->lastf1)
14387                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14388             if (myrpt->lastf2)
14389                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14390             dtmfed = 1;
14391          }
14392 #endif
14393          if (f->frametype == AST_FRAME_DTMF)
14394          {
14395             if (myrpt->lastf1)
14396                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14397             if (myrpt->lastf2)
14398                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14399             dtmfed = 1;
14400             if (handle_remote_phone_dtmf(myrpt,f->subclass,&keyed,phone_mode) == -1)
14401             {
14402                if (debug) printf("@@@@ rpt:Hung Up\n");
14403                ast_frfree(f);
14404                break;
14405             }
14406          }
14407          if (f->frametype == AST_FRAME_TEXT)
14408          {
14409             if (handle_remote_data(myrpt,f->data.ptr) == -1)
14410             {
14411                if (debug) printf("@@@@ rpt:Hung Up\n");
14412                ast_frfree(f);
14413                break;
14414             }
14415          }
14416          if (f->frametype == AST_FRAME_CONTROL)
14417          {
14418             if (f->subclass == AST_CONTROL_HANGUP)
14419             {
14420                if (debug) printf("@@@@ rpt:Hung Up\n");
14421                ast_frfree(f);
14422                break;
14423             }
14424             /* if RX key */
14425             if (f->subclass == AST_CONTROL_RADIO_KEY)
14426             {
14427                if (debug == 7) printf("@@@@ rx key\n");
14428                keyed = 1;
14429                myrpt->rerxtimer = 0;
14430             }
14431             /* if RX un-key */
14432             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
14433             {
14434                myrpt->rerxtimer = 0;
14435                if (debug == 7) printf("@@@@ rx un-key\n");
14436                keyed = 0;
14437             }
14438          }
14439          ast_frfree(f);
14440          continue;
14441       }
14442       if (who == myrpt->rxchannel) /* if it was a read from radio */
14443       {
14444          f = ast_read(myrpt->rxchannel);
14445          if (!f)
14446          {
14447             if (debug) printf("@@@@ link:Hung Up\n");
14448             break;
14449          }
14450          if (f->frametype == AST_FRAME_VOICE)
14451          {
14452             int myreming = 0;
14453 
14454             if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
14455                myreming = reming;
14456 
14457             if (myreming || (!remkeyed) ||
14458             ((myrpt->remote) && (myrpt->remotetx)) ||
14459               ((myrpt->remmode != REM_MODE_FM) &&
14460                 notremming))
14461                memset(f->data.ptr,0,f->datalen); 
14462              ast_write(myrpt->pchannel,f);
14463          }
14464          else if (f->frametype == AST_FRAME_CONTROL)
14465          {
14466             if (f->subclass == AST_CONTROL_HANGUP)
14467             {
14468                if (debug) printf("@@@@ rpt:Hung Up\n");
14469                ast_frfree(f);
14470                break;
14471             }
14472             /* if RX key */
14473             if (f->subclass == AST_CONTROL_RADIO_KEY)
14474             {
14475                if (debug == 7) printf("@@@@ remote rx key\n");
14476                if (!myrpt->remotetx)
14477                {
14478                   remkeyed = 1;
14479                }
14480             }
14481             /* if RX un-key */
14482             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
14483             {
14484                if (debug == 7) printf("@@@@ remote rx un-key\n");
14485                if (!myrpt->remotetx) 
14486                {
14487                   remkeyed = 0;
14488                }
14489             }
14490          }
14491          ast_frfree(f);
14492          continue;
14493       }
14494       if (who == myrpt->pchannel) /* if is remote mix output */
14495       {
14496          f = ast_read(myrpt->pchannel);
14497          if (!f)
14498          {
14499             if (debug) printf("@@@@ link:Hung Up\n");
14500             break;
14501          }
14502          if (f->frametype == AST_FRAME_VOICE)
14503          {
14504             ast_write(chan,f);
14505          }
14506          if (f->frametype == AST_FRAME_CONTROL)
14507          {
14508             if (f->subclass == AST_CONTROL_HANGUP)
14509             {
14510                if (debug) printf("@@@@ rpt:Hung Up\n");
14511                ast_frfree(f);
14512                break;
14513             }
14514          }
14515          ast_frfree(f);
14516          continue;
14517       }
14518       if ((myrpt->rxchannel != myrpt->txchannel) && 
14519          (who == myrpt->txchannel)) /* do this cuz you have to */
14520       {
14521          f = ast_read(myrpt->txchannel);
14522          if (!f)
14523          {
14524             if (debug) printf("@@@@ link:Hung Up\n");
14525             break;
14526          }
14527          if (f->frametype == AST_FRAME_CONTROL)
14528          {
14529             if (f->subclass == AST_CONTROL_HANGUP)
14530             {
14531                if (debug) printf("@@@@ rpt:Hung Up\n");
14532                ast_frfree(f);
14533                break;
14534             }
14535          }
14536          ast_frfree(f);
14537          continue;
14538       }
14539    }
14540    if (myrpt->p.archivedir)
14541    {
14542       char mycmd[100],*b,*b1;
14543 
14544       /* look at callerid to see what node this comes from */
14545       if (!chan->cid.cid_num) /* if doesn't have caller id */
14546       {
14547          b1 = "0";
14548       } else {
14549          ast_callerid_parse(chan->cid.cid_num,&b,&b1);
14550          ast_shrink_phone_number(b1);
14551       }
14552       sprintf(mycmd,"DISCONNECT,%s",b1);
14553       donodelog(myrpt,mycmd);
14554    }
14555    /* wait for telem to be done */
14556    while(myrpt->tele.next != &myrpt->tele) usleep(100000);
14557    sprintf(tmp,"mixmonitor stop %s",chan->name);
14558    ast_cli_command(nullfd,tmp);
14559    close(nullfd);
14560    rpt_mutex_lock(&myrpt->lock);
14561    myrpt->hfscanmode = 0;
14562    myrpt->hfscanstatus = 0;
14563    myrpt->remoteon = 0;
14564    rpt_mutex_unlock(&myrpt->lock);
14565    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
14566    myrpt->lastf1 = NULL;
14567    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
14568    myrpt->lastf2 = NULL;
14569    if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14570    {
14571       z.radpar = DAHDI_RADPAR_UIOMODE;
14572       z.data = 3;
14573       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14574       {
14575          ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
14576          return -1;
14577       }
14578       z.radpar = DAHDI_RADPAR_UIODATA;
14579       z.data = 3;
14580       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14581       {
14582          ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14583          return -1;
14584       }
14585       i = DAHDI_OFFHOOK;
14586       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i) == -1)
14587       {
14588          ast_log(LOG_ERROR,"Cannot set hook\n");
14589          return -1;
14590       }
14591    }
14592    if (myrpt->iofd) close(myrpt->iofd);
14593    myrpt->iofd = -1;
14594    ast_hangup(myrpt->pchannel);
14595    if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
14596    ast_hangup(myrpt->rxchannel);
14597    closerem(myrpt);
14598    if (myrpt->p.rptnode)
14599    {
14600       rpt_mutex_lock(&myrpt->lock);
14601       for(i = 0; i < nrpts; i++)
14602       {
14603          if (!strcasecmp(rpt_vars[i].name,myrpt->p.rptnode))
14604          {
14605             rpt_vars[i].xlink = 0;
14606             break;
14607          }
14608       }
14609       rpt_mutex_unlock(&myrpt->lock);
14610    }
14611 #ifdef   OLD_ASTERISK
14612    LOCAL_USER_REMOVE(u);
14613 #endif
14614    return res;
14615 }
14616 
14617 #ifndef OLD_ASTERISK
14618 /*!\brief callback to display list of locally configured nodes
14619    \addtogroup Group_AMI
14620  */
14621 static int manager_rpt_local_nodes(struct mansession *s, const struct message *m)
14622 {
14623     int i;
14624     astman_append(s, "<?xml version=\"1.0\"?>\r\n");
14625     astman_append(s, "<nodes>\r\n");
14626     for (i=0; i< nrpts; i++)
14627     {
14628         astman_append(s, "  <node>%s</node>\r\n", rpt_vars[i].name);        
14629     } /* for i */
14630     astman_append(s, "</nodes>\r\n");
14631     astman_append(s, "\r\n"); /* Properly terminate Manager output */
14632     return RESULT_SUCCESS;
14633 } /* manager_rpt_local_nodes() */
14634 
14635 
14636 
14637 /*
14638  * Append Success and ActionID to manager response message
14639  */
14640 
14641 static void rpt_manager_success(struct mansession *s, const struct message *m)
14642 {
14643    const char *id = astman_get_header(m, "ActionID");
14644    if (!ast_strlen_zero(id))
14645       astman_append(s, "ActionID: %s\r\n", id);
14646    astman_append(s, "Response: Success\r\n");
14647 }
14648 
14649 /*
14650 * Dump statistics to manager session
14651 */
14652 
14653 static int rpt_manager_do_stats(struct mansession *s, const struct message *m, char *str)
14654 {
14655    int i,j,numoflinks;
14656    int dailytxtime, dailykerchunks;
14657    time_t now;
14658    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
14659    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
14660    long long totaltxtime;
14661    struct   rpt_link *l;
14662    char *listoflinks[MAX_STAT_LINKS];  
14663    char *lastdtmfcommand,*parrot_ena;
14664    char *tot_state, *ider_state, *patch_state;
14665    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
14666    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
14667    char *transmitterkeyed;
14668    const char *node = astman_get_header(m, "Node");
14669    struct rpt *myrpt;
14670 
14671    static char *not_applicable = "N/A";
14672 
14673    tot_state = ider_state = 
14674    patch_state = reverse_patch_state = 
14675    input_signal = not_applicable;
14676    called_number = lastdtmfcommand = transmitterkeyed = NULL;
14677 
14678    time(&now);
14679    for(i = 0; i < nrpts; i++)
14680    {
14681       if ((node)&&(!strcmp(node,rpt_vars[i].name))){
14682          rpt_manager_success(s,m);
14683 
14684          myrpt = &rpt_vars[i];
14685 
14686          if(myrpt->remote){ /* Remote base ? */
14687             char *loginuser, *loginlevel, *freq, *rxpl, *txpl, *modestr;
14688             char offset = 0, powerlevel = 0, rxplon = 0, txplon = 0, remoteon, remmode = 0, reportfmstuff;
14689             char offsetc,powerlevelc;
14690 
14691             loginuser = loginlevel = freq = rxpl = txpl = NULL;
14692             /* Make a copy of all stat variables while locked */
14693             rpt_mutex_lock(&myrpt->lock); /* LOCK */
14694             if((remoteon = myrpt->remoteon)){
14695                if(!ast_strlen_zero(myrpt->loginuser))
14696                   loginuser = ast_strdup(myrpt->loginuser);
14697                if(!ast_strlen_zero(myrpt->loginlevel))
14698                   loginlevel = ast_strdup(myrpt->loginlevel);
14699                if(!ast_strlen_zero(myrpt->freq))
14700                   freq = ast_strdup(myrpt->freq);
14701                if(!ast_strlen_zero(myrpt->rxpl))
14702                   rxpl = ast_strdup(myrpt->rxpl);
14703                if(!ast_strlen_zero(myrpt->txpl))
14704                   txpl = ast_strdup(myrpt->txpl);
14705                remmode = myrpt->remmode;
14706                offset = myrpt->offset;
14707                powerlevel = myrpt->powerlevel;
14708                rxplon = myrpt->rxplon;
14709                txplon = myrpt->txplon;       
14710             }
14711             rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
14712             astman_append(s, "IsRemoteBase: YES\r\n");
14713             astman_append(s, "RemoteOn: %s\r\n",(remoteon) ? "YES": "NO");
14714             if(remoteon){
14715                if(loginuser){
14716                   astman_append(s, "LogInUser: %s\r\n", loginuser);
14717                   ast_free(loginuser);
14718                }
14719                if(loginlevel){
14720                   astman_append(s, "LogInLevel: %s\r\n", loginlevel);
14721                   ast_free(loginlevel);
14722                }
14723                if(freq){
14724                   astman_append(s, "Freq: %s\r\n", freq);
14725                   ast_free(freq);
14726                }
14727                reportfmstuff = 0;
14728                switch(remmode){
14729                   case REM_MODE_FM:
14730                      modestr = "FM";   
14731                      reportfmstuff = 1;
14732                      break;
14733                   case REM_MODE_AM:
14734                      modestr = "AM";
14735                      break;
14736                   case REM_MODE_USB:
14737                      modestr = "USB";
14738                      break;
14739                   default:
14740                      modestr = "LSB";
14741                      break;
14742                }
14743                astman_append(s, "RemMode: %s\r\n", modestr);
14744                if(reportfmstuff){
14745                   switch(offset){
14746                      case REM_SIMPLEX:
14747                         offsetc = 'S';
14748                         break;
14749                      case REM_MINUS:
14750                         offsetc = '-';
14751                         break;
14752                      default:
14753                         offsetc = '+';
14754                         break;
14755                   }
14756                   astman_append(s, "RemOffset: %c\r\n", offsetc);
14757                   if(rxplon && rxpl){
14758                      astman_append(s, "RxPl: %s\r\n",rxpl);
14759                      ast_free(rxpl);
14760                   }
14761                   if(txplon && txpl){
14762                      astman_append(s, "TxPl: %s\r\n",txpl);
14763                      ast_free(txpl);
14764                   }
14765                }
14766                switch(powerlevel){
14767                   case REM_LOWPWR:
14768                      powerlevelc = 'L';
14769                      break;
14770                   case REM_MEDPWR:
14771                      powerlevelc = 'M';
14772                      break;
14773                   default:
14774                      powerlevelc = 'H';
14775                      break;
14776                }
14777                astman_append(s,"PowerLevel: %c\r\n", powerlevelc);
14778             }
14779             astman_append(s, "\r\n");
14780             return 0; /* End of remote base status reporting */
14781          }  
14782 
14783          /* ELSE Process as a repeater node */
14784          /* Make a copy of all stat variables while locked */
14785          rpt_mutex_lock(&myrpt->lock); /* LOCK */
14786          dailytxtime = myrpt->dailytxtime;
14787          totaltxtime = myrpt->totaltxtime;
14788          dailykeyups = myrpt->dailykeyups;
14789          totalkeyups = myrpt->totalkeyups;
14790          dailykerchunks = myrpt->dailykerchunks;
14791          totalkerchunks = myrpt->totalkerchunks;
14792          dailyexecdcommands = myrpt->dailyexecdcommands;
14793          totalexecdcommands = myrpt->totalexecdcommands;
14794          timeouts = myrpt->timeouts;
14795 
14796 
14797          /* Traverse the list of connected nodes */
14798          reverse_patch_state = "DOWN";
14799          numoflinks = 0;
14800          l = myrpt->links.next;
14801          while(l && (l != &myrpt->links)){
14802             if(numoflinks >= MAX_STAT_LINKS){
14803                ast_log(LOG_NOTICE,
14804                "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
14805                break;
14806             }
14807             if (l->name[0] == '0'){ /* Skip '0' nodes */
14808                reverse_patch_state = "UP";
14809                l = l->next;
14810                continue;
14811             }
14812             listoflinks[numoflinks] = ast_strdup(l->name);
14813             if(listoflinks[numoflinks] == NULL){
14814                break;
14815             }
14816             else{
14817                numoflinks++;
14818             }
14819             l = l->next;
14820          }
14821 
14822          if(myrpt->keyed)
14823             input_signal = "YES";
14824          else
14825             input_signal = "NO";
14826          
14827          if(myrpt->txkeyed)
14828             transmitterkeyed = "YES";
14829          else
14830             transmitterkeyed = "NO";
14831 
14832          if(myrpt->p.parrotmode)
14833             parrot_ena = "ENABLED";
14834          else
14835             parrot_ena = "DISABLED";
14836 
14837          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
14838             sys_ena = "DISABLED";
14839          else
14840             sys_ena = "ENABLED";
14841 
14842          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
14843             tot_ena = "DISABLED";
14844          else
14845             tot_ena = "ENABLED";
14846 
14847          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
14848             link_ena = "DISABLED";
14849          else
14850             link_ena = "ENABLED";
14851 
14852          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
14853             patch_ena = "DISABLED";
14854          else
14855             patch_ena = "ENABLED";
14856 
14857          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
14858             sch_ena = "DISABLED";
14859          else
14860             sch_ena = "ENABLED";
14861 
14862          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
14863             user_funs = "DISABLED";
14864          else
14865             user_funs = "ENABLED";
14866 
14867          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
14868             tail_type = "ALTERNATE";
14869          else
14870             tail_type = "STANDARD";
14871 
14872          if(!myrpt->totimer)
14873             tot_state = "TIMED OUT!";
14874          else if(myrpt->totimer != myrpt->p.totime)
14875             tot_state = "ARMED";
14876          else
14877             tot_state = "RESET";
14878 
14879          if(myrpt->tailid)
14880             ider_state = "QUEUED IN TAIL";
14881          else if(myrpt->mustid)
14882             ider_state = "QUEUED FOR CLEANUP";
14883          else
14884             ider_state = "CLEAN";
14885 
14886          switch(myrpt->callmode){
14887             case 1:
14888                patch_state = "DIALING";
14889                break;
14890             case 2:
14891                patch_state = "CONNECTING";
14892                break;
14893             case 3:
14894                patch_state = "UP";
14895                break;
14896 
14897             case 4:
14898                patch_state = "CALL FAILED";
14899                break;
14900 
14901             default:
14902                patch_state = "DOWN";
14903          }
14904 
14905          if(strlen(myrpt->exten)){
14906             called_number = ast_strdup(myrpt->exten);
14907          }
14908 
14909          if(strlen(myrpt->lastdtmfcommand)){
14910             lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
14911          }
14912          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
14913 
14914          astman_append(s, "IsRemoteBase: NO\r\n");
14915          astman_append(s, "NodeState: %d\r\n", myrpt->p.sysstate_cur);
14916          astman_append(s, "SignalOnInput: %s\r\n", input_signal);
14917          astman_append(s, "TransmitterKeyed: %s\r\n", transmitterkeyed);
14918          astman_append(s, "Transmitter: %s\r\n", sys_ena);
14919          astman_append(s, "Parrot: %s\r\n", parrot_ena);
14920          astman_append(s, "Scheduler: %s\r\n", sch_ena);
14921          astman_append(s, "TailLength: %s\r\n", tail_type);
14922          astman_append(s, "TimeOutTimer: %s\r\n", tot_ena);
14923          astman_append(s, "TimeOutTimerState: %s\r\n", tot_state);
14924          astman_append(s, "TimeOutsSinceSystemInitialization: %d\r\n", timeouts);
14925          astman_append(s, "IdentifierState: %s\r\n", ider_state);
14926          astman_append(s, "KerchunksToday: %d\r\n", dailykerchunks);
14927          astman_append(s, "KerchunksSinceSystemInitialization: %d\r\n", totalkerchunks);
14928          astman_append(s, "KeyupsToday: %d\r\n", dailykeyups);
14929          astman_append(s, "KeyupsSinceSystemInitialization: %d\r\n", totalkeyups);
14930          astman_append(s, "DtmfCommandsToday: %d\r\n", dailyexecdcommands);
14931          astman_append(s, "DtmfCommandsSinceSystemInitialization: %d\r\n", totalexecdcommands);
14932          astman_append(s, "LastDtmfCommandExecuted: %s\r\n", 
14933          (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
14934          hours = dailytxtime/3600000;
14935          dailytxtime %= 3600000;
14936          minutes = dailytxtime/60000;
14937          dailytxtime %= 60000;
14938          seconds = dailytxtime/1000;
14939          dailytxtime %= 1000;
14940 
14941          astman_append(s, "TxTimeToday: %02d:%02d:%02d.%d\r\n",
14942             hours, minutes, seconds, dailytxtime);
14943 
14944          hours = (int) totaltxtime/3600000;
14945          totaltxtime %= 3600000;
14946          minutes = (int) totaltxtime/60000;
14947          totaltxtime %= 60000;
14948          seconds = (int)  totaltxtime/1000;
14949          totaltxtime %= 1000;
14950 
14951          astman_append(s, "TxTimeSinceSystemInitialization: %02d:%02d:%02d.%d\r\n",
14952              hours, minutes, seconds, (int) totaltxtime);
14953 
14954          sprintf(str, "NodesCurrentlyConnectedToUs: ");
14955                         if(!numoflinks){
14956                          strcat(str,"<NONE>");
14957                         }
14958          else{
14959             for(j = 0 ;j < numoflinks; j++){
14960                sprintf(str+strlen(str), "%s", listoflinks[j]);
14961                if(j < numoflinks - 1)
14962                   strcat(str,",");
14963             }
14964          }
14965          astman_append(s,"%s\r\n", str);
14966 
14967          astman_append(s, "Autopatch: %s\r\n", patch_ena);
14968          astman_append(s, "AutopatchState: %s\r\n", patch_state);
14969          astman_append(s, "AutopatchCalledNumber: %s\r\n",
14970          (called_number && strlen(called_number)) ? called_number : not_applicable);
14971          astman_append(s, "ReversePatchIaxrptConnected: %s\r\n", reverse_patch_state);
14972          astman_append(s, "UserLinkingCommands: %s\r\n", link_ena);
14973          astman_append(s, "UserFunctions: %s\r\n", user_funs);
14974 
14975          for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
14976             ast_free(listoflinks[j]);
14977          }
14978          if(called_number){
14979             ast_free(called_number);
14980          }
14981          if(lastdtmfcommand){
14982             ast_free(lastdtmfcommand);
14983          }
14984          astman_append(s, "\r\n"); /* We're Done! */
14985               return 0;
14986       }
14987    }
14988    astman_send_error(s, m, "RptStatus unknown or missing node");
14989    return -1;
14990 }
14991 
14992 
14993 
14994 /*
14995  * Implement the RptStatus Manager Interface
14996  */
14997 
14998 static int manager_rpt_status(struct mansession *s, const struct message *m)
14999 {
15000    int i,res,len,idx;
15001    int uptime,hours,minutes;
15002    time_t now;
15003    const char *cmd = astman_get_header(m, "Command");
15004    char *str;
15005    enum {MGRCMD_RPTSTAT,MGRCMD_NODESTAT};
15006    struct mgrcmdtbl{
15007       const char *cmd;
15008       int index;
15009    };
15010    static struct mgrcmdtbl mct[] = {
15011       {"RptStat",MGRCMD_RPTSTAT},
15012       {"NodeStat",MGRCMD_NODESTAT},
15013       {NULL,0} /* NULL marks end of command table */
15014    };
15015 
15016    time(&now);
15017 
15018    len = 1024; /* Allocate a working buffer */
15019    if(!(str = ast_malloc(len)))
15020       return -1;
15021 
15022    /* Check for Command */
15023    if(ast_strlen_zero(cmd)){
15024       astman_send_error(s, m, "RptStatus missing command");
15025       ast_free(str);
15026       return 0;
15027    }
15028    /* Try to find the command in the table */
15029    for(i = 0 ; mct[i].cmd ; i++){
15030       if(!strcmp(mct[i].cmd, cmd))
15031          break;
15032    }
15033 
15034    if(!mct[i].cmd){ /* Found or not found ? */
15035       astman_send_error(s, m, "RptStatus unknown command");
15036       ast_free(str);
15037       return 0;
15038    }
15039    else
15040       idx = mct[i].index;
15041 
15042    switch(idx){ /* Use the index to go to the correct command */
15043 
15044       case MGRCMD_RPTSTAT:
15045          /* Return Nodes: and a comma separated list of nodes */
15046          if((res = snprintf(str, len, "Nodes: ")) > -1)
15047             len -= res;
15048          else{
15049             ast_free(str);
15050             return 0;
15051          }
15052          for(i = 0; i < nrpts; i++){
15053             if(i < nrpts - 1){
15054                if((res = snprintf(str+strlen(str), len, "%s,",rpt_vars[i].name)) < 0){
15055                   ast_free(str);
15056                   return 0;
15057                }
15058             }
15059             else{
15060                if((res = snprintf(str+strlen(str), len, "%s",rpt_vars[i].name)) < 0){
15061                   ast_free(str);
15062                   return 0;
15063                }
15064             }
15065             len -= res;
15066          }
15067 
15068          rpt_manager_success(s,m);
15069          
15070          if(!nrpts)
15071             astman_append(s, "<NONE>\r\n");
15072          else
15073             astman_append(s, "%s\r\n", str);
15074 
15075          uptime = (int)(now - starttime);
15076                         hours = uptime/3600;
15077                         uptime %= 3600;
15078                         minutes = uptime/60;
15079                         uptime %= 60;
15080 
15081                         astman_append(s, "RptUptime: %02d:%02d:%02d\r\n",
15082                                 hours, minutes, uptime);
15083 
15084          astman_append(s, "\r\n");
15085          break;      
15086 
15087       case  MGRCMD_NODESTAT:
15088          res = rpt_manager_do_stats(s,m,str);
15089          ast_free(str);
15090          return res;
15091 
15092       default:
15093          astman_send_error(s, m, "RptStatus invalid command");
15094          break;
15095    }
15096    ast_free(str);
15097    return 0;
15098 }
15099 
15100 #endif
15101 
15102 #ifdef   OLD_ASTERISK
15103 int unload_module()
15104 #else
15105 static int unload_module(void)
15106 #endif
15107 {
15108    int i, res;
15109 
15110 #ifdef   OLD_ASTERISK
15111    STANDARD_HANGUP_LOCALUSERS;
15112 #endif
15113    for(i = 0; i < nrpts; i++) {
15114       if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
15115                 ast_mutex_destroy(&rpt_vars[i].lock);
15116                 ast_mutex_destroy(&rpt_vars[i].remlock);
15117    }
15118    res = ast_unregister_application(app);
15119 
15120 #ifdef   NEW_ASTERISK
15121    ast_cli_unregister_multiple(rpt_cli, ARRAY_LEN(rpt_cli));
15122 #else
15123    /* Unregister cli extensions */
15124    ast_cli_unregister(&cli_debug);
15125    ast_cli_unregister(&cli_dump);
15126    ast_cli_unregister(&cli_stats);
15127    ast_cli_unregister(&cli_lstats);
15128    ast_cli_unregister(&cli_nodes);
15129    ast_cli_unregister(&cli_local_nodes);
15130    ast_cli_unregister(&cli_reload);
15131    ast_cli_unregister(&cli_restart);
15132    ast_cli_unregister(&cli_fun);
15133    ast_cli_unregister(&cli_fun1);
15134    res |= ast_cli_unregister(&cli_cmd);
15135 #endif
15136 #ifndef OLD_ASTERISK
15137    res |= ast_manager_unregister("RptLocalNodes");
15138    res |= ast_manager_unregister("RptStatus");
15139 #endif
15140    return res;
15141 }
15142 
15143 #ifdef   OLD_ASTERISK
15144 int load_module()
15145 #else
15146 static int load_module(void)
15147 #endif
15148 {
15149    int res;
15150    ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
15151 
15152 #ifdef   NEW_ASTERISK
15153    ast_cli_register_multiple(rpt_cli, ARRAY_LEN(rpt_cli));
15154    res = 0;
15155 #else
15156    /* Register cli extensions */
15157    ast_cli_register(&cli_debug);
15158    ast_cli_register(&cli_dump);
15159    ast_cli_register(&cli_stats);
15160    ast_cli_register(&cli_lstats);
15161    ast_cli_register(&cli_nodes);
15162    ast_cli_register(&cli_local_nodes);
15163    ast_cli_register(&cli_reload);
15164    ast_cli_register(&cli_restart);
15165    ast_cli_register(&cli_fun);
15166    ast_cli_register(&cli_fun1);
15167    res = ast_cli_register(&cli_cmd);
15168 #endif
15169 #ifndef OLD_ASTERISK
15170    res |= ast_manager_register("RptLocalNodes", 0, manager_rpt_local_nodes, "List local node numbers");
15171    res |= ast_manager_register("RptStatus", 0, manager_rpt_status, "Return Rpt Status for CGI");
15172 
15173 #endif
15174    res |= ast_register_application(app, rpt_exec, synopsis, descrip);
15175    return res;
15176 }
15177 
15178 #ifdef   OLD_ASTERISK
15179 char *description()
15180 {
15181    return tdesc;
15182 }
15183 int usecount(void)
15184 {
15185    int res;
15186    STANDARD_USECOUNT(res);
15187    return res;
15188 }
15189 
15190 char *key()
15191 {
15192    return ASTERISK_GPL_KEY;
15193 }
15194 #endif
15195 
15196 #ifdef   OLD_ASTERISK
15197 int reload()
15198 #else
15199 static int reload(void)
15200 #endif
15201 {
15202 int   n;
15203 
15204    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
15205    return(0);
15206 }
15207 
15208 
15209 #ifndef  OLD_ASTERISK
15210 /* STD_MOD(MOD_1, reload, NULL, NULL); */
15211 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application",
15212       .load = load_module,
15213       .unload = unload_module,
15214       .reload = reload,
15215           );
15216 #endif
15217