Fri Jul 15 2011 11:57:07

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  ***/
00158 
00159 /* Un-comment the following to include support for MDC-1200 digital tone
00160    signalling protocol (using KA6SQG's GPL'ed implementation) */
00161 /* #include "mdc_decode.c" */
00162 
00163 /* Un-comment the following to include support for notch filters in the
00164    rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
00165 /* #include "rpt_notch.c" */
00166 
00167 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
00168 
00169 #ifdef OLD_ASTERISK
00170 #define ast_free free
00171 #define ast_malloc malloc
00172 #define ast_strdup strdup
00173 #endif
00174 
00175 
00176 #define  MAXDTMF 32
00177 #define  MAXMACRO 2048
00178 #define  MAXLINKLIST 512
00179 #define  LINKLISTTIME 10000
00180 #define  LINKLISTSHORTTIME 200
00181 #define  LINKPOSTTIME 30000
00182 #define  LINKPOSTSHORTTIME 200
00183 #define  KEYPOSTTIME 30000
00184 #define  KEYPOSTSHORTTIME 200
00185 #define  MACROTIME 100
00186 #define  MACROPTIME 500
00187 #define  DTMF_TIMEOUT 3
00188 #define  KENWOOD_RETRIES 5
00189 #define  TOPKEYN 32
00190 #define  TOPKEYWAIT 3
00191 #define  TOPKEYMAXSTR 30
00192 
00193 #define  AUTHTELLTIME 7000
00194 #define  AUTHTXTIME 1000
00195 #define  AUTHLOGOUTTIME 25000
00196 
00197 #ifdef   __RPT_NOTCH
00198 #define  MAXFILTERS 10
00199 #endif
00200 
00201 #define  DISC_TIME 10000  /* report disc after 10 seconds of no connect */
00202 #define  MAX_RETRIES 5
00203 #define  MAX_RETRIES_PERM 1000000000
00204 
00205 #define  REDUNDANT_TX_TIME 2000
00206 
00207 #define  RETRY_TIMER_MS 5000
00208 
00209 #define  PATCH_DIALPLAN_TIMEOUT 1500
00210 
00211 #ifdef OLD_ASTERISK
00212 #define  START_DELAY 10
00213 #else
00214 #define  START_DELAY 2
00215 #endif
00216 
00217 #define  RPT_LOCKOUT_SECS 10
00218 
00219 #define MAXPEERSTR 31
00220 #define  MAXREMSTR 15
00221 
00222 #define  DELIMCHR ','
00223 #define  QUOTECHR 34
00224 
00225 #define  MONITOR_DISK_BLOCKS_PER_MINUTE 38
00226 
00227 #define  DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000
00228 #define  DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60)
00229 #define  DEFAULT_REMOTE_TIMEOUT (60 * 60)
00230 #define  DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60)
00231 #define  DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30
00232 
00233 #define  NODES "nodes"
00234 #define  EXTNODES "extnodes"
00235 #define MEMORY "memory"
00236 #define MACRO "macro"
00237 #define  FUNCTIONS "functions"
00238 #define TELEMETRY "telemetry"
00239 #define MORSE "morse"
00240 #define  TONEMACRO "tonemacro"
00241 #define  FUNCCHAR '*'
00242 #define  ENDCHAR '#'
00243 #define  EXTNODEFILE "/var/lib/asterisk/rpt_extnodes"
00244 #define  NODENAMES "rpt/nodenames"
00245 #define  PARROTFILE "/tmp/parrot_%s_%u"
00246 
00247 #define  PARROTTIME 1000
00248 
00249 #define  DEFAULT_IOBASE 0x378
00250 
00251 #define  DEFAULT_CIV_ADDR 0x58
00252 
00253 #define  MAXCONNECTTIME 5000
00254 
00255 #define MAXNODESTR 300
00256 
00257 #define MAXNODELEN 16
00258 
00259 #define MAXIDENTLEN 32
00260 
00261 #define MAXPATCHCONTEXT 100
00262 
00263 #define ACTIONSIZE 32
00264 
00265 #define TELEPARAMSIZE 256
00266 
00267 #define REM_SCANTIME 100
00268 
00269 #define  DTMF_LOCAL_TIME 250
00270 #define  DTMF_LOCAL_STARTTIME 500
00271 
00272 #define  IC706_PL_MEMORY_OFFSET 50
00273 
00274 #define  VOX_ON_DEBOUNCE_COUNT 3
00275 #define  VOX_OFF_DEBOUNCE_COUNT 20
00276 #define  VOX_MAX_THRESHOLD 10000.0
00277 #define  VOX_MIN_THRESHOLD 3000.0
00278 #define  VOX_TIMEOUT_MS 5000
00279 #define  VOX_RECOVER_MS 500
00280 #define  SIMPLEX_PATCH_DELAY 25
00281 #define  SIMPLEX_PHONE_DELAY 25
00282 
00283 #define  STATPOST_PROGRAM "/usr/bin/wget,-q,--output-document=/dev/null,--no-check-certificate"
00284 
00285 #define  ALLOW_LOCAL_CHANNELS
00286 
00287 enum {REM_OFF,REM_MONITOR,REM_TX};
00288 
00289 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
00290    CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME, PLAYBACK,
00291    STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
00292    TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS,
00293    MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS,
00294    REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE, TOPKEY,
00295    TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX, PARROT,
00296    STATS_TIME_LOCAL};
00297 
00298 
00299 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
00300 
00301 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
00302 
00303 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY};
00304 
00305 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE, SOURCE_ALT};
00306 
00307 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY, DLY_PARROT};
00308 
00309 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
00310 
00311 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
00312       HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
00313 
00314 #include "asterisk.h"
00315 
00316 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211580 $")
00317 
00318 #include <signal.h>
00319 #include <stdio.h>
00320 #include <stdint.h>
00321 #include <unistd.h>
00322 #include <string.h>
00323 #include <stdlib.h>
00324 #include <search.h>
00325 #include <sys/types.h>
00326 #include <sys/stat.h>
00327 #include <errno.h>
00328 #include <dirent.h>
00329 #include <ctype.h>
00330 #include <sys/stat.h>
00331 #include <sys/time.h>
00332 #include <sys/file.h>
00333 #include <sys/ioctl.h>
00334 #ifdef HAVE_SYS_IO_H
00335 #include <sys/io.h>
00336 #endif
00337 #include <sys/vfs.h>
00338 #include <math.h>
00339 #include <dahdi/user.h>
00340 #include <dahdi/tonezone.h>
00341 #include <netinet/in.h>
00342 #include <arpa/inet.h>
00343 
00344 #include "asterisk/utils.h"
00345 #include "asterisk/lock.h"
00346 #include "asterisk/file.h"
00347 #include "asterisk/logger.h"
00348 #include "asterisk/channel.h"
00349 #include "asterisk/callerid.h"
00350 #include "asterisk/pbx.h"
00351 #include "asterisk/module.h"
00352 #include "asterisk/translate.h"
00353 #include "asterisk/features.h"
00354 #include "asterisk/options.h"
00355 #include "asterisk/cli.h"
00356 #include "asterisk/config.h"
00357 #include "asterisk/say.h"
00358 #include "asterisk/localtime.h"
00359 #include "asterisk/cdr.h"
00360 #include "asterisk/options.h"
00361 #include "asterisk/manager.h"
00362 #include "asterisk/app.h"
00363 
00364 #include <termios.h>
00365 
00366 #ifdef   NEW_ASTERISK
00367 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
00368 #endif
00369 
00370 
00371 /* Start a tone-list going */
00372 int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
00373 /*! Stop the tones from playing */
00374 void ast_playtones_stop(struct ast_channel *chan);
00375 
00376 static  char *tdesc = "Radio Repeater / Remote Base  version 0.115  5/12/2008";
00377 
00378 static char *app = "Rpt";
00379 
00380 static char *synopsis = "Radio Repeater/Remote Base Control System";
00381 
00382 static char *descrip = 
00383 "  Rpt(nodename[|options][|M][|*]):  \n"
00384 "    Radio Remote Link or Remote Base Link Endpoint Process.\n"
00385 "\n"
00386 "    Not specifying an option puts it in normal endpoint mode (where source\n"
00387 "    IP and nodename are verified).\n"
00388 "\n"
00389 "    Options are as follows:\n"
00390 "\n"
00391 "        X - Normal endpoint mode WITHOUT security check. Only specify\n"
00392 "            this if you have checked security already (like with an IAX2\n"
00393 "            user/password or something).\n"
00394 "\n"
00395 "        Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
00396 "            Reverse Autopatch. Caller is put on hold, and announcement (as\n"
00397 "            specified by the 'announce-string') is played on radio system.\n"
00398 "            Users of radio system can access autopatch, dial specified\n"
00399 "            code, and pick up call. Announce-string is list of names of\n"
00400 "            recordings, or \"PARKED\" to substitute code for un-parking,\n"
00401 "            or \"NODE\" to substitute node number.\n"
00402 "\n"
00403 "        P - Phone Control mode. This allows a regular phone user to have\n"
00404 "            full control and audio access to the radio system. For the\n"
00405 "            user to have DTMF control, the 'phone_functions' parameter\n"
00406 "            must be specified for the node in 'rpt.conf'. An additional\n"
00407 "            function (cop,6) must be listed so that PTT control is available.\n"
00408 "\n"
00409 "        D - Dumb Phone Control mode. This allows a regular phone user to\n"
00410 "            have full control and audio access to the radio system. In this\n"
00411 "            mode, the PTT is activated for the entire length of the call.\n"
00412 "            For the user to have DTMF control (not generally recomended in\n"
00413 "            this mode), the 'dphone_functions' parameter must be specified\n"
00414 "            for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
00415 "            available to the phone user.\n"
00416 "\n"
00417 "        S - Simplex Dumb Phone Control mode. This allows a regular phone user\n"
00418 "            audio-only access to the radio system. In this mode, the\n"
00419 "            transmitter is toggled on and off when the phone user presses the\n"
00420 "            funcchar (*) key on the telephone set. In addition, the transmitter\n"
00421 "            will turn off if the endchar (#) key is pressed. When a user first\n"
00422 "            calls in, the transmitter will be off, and the user can listen for\n"
00423 "            radio traffic. When the user wants to transmit, they press the *\n" 
00424 "            key, start talking, then press the * key again or the # key to turn\n"
00425 "            the transmitter off.  No other functions can be executed by the\n"
00426 "            user on the phone when this mode is selected. Note: If your\n"
00427 "            radio system is full-duplex, we recommend using either P or D\n"
00428 "            modes as they provide more flexibility.\n"
00429 "\n"
00430 "        q - Query Status. Sets channel variables and returns + 101 in plan.\n"
00431 "\n"
00432 "        M - Memory Channel Steer as MXX where XX is the memory channel number.\n"
00433 "\n"
00434 "        * - Alt Macro to execute (e.g. *7 for status)\n"
00435 "\n";
00436 ;
00437 
00438 static int debug = 0;  /* Set this >0 for extra debug output */
00439 static int nrpts = 0;
00440 
00441 static char remdtmfstr[] = "0123456789*#ABCD";
00442 
00443 enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
00444 
00445 int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
00446 
00447 #define NRPTSTAT 7
00448 
00449 struct rpt_chan_stat
00450 {
00451    struct timeval last;
00452    long long total;
00453    unsigned long count;
00454    unsigned long largest;
00455    struct timeval largest_time;
00456 };
00457 
00458 char *discstr = "!!DISCONNECT!!";
00459 char *newkeystr = "!NEWKEY!";
00460 static char *remote_rig_ft897="ft897";
00461 static char *remote_rig_rbi="rbi";
00462 static char *remote_rig_kenwood="kenwood";
00463 static char *remote_rig_tm271="tm271";
00464 static char *remote_rig_ic706="ic706";
00465 static char *remote_rig_rtx150="rtx150";
00466 static char *remote_rig_rtx450="rtx450";
00467 static char *remote_rig_ppp16="ppp16";       // parallel port programmable 16 channels
00468 
00469 #define ISRIG_RTX(x) ((!strcmp(x,remote_rig_rtx150)) || (!strcmp(x,remote_rig_rtx450)))
00470 #define  IS_XPMR(x) (!strncasecmp(x->rxchanname,"rad",3))
00471 
00472 #ifdef   OLD_ASTERISK
00473 STANDARD_LOCAL_USER;
00474 LOCAL_USER_DECL;
00475 #endif
00476 
00477 #define  MSWAIT 200
00478 #define  HANGTIME 5000
00479 #define  TOTIME 180000
00480 #define  IDTIME 300000
00481 #define  MAXRPTS 20
00482 #define MAX_STAT_LINKS 32
00483 #define POLITEID 30000
00484 #define FUNCTDELAY 1500
00485 
00486 #define  MAXXLAT 20
00487 #define  MAXXLATTIME 3
00488 
00489 #define MAX_SYSSTATES 10
00490 
00491 struct vox {
00492    float speech_energy;
00493    float noise_energy;
00494    int   enacount;
00495    char  voxena;
00496    char  lastvox;
00497    int   offdebcnt;
00498    int   ondebcnt;
00499 } ;
00500 
00501 #define  mymax(x,y) ((x > y) ? x : y)
00502 #define  mymin(x,y) ((x < y) ? x : y)
00503 
00504 struct rpt_topkey
00505 {
00506 char  node[TOPKEYMAXSTR];
00507 int   timesince;
00508 int   keyed;
00509 } ;
00510 
00511 struct rpt_xlat
00512 {
00513 char  funccharseq[MAXXLAT];
00514 char  endcharseq[MAXXLAT];
00515 char  passchars[MAXXLAT];
00516 int   funcindex;
00517 int   endindex;
00518 time_t   lastone;
00519 } ;
00520 
00521 static time_t  starttime = 0;
00522 
00523 static  pthread_t rpt_master_thread;
00524 
00525 struct rpt;
00526 
00527 struct rpt_link
00528 {
00529    struct rpt_link *next;
00530    struct rpt_link *prev;
00531    char  mode;       /* 1 if in tx mode */
00532    char  isremote;
00533    char  phonemode;
00534    char  phonevox;      /* vox the phone */
00535    char  name[MAXNODESTR]; /* identifier (routing) string */
00536    char  lasttx;
00537    char  lasttx1;
00538    char  lastrx;
00539    char  lastrealrx;
00540    char  lastrx1;
00541    char  connected;
00542    char  hasconnected;
00543    char  perma;
00544    char  thisconnected;
00545    char  outbound;
00546    char  disced;
00547    char  killme;
00548    long  elaptime;
00549    long  disctime;
00550    long  retrytimer;
00551    long  retxtimer;
00552    long  rerxtimer;
00553    int   retries;
00554    int   max_retries;
00555    int   reconnects;
00556    long long connecttime;
00557    struct ast_channel *chan;  
00558    struct ast_channel *pchan; 
00559    char  linklist[MAXLINKLIST];
00560    time_t   linklistreceived;
00561    long  linklisttimer;
00562    int   dtmfed;
00563    int linkunkeytocttimer;
00564    struct timeval lastlinktv;
00565    struct   ast_frame *lastf1,*lastf2;
00566    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00567    struct vox vox;
00568    char wasvox;
00569    int voxtotimer;
00570    char voxtostate;
00571    char newkey;
00572 #ifdef OLD_ASTERISK
00573         AST_LIST_HEAD(, ast_frame) rxq;
00574 #else
00575    AST_LIST_HEAD_NOLOCK(, ast_frame) rxq;
00576 #endif
00577 } ;
00578 
00579 struct rpt_lstat
00580 {
00581    struct   rpt_lstat *next;
00582    struct   rpt_lstat *prev;
00583    char  peer[MAXPEERSTR];
00584    char  name[MAXNODESTR];
00585    char  mode;
00586    char  outbound;
00587    char  reconnects;
00588    char  thisconnected;
00589    long long   connecttime;
00590    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00591 } ;
00592 
00593 struct rpt_tele
00594 {
00595    struct rpt_tele *next;
00596    struct rpt_tele *prev;
00597    struct rpt *rpt;
00598    struct ast_channel *chan;
00599    int   mode;
00600    struct rpt_link mylink;
00601    char param[TELEPARAMSIZE];
00602    intptr_t submode;
00603    uintptr_t  parrot;
00604    pthread_t threadid;
00605 } ;
00606 
00607 struct function_table_tag
00608 {
00609    char action[ACTIONSIZE];
00610    int (*function)(struct rpt *myrpt, char *param, char *digitbuf, 
00611       int command_source, struct rpt_link *mylink);
00612 } ;
00613 
00614 /* Used to store the morse code patterns */
00615 
00616 struct morse_bits
00617 {       
00618    int len;
00619    int ddcomb;
00620 } ;
00621 
00622 struct telem_defaults
00623 {
00624    char name[20];
00625    char value[80];
00626 } ;
00627 
00628 
00629 struct sysstate
00630 {
00631    char txdisable;
00632    char totdisable;
00633    char linkfundisable;
00634    char autopatchdisable;
00635    char schedulerdisable;
00636    char userfundisable;
00637    char alternatetail;
00638 };
00639 
00640 /* rpt cmd support */
00641 #define CMD_DEPTH 1
00642 #define CMD_STATE_IDLE 0
00643 #define CMD_STATE_BUSY 1
00644 #define CMD_STATE_READY 2
00645 #define CMD_STATE_EXECUTING 3
00646 
00647 struct rpt_cmd_struct
00648 {
00649     int state;
00650     int functionNumber;
00651     char param[MAXDTMF];
00652     char digits[MAXDTMF];
00653     int command_source;
00654 };
00655 
00656 static struct rpt
00657 {
00658    ast_mutex_t lock;
00659    ast_mutex_t remlock;
00660    ast_mutex_t statpost_lock;
00661    struct ast_config *cfg;
00662    char reload;
00663    char xlink;                         // cross link state of a share repeater/remote radio
00664    unsigned int statpost_seqno;
00665 
00666    char *name;
00667    char *rxchanname;
00668    char *txchanname;
00669    char remote;
00670    char *remoterig;
00671    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00672    unsigned int scram;
00673 
00674    struct {
00675       char *ourcontext;
00676       char *ourcallerid;
00677       char *acctcode;
00678       char *ident;
00679       char *tonezone;
00680       char simple;
00681       char *functions;
00682       char *link_functions;
00683       char *phone_functions;
00684       char *dphone_functions;
00685       char *alt_functions;
00686       char *nodes;
00687       char *extnodes;
00688       char *extnodefile;
00689       int hangtime;
00690       int althangtime;
00691       int totime;
00692       int idtime;
00693       int tailmessagetime;
00694       int tailsquashedtime;
00695       int duplex;
00696       int politeid;
00697       char *tailmessages[500];
00698       int tailmessagemax;
00699       char  *memory;
00700       char  *macro;
00701       char  *tonemacro;
00702       char  *startupmacro;
00703       int iobase;
00704       char *ioport;
00705       char funcchar;
00706       char endchar;
00707       char nobusyout;
00708       char notelemtx;
00709       char propagate_dtmf;
00710       char propagate_phonedtmf;
00711       char linktolink;
00712       unsigned char civaddr;
00713       struct rpt_xlat inxlat;
00714       struct rpt_xlat outxlat;
00715       char *archivedir;
00716       int authlevel;
00717       char *csstanzaname;
00718       char *skedstanzaname;
00719       char *txlimitsstanzaname;
00720       long monminblocks;
00721       int remoteinacttimeout;
00722       int remotetimeout;
00723       int remotetimeoutwarning;
00724       int remotetimeoutwarningfreq;
00725       int sysstate_cur;
00726       struct sysstate s[MAX_SYSSTATES];
00727       char parrotmode;
00728       int parrottime;
00729       char *rptnode;
00730       char remote_mars;
00731       int voxtimeout_ms;
00732       int voxrecover_ms;
00733       int simplexpatchdelay;
00734       int simplexphonedelay;
00735       char *statpost_program;
00736       char *statpost_url;
00737    } p;
00738    struct rpt_link links;
00739    int unkeytocttimer;
00740    time_t lastkeyedtime;
00741    time_t lasttxkeyedtime;
00742    char keyed;
00743    char txkeyed;
00744    char exttx;
00745    char localtx;
00746    char remoterx;
00747    char remotetx;
00748    char remoteon;
00749    char remtxfreqok;
00750    char tounkeyed;
00751    char tonotify;
00752    char dtmfbuf[MAXDTMF];
00753    char macrobuf[MAXMACRO];
00754    char rem_dtmfbuf[MAXDTMF];
00755    char lastdtmfcommand[MAXDTMF];
00756    char cmdnode[50];
00757    char nowchan;                 // channel now
00758    char waschan;                 // channel selected initially or by command
00759    char bargechan;                  // barge in channel
00760    char macropatch;              // autopatch via tonemacro state
00761    char parrotstate;
00762    int  parrottimer;
00763    unsigned int parrotcnt;
00764    struct ast_channel *rxchannel,*txchannel, *monchannel, *parrotchannel;
00765    struct ast_channel *pchannel,*txpchannel, *dahdirxchannel, *dahditxchannel;
00766    struct ast_channel *voxchannel;
00767    struct ast_frame *lastf1,*lastf2;
00768    struct rpt_tele tele;
00769    struct timeval lasttv,curtv;
00770    pthread_t rpt_call_thread,rpt_thread;
00771    time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
00772    int calldigittimer;
00773    int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
00774    int mustid,tailid;
00775    int tailevent;
00776    int telemrefcount;
00777    int dtmfidx,rem_dtmfidx;
00778    int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
00779    int totalexecdcommands, dailyexecdcommands;
00780    long  retxtimer;
00781    long  rerxtimer;
00782    long long totaltxtime;
00783    char mydtmf;
00784    char exten[AST_MAX_EXTENSION];
00785    char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
00786    char offset;
00787    char powerlevel;
00788    char txplon;
00789    char rxplon;
00790    char remmode;
00791    char tunerequest;
00792    char hfscanmode;
00793    int hfscanstatus;
00794    char hfscanstop;
00795    char lastlinknode[MAXNODESTR];
00796    char savednodes[MAXNODESTR];
00797    int stopgen;
00798    char patchfarenddisconnect;
00799    char patchnoct;
00800    char patchquiet;
00801    char patchcontext[MAXPATCHCONTEXT];
00802    int patchdialtime;
00803    int macro_longest;
00804    int phone_longestfunc;
00805    int alt_longestfunc;
00806    int dphone_longestfunc;
00807    int link_longestfunc;
00808    int longestfunc;
00809    int longestnode;
00810    int threadrestarts;     
00811    int tailmessagen;
00812    time_t disgorgetime;
00813    time_t lastthreadrestarttime;
00814    long  macrotimer;
00815    char  lastnodewhichkeyedusup[MAXNODESTR];
00816    int   dtmf_local_timer;
00817    char  dtmf_local_str[100];
00818    struct ast_filestream *monstream,*parrotstream;
00819    char  loginuser[50];
00820    char  loginlevel[10];
00821    long  authtelltimer;
00822    long  authtimer;
00823    int iofd;
00824    time_t start_time,last_activity_time;
00825    char  lasttone[32];
00826    struct rpt_tele *active_telem;
00827    struct   rpt_topkey topkey[TOPKEYN];
00828    int topkeystate;
00829    time_t topkeytime;
00830    int topkeylong;
00831    struct vox vox;
00832    char wasvox;
00833    int voxtotimer;
00834    char voxtostate;
00835    int linkposttimer;         
00836    int keyposttimer;       
00837    char newkey;
00838    char inpadtest;
00839 #ifdef OLD_ASTERISK
00840    AST_LIST_HEAD(, ast_frame) txq;
00841 #else
00842    AST_LIST_HEAD_NOLOCK(, ast_frame) txq;
00843 #endif
00844    char txrealkeyed;
00845 #ifdef   __RPT_NOTCH
00846    struct rptfilter
00847    {
00848       char  desc[100];
00849       float x0;
00850       float x1;
00851       float x2;
00852       float y0;
00853       float y1;
00854       float y2;
00855       float gain;
00856       float const0;
00857       float const1;
00858       float const2;
00859    } filters[MAXFILTERS];
00860 #endif
00861 #ifdef   _MDC_DECODE_H_
00862    mdc_decoder_t *mdc;
00863    unsigned short lastunit;
00864 #endif
00865    struct rpt_cmd_struct cmdAction;
00866 } rpt_vars[MAXRPTS]; 
00867 
00868 struct nodelog {
00869 struct nodelog *next;
00870 struct nodelog *prev;
00871 time_t   timestamp;
00872 char archivedir[MAXNODESTR];
00873 char str[MAXNODESTR * 2];
00874 } nodelog;
00875 
00876 static int service_scan(struct rpt *myrpt);
00877 static int set_mode_ft897(struct rpt *myrpt, char newmode);
00878 static int set_mode_ic706(struct rpt *myrpt, char newmode);
00879 static int simple_command_ft897(struct rpt *myrpt, char command);
00880 static int setrem(struct rpt *myrpt);
00881 static int setrtx_check(struct rpt *myrpt);
00882 static int channel_revert(struct rpt *myrpt);
00883 static int channel_steer(struct rpt *myrpt, char *data);
00884 
00885 AST_MUTEX_DEFINE_STATIC(nodeloglock);
00886 
00887 AST_MUTEX_DEFINE_STATIC(nodelookuplock);
00888 
00889 #ifdef   APP_RPT_LOCK_DEBUG
00890 
00891 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
00892 
00893 #define  MAXLOCKTHREAD 100
00894 
00895 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
00896 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
00897 
00898 struct lockthread
00899 {
00900    pthread_t id;
00901    int lockcount;
00902    int lastlock;
00903    int lastunlock;
00904 } lockthreads[MAXLOCKTHREAD];
00905 
00906 
00907 struct by_lightning
00908 {
00909    int line;
00910    struct timeval tv;
00911    struct rpt *rpt;
00912    struct lockthread lockthread;
00913 } lock_ring[32];
00914 
00915 int lock_ring_index = 0;
00916 
00917 AST_MUTEX_DEFINE_STATIC(locklock);
00918 
00919 static struct lockthread *get_lockthread(pthread_t id)
00920 {
00921 int   i;
00922 
00923    for(i = 0; i < MAXLOCKTHREAD; i++)
00924    {
00925       if (lockthreads[i].id == id) return(&lockthreads[i]);
00926    }
00927    return(NULL);
00928 }
00929 
00930 static struct lockthread *put_lockthread(pthread_t id)
00931 {
00932 int   i;
00933 
00934    for(i = 0; i < MAXLOCKTHREAD; i++)
00935    {
00936       if (lockthreads[i].id == id)
00937          return(&lockthreads[i]);
00938    }
00939    for(i = 0; i < MAXLOCKTHREAD; i++)
00940    {
00941       if (!lockthreads[i].id)
00942       {
00943          lockthreads[i].lockcount = 0;
00944          lockthreads[i].lastlock = 0;
00945          lockthreads[i].lastunlock = 0;
00946          lockthreads[i].id = id;
00947          return(&lockthreads[i]);
00948       }
00949    }
00950    return(NULL);
00951 }
00952 
00953 
00954 static void rpt_mutex_spew(void)
00955 {
00956    struct by_lightning lock_ring_copy[32];
00957    int lock_ring_index_copy;
00958    int i,j;
00959    long long diff;
00960    char a[100];
00961    struct timeval lasttv;
00962 
00963    ast_mutex_lock(&locklock);
00964    memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
00965    lock_ring_index_copy = lock_ring_index;
00966    ast_mutex_unlock(&locklock);
00967 
00968    lasttv.tv_sec = lasttv.tv_usec = 0;
00969    for(i = 0 ; i < 32 ; i++)
00970    {
00971       j = (i + lock_ring_index_copy) % 32;
00972       strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
00973          localtime(&lock_ring_copy[j].tv.tv_sec));
00974       diff = 0;
00975       if(lasttv.tv_sec)
00976       {
00977          diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
00978             * 1000000;
00979          diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
00980       }
00981       lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
00982       lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
00983       if (!lock_ring_copy[j].tv.tv_sec) continue;
00984       if (lock_ring_copy[j].line < 0)
00985       {
00986          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00987             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);
00988       }
00989       else
00990       {
00991          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00992             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);
00993       }
00994    }
00995 }
00996 
00997 
00998 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
00999 {
01000 struct lockthread *t;
01001 pthread_t id;
01002 
01003    id = pthread_self();
01004    ast_mutex_lock(&locklock);
01005    t = put_lockthread(id);
01006    if (!t)
01007    {
01008       ast_mutex_unlock(&locklock);
01009       return;
01010    }
01011    if (t->lockcount)
01012    {
01013       int lastline = t->lastlock;
01014       ast_mutex_unlock(&locklock);
01015       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);
01016       rpt_mutex_spew();
01017       return;
01018    }
01019    t->lastlock = line;
01020    t->lockcount = 1;
01021    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
01022    lock_ring[lock_ring_index].rpt = myrpt;
01023    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
01024    lock_ring[lock_ring_index++].line = line;
01025    if(lock_ring_index == 32)
01026       lock_ring_index = 0;
01027    ast_mutex_unlock(&locklock);
01028    ast_mutex_lock(lockp);
01029 }
01030 
01031 
01032 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
01033 {
01034 struct lockthread *t;
01035 pthread_t id;
01036 
01037    id = pthread_self();
01038    ast_mutex_lock(&locklock);
01039    t = put_lockthread(id);
01040    if (!t)
01041    {
01042       ast_mutex_unlock(&locklock);
01043       return;
01044    }
01045    if (!t->lockcount)
01046    {
01047       int lastline = t->lastunlock;
01048       ast_mutex_unlock(&locklock);
01049       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);
01050       rpt_mutex_spew();
01051       return;
01052    }
01053    t->lastunlock = line;
01054    t->lockcount = 0;
01055    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
01056    lock_ring[lock_ring_index].rpt = myrpt;
01057    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
01058    lock_ring[lock_ring_index++].line = -line;
01059    if(lock_ring_index == 32)
01060       lock_ring_index = 0;
01061    ast_mutex_unlock(&locklock);
01062    ast_mutex_unlock(lockp);
01063 }
01064 
01065 #else  /* APP_RPT_LOCK_DEBUG */
01066 
01067 #define rpt_mutex_lock(x) ast_mutex_lock(x)
01068 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
01069 
01070 #endif  /* APP_RPT_LOCK_DEBUG */
01071 
01072 /*
01073 * Return 1 if rig is multimode capable
01074 */
01075 
01076 static int multimode_capable(struct rpt *myrpt)
01077 {
01078    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
01079       return 1;
01080    if(!strcmp(myrpt->remoterig, remote_rig_ic706))
01081       return 1;
01082    return 0;
01083 }  
01084 
01085 static void voxinit_rpt(struct rpt *myrpt,char enable)
01086 {
01087 
01088    myrpt->vox.speech_energy = 0.0;
01089    myrpt->vox.noise_energy = 0.0;
01090    myrpt->vox.enacount = 0;
01091    myrpt->vox.voxena = 0;
01092    if (!enable) myrpt->vox.voxena = -1;
01093    myrpt->vox.lastvox = 0;
01094    myrpt->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
01095    myrpt->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
01096    myrpt->wasvox = 0;
01097    myrpt->voxtotimer = 0;
01098    myrpt->voxtostate = 0;
01099 }
01100 
01101 static void voxinit_link(struct rpt_link *mylink,char enable)
01102 {
01103 
01104    mylink->vox.speech_energy = 0.0;
01105    mylink->vox.noise_energy = 0.0;
01106    mylink->vox.enacount = 0;
01107    mylink->vox.voxena = 0;
01108    if (!enable) mylink->vox.voxena = -1;
01109    mylink->vox.lastvox = 0;
01110    mylink->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
01111    mylink->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
01112    mylink->wasvox = 0;
01113    mylink->voxtotimer = 0;
01114    mylink->voxtostate = 0;
01115 }
01116 
01117 static int dovox(struct vox *v,short *buf,int bs)
01118 {
01119 
01120    int i;
01121    float esquare = 0.0;
01122    float energy = 0.0;
01123    float threshold = 0.0;
01124    
01125    if (v->voxena < 0) return(v->lastvox);
01126    for(i = 0; i < bs; i++)
01127    {
01128       esquare += (float) buf[i] * (float) buf[i];
01129    }
01130    energy = sqrt(esquare);
01131 
01132    if (energy >= v->speech_energy)
01133       v->speech_energy += (energy - v->speech_energy) / 4;
01134    else
01135       v->speech_energy += (energy - v->speech_energy) / 64;
01136 
01137    if (energy >= v->noise_energy)
01138       v->noise_energy += (energy - v->noise_energy) / 64;
01139    else
01140       v->noise_energy += (energy - v->noise_energy) / 4;
01141    
01142    if (v->voxena) threshold = v->speech_energy / 8;
01143    else
01144    {
01145       threshold = mymax(v->speech_energy / 16,v->noise_energy * 2);
01146       threshold = mymin(threshold,VOX_MAX_THRESHOLD);
01147    }
01148    threshold = mymax(threshold,VOX_MIN_THRESHOLD);
01149    if (energy > threshold)
01150    {
01151       if (v->voxena) v->noise_energy *= 0.75;
01152       v->voxena = 1;
01153    } else   v->voxena = 0;
01154    if (v->lastvox != v->voxena)
01155    {
01156       if (v->enacount++ >= ((v->lastvox) ? v->offdebcnt : v->ondebcnt))
01157       {
01158          v->lastvox = v->voxena;
01159          v->enacount = 0;
01160       }
01161    } else v->enacount = 0;
01162    return(v->lastvox);
01163 }
01164 
01165 
01166 
01167 
01168 /*
01169 * CLI extensions
01170 */
01171 
01172 /* Debug mode */
01173 static int rpt_do_debug(int fd, int argc, char *argv[]);
01174 static int rpt_do_dump(int fd, int argc, char *argv[]);
01175 static int rpt_do_stats(int fd, int argc, char *argv[]);
01176 static int rpt_do_lstats(int fd, int argc, char *argv[]);
01177 static int rpt_do_nodes(int fd, int argc, char *argv[]);
01178 static int rpt_do_local_nodes(int fd, int argc, char *argv[]);
01179 static int rpt_do_reload(int fd, int argc, char *argv[]);
01180 static int rpt_do_restart(int fd, int argc, char *argv[]);
01181 static int rpt_do_fun(int fd, int argc, char *argv[]);
01182 static int rpt_do_fun1(int fd, int argc, char *argv[]);
01183 static int rpt_do_cmd(int fd, int argc, char *argv[]);
01184 
01185 static char debug_usage[] =
01186 "Usage: rpt debug level {0-7}\n"
01187 "       Enables debug messages in app_rpt\n";
01188 
01189 static char dump_usage[] =
01190 "Usage: rpt dump <nodename>\n"
01191 "       Dumps struct debug info to log\n";
01192 
01193 static char dump_stats[] =
01194 "Usage: rpt stats <nodename>\n"
01195 "       Dumps node statistics to console\n";
01196 
01197 static char dump_lstats[] =
01198 "Usage: rpt lstats <nodename>\n"
01199 "       Dumps link statistics to console\n";
01200 
01201 static char dump_nodes[] =
01202 "Usage: rpt nodes <nodename>\n"
01203 "       Dumps a list of directly and indirectly connected nodes to the console\n";
01204 
01205 static char usage_local_nodes[] =
01206 "Usage: rpt localnodes\n"
01207 "       Dumps a list of the locally configured node numbers to the console.\n";
01208 
01209 static char reload_usage[] =
01210 "Usage: rpt reload\n"
01211 "       Reloads app_rpt running config parameters\n";
01212 
01213 static char restart_usage[] =
01214 "Usage: rpt restart\n"
01215 "       Restarts app_rpt\n";
01216 
01217 static char fun_usage[] =
01218 "Usage: rpt fun <nodename> <command>\n"
01219 "       Send a DTMF function to a node\n";
01220 
01221 static char cmd_usage[] =
01222 "Usage: rpt cmd <nodename> <cmd-name> <cmd-index> <cmd-args.\n"
01223 "       Send a command to a node.\n        i.e. rpt cmd 2000 ilink 3 2001\n";
01224 
01225 #ifndef  NEW_ASTERISK
01226 
01227 static struct ast_cli_entry  cli_debug =
01228         { { "rpt", "debug", "level" }, rpt_do_debug, 
01229       "Enable app_rpt debugging", debug_usage };
01230 
01231 static struct ast_cli_entry  cli_dump =
01232         { { "rpt", "dump" }, rpt_do_dump,
01233       "Dump app_rpt structs for debugging", dump_usage };
01234 
01235 static struct ast_cli_entry  cli_stats =
01236         { { "rpt", "stats" }, rpt_do_stats,
01237       "Dump node statistics", dump_stats };
01238 
01239 static struct ast_cli_entry  cli_nodes =
01240         { { "rpt", "nodes" }, rpt_do_nodes,
01241       "Dump node list", dump_nodes };
01242 
01243 static struct ast_cli_entry  cli_local_nodes =
01244         { { "rpt", "localnodes" }, rpt_do_local_nodes,
01245       "Dump list of local node numbers", usage_local_nodes };
01246 
01247 static struct ast_cli_entry  cli_lstats =
01248         { { "rpt", "lstats" }, rpt_do_lstats,
01249       "Dump link statistics", dump_lstats };
01250 
01251 static struct ast_cli_entry  cli_reload =
01252         { { "rpt", "reload" }, rpt_do_reload,
01253       "Reload app_rpt config", reload_usage };
01254 
01255 static struct ast_cli_entry  cli_restart =
01256         { { "rpt", "restart" }, rpt_do_restart,
01257       "Restart app_rpt", restart_usage };
01258 
01259 static struct ast_cli_entry  cli_fun =
01260         { { "rpt", "fun" }, rpt_do_fun,
01261       "Execute a DTMF function", fun_usage };
01262 
01263 static struct ast_cli_entry  cli_fun1 =
01264         { { "rpt", "fun1" }, rpt_do_fun1,
01265       "Execute a DTMF function", fun_usage };
01266 
01267 static struct ast_cli_entry  cli_cmd =
01268         { { "rpt", "cmd" }, rpt_do_cmd,
01269       "Execute a DTMF function", cmd_usage };
01270 
01271 #endif
01272 
01273 /*
01274 * Telemetry defaults
01275 */
01276 
01277 
01278 static struct telem_defaults tele_defs[] = {
01279    {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
01280    {"ct2","|t(660,880,150,3072)"},
01281    {"ct3","|t(440,0,150,3072)"},
01282    {"ct4","|t(550,0,150,3072)"},
01283    {"ct5","|t(660,0,150,3072)"},
01284    {"ct6","|t(880,0,150,3072)"},
01285    {"ct7","|t(660,440,150,3072)"},
01286    {"ct8","|t(700,1100,150,3072)"},
01287    {"remotemon","|t(1600,0,75,2048)"},
01288    {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
01289    {"cmdmode","|t(900,904,200,2048)"},
01290    {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
01291 } ;
01292 
01293 /*
01294 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
01295 */
01296 
01297 static int setrbi(struct rpt *myrpt);
01298 static int set_ft897(struct rpt *myrpt);
01299 static int set_ic706(struct rpt *myrpt);
01300 static int setkenwood(struct rpt *myrpt);
01301 static int set_tm271(struct rpt *myrpt);
01302 static int setrbi_check(struct rpt *myrpt);
01303 
01304 
01305 
01306 /*
01307 * Define function protos for function table here
01308 */
01309 
01310 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01311 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01312 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01313 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01314 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01315 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01316 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01317 static int function_playback(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01318 /*
01319 * Function table
01320 */
01321 
01322 static struct function_table_tag function_table[] = {
01323    {"cop", function_cop},
01324    {"autopatchup", function_autopatchup},
01325    {"autopatchdn", function_autopatchdn},
01326    {"ilink", function_ilink},
01327    {"status", function_status},
01328    {"remote", function_remote},
01329    {"macro", function_macro},
01330    {"playback", function_playback}
01331 } ;
01332 
01333 static long diskavail(struct rpt *myrpt)
01334 {
01335 struct   statfs statfsbuf;
01336 
01337    if (!myrpt->p.archivedir) return(0);
01338    if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
01339    {
01340       ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
01341          myrpt->p.archivedir,myrpt->name);
01342       return(-1);
01343    }
01344    return(statfsbuf.f_bavail);
01345 }
01346 
01347 static void flush_telem(struct rpt *myrpt)
01348 {
01349    struct rpt_tele *telem;
01350    if(debug > 2)
01351       ast_log(LOG_NOTICE, "flush_telem()!!");
01352    rpt_mutex_lock(&myrpt->lock);
01353    telem = myrpt->tele.next;
01354    while(telem != &myrpt->tele)
01355    {
01356       if (telem->mode != SETREMOTE) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
01357       telem = telem->next;
01358    }
01359    rpt_mutex_unlock(&myrpt->lock);
01360 }
01361 /*
01362    return via error priority
01363 */
01364 static int priority_jump(struct rpt *myrpt, struct ast_channel *chan)
01365 {
01366    int res=0;
01367 
01368    // if (ast_test_flag(&flags,OPT_JUMP) && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
01369    if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
01370       res = 0;
01371    } else {
01372       res = -1;
01373    }
01374    return res;
01375 }
01376 /*
01377 */
01378 static int linkcount(struct rpt *myrpt)
01379 {
01380    struct   rpt_link *l;
01381    char *reverse_patch_state;
01382    int numoflinks;
01383 
01384    reverse_patch_state = "DOWN";
01385    numoflinks = 0;
01386    l = myrpt->links.next;
01387    while(l && (l != &myrpt->links)){
01388       if(numoflinks >= MAX_STAT_LINKS){
01389          ast_log(LOG_WARNING,
01390          "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
01391          break;
01392       }
01393       //if (l->name[0] == '0'){ /* Skip '0' nodes */
01394       // reverse_patch_state = "UP";
01395       // l = l->next;
01396       // continue;
01397       //}
01398       numoflinks++;
01399     
01400       l = l->next;
01401    }
01402    ast_log(LOG_NOTICE, "numoflinks=%i\n",numoflinks);
01403    return numoflinks;
01404 }
01405 /*
01406  * Retrieve a memory channel
01407  * Return 0 if sucessful,
01408  * -1 if channel not found,
01409  *  1 if parse error
01410  */
01411 static int retreive_memory(struct rpt *myrpt, char *memory)
01412 {
01413    char tmp[30], *s, *s1, *val;
01414 
01415    if (debug)ast_log(LOG_NOTICE, "memory=%s block=%s\n",memory,myrpt->p.memory);
01416 
01417    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, memory);
01418    if (!val){
01419       return -1;
01420    }        
01421    strncpy(tmp,val,sizeof(tmp) - 1);
01422    tmp[sizeof(tmp)-1] = 0;
01423 
01424    s = strchr(tmp,',');
01425    if (!s)
01426       return 1; 
01427    *s++ = 0;
01428    s1 = strchr(s,',');
01429    if (!s1)
01430       return 1;
01431    *s1++ = 0;
01432    strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
01433    strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
01434    strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
01435    myrpt->remmode = REM_MODE_FM;
01436    myrpt->offset = REM_SIMPLEX;
01437    myrpt->powerlevel = REM_MEDPWR;
01438    myrpt->txplon = myrpt->rxplon = 0;
01439    while(*s1){
01440       switch(*s1++){
01441          case 'A':
01442          case 'a':
01443             strcpy(myrpt->rxpl, "100.0");
01444             strcpy(myrpt->txpl, "100.0");
01445             myrpt->remmode = REM_MODE_AM; 
01446             break;
01447          case 'B':
01448          case 'b':
01449             strcpy(myrpt->rxpl, "100.0");
01450             strcpy(myrpt->txpl, "100.0");
01451             myrpt->remmode = REM_MODE_LSB;
01452             break;
01453          case 'F':
01454             myrpt->remmode = REM_MODE_FM;
01455             break;
01456          case 'L':
01457          case 'l':
01458             myrpt->powerlevel = REM_LOWPWR;
01459             break;               
01460          case 'H':
01461          case 'h':
01462             myrpt->powerlevel = REM_HIPWR;
01463             break;
01464                
01465          case 'M':
01466          case 'm':
01467             myrpt->powerlevel = REM_MEDPWR;
01468             break;
01469                   
01470          case '-':
01471             myrpt->offset = REM_MINUS;
01472             break;
01473                   
01474          case '+':
01475             myrpt->offset = REM_PLUS;
01476             break;
01477                   
01478          case 'S':
01479          case 's':
01480             myrpt->offset = REM_SIMPLEX;
01481             break;
01482                   
01483          case 'T':
01484          case 't':
01485             myrpt->txplon = 1;
01486             break;
01487                   
01488          case 'R':
01489          case 'r':
01490             myrpt->rxplon = 1;
01491             break;
01492 
01493          case 'U':
01494          case 'u':
01495             strcpy(myrpt->rxpl, "100.0");
01496             strcpy(myrpt->txpl, "100.0");
01497             myrpt->remmode = REM_MODE_USB;
01498             break;
01499          default:
01500             return 1;
01501       }
01502    }
01503    return 0;
01504 }
01505 /*
01506 
01507 */
01508 static void birdbath(struct rpt *myrpt)
01509 {
01510    struct rpt_tele *telem;
01511    if(debug > 2)
01512       ast_log(LOG_NOTICE, "birdbath!!");
01513    rpt_mutex_lock(&myrpt->lock);
01514    telem = myrpt->tele.next;
01515    while(telem != &myrpt->tele)
01516    {
01517       if (telem->mode == PARROT) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
01518       telem = telem->next;
01519    }
01520    rpt_mutex_unlock(&myrpt->lock);
01521 }
01522 
01523 static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
01524 {
01525 struct        rpt_link *l;
01526 
01527        l = myrpt->links.next;
01528        /* go thru all the links */
01529        while(l != &myrpt->links)
01530        {
01531                if (!l->phonemode)
01532                {
01533                        l = l->next;
01534                        continue;
01535                }
01536                /* dont send to self */
01537                if (mylink && (l == mylink))
01538                {
01539                        l = l->next;
01540                        continue;
01541                }
01542 #ifdef   NEW_ASTERISK
01543                if (l->chan) ast_senddigit(l->chan,c,0);
01544 #else
01545                if (l->chan) ast_senddigit(l->chan,c);
01546 #endif
01547                l = l->next;
01548        }
01549        return;
01550 }
01551 
01552 /* node logging function */
01553 static void donodelog(struct rpt *myrpt,char *str)
01554 {
01555 struct nodelog *nodep;
01556 char  datestr[100];
01557 
01558    if (!myrpt->p.archivedir) return;
01559    nodep = (struct nodelog *)ast_malloc(sizeof(struct nodelog));
01560    if (nodep == NULL)
01561    {
01562       ast_log(LOG_ERROR,"Cannot get memory for node log");
01563       return;
01564    }
01565    time(&nodep->timestamp);
01566    strncpy(nodep->archivedir,myrpt->p.archivedir,
01567       sizeof(nodep->archivedir) - 1);
01568    strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
01569       localtime(&nodep->timestamp));
01570    snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
01571       myrpt->name,datestr,str);
01572    ast_mutex_lock(&nodeloglock);
01573    insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
01574    ast_mutex_unlock(&nodeloglock);
01575 }
01576 
01577 /* must be called locked */
01578 static void do_dtmf_local(struct rpt *myrpt, char c)
01579 {
01580 int   i;
01581 char  digit;
01582 static const char* dtmf_tones[] = {
01583    "!941+1336/200,!0/200", /* 0 */
01584    "!697+1209/200,!0/200", /* 1 */
01585    "!697+1336/200,!0/200", /* 2 */
01586    "!697+1477/200,!0/200", /* 3 */
01587    "!770+1209/200,!0/200", /* 4 */
01588    "!770+1336/200,!0/200", /* 5 */
01589    "!770+1477/200,!0/200", /* 6 */
01590    "!852+1209/200,!0/200", /* 7 */
01591    "!852+1336/200,!0/200", /* 8 */
01592    "!852+1477/200,!0/200", /* 9 */
01593    "!697+1633/200,!0/200", /* A */
01594    "!770+1633/200,!0/200", /* B */
01595    "!852+1633/200,!0/200", /* C */
01596    "!941+1633/200,!0/200", /* D */
01597    "!941+1209/200,!0/200", /* * */
01598    "!941+1477/200,!0/200" };  /* # */
01599 
01600 
01601    if (c)
01602    {
01603       snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
01604       if (!myrpt->dtmf_local_timer) 
01605           myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
01606    }
01607    /* if at timeout */
01608    if (myrpt->dtmf_local_timer == 1)
01609    {
01610       if(debug > 6)
01611          ast_log(LOG_NOTICE,"time out dtmf_local_timer=%i\n",myrpt->dtmf_local_timer);
01612 
01613       /* if anything in the string */
01614       if (myrpt->dtmf_local_str[0])
01615       {
01616          digit = myrpt->dtmf_local_str[0];
01617          myrpt->dtmf_local_str[0] = 0;
01618          for(i = 1; myrpt->dtmf_local_str[i]; i++)
01619          {
01620             myrpt->dtmf_local_str[i - 1] =
01621                myrpt->dtmf_local_str[i];
01622          }
01623          myrpt->dtmf_local_str[i - 1] = 0;
01624          myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
01625          rpt_mutex_unlock(&myrpt->lock);
01626          if (digit >= '0' && digit <='9')
01627             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
01628          else if (digit >= 'A' && digit <= 'D')
01629             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
01630          else if (digit == '*')
01631             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
01632          else if (digit == '#')
01633             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
01634          else {
01635             /* not handled */
01636             ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name);
01637          }
01638          rpt_mutex_lock(&myrpt->lock);
01639       }
01640       else
01641       {
01642          myrpt->dtmf_local_timer = 0;
01643       }
01644    }
01645 }
01646 
01647 static int setdtr(int fd, int enable)
01648 {
01649 struct termios mode;
01650 
01651    if (fd < 0) return -1;
01652    if (tcgetattr(fd, &mode)) {
01653       ast_log(LOG_WARNING, "Unable to get serial parameters for dtr: %s\n", strerror(errno));
01654       return -1;
01655    }
01656    if (enable)
01657    {
01658       cfsetspeed(&mode, B9600);
01659    }
01660    else
01661    {
01662       cfsetspeed(&mode, B0);
01663       usleep(100000);
01664    }
01665    if (tcsetattr(fd, TCSADRAIN, &mode)) {
01666       ast_log(LOG_WARNING, "Unable to set serial parameters for dtr: %s\n", strerror(errno));
01667       return -1;
01668    }
01669    if (enable) usleep(100000);
01670    return 0;
01671 }
01672 
01673 static int openserial(struct rpt *myrpt,char *fname)
01674 {
01675    struct termios mode;
01676    int fd;
01677 
01678    fd = open(fname,O_RDWR);
01679    if (fd == -1)
01680    {
01681       ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
01682       return -1;
01683    }
01684    memset(&mode, 0, sizeof(mode));
01685    if (tcgetattr(fd, &mode)) {
01686       ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
01687       return -1;
01688    }
01689 #ifndef  SOLARIS
01690    cfmakeraw(&mode);
01691 #else
01692         mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
01693                         |INLCR|IGNCR|ICRNL|IXON);
01694         mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
01695         mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
01696         mode.c_cflag |= CS8;
01697    mode.c_cc[VTIME] = 3;
01698    mode.c_cc[VMIN] = 1; 
01699 #endif
01700 
01701    cfsetispeed(&mode, B9600);
01702    cfsetospeed(&mode, B9600);
01703    if (tcsetattr(fd, TCSANOW, &mode)) 
01704       ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
01705    if(!strcmp(myrpt->remoterig, remote_rig_kenwood)) setdtr(fd,0); 
01706    usleep(100000);
01707    if (debug)ast_log(LOG_NOTICE,"Opened serial port %s\n",fname);
01708    return(fd); 
01709 }
01710 
01711 static void mdc1200_notify(struct rpt *myrpt,char *fromnode, unsigned int unit)
01712 {
01713    if (!fromnode)
01714    {
01715       ast_verbose("Got MDC-1200 ID %04X from local system (%s)\n",
01716          unit,myrpt->name);
01717    }
01718    else
01719    {
01720       ast_verbose("Got MDC-1200 ID %04X from node %s (%s)\n",
01721          unit,fromnode,myrpt->name);
01722    }
01723 }
01724 
01725 #ifdef   _MDC_DECODE_H_
01726 
01727 static void mdc1200_send(struct rpt *myrpt, unsigned int unit)
01728 {
01729 struct rpt_link *l;
01730 struct   ast_frame wf;
01731 char  str[200];
01732 
01733 
01734    sprintf(str,"I %s %04X",myrpt->name,unit);
01735 
01736    wf.frametype = AST_FRAME_TEXT;
01737    wf.subclass = 0;
01738    wf.offset = 0;
01739    wf.mallocd = 0;
01740    wf.datalen = strlen(str) + 1;
01741    wf.samples = 0;
01742 
01743 
01744    l = myrpt->links.next;
01745    /* otherwise, send it to all of em */
01746    while(l != &myrpt->links)
01747    {
01748       if (l->name[0] == '0') 
01749       {
01750          l = l->next;
01751          continue;
01752       }
01753       wf.data = str;
01754       if (l->chan) ast_write(l->chan,&wf); 
01755       l = l->next;
01756    }
01757    return;
01758 }
01759 
01760 #endif
01761 
01762 static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
01763 {
01764 time_t   now;
01765 int   gotone;
01766 
01767    time(&now);
01768    gotone = 0;
01769    /* if too much time, reset the skate machine */
01770    if ((now - xlat->lastone) > MAXXLATTIME)
01771    {
01772       xlat->funcindex = xlat->endindex = 0;
01773    }
01774    if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
01775    {
01776       time(&xlat->lastone);
01777       gotone = 1;
01778       if (!xlat->funccharseq[xlat->funcindex])
01779       {
01780          xlat->funcindex = xlat->endindex = 0;
01781          return(myrpt->p.funcchar);
01782       }
01783    } else xlat->funcindex = 0;
01784    if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
01785    {
01786       time(&xlat->lastone);
01787       gotone = 1;
01788       if (!xlat->endcharseq[xlat->endindex])
01789       {
01790          xlat->funcindex = xlat->endindex = 0;
01791          return(myrpt->p.endchar);
01792       }
01793    } else xlat->endindex = 0;
01794    /* if in middle of decode seq, send nothing back */
01795    if (gotone) return(0);
01796    /* if no pass chars specified, return em all */
01797    if (!xlat->passchars[0]) return(c);
01798    /* if a "pass char", pass it */
01799    if (strchr(xlat->passchars,c)) return(c);
01800    return(0);
01801 }
01802 
01803 /*
01804  * Return a pointer to the first non-whitespace character
01805  */
01806 
01807 static char *eatwhite(char *s)
01808 {
01809    while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
01810       if(!*s)
01811          break;
01812       s++;
01813    }
01814    return s;
01815 }
01816 
01817 /*
01818 * Break up a delimited string into a table of substrings
01819 *
01820 * str - delimited string ( will be modified )
01821 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
01822 * limit- maximum number of substrings to process
01823 */
01824    
01825 
01826 
01827 static int finddelim(char *str, char *strp[], int limit)
01828 {
01829 int     i,l,inquo;
01830 
01831         inquo = 0;
01832         i = 0;
01833         strp[i++] = str;
01834         if (!*str)
01835            {
01836                 strp[0] = 0;
01837                 return(0);
01838            }
01839         for(l = 0; *str && (l < limit) ; str++)
01840            {
01841                 if (*str == QUOTECHR)
01842                    {
01843                         if (inquo)
01844                            {
01845                                 *str = 0;
01846                                 inquo = 0;
01847                            }
01848                         else
01849                            {
01850                                 strp[i - 1] = str + 1;
01851                                 inquo = 1;
01852                            }
01853       }
01854                 if ((*str == DELIMCHR) && (!inquo))
01855                 {
01856                         *str = 0;
01857          l++;
01858                         strp[i++] = str + 1;
01859                 }
01860            }
01861         strp[i] = 0;
01862         return(i);
01863 
01864 }
01865 /*
01866    send asterisk frame text message on the current tx channel
01867 */
01868 static int send_usb_txt(struct rpt *myrpt, char *txt) 
01869 {
01870    struct ast_frame wf;
01871  
01872    if (debug)ast_log(LOG_NOTICE, "send_usb_txt %s\n",txt);
01873    wf.frametype = AST_FRAME_TEXT;
01874    wf.subclass = 0;
01875    wf.offset = 0;
01876    wf.mallocd = 0;
01877    wf.datalen = strlen(txt) + 1;
01878    wf.data.ptr = txt;
01879    wf.samples = 0;
01880    ast_write(myrpt->txchannel,&wf); 
01881    return 0;
01882 }
01883 /* must be called locked */
01884 static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
01885 {
01886 struct rpt_link *l;
01887 char mode;
01888 int   i,spos;
01889 
01890    buf[0] = 0; /* clear output buffer */
01891    if (myrpt->remote) return;
01892    /* go thru all links */
01893    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01894    {
01895       /* if is not a real link, ignore it */
01896       if (l->name[0] == '0') continue;
01897       /* dont count our stuff */
01898       if (l == mylink) continue;
01899       if (mylink && (!strcmp(l->name,mylink->name))) continue;
01900       /* figure out mode to report */
01901       mode = 'T'; /* use Tranceive by default */
01902       if (!l->mode) mode = 'R'; /* indicate RX for our mode */
01903       if (!l->thisconnected)  mode = 'C'; /* indicate connecting */
01904       spos = strlen(buf); /* current buf size (b4 we add our stuff) */
01905       if (spos)
01906       {
01907          strcat(buf,",");
01908          spos++;
01909       }
01910       /* add nodes into buffer */
01911       if (l->linklist[0])
01912       {
01913          snprintf(buf + spos,MAXLINKLIST - spos,
01914             "%c%s,%s",mode,l->name,l->linklist);
01915       }
01916       else /* if no nodes, add this node into buffer */
01917       {
01918          snprintf(buf + spos,MAXLINKLIST - spos,
01919             "%c%s",mode,l->name);
01920       }
01921       /* if we are in tranceive mode, let all modes stand */
01922       if (mode == 'T') continue;
01923       /* downgrade everyone on this node if appropriate */
01924       for(i = spos; buf[i]; i++)
01925       {
01926          if (buf[i] == 'T') buf[i] = mode;
01927          if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
01928       }
01929    }
01930    return;
01931 }
01932 
01933 /* must be called locked */
01934 static void __kickshort(struct rpt *myrpt)
01935 {
01936 struct rpt_link *l;
01937 
01938    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01939    {
01940       /* if is not a real link, ignore it */
01941       if (l->name[0] == '0') continue;
01942       l->linklisttimer = LINKLISTSHORTTIME;
01943    }
01944    myrpt->linkposttimer = LINKPOSTSHORTTIME;
01945    return;
01946 }
01947 
01948 static void statpost(struct rpt *myrpt,char *pairs)
01949 {
01950 char *str,*astr;
01951 char *astrs[100];
01952 int   n,pid;
01953 time_t   now;
01954 unsigned int seq;
01955 
01956    if (!myrpt->p.statpost_url) return;
01957    str = ast_malloc(strlen(pairs) + strlen(myrpt->p.statpost_url) + 200);
01958    astr = ast_strdup(myrpt->p.statpost_program);
01959    if ((!str) || (!astr)) return;
01960    n = finddelim(astr,astrs,100);
01961    if (n < 1) return;
01962    ast_mutex_lock(&myrpt->statpost_lock);
01963    seq = ++myrpt->statpost_seqno;
01964    ast_mutex_unlock(&myrpt->statpost_lock);
01965    astrs[n++] = str;
01966    astrs[n] = NULL;
01967    time(&now);
01968    sprintf(str,"%s?node=%s&time=%u&seqno=%u",myrpt->p.statpost_url,
01969       myrpt->name,(unsigned int) now,seq);
01970    if (pairs) sprintf(str + strlen(str),"&%s",pairs);
01971    if (!(pid = ast_safe_fork(0)))
01972    {
01973       execv(astrs[0],astrs);
01974       ast_log(LOG_ERROR, "exec of %s failed.\n", astrs[0]);
01975       perror("asterisk");
01976       exit(0);
01977    }
01978    ast_free(astr);
01979    ast_free(str);
01980    return;
01981 }
01982 
01983 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
01984 {
01985 
01986 char *val;
01987 int longestnode,j;
01988 struct stat mystat;
01989 static time_t last = 0;
01990 static struct ast_config *ourcfg = NULL;
01991 struct ast_variable *vp;
01992 
01993    /* try to look it up locally first */
01994    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
01995    if (val) return(val);
01996    ast_mutex_lock(&nodelookuplock);
01997    /* if file does not exist */
01998    if (stat(myrpt->p.extnodefile,&mystat) == -1)
01999    {
02000       if (ourcfg) ast_config_destroy(ourcfg);
02001       ourcfg = NULL;
02002       ast_mutex_unlock(&nodelookuplock);
02003       return(NULL);
02004    }
02005    /* if we need to reload */
02006    if (mystat.st_mtime > last)
02007    {
02008       if (ourcfg) ast_config_destroy(ourcfg);
02009 #ifdef   NEW_ASTERISK
02010       ourcfg = ast_config_load(myrpt->p.extnodefile,config_flags);
02011 #else
02012       ourcfg = ast_config_load(myrpt->p.extnodefile);
02013 #endif
02014       /* if file not there, just bail */
02015       if (!ourcfg || ourcfg == CONFIG_STATUS_FILEINVALID)
02016       {
02017          ast_mutex_unlock(&nodelookuplock);
02018          return(NULL);
02019       }
02020       /* reset "last" time */
02021       last = mystat.st_mtime;
02022 
02023       /* determine longest node length again */    
02024       longestnode = 0;
02025       vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
02026       while(vp){
02027          j = strlen(vp->name);
02028          if (j > longestnode)
02029             longestnode = j;
02030          vp = vp->next;
02031       }
02032 
02033       vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
02034       while(vp){
02035          j = strlen(vp->name);
02036          if (j > longestnode)
02037             longestnode = j;
02038          vp = vp->next;
02039       }
02040 
02041       myrpt->longestnode = longestnode;
02042    }
02043    val = NULL;
02044    if (ourcfg)
02045       val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
02046    ast_mutex_unlock(&nodelookuplock);
02047    return(val);
02048 }
02049 
02050 /*
02051 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
02052 * If param is passed in non-null, then it will be set to the first character past the match
02053 */
02054 
02055 static int matchkeyword(char *string, char **param, char *keywords[])
02056 {
02057 int   i,ls;
02058    for( i = 0 ; keywords[i] ; i++){
02059       ls = strlen(keywords[i]);
02060       if(!ls){
02061          *param = NULL;
02062          return 0;
02063       }
02064       if(!strncmp(string, keywords[i], ls)){
02065          if(param)
02066             *param = string + ls;
02067          return i + 1; 
02068       }
02069    }
02070    *param = NULL;
02071    return 0;
02072 }
02073 
02074 /*
02075 * Skip characters in string which are in charlist, and return a pointer to the
02076 * first non-matching character
02077 */
02078 
02079 static char *skipchars(char *string, char *charlist)
02080 {
02081 int i;   
02082    while(*string){
02083       for(i = 0; charlist[i] ; i++){
02084          if(*string == charlist[i]){
02085             string++;
02086             break;
02087          }
02088       }
02089       if(!charlist[i])
02090          return string;
02091    }
02092    return string;
02093 }  
02094                
02095 
02096 
02097 static int myatoi(char *str)
02098 {
02099 int   ret;
02100 
02101    if (str == NULL) return -1;
02102    /* leave this %i alone, non-base-10 input is useful here */
02103    if (sscanf(str, "%30i", &ret) != 1) {
02104       return -1;
02105    }
02106 
02107    return ret;
02108 }
02109 
02110 static int mycompar(const void *a, const void *b)
02111 {
02112 char  **x = (char **) a;
02113 char  **y = (char **) b;
02114 int   xoff,yoff;
02115 
02116    if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
02117    if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
02118    return(strcmp((*x) + xoff,(*y) + yoff));
02119 }
02120 
02121 static int topcompar(const void *a, const void *b)
02122 {
02123 struct rpt_topkey *x = (struct rpt_topkey *) a;
02124 struct rpt_topkey *y = (struct rpt_topkey *) b;
02125 
02126    return(x->timesince - y->timesince);
02127 }
02128 
02129 #ifdef   __RPT_NOTCH
02130 
02131 /* rpt filter routine */
02132 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
02133 {
02134 int   i,j;
02135 struct   rptfilter *f;
02136 
02137    for(i = 0; i < len; i++)
02138    {
02139       for(j = 0; j < MAXFILTERS; j++)
02140       {
02141          f = &myrpt->filters[j];
02142          if (!*f->desc) continue;
02143          f->x0 = f->x1; f->x1 = f->x2;
02144               f->x2 = ((float)buf[i]) / f->gain;
02145               f->y0 = f->y1; f->y1 = f->y2;
02146               f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
02147                            + (f->const1 * f->y0) + (f->const2 * f->y1);
02148          buf[i] = (short)f->y2;
02149       }
02150    }
02151 }
02152 
02153 #endif
02154 
02155 
02156 /*
02157  Get the time for the machine's time zone
02158  Note: Asterisk requires a copy of localtime
02159  in the /etc directory for this to work properly.
02160  If /etc/localtime is not present, you will get
02161  GMT time! This is especially important on systems
02162  running embedded linux distributions as they don't usually
02163  have support for locales. 
02164 
02165  If OLD_ASTERISK is defined, then the older localtime_r
02166  function will be used. The /etc/localtime file is not
02167  required in this case. This provides backward compatibility
02168  with Asterisk 1.2 systems.
02169 
02170 */
02171 
02172 #ifdef   NEW_ASTERISK
02173 static void rpt_localtime( time_t * t, struct ast_tm *lt)
02174 {
02175    struct timeval when;
02176 
02177    when.tv_sec = *t;
02178    when.tv_usec = 0;
02179    ast_localtime(&when, lt, NULL);
02180 }
02181 
02182 #else
02183 static void rpt_localtime( time_t * t, struct tm *lt)
02184 {
02185 #ifdef OLD_ASTERISK
02186    localtime_r(t, lt);
02187 #else
02188    ast_localtime(t, lt, NULL);
02189 #endif
02190 }
02191 #endif
02192 
02193 
02194 /* Retrieve an int from a config file */
02195                                                                                 
02196 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
02197 {
02198         char *var;
02199         int ret;
02200    char include_zero = 0;
02201 
02202    if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
02203       min = -min;
02204       include_zero = 1;
02205    }           
02206                                                                      
02207         var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
02208         if(var){
02209                 ret = myatoi(var);
02210       if(include_zero && !ret)
02211          return 0;
02212                 if(ret < min)
02213                         ret = min;
02214                 if(ret > max)
02215                         ret = max;
02216         }
02217         else
02218                 ret = defl;
02219         return ret;
02220 }
02221 
02222 
02223 static void load_rpt_vars(int n,int init)
02224 {
02225 char *this,*val;
02226 int   i,j,longestnode;
02227 struct ast_variable *vp;
02228 struct ast_config *cfg;
02229 char *strs[100];
02230 char s1[256];
02231 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
02232             "ufena","ufdis","atena","atdis",NULL};
02233 
02234    if (option_verbose > 2)
02235       ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
02236          (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
02237    ast_mutex_lock(&rpt_vars[n].lock);
02238    if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
02239 #ifdef   NEW_ASTERISK
02240    cfg = ast_config_load("rpt.conf",config_flags);
02241 #else
02242    cfg = ast_config_load("rpt.conf");
02243 #endif
02244    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
02245       ast_mutex_unlock(&rpt_vars[n].lock);
02246       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
02247       pthread_exit(NULL);
02248    }
02249    rpt_vars[n].cfg = cfg; 
02250    this = rpt_vars[n].name;
02251    memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
02252    if (init)
02253    {
02254       char *cp;
02255       int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
02256 
02257       cp = (char *) &rpt_vars[n].p;
02258       memset(cp + sizeof(rpt_vars[n].p),0,
02259          sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
02260       rpt_vars[n].tele.next = &rpt_vars[n].tele;
02261       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
02262       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
02263       rpt_vars[n].tailmessagen = 0;
02264    }
02265 #ifdef   __RPT_NOTCH
02266    /* zot out filters stuff */
02267    memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
02268 #endif
02269    val = (char *) ast_variable_retrieve(cfg,this,"context");
02270    if (val) rpt_vars[n].p.ourcontext = val;
02271    else rpt_vars[n].p.ourcontext = this;
02272    val = (char *) ast_variable_retrieve(cfg,this,"callerid");
02273    if (val) rpt_vars[n].p.ourcallerid = val;
02274    val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
02275    if (val) rpt_vars[n].p.acctcode = val;
02276    val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
02277    if (val) rpt_vars[n].p.ident = val;
02278    val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
02279    if (val) rpt_vars[n].p.hangtime = atoi(val);
02280       else rpt_vars[n].p.hangtime = HANGTIME;
02281    val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
02282    if (val) rpt_vars[n].p.althangtime = atoi(val);
02283       else rpt_vars[n].p.althangtime = HANGTIME;
02284    val = (char *) ast_variable_retrieve(cfg,this,"totime");
02285    if (val) rpt_vars[n].p.totime = atoi(val);
02286       else rpt_vars[n].p.totime = TOTIME;
02287    val = (char *) ast_variable_retrieve(cfg,this,"voxtimeout");
02288    if (val) rpt_vars[n].p.voxtimeout_ms = atoi(val);
02289       else rpt_vars[n].p.voxtimeout_ms = VOX_TIMEOUT_MS;
02290    val = (char *) ast_variable_retrieve(cfg,this,"voxrecover");
02291    if (val) rpt_vars[n].p.voxrecover_ms = atoi(val);
02292       else rpt_vars[n].p.voxrecover_ms = VOX_RECOVER_MS;
02293    val = (char *) ast_variable_retrieve(cfg,this,"simplexpatchdelay");
02294    if (val) rpt_vars[n].p.simplexpatchdelay = atoi(val);
02295       else rpt_vars[n].p.simplexpatchdelay = SIMPLEX_PATCH_DELAY;
02296    val = (char *) ast_variable_retrieve(cfg,this,"simplexphonedelay");
02297    if (val) rpt_vars[n].p.simplexphonedelay = atoi(val);
02298       else rpt_vars[n].p.simplexphonedelay = SIMPLEX_PHONE_DELAY;
02299    val = (char *) ast_variable_retrieve(cfg,this,"statpost_program");
02300    if (val) rpt_vars[n].p.statpost_program = val;
02301       else rpt_vars[n].p.statpost_program = STATPOST_PROGRAM;
02302    rpt_vars[n].p.statpost_url = 
02303       (char *) ast_variable_retrieve(cfg,this,"statpost_url");
02304    rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);    
02305    rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);     
02306    rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
02307    rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME);   /* Enforce a min max including zero */
02308    rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
02309    val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
02310    if (val) rpt_vars[n].p.tonezone = val;
02311    rpt_vars[n].p.tailmessages[0] = 0;
02312    rpt_vars[n].p.tailmessagemax = 0;
02313    val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
02314    if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
02315    val = (char *) ast_variable_retrieve(cfg,this,"memory");
02316    if (!val) val = MEMORY;
02317    rpt_vars[n].p.memory = val;
02318    val = (char *) ast_variable_retrieve(cfg,this,"macro");
02319    if (!val) val = MACRO;
02320    rpt_vars[n].p.macro = val;
02321    val = (char *) ast_variable_retrieve(cfg,this,"tonemacro");
02322    if (!val) val = TONEMACRO;
02323    rpt_vars[n].p.tonemacro = val;
02324    val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
02325    if (val) rpt_vars[n].p.startupmacro = val;
02326    val = (char *) ast_variable_retrieve(cfg,this,"iobase");
02327    /* do not use atoi() here, we need to be able to have
02328       the input specified in hex or decimal so we use
02329       sscanf with a %i */
02330    if ((!val) || (sscanf(val,"%30i",&rpt_vars[n].p.iobase) != 1))
02331       rpt_vars[n].p.iobase = DEFAULT_IOBASE;
02332    val = (char *) ast_variable_retrieve(cfg,this,"ioport");
02333    rpt_vars[n].p.ioport = val;
02334    val = (char *) ast_variable_retrieve(cfg,this,"functions");
02335    if (!val)
02336       {
02337          val = FUNCTIONS;
02338          rpt_vars[n].p.simple = 1;
02339       } 
02340    rpt_vars[n].p.functions = val;
02341    val =  (char *) ast_variable_retrieve(cfg,this,"link_functions");
02342    if (val) rpt_vars[n].p.link_functions = val;
02343    else 
02344       rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
02345    val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
02346    if (val) rpt_vars[n].p.phone_functions = val;
02347    val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
02348    if (val) rpt_vars[n].p.dphone_functions = val;
02349    val = (char *) ast_variable_retrieve(cfg,this,"alt_functions");
02350    if (val) rpt_vars[n].p.alt_functions = val;
02351    val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
02352    if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
02353       rpt_vars[n].p.funcchar = *val;      
02354    val = (char *) ast_variable_retrieve(cfg,this,"endchar");
02355    if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
02356       rpt_vars[n].p.endchar = *val;    
02357    val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
02358    if (val) rpt_vars[n].p.nobusyout = ast_true(val);
02359    val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
02360    if (val) rpt_vars[n].p.notelemtx = ast_true(val);
02361    val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
02362    if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
02363    val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
02364    if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
02365    val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
02366    if (val) rpt_vars[n].p.linktolink = ast_true(val);
02367    val = (char *) ast_variable_retrieve(cfg,this,"nodes");
02368    if (!val) val = NODES;
02369    rpt_vars[n].p.nodes = val;
02370    val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
02371    if (!val) val = EXTNODES;
02372    rpt_vars[n].p.extnodes = val;
02373    val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
02374    if (!val) val = EXTNODEFILE;
02375    rpt_vars[n].p.extnodefile = val;
02376    val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
02377    if (val) rpt_vars[n].p.archivedir = val;
02378    val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
02379    if (val) rpt_vars[n].p.authlevel = atoi(val); 
02380    else rpt_vars[n].p.authlevel = 0;
02381    val = (char *) ast_variable_retrieve(cfg,this,"parrot");
02382    if (val) rpt_vars[n].p.parrotmode = ast_true(val) * 2;
02383    else rpt_vars[n].p.parrotmode = 0;
02384    val = (char *) ast_variable_retrieve(cfg,this,"parrottime");
02385    if (val) rpt_vars[n].p.parrottime = atoi(val); 
02386    else rpt_vars[n].p.parrottime = PARROTTIME;
02387    val = (char *) ast_variable_retrieve(cfg,this,"rptnode");
02388    rpt_vars[n].p.rptnode = val;
02389    val = (char *) ast_variable_retrieve(cfg,this,"mars");
02390    if (val) rpt_vars[n].p.remote_mars = atoi(val); 
02391    else rpt_vars[n].p.remote_mars = 0;
02392    val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
02393    if (val) rpt_vars[n].p.monminblocks = atol(val); 
02394    else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
02395    val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
02396    if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); 
02397    else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
02398    val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
02399    if (val) rpt_vars[n].p.civaddr = atoi(val); 
02400    else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
02401    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
02402    if (val) rpt_vars[n].p.remotetimeout = atoi(val); 
02403    else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
02404    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
02405    if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); 
02406    else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
02407    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
02408    if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); 
02409    else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
02410 #ifdef   __RPT_NOTCH
02411    val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
02412    if (val) {
02413       i = finddelim(val,strs,MAXFILTERS * 2);
02414       i &= ~1; /* force an even number, rounded down */
02415       if (i >= 2) for(j = 0; j < i; j += 2)
02416       {
02417          rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
02418            &rpt_vars[n].filters[j >> 1].gain,
02419              &rpt_vars[n].filters[j >> 1].const0,
02420             &rpt_vars[n].filters[j >> 1].const1,
02421                 &rpt_vars[n].filters[j >> 1].const2);
02422          sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
02423             strs[j],strs[j + 1]);
02424       }
02425 
02426    }
02427 #endif
02428    val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
02429    if (val) {
02430       memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
02431       i = finddelim(val,strs,3);
02432       if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
02433       if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
02434       if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
02435    }
02436    val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
02437    if (val) {
02438       memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
02439       i = finddelim(val,strs,3);
02440       if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
02441       if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
02442       if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
02443    }
02444    /* retreive the stanza name for the control states if there is one */
02445    val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
02446    rpt_vars[n].p.csstanzaname = val;
02447       
02448    /* retreive the stanza name for the scheduler if there is one */
02449    val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
02450    rpt_vars[n].p.skedstanzaname = val;
02451 
02452    /* retreive the stanza name for the txlimits */
02453    val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
02454    rpt_vars[n].p.txlimitsstanzaname = val;
02455 
02456    longestnode = 0;
02457 
02458    vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
02459       
02460    while(vp){
02461       j = strlen(vp->name);
02462       if (j > longestnode)
02463          longestnode = j;
02464       vp = vp->next;
02465    }
02466 
02467    rpt_vars[n].longestnode = longestnode;
02468       
02469    /*
02470    * For this repeater, Determine the length of the longest function 
02471    */
02472    rpt_vars[n].longestfunc = 0;
02473    vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
02474    while(vp){
02475       j = strlen(vp->name);
02476       if (j > rpt_vars[n].longestfunc)
02477          rpt_vars[n].longestfunc = j;
02478       vp = vp->next;
02479    }
02480    /*
02481    * For this repeater, Determine the length of the longest function 
02482    */
02483    rpt_vars[n].link_longestfunc = 0;
02484    vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
02485    while(vp){
02486       j = strlen(vp->name);
02487       if (j > rpt_vars[n].link_longestfunc)
02488          rpt_vars[n].link_longestfunc = j;
02489       vp = vp->next;
02490    }
02491    rpt_vars[n].phone_longestfunc = 0;
02492    if (rpt_vars[n].p.phone_functions)
02493    {
02494       vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
02495       while(vp){
02496          j = strlen(vp->name);
02497          if (j > rpt_vars[n].phone_longestfunc)
02498             rpt_vars[n].phone_longestfunc = j;
02499          vp = vp->next;
02500       }
02501    }
02502    rpt_vars[n].dphone_longestfunc = 0;
02503    if (rpt_vars[n].p.dphone_functions)
02504    {
02505       vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
02506       while(vp){
02507          j = strlen(vp->name);
02508          if (j > rpt_vars[n].dphone_longestfunc)
02509             rpt_vars[n].dphone_longestfunc = j;
02510          vp = vp->next;
02511       }
02512    }
02513    rpt_vars[n].alt_longestfunc = 0;
02514    if (rpt_vars[n].p.alt_functions)
02515    {
02516       vp = ast_variable_browse(cfg, rpt_vars[n].p.alt_functions);
02517       while(vp){
02518          j = strlen(vp->name);
02519          if (j > rpt_vars[n].alt_longestfunc)
02520             rpt_vars[n].alt_longestfunc = j;
02521          vp = vp->next;
02522       }
02523    }
02524    rpt_vars[n].macro_longest = 1;
02525    vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
02526    while(vp){
02527       j = strlen(vp->name);
02528       if (j > rpt_vars[n].macro_longest)
02529          rpt_vars[n].macro_longest = j;
02530       vp = vp->next;
02531    }
02532    
02533    /* Browse for control states */
02534    if(rpt_vars[n].p.csstanzaname)
02535       vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
02536    else
02537       vp = NULL;
02538    for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
02539       int k,nukw,statenum;
02540       statenum=atoi(vp->name);
02541       strncpy(s1, vp->value, 255);
02542       s1[255] = 0;
02543       nukw  = finddelim(s1,strs,32);
02544       
02545       for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */  
02546          for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
02547             if(!strcmp(strs[k],cs_keywords[j])){
02548                switch(j){
02549                   case 0: /* rptena */
02550                      rpt_vars[n].p.s[statenum].txdisable = 0;
02551                      break;
02552                   case 1: /* rptdis */
02553                      rpt_vars[n].p.s[statenum].txdisable = 1;
02554                      break;
02555          
02556                   case 2: /* apena */
02557                      rpt_vars[n].p.s[statenum].autopatchdisable = 0;
02558                      break;
02559 
02560                   case 3: /* apdis */
02561                      rpt_vars[n].p.s[statenum].autopatchdisable = 1;
02562                      break;
02563 
02564                   case 4: /* lnkena */
02565                      rpt_vars[n].p.s[statenum].linkfundisable = 0;
02566                      break;
02567    
02568                   case 5: /* lnkdis */
02569                      rpt_vars[n].p.s[statenum].linkfundisable = 1;
02570                      break;
02571 
02572                   case 6: /* totena */
02573                      rpt_vars[n].p.s[statenum].totdisable = 0;
02574                      break;
02575                
02576                   case 7: /* totdis */
02577                      rpt_vars[n].p.s[statenum].totdisable = 1;
02578                      break;
02579 
02580                   case 8: /* skena */
02581                      rpt_vars[n].p.s[statenum].schedulerdisable = 0;
02582                      break;
02583 
02584                   case 9: /* skdis */
02585                      rpt_vars[n].p.s[statenum].schedulerdisable = 1;
02586                      break;
02587 
02588                   case 10: /* ufena */
02589                      rpt_vars[n].p.s[statenum].userfundisable = 0;
02590                      break;
02591 
02592                   case 11: /* ufdis */
02593                      rpt_vars[n].p.s[statenum].userfundisable = 1;
02594                      break;
02595 
02596                   case 12: /* atena */
02597                      rpt_vars[n].p.s[statenum].alternatetail = 1;
02598                      break;
02599 
02600                   case 13: /* atdis */
02601                      rpt_vars[n].p.s[statenum].alternatetail = 0;
02602                      break;
02603          
02604                   default:
02605                      ast_log(LOG_WARNING,
02606                         "Unhandled control state keyword %s", cs_keywords[i]);
02607                      break;
02608                }
02609             }
02610          }
02611       }
02612       vp = vp->next;
02613    }
02614    ast_mutex_unlock(&rpt_vars[n].lock);
02615 }
02616 
02617 /*
02618 * Enable or disable debug output at a given level at the console
02619 */
02620                                                                                                                                  
02621 static int rpt_do_debug(int fd, int argc, char *argv[])
02622 {
02623    int newlevel;
02624 
02625         if (argc != 4)
02626                 return RESULT_SHOWUSAGE;
02627         newlevel = myatoi(argv[3]);
02628         if((newlevel < 0) || (newlevel > 7))
02629                 return RESULT_SHOWUSAGE;
02630         if(newlevel)
02631                 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
02632         else
02633                 ast_cli(fd, "app_rpt Debugging disabled\n");
02634 
02635         debug = newlevel;                                                                                                                          
02636         return RESULT_SUCCESS;
02637 }
02638 
02639 /*
02640 * Dump rpt struct debugging onto console
02641 */
02642                                                                                                                                  
02643 static int rpt_do_dump(int fd, int argc, char *argv[])
02644 {
02645    int i;
02646 
02647         if (argc != 3)
02648                 return RESULT_SHOWUSAGE;
02649 
02650    for(i = 0; i < nrpts; i++)
02651    {
02652       if (!strcmp(argv[2],rpt_vars[i].name))
02653       {
02654          rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
02655               ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
02656               return RESULT_SUCCESS;
02657       }
02658    }
02659    return RESULT_FAILURE;
02660 }
02661 
02662 /*
02663 * Dump statistics onto console
02664 */
02665 
02666 static int rpt_do_stats(int fd, int argc, char *argv[])
02667 {
02668    int i,j,numoflinks;
02669    int dailytxtime, dailykerchunks;
02670    time_t now;
02671    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
02672    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
02673    int uptime;
02674    long long totaltxtime;
02675    struct   rpt_link *l;
02676    char *listoflinks[MAX_STAT_LINKS];  
02677    char *lastdtmfcommand,*parrot_ena;
02678    char *tot_state, *ider_state, *patch_state;
02679    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
02680    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
02681    struct rpt *myrpt;
02682 
02683    static char *not_applicable = "N/A";
02684 
02685    if(argc != 3)
02686       return RESULT_SHOWUSAGE;
02687 
02688    tot_state = ider_state = 
02689    patch_state = reverse_patch_state = 
02690    input_signal = not_applicable;
02691    called_number = lastdtmfcommand = NULL;
02692 
02693    time(&now);
02694    for(i = 0; i < nrpts; i++)
02695    {
02696       if (!strcmp(argv[2],rpt_vars[i].name)){
02697          /* Make a copy of all stat variables while locked */
02698          myrpt = &rpt_vars[i];
02699          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02700          uptime = (int)(now - starttime);
02701          dailytxtime = myrpt->dailytxtime;
02702          totaltxtime = myrpt->totaltxtime;
02703          dailykeyups = myrpt->dailykeyups;
02704          totalkeyups = myrpt->totalkeyups;
02705          dailykerchunks = myrpt->dailykerchunks;
02706          totalkerchunks = myrpt->totalkerchunks;
02707          dailyexecdcommands = myrpt->dailyexecdcommands;
02708          totalexecdcommands = myrpt->totalexecdcommands;
02709          timeouts = myrpt->timeouts;
02710 
02711          /* Traverse the list of connected nodes */
02712          reverse_patch_state = "DOWN";
02713          numoflinks = 0;
02714          l = myrpt->links.next;
02715          while(l && (l != &myrpt->links)){
02716             if(numoflinks >= MAX_STAT_LINKS){
02717                ast_log(LOG_NOTICE,
02718                "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
02719                break;
02720             }
02721             if (l->name[0] == '0'){ /* Skip '0' nodes */
02722                reverse_patch_state = "UP";
02723                l = l->next;
02724                continue;
02725             }
02726             listoflinks[numoflinks] = ast_strdup(l->name);
02727             if(listoflinks[numoflinks] == NULL){
02728                break;
02729             }
02730             else{
02731                numoflinks++;
02732             }
02733             l = l->next;
02734          }
02735 
02736          if(myrpt->keyed)
02737             input_signal = "YES";
02738          else
02739             input_signal = "NO";
02740 
02741          if(myrpt->p.parrotmode)
02742             parrot_ena = "ENABLED";
02743          else
02744             parrot_ena = "DISABLED";
02745 
02746          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
02747             sys_ena = "DISABLED";
02748          else
02749             sys_ena = "ENABLED";
02750 
02751          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
02752             tot_ena = "DISABLED";
02753          else
02754             tot_ena = "ENABLED";
02755 
02756          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
02757             link_ena = "DISABLED";
02758          else
02759             link_ena = "ENABLED";
02760 
02761          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
02762             patch_ena = "DISABLED";
02763          else
02764             patch_ena = "ENABLED";
02765 
02766          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
02767             sch_ena = "DISABLED";
02768          else
02769             sch_ena = "ENABLED";
02770 
02771          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
02772             user_funs = "DISABLED";
02773          else
02774             user_funs = "ENABLED";
02775 
02776          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
02777             tail_type = "ALTERNATE";
02778          else
02779             tail_type = "STANDARD";
02780 
02781          if(!myrpt->totimer)
02782             tot_state = "TIMED OUT!";
02783          else if(myrpt->totimer != myrpt->p.totime)
02784             tot_state = "ARMED";
02785          else
02786             tot_state = "RESET";
02787 
02788          if(myrpt->tailid)
02789             ider_state = "QUEUED IN TAIL";
02790          else if(myrpt->mustid)
02791             ider_state = "QUEUED FOR CLEANUP";
02792          else
02793             ider_state = "CLEAN";
02794 
02795          switch(myrpt->callmode){
02796             case 1:
02797                patch_state = "DIALING";
02798                break;
02799             case 2:
02800                patch_state = "CONNECTING";
02801                break;
02802             case 3:
02803                patch_state = "UP";
02804                break;
02805 
02806             case 4:
02807                patch_state = "CALL FAILED";
02808                break;
02809 
02810             default:
02811                patch_state = "DOWN";
02812          }
02813 
02814          if(strlen(myrpt->exten)){
02815             called_number = ast_strdup(myrpt->exten);
02816          }
02817 
02818          if(strlen(myrpt->lastdtmfcommand)){
02819             lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
02820          }
02821          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02822 
02823          ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
02824          ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
02825          ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
02826          ast_cli(fd, "System...........................................: %s\n", sys_ena);
02827          ast_cli(fd, "Parrot Mode......................................: %s\n", parrot_ena);
02828          ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
02829          ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
02830          ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
02831          ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
02832          ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
02833          ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
02834          ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
02835          ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
02836          ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
02837          ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
02838          ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
02839          ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
02840          ast_cli(fd, "Last DTMF command executed.......................: %s\n", 
02841          (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
02842          hours = dailytxtime/3600000;
02843          dailytxtime %= 3600000;
02844          minutes = dailytxtime/60000;
02845          dailytxtime %= 60000;
02846          seconds = dailytxtime/1000;
02847          dailytxtime %= 1000;
02848 
02849          ast_cli(fd, "TX time today....................................: %02d:%02d:%02d.%d\n",
02850             hours, minutes, seconds, dailytxtime);
02851 
02852          hours = (int) totaltxtime/3600000;
02853          totaltxtime %= 3600000;
02854          minutes = (int) totaltxtime/60000;
02855          totaltxtime %= 60000;
02856          seconds = (int)  totaltxtime/1000;
02857          totaltxtime %= 1000;
02858 
02859          ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
02860              hours, minutes, seconds, (int) totaltxtime);
02861 
02862                         hours = uptime/3600;
02863                         uptime %= 3600;
02864                         minutes = uptime/60;
02865                         uptime %= 60;
02866 
02867                         ast_cli(fd, "Uptime...........................................: %02d:%02d:%02d\n",
02868                                 hours, minutes, uptime);
02869 
02870          ast_cli(fd, "Nodes currently connected to us..................: ");
02871                         if(!numoflinks){
02872                          ast_cli(fd,"<NONE>");
02873                         }
02874          else{
02875             for(j = 0 ;j < numoflinks; j++){
02876                ast_cli(fd, "%s", listoflinks[j]);
02877                if(j % 4 == 3){
02878                   ast_cli(fd, "\n");
02879                   ast_cli(fd, "                                                 : ");
02880                }  
02881                else{
02882                   if((numoflinks - 1) - j  > 0)
02883                      ast_cli(fd, ", ");
02884                }
02885             }
02886          }
02887          ast_cli(fd,"\n");
02888 
02889          ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
02890          ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
02891          ast_cli(fd, "Autopatch called number..........................: %s\n",
02892          (called_number && strlen(called_number)) ? called_number : not_applicable);
02893          ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
02894          ast_cli(fd, "User linking commands............................: %s\n", link_ena);
02895          ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
02896 
02897          for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
02898             ast_free(listoflinks[j]);
02899          }
02900          if(called_number){
02901             ast_free(called_number);
02902          }
02903          if(lastdtmfcommand){
02904             ast_free(lastdtmfcommand);
02905          }
02906               return RESULT_SUCCESS;
02907       }
02908    }
02909    return RESULT_FAILURE;
02910 }
02911 
02912 /*
02913 * Link stats function
02914 */
02915 
02916 static int rpt_do_lstats(int fd, int argc, char *argv[])
02917 {
02918    int i,j;
02919    char *connstate;
02920    struct rpt *myrpt;
02921    struct rpt_link *l;
02922    struct rpt_lstat *s,*t;
02923    struct rpt_lstat s_head;
02924    if(argc != 3)
02925       return RESULT_SHOWUSAGE;
02926 
02927    s = NULL;
02928    s_head.next = &s_head;
02929    s_head.prev = &s_head;
02930 
02931    for(i = 0; i < nrpts; i++)
02932    {
02933       if (!strcmp(argv[2],rpt_vars[i].name)){
02934          /* Make a copy of all stat variables while locked */
02935          myrpt = &rpt_vars[i];
02936          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02937          /* Traverse the list of connected nodes */
02938          j = 0;
02939          l = myrpt->links.next;
02940          while(l && (l != &myrpt->links)){
02941             if (l->name[0] == '0'){ /* Skip '0' nodes */
02942                l = l->next;
02943                continue;
02944             }
02945             if((s = (struct rpt_lstat *) ast_malloc(sizeof(struct rpt_lstat))) == NULL){
02946                ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
02947                rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02948                return RESULT_FAILURE;
02949             }
02950             memset(s, 0, sizeof(struct rpt_lstat));
02951             strncpy(s->name, l->name, MAXREMSTR - 1);
02952             if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
02953             else strcpy(s->peer,"(none)");
02954             s->mode = l->mode;
02955             s->outbound = l->outbound;
02956             s->reconnects = l->reconnects;
02957             s->connecttime = l->connecttime;
02958             s->thisconnected = l->thisconnected;
02959             memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
02960             insque((struct qelem *) s, (struct qelem *) s_head.next);
02961             memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
02962             l = l->next;
02963          }
02964          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02965          ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME        CONNECT STATE\n");
02966          ast_cli(fd, "----      ----                ----------  ---------  ------------        -------------\n");
02967 
02968          for(s = s_head.next; s != &s_head; s = s->next){
02969             int hours, minutes, seconds;
02970             long long connecttime = s->connecttime;
02971             char conntime[21];
02972             hours = (int) connecttime/3600000;
02973             connecttime %= 3600000;
02974             minutes = (int) connecttime/60000;
02975             connecttime %= 60000;
02976             seconds = (int)  connecttime/1000;
02977             connecttime %= 1000;
02978             snprintf(conntime, 20, "%02d:%02d:%02d.%d",
02979                hours, minutes, seconds, (int) connecttime);
02980             conntime[20] = 0;
02981             if(s->thisconnected)
02982                connstate  = "ESTABLISHED";
02983             else
02984                connstate = "CONNECTING";
02985             ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
02986                s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
02987          }  
02988          /* destroy our local link queue */
02989          s = s_head.next;
02990          while(s != &s_head){
02991             t = s;
02992             s = s->next;
02993             remque((struct qelem *)t);
02994             ast_free(t);
02995          }        
02996          return RESULT_SUCCESS;
02997       }
02998    }
02999    return RESULT_FAILURE;
03000 }
03001 
03002 /*
03003 * List all nodes connected, directly or indirectly
03004 */
03005 
03006 static int rpt_do_nodes(int fd, int argc, char *argv[])
03007 {
03008    int i,j;
03009    char ns;
03010    char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
03011    struct rpt *myrpt;
03012    if(argc != 3)
03013       return RESULT_SHOWUSAGE;
03014 
03015    for(i = 0; i < nrpts; i++)
03016    {
03017       if (!strcmp(argv[2],rpt_vars[i].name)){
03018          /* Make a copy of all stat variables while locked */
03019          myrpt = &rpt_vars[i];
03020          rpt_mutex_lock(&myrpt->lock); /* LOCK */
03021          __mklinklist(myrpt,NULL,lbuf);
03022          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
03023          /* parse em */
03024          ns = finddelim(lbuf,strs,MAXLINKLIST);
03025          /* sort em */
03026          if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
03027          ast_cli(fd,"\n");
03028          ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
03029          for(j = 0 ;; j++){
03030             if(!strs[j]){
03031                if(!j){
03032                   ast_cli(fd,"<NONE>");
03033                }
03034                break;
03035             }
03036             ast_cli(fd, "%s", strs[j]);
03037             if(j % 8 == 7){
03038                ast_cli(fd, "\n");
03039             }
03040             else{
03041                if(strs[j + 1])
03042                   ast_cli(fd, ", ");
03043             }
03044          }
03045          ast_cli(fd,"\n\n");
03046          return RESULT_SUCCESS;
03047       }
03048    }
03049    return RESULT_FAILURE;
03050 }
03051 
03052 /*
03053 * List all locally configured nodes
03054 */
03055 
03056 static int rpt_do_local_nodes(int fd, int argc, char *argv[])
03057 {
03058 
03059     int i;
03060     ast_cli(fd, "\nNode\n----\n");
03061     for (i=0; i< nrpts; i++)
03062     {
03063         ast_cli(fd, "%s\n", rpt_vars[i].name);        
03064     } /* for i */
03065     ast_cli(fd,"\n");
03066     return RESULT_SUCCESS;
03067 } 
03068 
03069 
03070 /*
03071 * reload vars 
03072 */
03073 
03074 static int rpt_do_reload(int fd, int argc, char *argv[])
03075 {
03076 int   n;
03077 
03078         if (argc > 2) return RESULT_SHOWUSAGE;
03079 
03080    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
03081 
03082    return RESULT_FAILURE;
03083 }
03084 
03085 /*
03086 * restart app_rpt
03087 */
03088                                                                                                                                  
03089 static int rpt_do_restart(int fd, int argc, char *argv[])
03090 {
03091 int   i;
03092 
03093         if (argc > 2) return RESULT_SHOWUSAGE;
03094    for(i = 0; i < nrpts; i++)
03095    {
03096       if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
03097    }
03098    return RESULT_FAILURE;
03099 }
03100 
03101 
03102 /*
03103 * send an app_rpt DTMF function from the CLI
03104 */
03105                                                                                                                                  
03106 static int rpt_do_fun(int fd, int argc, char *argv[])
03107 {
03108    int   i,busy=0;
03109 
03110         if (argc != 4) return RESULT_SHOWUSAGE;
03111 
03112    for(i = 0; i < nrpts; i++){
03113       if(!strcmp(argv[2], rpt_vars[i].name)){
03114          struct rpt *myrpt = &rpt_vars[i];
03115          rpt_mutex_lock(&myrpt->lock);
03116          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
03117             rpt_mutex_unlock(&myrpt->lock);
03118             busy=1;
03119          }
03120          if(!busy){
03121             myrpt->macrotimer = MACROTIME;
03122             strncat(myrpt->macrobuf,argv[3],MAXMACRO - 1);
03123          }
03124          rpt_mutex_unlock(&myrpt->lock);
03125       }
03126    }
03127    if(busy){
03128       ast_cli(fd, "Function decoder busy");
03129    }
03130    return RESULT_FAILURE;
03131 }
03132 /*
03133    the convention is that macros in the data from the rpt() application
03134    are all at the end of the data, separated by the | and start with a *
03135    when put into the macro buffer, the characters have their high bit
03136    set so the macro processor knows they came from the application data
03137    and to use the alt-functions table.
03138    sph:
03139 */
03140 static int rpt_push_alt_macro(struct rpt *myrpt, char *sptr)
03141 {
03142    int   busy=0;
03143 
03144    rpt_mutex_lock(&myrpt->lock);
03145    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(sptr)){
03146       rpt_mutex_unlock(&myrpt->lock);
03147       busy=1;
03148    }
03149    if(!busy){
03150       int x;
03151       if (debug)ast_log(LOG_NOTICE, "rpt_push_alt_macro %s\n",sptr);
03152       myrpt->macrotimer = MACROTIME;
03153       for(x = 0; *(sptr + x); x++)
03154           myrpt->macrobuf[x] = *(sptr + x) | 0x80;
03155       *(sptr + x) = 0;
03156    }
03157    rpt_mutex_unlock(&myrpt->lock);
03158 
03159    if(busy)ast_log(LOG_WARNING, "Function decoder busy on app_rpt command macro.\n");
03160 
03161    return busy;
03162 }
03163 /*
03164    allows us to test rpt() application data commands
03165 */
03166 static int rpt_do_fun1(int fd, int argc, char *argv[])
03167 {
03168    int   i;
03169 
03170     if (argc != 4) return RESULT_SHOWUSAGE;
03171 
03172    for(i = 0; i < nrpts; i++){
03173       if(!strcmp(argv[2], rpt_vars[i].name)){
03174          struct rpt *myrpt = &rpt_vars[i];
03175          rpt_push_alt_macro(myrpt,argv[3]);
03176       }
03177    }
03178    return RESULT_FAILURE;
03179 }
03180 /*
03181 * send an app_rpt **command** from the CLI
03182 */
03183 
03184 static int rpt_do_cmd(int fd, int argc, char *argv[])
03185 {
03186    int i, l;
03187    int busy=0;
03188    int maxActions = sizeof(function_table)/sizeof(struct function_table_tag);
03189 
03190    int thisRpt = -1;
03191    int thisAction = -1;
03192    struct rpt *myrpt = NULL;
03193    if (argc != 6) return RESULT_SHOWUSAGE;
03194    
03195    for(i = 0; i < nrpts; i++)
03196    {
03197       if(!strcmp(argv[2], rpt_vars[i].name))
03198       {
03199          thisRpt = i;
03200          myrpt = &rpt_vars[i];
03201          break;
03202       } /* if !strcmp... */
03203    } /* for i */
03204 
03205    if (thisRpt < 0)
03206    {
03207       ast_cli(fd, "Unknown node number %s.\n", argv[2]);
03208       return RESULT_FAILURE;
03209    } /* if thisRpt < 0 */
03210    
03211    /* Look up the action */
03212    l = strlen(argv[3]);
03213    for(i = 0 ; i < maxActions; i++)
03214    {
03215       if(!strncasecmp(argv[3], function_table[i].action, l))
03216       {
03217          thisAction = i;
03218          break;
03219       } /* if !strncasecmp... */
03220    } /* for i */
03221    
03222    if (thisAction < 0)
03223    {
03224       ast_cli(fd, "Unknown action name %s.\n", argv[3]);
03225       return RESULT_FAILURE;
03226    } /* if thisAction < 0 */
03227 
03228    /* at this point, it looks like all the arguments make sense... */
03229 
03230    rpt_mutex_lock(&myrpt->lock);
03231 
03232    if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE)
03233    {
03234       rpt_vars[thisRpt].cmdAction.state = CMD_STATE_BUSY;
03235       rpt_vars[thisRpt].cmdAction.functionNumber = thisAction;
03236       strncpy(rpt_vars[thisRpt].cmdAction.param, argv[4], MAXDTMF);
03237       strncpy(rpt_vars[thisRpt].cmdAction.digits, argv[5], MAXDTMF);
03238       rpt_vars[thisRpt].cmdAction.command_source = SOURCE_RPT;
03239       rpt_vars[thisRpt].cmdAction.state = CMD_STATE_READY;
03240    } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
03241    else
03242    {
03243       busy = 1;
03244    } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
03245    rpt_mutex_unlock(&myrpt->lock);
03246 
03247    return (busy ? RESULT_FAILURE : RESULT_SUCCESS);
03248 } /* rpt_do_cmd() */
03249 
03250 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
03251 {
03252    int res;
03253 
03254         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
03255                 return res;
03256                                                                                                                                             
03257         while(chan->generatordata) {
03258       if (ast_safe_sleep(chan,1)) return -1;
03259    }
03260 
03261         return 0;
03262 }
03263 
03264 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
03265 {
03266    return play_tone_pair(chan, freq, 0, duration, amplitude);
03267 }
03268 
03269 static int play_silence(struct ast_channel *chan, int duration)
03270 {
03271    return play_tone_pair(chan, 0, 0, duration, 0);
03272 }
03273 
03274 #ifdef   NEW_ASTERISK
03275 
03276 static char *res2cli(int r)
03277 
03278 {
03279    switch (r)
03280    {
03281        case RESULT_SUCCESS:
03282       return(CLI_SUCCESS);
03283        case RESULT_SHOWUSAGE:
03284       return(CLI_SHOWUSAGE);
03285        default:
03286       return(CLI_FAILURE);
03287    }
03288 }
03289 
03290 static char *handle_cli_debug(struct ast_cli_entry *e,
03291    int cmd, struct ast_cli_args *a)
03292 {
03293         switch (cmd) {
03294         case CLI_INIT:
03295                 e->command = "rpt debug level";
03296                 e->usage = debug_usage;
03297                 return NULL;
03298         case CLI_GENERATE:
03299                 return NULL;
03300    }
03301    return res2cli(rpt_do_debug(a->fd,a->argc,a->argv));
03302 }
03303 
03304 static char *handle_cli_dump(struct ast_cli_entry *e,
03305    int cmd, struct ast_cli_args *a)
03306 {
03307         switch (cmd) {
03308         case CLI_INIT:
03309                 e->command = "rpt dump level";
03310                 e->usage = dump_usage;
03311                 return NULL;
03312         case CLI_GENERATE:
03313                 return NULL;
03314    }
03315    return res2cli(rpt_do_dump(a->fd,a->argc,a->argv));
03316 }
03317 
03318 
03319 static char *handle_cli_stats(struct ast_cli_entry *e,
03320    int cmd, struct ast_cli_args *a)
03321 {
03322         switch (cmd) {
03323         case CLI_INIT:
03324                 e->command = "rpt stats";
03325                 e->usage = dump_stats;
03326                 return NULL;
03327         case CLI_GENERATE:
03328                 return NULL;
03329    }
03330    return res2cli(rpt_do_stats(a->fd,a->argc,a->argv));
03331 }
03332 
03333 static char *handle_cli_nodes(struct ast_cli_entry *e,
03334    int cmd, struct ast_cli_args *a)
03335 {
03336         switch (cmd) {
03337         case CLI_INIT:
03338                 e->command = "rpt nodes";
03339                 e->usage = dump_nodes;
03340                 return NULL;
03341         case CLI_GENERATE:
03342                 return NULL;
03343    }
03344    return res2cli(rpt_do_nodes(a->fd,a->argc,a->argv));
03345 }
03346 
03347 static char *handle_cli_local_nodes(struct ast_cli_entry *e,
03348    int cmd, struct ast_cli_args *a)
03349 {
03350         switch (cmd) {
03351         case CLI_INIT:
03352                 e->command = "rpt localnodes";
03353                 e->usage = usage_local_nodes;
03354                 return NULL;
03355         case CLI_GENERATE:
03356                 return NULL;
03357    }
03358    return res2cli(rpt_do_local_nodes(a->fd,a->argc,a->argv));
03359 }
03360 
03361 static char *handle_cli_lstats(struct ast_cli_entry *e,
03362    int cmd, struct ast_cli_args *a)
03363 {
03364         switch (cmd) {
03365         case CLI_INIT:
03366                 e->command = "rpt lstats";
03367                 e->usage = dump_lstats;
03368                 return NULL;
03369         case CLI_GENERATE:
03370                 return NULL;
03371    }
03372    return res2cli(rpt_do_lstats(a->fd,a->argc,a->argv));
03373 }
03374 
03375 static char *handle_cli_reload(struct ast_cli_entry *e,
03376    int cmd, struct ast_cli_args *a)
03377 {
03378         switch (cmd) {
03379         case CLI_INIT:
03380                 e->command = "rpt reload";
03381                 e->usage = reload_usage;
03382                 return NULL;
03383         case CLI_GENERATE:
03384                 return NULL;
03385    }
03386    return res2cli(rpt_do_reload(a->fd,a->argc,a->argv));
03387 }
03388 
03389 static char *handle_cli_restart(struct ast_cli_entry *e,
03390    int cmd, struct ast_cli_args *a)
03391 {
03392         switch (cmd) {
03393         case CLI_INIT:
03394                 e->command = "rpt restart";
03395                 e->usage = restart_usage;
03396                 return NULL;
03397         case CLI_GENERATE:
03398                 return NULL;
03399    }
03400    return res2cli(rpt_do_restart(a->fd,a->argc,a->argv));
03401 }
03402 
03403 static char *handle_cli_fun(struct ast_cli_entry *e,
03404    int cmd, struct ast_cli_args *a)
03405 {
03406         switch (cmd) {
03407         case CLI_INIT:
03408                 e->command = "rpt fun";
03409                 e->usage = fun_usage;
03410                 return NULL;
03411         case CLI_GENERATE:
03412                 return NULL;
03413    }
03414    return res2cli(rpt_do_fun(a->fd,a->argc,a->argv));
03415 }
03416 
03417 static char *handle_cli_fun1(struct ast_cli_entry *e,
03418    int cmd, struct ast_cli_args *a)
03419 {
03420         switch (cmd) {
03421         case CLI_INIT:
03422                 e->command = "rpt fun1";
03423                 e->usage = fun_usage;
03424                 return NULL;
03425         case CLI_GENERATE:
03426                 return NULL;
03427    }
03428    return res2cli(rpt_do_fun1(a->fd,a->argc,a->argv));
03429 }
03430 
03431 static char *handle_cli_cmd(struct ast_cli_entry *e,
03432    int cmd, struct ast_cli_args *a)
03433 {
03434         switch (cmd) {
03435         case CLI_INIT:
03436                 e->command = "rpt cmd";
03437                 e->usage = cmd_usage;
03438                 return NULL;
03439         case CLI_GENERATE:
03440                 return NULL;
03441    }
03442    return res2cli(rpt_do_cmd(a->fd,a->argc,a->argv));
03443 }
03444 
03445 static struct ast_cli_entry rpt_cli[] = {
03446    AST_CLI_DEFINE(handle_cli_debug,"Enable app_rpt debugging"),
03447    AST_CLI_DEFINE(handle_cli_dump,"Dump app_rpt structs for debugging"),
03448    AST_CLI_DEFINE(handle_cli_stats,"Dump node statistics"),
03449    AST_CLI_DEFINE(handle_cli_nodes,"Dump node list"),
03450    AST_CLI_DEFINE(handle_cli_local_nodes, "Dump list of local node numbers"),
03451    AST_CLI_DEFINE(handle_cli_lstats,"Dump link statistics"),
03452    AST_CLI_DEFINE(handle_cli_reload,"Reload app_rpt config"),
03453    AST_CLI_DEFINE(handle_cli_restart,"Restart app_rpt"),
03454    AST_CLI_DEFINE(handle_cli_fun,"Execute a DTMF function"),
03455    AST_CLI_DEFINE(handle_cli_fun1,"Execute a DTMF function"),
03456    AST_CLI_DEFINE(handle_cli_cmd,"Execute a DTMF function")
03457 };
03458 
03459 #endif
03460 
03461 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
03462 {
03463 
03464 static struct morse_bits mbits[] = {
03465       {0, 0}, /* SPACE */
03466       {0, 0}, 
03467       {6, 18},/* " */
03468       {0, 0},
03469       {7, 72},/* $ */
03470       {0, 0},
03471       {0, 0},
03472       {6, 30},/* ' */
03473       {5, 13},/* ( */
03474       {6, 29},/* ) */
03475       {0, 0},
03476       {5, 10},/* + */
03477       {6, 51},/* , */
03478       {6, 33},/* - */
03479       {6, 42},/* . */
03480       {5, 9}, /* / */
03481       {5, 31},/* 0 */
03482       {5, 30},/* 1 */
03483       {5, 28},/* 2 */
03484       {5, 24},/* 3 */
03485       {5, 16},/* 4 */
03486       {5, 0}, /* 5 */
03487       {5, 1}, /* 6 */
03488       {5, 3}, /* 7 */
03489       {5, 7}, /* 8 */
03490       {5, 15},/* 9 */
03491       {6, 7}, /* : */
03492       {6, 21},/* ; */
03493       {0, 0},
03494       {5, 33},/* = */
03495       {0, 0},
03496       {6, 12},/* ? */
03497       {0, 0},
03498          {2, 2}, /* A */
03499       {4, 1}, /* B */
03500       {4, 5}, /* C */
03501       {3, 1}, /* D */
03502       {1, 0}, /* E */
03503       {4, 4}, /* F */
03504       {3, 3}, /* G */
03505       {4, 0}, /* H */
03506       {2, 0}, /* I */
03507       {4, 14},/* J */
03508       {3, 5}, /* K */
03509       {4, 2}, /* L */
03510       {2, 3}, /* M */
03511       {2, 1}, /* N */
03512       {3, 7}, /* O */
03513       {4, 6}, /* P */
03514       {4, 11},/* Q */
03515       {3, 2}, /* R */
03516       {3, 0}, /* S */
03517       {1, 1}, /* T */
03518       {3, 4}, /* U */
03519       {4, 8}, /* V */
03520       {3, 6}, /* W */
03521       {4, 9}, /* X */
03522       {4, 13},/* Y */
03523       {4, 3}  /* Z */
03524    };
03525 
03526 
03527    int dottime;
03528    int dashtime;
03529    int intralettertime;
03530    int interlettertime;
03531    int interwordtime;
03532    int len, ddcomb;
03533    int res;
03534    int c;
03535    int i;
03536    int flags;
03537          
03538    res = 0;
03539    
03540    /* Approximate the dot time from the speed arg. */
03541    
03542    dottime = 900/speed;
03543    
03544    /* Establish timing releationships */
03545    
03546    dashtime = 3 * dottime;
03547    intralettertime = dottime;
03548    interlettertime = dottime * 4 ;
03549    interwordtime = dottime * 7;
03550    
03551    for(;(*string) && (!res); string++){
03552    
03553       c = *string;
03554       
03555       /* Convert lower case to upper case */
03556       
03557       if((c >= 'a') && (c <= 'z'))
03558          c -= 0x20;
03559       
03560       /* Can't deal with any char code greater than Z, skip it */
03561       
03562       if(c  > 'Z')
03563          continue;
03564       
03565       /* If space char, wait the inter word time */
03566                
03567       if(c == ' '){
03568          if(!res)
03569             res = play_silence(chan, interwordtime);
03570          continue;
03571       }
03572       
03573       /* Subtract out control char offset to match our table */
03574       
03575       c -= 0x20;
03576       
03577       /* Get the character data */
03578       
03579       len = mbits[c].len;
03580       ddcomb = mbits[c].ddcomb;
03581       
03582       /* Send the character */
03583       
03584       for(; len ; len--){
03585          if(!res)
03586             res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
03587          if(!res)
03588             res = play_silence(chan, intralettertime);
03589          ddcomb >>= 1;
03590       }
03591       
03592       /* Wait the interletter time */
03593       
03594       if(!res)
03595          res = play_silence(chan, interlettertime - intralettertime);
03596    }
03597    
03598    /* Wait for all the frames to be sent */
03599    
03600    if (!res) 
03601       res = ast_waitstream(chan, "");
03602    ast_stopstream(chan);
03603    
03604    /*
03605    * Wait for the DAHDI driver to physically write the tone blocks to the hardware
03606    */
03607 
03608    for(i = 0; i < 20 ; i++){
03609       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
03610       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
03611       if(flags & DAHDI_IOMUX_WRITEEMPTY)
03612          break;
03613       if( ast_safe_sleep(chan, 50)){
03614          res = -1;
03615          break;
03616       }
03617    }
03618 
03619    
03620    return res;
03621 }
03622 
03623 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
03624 {
03625    char *p,*stringp;
03626    char *tonesubset;
03627    int f1,f2;
03628    int duration;
03629    int amplitude;
03630    int res;
03631    int i;
03632    int flags;
03633    
03634    res = 0;
03635 
03636    if(!tonestring)
03637       return res;
03638    
03639    p = stringp = ast_strdup(tonestring);
03640 
03641    for(;tonestring;){
03642       tonesubset = strsep(&stringp,")");
03643       if(!tonesubset)
03644          break;
03645       if(sscanf(tonesubset,"(%30d,%30d,%30d,%30d", &f1, &f2, &duration, &amplitude) != 4)
03646          break;
03647       res = play_tone_pair(chan, f1, f2, duration, amplitude);
03648       if(res)
03649          break;
03650    }
03651    if(p)
03652       ast_free(p);
03653    if(!res)
03654       res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
03655    
03656    if (!res) 
03657       res = ast_waitstream(chan, "");
03658 
03659    ast_stopstream(chan);
03660 
03661    /*
03662    * Wait for the DAHDI driver to physically write the tone blocks to the hardware
03663    */
03664 
03665    for(i = 0; i < 20 ; i++){
03666       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
03667       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
03668       if(flags & DAHDI_IOMUX_WRITEEMPTY)
03669          break;
03670       if( ast_safe_sleep(chan, 50)){
03671          res = -1;
03672          break;
03673       }
03674    }
03675       
03676    return res;
03677       
03678 }
03679 
03680 static int sayfile(struct ast_channel *mychannel,char *fname)
03681 {
03682 int   res;
03683 
03684    res = ast_streamfile(mychannel, fname, mychannel->language);
03685    if (!res) 
03686       res = ast_waitstream(mychannel, "");
03687    else
03688        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03689    ast_stopstream(mychannel);
03690    return res;
03691 }
03692 
03693 static int saycharstr(struct ast_channel *mychannel,char *str)
03694 {
03695 int   res;
03696 
03697    res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
03698    if (!res) 
03699       res = ast_waitstream(mychannel, "");
03700    else
03701        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03702    ast_stopstream(mychannel);
03703    return res;
03704 }
03705 
03706 static int saynum(struct ast_channel *mychannel, int num)
03707 {
03708    int res;
03709    res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
03710    if(!res)
03711       res = ast_waitstream(mychannel, "");
03712    else
03713       ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03714    ast_stopstream(mychannel);
03715    return res;
03716 }
03717 
03718 /* say a node and nodename. Try to look in dir referred to by nodenames in
03719 config, and see if there's a custom node file to play, and if so, play it */
03720 
03721 static int saynode(struct rpt *myrpt, struct ast_channel *mychannel, char *name)
03722 {
03723 int   res;
03724 char  *val,fname[300];
03725 
03726    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "nodenames");
03727    if (!val) val = NODENAMES;
03728    snprintf(fname,sizeof(fname) - 1,"%s/%s",val,name);
03729    if (ast_fileexists(fname,NULL,mychannel->language) > 0)
03730       return(sayfile(mychannel,fname));
03731    res = sayfile(mychannel,"rpt/node");
03732    if (!res) 
03733       res = ast_say_character_str(mychannel,name,NULL,mychannel->language);
03734    return res;
03735 }
03736 
03737 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
03738 {
03739    int res;
03740    char c;
03741    
03742    static int morsespeed;
03743    static int morsefreq;
03744    static int morseampl;
03745    static int morseidfreq = 0;
03746    static int morseidampl;
03747    static char mcat[] = MORSE;
03748    
03749    res = 0;
03750    
03751    if(!morseidfreq){ /* Get the morse parameters if not already loaded */
03752       morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
03753          morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
03754          morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
03755       morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
03756       morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330); 
03757    }
03758    
03759    /* Is it a file, or a tone sequence? */
03760          
03761    if(entry[0] == '|'){
03762       c = entry[1];
03763       if((c >= 'a')&&(c <= 'z'))
03764          c -= 0x20;
03765    
03766       switch(c){
03767          case 'I': /* Morse ID */
03768             res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
03769             break;
03770          
03771          case 'M': /* Morse Message */
03772             res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
03773             break;
03774          
03775          case 'T': /* Tone sequence */
03776             res = send_tone_telemetry(chan, entry + 2);
03777             break;
03778          default:
03779             res = -1;
03780       }
03781    }
03782    else
03783       res = sayfile(chan, entry); /* File */
03784    return res;
03785 }
03786 
03787 /*
03788 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
03789 *
03790 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
03791 */
03792 
03793 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
03794 {
03795    
03796    int res;
03797    int i;
03798    char *entry;
03799    char *telemetry;
03800    char *telemetry_save;
03801 
03802    res = 0;
03803    telemetry_save = NULL;
03804    entry = NULL;
03805    
03806    /* Retrieve the section name for telemetry from the node section */
03807    telemetry = (char *) ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
03808    if(telemetry ){
03809       telemetry_save = ast_strdup(telemetry);
03810       if(!telemetry_save){
03811          ast_log(LOG_WARNING,"ast_strdup() failed in telem_lookup()\n");
03812          return res;
03813       }
03814       entry = (char *) ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
03815    }
03816    
03817    /* Try to look up the telemetry name */   
03818 
03819    if(!entry){
03820       /* Telemetry name wasn't found in the config file, use the default */
03821       for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
03822          if(!strcasecmp(tele_defs[i].name, name))
03823             entry = tele_defs[i].value;
03824       }
03825    }
03826    if(entry){  
03827       if(strlen(entry))
03828          if (chan) telem_any(myrpt,chan, entry);
03829    }
03830    else{
03831       res = -1;
03832    }
03833    if(telemetry_save)
03834       ast_free(telemetry_save);
03835    return res;
03836 }
03837 
03838 /*
03839 * Retrieve a wait interval
03840 */
03841 
03842 static int get_wait_interval(struct rpt *myrpt, int type)
03843 {
03844         int interval;
03845         char *wait_times;
03846         char *wait_times_save;
03847                                                                                                                   
03848         wait_times_save = NULL;
03849         wait_times = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
03850                                                                                                                   
03851         if(wait_times){
03852                 wait_times_save = ast_strdup(wait_times);
03853                 if(!wait_times_save)
03854          return 0;
03855                 
03856         }
03857                                                                                                                   
03858         switch(type){
03859                 case DLY_TELEM:
03860                         if(wait_times)
03861                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
03862                         else
03863                                 interval = 1000;
03864                         break;
03865                                                                                                                   
03866                 case DLY_ID:
03867                         if(wait_times)
03868                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
03869                         else
03870                                 interval = 500;
03871                         break;
03872                                                                                                                   
03873                 case DLY_UNKEY:
03874                         if(wait_times)
03875                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",50,5000,1000);
03876                         else
03877                                 interval = 1000;
03878                         break;
03879                                                                                                                   
03880                 case DLY_LINKUNKEY:
03881                         if(wait_times)
03882                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "linkunkeywait",500,5000,1000);
03883                         else
03884                                 interval = 1000;
03885                         break;
03886                                                                                                                   
03887                 case DLY_CALLTERM:
03888                         if(wait_times)
03889                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
03890                         else
03891                                 interval = 1500;
03892                         break;
03893                                                                                                                   
03894                 case DLY_COMP:
03895                         if(wait_times)
03896                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "compwait",500,5000,200);
03897                         else
03898                                 interval = 200;
03899                         break;
03900                                                                                                                   
03901                 case DLY_PARROT:
03902                         if(wait_times)
03903                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "parrotwait",500,5000,200);
03904                         else
03905                                 interval = 200;
03906                         break;
03907                                                                                                                   
03908                 default:
03909          interval = 0;
03910          break;
03911         }
03912    if(wait_times_save)
03913             ast_free(wait_times_save);
03914    return interval;
03915 }                                                                                                                  
03916 
03917 
03918 /*
03919 * Wait a configurable interval of time 
03920 */
03921 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
03922 {
03923    int interval;
03924    interval = get_wait_interval(myrpt, type);
03925    if(debug)
03926       ast_log(LOG_NOTICE,"Delay interval = %d\n", interval);
03927    if(interval)
03928       ast_safe_sleep(chan,interval);
03929    if(debug)
03930       ast_log(LOG_NOTICE,"Delay complete\n");
03931    return;
03932 }
03933 
03934 static int split_freq(char *mhz, char *decimals, char *freq);
03935 
03936 static void *rpt_tele_thread(void *this)
03937 {
03938 struct dahdi_confinfo ci;  /* conference info */
03939 int   res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
03940 struct   rpt_tele *mytele = (struct rpt_tele *)this;
03941 struct  rpt_tele *tlist;
03942 struct   rpt *myrpt;
03943 struct   rpt_link *l,*l1,linkbase;
03944 struct   ast_channel *mychannel;
03945 int vmajor, vminor, m;
03946 char *p,*ct,*ct_copy,*ident, *nodename,*cp;
03947 time_t t;
03948 #ifdef   NEW_ASTERISK
03949 struct ast_tm localtm;
03950 #else
03951 struct tm localtm;
03952 #endif
03953 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
03954 int   i,ns,rbimode;
03955 char mhz[MAXREMSTR];
03956 char decimals[MAXREMSTR];
03957 char  mystr[200];
03958 struct dahdi_params par;
03959 
03960 
03961    /* get a pointer to myrpt */
03962    myrpt = mytele->rpt;
03963 
03964    /* Snag copies of a few key myrpt variables */
03965    rpt_mutex_lock(&myrpt->lock);
03966    nodename = ast_strdup(myrpt->name);
03967    if(!nodename)
03968    {
03969        fprintf(stderr,"rpt:Sorry unable strdup nodename\n");
03970        rpt_mutex_lock(&myrpt->lock);
03971        remque((struct qelem *)mytele);
03972        ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03973        rpt_mutex_unlock(&myrpt->lock);
03974        ast_free(mytele);
03975        pthread_exit(NULL);
03976    }
03977 
03978    if (myrpt->p.ident){
03979       ident = ast_strdup(myrpt->p.ident);
03980          if(!ident)
03981       {
03982                  fprintf(stderr,"rpt:Sorry unable strdup ident\n");
03983          rpt_mutex_lock(&myrpt->lock);
03984                   remque((struct qelem *)mytele);
03985                   ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",
03986          __LINE__, mytele->mode); /*@@@@@@@@@@@*/
03987                   rpt_mutex_unlock(&myrpt->lock);
03988          ast_free(nodename);
03989                   ast_free(mytele);
03990                   pthread_exit(NULL);
03991          }
03992    }
03993    else
03994    {
03995       ident = "";
03996    }
03997    rpt_mutex_unlock(&myrpt->lock);
03998       
03999 
04000 
04001    /* allocate a pseudo-channel thru asterisk */
04002    mychannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
04003    if (!mychannel)
04004    {
04005       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
04006       rpt_mutex_lock(&myrpt->lock);
04007       remque((struct qelem *)mytele);
04008       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04009       rpt_mutex_unlock(&myrpt->lock);
04010       ast_free(nodename);
04011       ast_free(ident);
04012       ast_free(mytele);    
04013       pthread_exit(NULL);
04014    }
04015 #ifdef   AST_CDR_FLAG_POST_DISABLED
04016    if (mychannel->cdr) 
04017       ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
04018 #endif
04019    rpt_mutex_lock(&myrpt->lock);
04020    mytele->chan = mychannel;
04021    rpt_mutex_unlock(&myrpt->lock);
04022 
04023    while((mytele->mode != SETREMOTE) && (mytele->mode != UNKEY) &&
04024       (mytele->mode != LINKUNKEY))
04025    {  
04026                 rpt_mutex_lock(&myrpt->lock);
04027       if (!myrpt->active_telem)
04028       {
04029          myrpt->active_telem = mytele;
04030                    rpt_mutex_unlock(&myrpt->lock);
04031          break;
04032       }
04033                 rpt_mutex_unlock(&myrpt->lock);
04034       usleep(100000);
04035    }
04036 
04037    /* make a conference for the tx */
04038    ci.chan = 0;
04039    /* If the telemetry is only intended for a local audience, */
04040    /* only connect the ID audio to the local tx conference so */
04041    /* linked systems can't hear it */
04042    ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
04043       (mytele->mode == TAILMSG) || (mytele->mode == LINKUNKEY) || (mytele->mode == TIMEOUT) || 
04044       (mytele->mode == PARROT) || (mytele->mode == STATS_TIME_LOCAL)) ? 
04045          myrpt->txconf : myrpt->conf);
04046    ci.confmode = DAHDI_CONF_CONFANN;
04047    /* first put the channel on the conference in announce mode */
04048    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04049    {
04050       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04051       rpt_mutex_lock(&myrpt->lock);
04052       myrpt->active_telem = NULL;
04053       remque((struct qelem *)mytele);
04054       rpt_mutex_unlock(&myrpt->lock);
04055       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04056       ast_free(nodename);
04057       ast_free(ident);
04058       ast_free(mytele);    
04059       ast_hangup(mychannel);
04060       pthread_exit(NULL);
04061    }
04062    ast_stopstream(mychannel);
04063    switch(mytele->mode)
04064    {
04065        case ID:
04066        case ID1:
04067       /* wait a bit */
04068       wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
04069       res = telem_any(myrpt,mychannel, ident); 
04070       imdone=1;   
04071       break;
04072       
04073        case TAILMSG:
04074       res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language); 
04075       break;
04076       
04077        case IDTALKOVER:
04078          p = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
04079          if(p)
04080          res = telem_any(myrpt,mychannel, p); 
04081       imdone=1;   
04082          break;
04083             
04084        case PROC:
04085       /* wait a little bit longer */
04086       wait_interval(myrpt, DLY_TELEM, mychannel);
04087       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
04088       if(res < 0){ /* Then default message */
04089          res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
04090       }
04091       break;
04092        case TERM:
04093       /* wait a little bit longer */
04094       wait_interval(myrpt, DLY_CALLTERM, mychannel);
04095       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
04096       if(res < 0){ /* Then default message */
04097          res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
04098       }
04099       break;
04100        case COMPLETE:
04101       /* wait a little bit */
04102       wait_interval(myrpt, DLY_TELEM, mychannel);
04103       res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04104       break;
04105        case MACRO_NOTFOUND:
04106       /* wait a little bit */
04107       wait_interval(myrpt, DLY_TELEM, mychannel);
04108       res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
04109       break;
04110        case MACRO_BUSY:
04111       /* wait a little bit */
04112       wait_interval(myrpt, DLY_TELEM, mychannel);
04113       res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
04114       break;
04115        case UNKEY:
04116       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
04117          imdone = 1;
04118          break;
04119       }
04120          
04121       /*
04122       * Reset the Unkey to CT timer
04123       */
04124 
04125       x = get_wait_interval(myrpt, DLY_UNKEY);
04126       rpt_mutex_lock(&myrpt->lock);
04127       myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
04128       rpt_mutex_unlock(&myrpt->lock);
04129 
04130       /*
04131       * If there's one already queued, don't do another
04132       */
04133 
04134       tlist = myrpt->tele.next;
04135       unkeys_queued = 0;
04136                 if (tlist != &myrpt->tele)
04137                 {
04138                         rpt_mutex_lock(&myrpt->lock);
04139                         while(tlist != &myrpt->tele){
04140                                 if (tlist->mode == UNKEY) unkeys_queued++;
04141                                 tlist = tlist->next;
04142                         }
04143                         rpt_mutex_unlock(&myrpt->lock);
04144       }
04145       if( unkeys_queued > 1){
04146          imdone = 1;
04147          break;
04148       }
04149 
04150       /* Wait for the telemetry timer to expire */
04151       /* Periodically check the timer since it can be re-initialized above */
04152       while(myrpt->unkeytocttimer)
04153       {
04154          int ctint;
04155          if(myrpt->unkeytocttimer > 100)
04156             ctint = 100;
04157          else
04158             ctint = myrpt->unkeytocttimer;
04159          ast_safe_sleep(mychannel, ctint);
04160          rpt_mutex_lock(&myrpt->lock);
04161          if(myrpt->unkeytocttimer < ctint)
04162             myrpt->unkeytocttimer = 0;
04163          else
04164             myrpt->unkeytocttimer -= ctint;
04165          rpt_mutex_unlock(&myrpt->lock);
04166       }
04167    
04168       /*
04169       * Now, the carrier on the rptr rx should be gone. 
04170       * If it re-appeared, then forget about sending the CT
04171       */
04172       if(myrpt->keyed){
04173          imdone = 1;
04174          break;
04175       }
04176       
04177       rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
04178       myrpt->dailykerchunks++;
04179       myrpt->totalkerchunks++;
04180       rpt_mutex_unlock(&myrpt->lock);
04181    
04182       haslink = 0;
04183       hastx = 0;
04184       hasremote = 0;    
04185       l = myrpt->links.next;
04186       if (l != &myrpt->links)
04187       {
04188          rpt_mutex_lock(&myrpt->lock);
04189          while(l != &myrpt->links)
04190          {
04191             if (l->name[0] == '0')
04192             {
04193                l = l->next;
04194                continue;
04195             }
04196             haslink = 1;
04197             if (l->mode) {
04198                hastx++;
04199                if (l->isremote) hasremote++;
04200             }
04201             l = l->next;
04202          }
04203          rpt_mutex_unlock(&myrpt->lock);
04204       }
04205       if (haslink)
04206       {
04207 
04208          res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
04209          if(res)
04210             ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
04211          
04212       
04213          /* if in remote cmd mode, indicate it */
04214          if (myrpt->cmdnode[0])
04215          {
04216             ast_safe_sleep(mychannel,200);
04217             res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
04218             if(res)
04219                ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
04220             ast_stopstream(mychannel);
04221          }
04222       }
04223       else if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
04224          ct_copy = ast_strdup(ct);
04225          if(ct_copy)
04226          {
04227             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04228             ast_free(ct_copy);
04229          }
04230          else
04231             res = -1;
04232          if(res)
04233             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
04234       }  
04235       if (hasremote && (!myrpt->cmdnode[0]))
04236       {
04237          /* set for all to hear */
04238          ci.chan = 0;
04239          ci.confno = myrpt->conf;
04240          ci.confmode = DAHDI_CONF_CONFANN;
04241          /* first put the channel on the conference in announce mode */
04242          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04243          {
04244             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04245             rpt_mutex_lock(&myrpt->lock);
04246             myrpt->active_telem = NULL;
04247             remque((struct qelem *)mytele);
04248             rpt_mutex_unlock(&myrpt->lock);
04249             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04250             ast_free(nodename);
04251             ast_free(ident);
04252             ast_free(mytele);    
04253             ast_hangup(mychannel);
04254             pthread_exit(NULL);
04255          }
04256          if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
04257             ast_safe_sleep(mychannel,200);
04258             ct_copy = ast_strdup(ct);
04259             if(ct_copy)
04260             {
04261                res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04262                ast_free(ct_copy);
04263             }
04264             else
04265                res = -1;
04266       
04267             if(res)
04268                ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
04269          }  
04270       }
04271 #if   defined(_MDC_DECODE_H_) && defined(MDC_SAY_WHEN_DOING_CT)
04272       if (myrpt->lastunit)
04273       {
04274          char mystr[10];
04275 
04276          ast_safe_sleep(mychannel,200);
04277          /* set for all to hear */
04278          ci.chan = 0;
04279          ci.confno = myrpt->txconf;
04280          ci.confmode = DAHDI_CONF_CONFANN;
04281          /* first put the channel on the conference in announce mode */
04282          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04283          {
04284             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04285             rpt_mutex_lock(&myrpt->lock);
04286             myrpt->active_telem = NULL;
04287             remque((struct qelem *)mytele);
04288             rpt_mutex_unlock(&myrpt->lock);
04289             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04290             ast_free(nodename);
04291             ast_free(ident);
04292             ast_free(mytele);    
04293             ast_hangup(mychannel);
04294             pthread_exit(NULL);
04295          }
04296          sprintf(mystr,"%04x",myrpt->lastunit);
04297          myrpt->lastunit = 0;
04298          ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
04299          break;
04300       }
04301 #endif
04302       imdone = 1;
04303       break;
04304        case LINKUNKEY:
04305       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
04306          imdone = 1;
04307          break;
04308       }
04309          
04310       /*
04311       * Reset the Unkey to CT timer
04312       */
04313 
04314       x = get_wait_interval(myrpt, DLY_LINKUNKEY);
04315       mytele->mylink.linkunkeytocttimer = x; /* Must be protected as it is changed below */
04316 
04317       /*
04318       * If there's one already queued, don't do another
04319       */
04320 
04321       tlist = myrpt->tele.next;
04322       unkeys_queued = 0;
04323                 if (tlist != &myrpt->tele)
04324                 {
04325                         rpt_mutex_lock(&myrpt->lock);
04326                         while(tlist != &myrpt->tele){
04327                                 if (tlist->mode == LINKUNKEY) unkeys_queued++;
04328                                 tlist = tlist->next;
04329                         }
04330                         rpt_mutex_unlock(&myrpt->lock);
04331       }
04332       if( unkeys_queued > 1){
04333          imdone = 1;
04334          break;
04335       }
04336 
04337       /* Wait for the telemetry timer to expire */
04338       /* Periodically check the timer since it can be re-initialized above */
04339       while(mytele->mylink.linkunkeytocttimer)
04340       {
04341          int ctint;
04342          if(mytele->mylink.linkunkeytocttimer > 100)
04343             ctint = 100;
04344          else
04345             ctint = mytele->mylink.linkunkeytocttimer;
04346          ast_safe_sleep(mychannel, ctint);
04347          rpt_mutex_lock(&myrpt->lock);
04348          if(mytele->mylink.linkunkeytocttimer < ctint)
04349             mytele->mylink.linkunkeytocttimer = 0;
04350          else
04351             mytele->mylink.linkunkeytocttimer -= ctint;
04352          rpt_mutex_unlock(&myrpt->lock);
04353       }
04354    
04355       if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "linkunkeyct"))){ /* Unlinked Courtesy Tone */
04356          ct_copy = ast_strdup(ct);
04357          if(ct_copy){
04358             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04359             ast_free(ct_copy);
04360          }
04361          else
04362             res = -1;
04363          if(res)
04364             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
04365       }  
04366       imdone = 1;
04367       break;
04368        case REMDISC:
04369       /* wait a little bit */
04370       wait_interval(myrpt, DLY_TELEM, mychannel);
04371       l = myrpt->links.next;
04372       haslink = 0;
04373       /* dont report if a link for this one still on system */
04374       if (l != &myrpt->links)
04375       {
04376          rpt_mutex_lock(&myrpt->lock);
04377          while(l != &myrpt->links)
04378          {
04379             if (l->name[0] == '0')
04380             {
04381                l = l->next;
04382                continue;
04383             }
04384             if (!strcmp(l->name,mytele->mylink.name))
04385             {
04386                haslink = 1;
04387                break;
04388             }
04389             l = l->next;
04390          }
04391          rpt_mutex_unlock(&myrpt->lock);
04392       }
04393       if (haslink)
04394       {
04395          imdone = 1;
04396          break;
04397       }
04398       res = saynode(myrpt,mychannel,mytele->mylink.name);
04399       if (!res) 
04400           res = ast_streamfile(mychannel, ((mytele->mylink.hasconnected) ? 
04401          "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
04402       break;
04403        case REMALREADY:
04404       /* wait a little bit */
04405       wait_interval(myrpt, DLY_TELEM, mychannel);
04406       res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
04407       break;
04408        case REMNOTFOUND:
04409       /* wait a little bit */
04410       wait_interval(myrpt, DLY_TELEM, mychannel);
04411       res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
04412       break;
04413        case REMGO:
04414       /* wait a little bit */
04415       wait_interval(myrpt, DLY_TELEM, mychannel);
04416       res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
04417       break;
04418        case CONNECTED:
04419       /* wait a little bit */
04420       wait_interval(myrpt, DLY_TELEM,  mychannel);
04421       res = saynode(myrpt,mychannel,mytele->mylink.name);
04422       if (!res)
04423           res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
04424       if (!res) 
04425          res = ast_waitstream(mychannel, "");
04426       else
04427           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04428       ast_stopstream(mychannel);
04429       res = ast_streamfile(mychannel, "digits/2", mychannel->language);
04430       if (!res) 
04431          res = ast_waitstream(mychannel, "");
04432       else
04433           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04434       ast_stopstream(mychannel);
04435       res = saynode(myrpt,mychannel,myrpt->name);
04436       imdone = 1;
04437       break;
04438        case CONNFAIL:
04439       res = saynode(myrpt,mychannel,mytele->mylink.name);
04440       if (!res) 
04441           res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
04442       break;
04443        case MEMNOTFOUND:
04444       /* wait a little bit */
04445       wait_interval(myrpt, DLY_TELEM, mychannel);
04446       res = ast_streamfile(mychannel, "rpt/memory_notfound", mychannel->language);
04447       break;
04448        case PLAYBACK:
04449       /* wait a little bit */
04450       wait_interval(myrpt, DLY_TELEM, mychannel);
04451       res = ast_streamfile(mychannel, mytele->param, mychannel->language);
04452       break;
04453        case TOPKEY:
04454       /* wait a little bit */
04455       wait_interval(myrpt, DLY_TELEM, mychannel);
04456       for(i = 0; i < TOPKEYN; i++)
04457       {
04458          if (!myrpt->topkey[i].node[0]) continue;
04459          if ((!myrpt->topkeylong) && (myrpt->topkey[i].keyed)) continue;
04460          res = saynode(myrpt, mychannel,  myrpt->topkey[i].node);
04461          if (!res) res = sayfile(mychannel,(myrpt->topkey[i].keyed) ?
04462             "rpt/keyedfor" : "rpt/unkeyedfor");
04463          if (!res) res = saynum(mychannel,
04464             myrpt->topkey[i].timesince);
04465          if (!res) res = sayfile(mychannel,"rpt/seconds");
04466          if (!myrpt->topkeylong) break;
04467       }
04468       imdone = 1;
04469       break;
04470        case SETREMOTE:
04471       ast_mutex_lock(&myrpt->remlock);
04472       res = 0;
04473       if(!strcmp(myrpt->remoterig, remote_rig_ft897))
04474       {
04475          res = set_ft897(myrpt);
04476       }
04477       else if(!strcmp(myrpt->remoterig, remote_rig_tm271))
04478       {
04479          res = set_tm271(myrpt);
04480       }
04481       else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
04482       {
04483          res = set_ic706(myrpt);
04484       }
04485 #ifdef HAVE_IOPERM
04486       else if(!strcmp(myrpt->remoterig, remote_rig_rbi)||!strcmp(myrpt->remoterig, remote_rig_ppp16))
04487       {
04488          if (ioperm(myrpt->p.iobase,1,1) == -1)
04489          {
04490             rpt_mutex_unlock(&myrpt->lock);
04491             ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
04492             res = -1;
04493          }
04494          else res = setrbi(myrpt);
04495       }
04496 #endif
04497       else if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
04498       {
04499          if (myrpt->iofd >= 0) setdtr(myrpt->iofd,1);
04500          res = setkenwood(myrpt);
04501          if (myrpt->iofd >= 0) setdtr(myrpt->iofd,0);
04502          if (ast_safe_sleep(mychannel,200) == -1)
04503          {
04504             ast_mutex_unlock(&myrpt->remlock);
04505             res = -1;
04506             break;
04507          }
04508          if (myrpt->iofd < 0)
04509          {
04510             i = DAHDI_FLUSH_EVENT;
04511             if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_FLUSH,&i) == -1)
04512             {
04513                ast_mutex_unlock(&myrpt->remlock);
04514                ast_log(LOG_ERROR,"Cant flush events");
04515                res = -1;
04516                break;
04517             }
04518             if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_GET_PARAMS,&par) == -1)
04519             {
04520                ast_mutex_unlock(&myrpt->remlock);
04521                ast_log(LOG_ERROR,"Cant get params");
04522                res = -1;
04523                break;
04524             }
04525             myrpt->remoterx = 
04526                (par.rxisoffhook || (myrpt->tele.next != &myrpt->tele));
04527          }
04528       }
04529 
04530       ast_mutex_unlock(&myrpt->remlock);
04531       if (!res)
04532       {
04533          imdone = 1;
04534          break;
04535       }
04536       /* fall thru to invalid freq */
04537        case INVFREQ:
04538       /* wait a little bit */
04539       wait_interval(myrpt, DLY_TELEM, mychannel);
04540       res = ast_streamfile(mychannel, "rpt/invalid-freq", mychannel->language);
04541       break;
04542        case REMMODE:
04543       cp = 0;
04544       wait_interval(myrpt, DLY_TELEM, mychannel);
04545       switch(myrpt->remmode)
04546       {
04547           case REM_MODE_FM:
04548          saycharstr(mychannel,"FM");
04549          break;
04550           case REM_MODE_USB:
04551          saycharstr(mychannel,"USB");
04552          break;
04553           case REM_MODE_LSB:
04554          saycharstr(mychannel,"LSB");
04555          break;
04556           case REM_MODE_AM:
04557          saycharstr(mychannel,"AM");
04558          break;
04559       }
04560       wait_interval(myrpt, DLY_COMP, mychannel);
04561       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04562       break;
04563        case LOGINREQ:
04564       wait_interval(myrpt, DLY_TELEM, mychannel);
04565       sayfile(mychannel,"rpt/login");
04566       saycharstr(mychannel,myrpt->name);
04567       break;
04568        case REMLOGIN:
04569       wait_interval(myrpt, DLY_TELEM, mychannel);
04570       saycharstr(mychannel,myrpt->loginuser);
04571       saynode(myrpt,mychannel,myrpt->name);
04572       wait_interval(myrpt, DLY_COMP, mychannel);
04573       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04574       break;
04575        case REMXXX:
04576       wait_interval(myrpt, DLY_TELEM, mychannel);
04577       res = 0;
04578       switch(mytele->submode)
04579       {
04580           case 100: /* RX PL Off */
04581          sayfile(mychannel, "rpt/rxpl");
04582          sayfile(mychannel, "rpt/off");
04583          break;
04584           case 101: /* RX PL On */
04585          sayfile(mychannel, "rpt/rxpl");
04586          sayfile(mychannel, "rpt/on");
04587          break;
04588           case 102: /* TX PL Off */
04589          sayfile(mychannel, "rpt/txpl");
04590          sayfile(mychannel, "rpt/off");
04591          break;
04592           case 103: /* TX PL On */
04593          sayfile(mychannel, "rpt/txpl");
04594          sayfile(mychannel, "rpt/on");
04595          break;
04596           case 104: /* Low Power */
04597          sayfile(mychannel, "rpt/lopwr");
04598          break;
04599           case 105: /* Medium Power */
04600          sayfile(mychannel, "rpt/medpwr");
04601          break;
04602           case 106: /* Hi Power */
04603          sayfile(mychannel, "rpt/hipwr");
04604          break;
04605           case 113: /* Scan down slow */
04606          sayfile(mychannel,"rpt/down");
04607          sayfile(mychannel, "rpt/slow");
04608          break;
04609           case 114: /* Scan down quick */
04610          sayfile(mychannel,"rpt/down");
04611          sayfile(mychannel, "rpt/quick");
04612          break;
04613           case 115: /* Scan down fast */
04614          sayfile(mychannel,"rpt/down");
04615          sayfile(mychannel, "rpt/fast");
04616          break;
04617           case 116: /* Scan up slow */
04618          sayfile(mychannel,"rpt/up");
04619          sayfile(mychannel, "rpt/slow");
04620          break;
04621           case 117: /* Scan up quick */
04622          sayfile(mychannel,"rpt/up");
04623          sayfile(mychannel, "rpt/quick");
04624          break;
04625           case 118: /* Scan up fast */
04626          sayfile(mychannel,"rpt/up");
04627          sayfile(mychannel, "rpt/fast");
04628          break;
04629           default:
04630          res = -1;
04631       }
04632       wait_interval(myrpt, DLY_COMP, mychannel);
04633       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04634       break;
04635        case SCAN:
04636       ast_mutex_lock(&myrpt->remlock);
04637       if (myrpt->hfscanstop)
04638       {
04639          myrpt->hfscanstatus = 0;
04640          myrpt->hfscanmode = 0;
04641          myrpt->hfscanstop = 0;
04642          mytele->mode = SCANSTAT;
04643          ast_mutex_unlock(&myrpt->remlock);
04644          if (ast_safe_sleep(mychannel,1000) == -1) break;
04645          sayfile(mychannel, "rpt/stop"); 
04646          imdone = 1;
04647          break;
04648       }
04649       if (myrpt->hfscanstatus > -2) service_scan(myrpt);
04650       i = myrpt->hfscanstatus;
04651       myrpt->hfscanstatus = 0;
04652       if (i) mytele->mode = SCANSTAT;
04653       ast_mutex_unlock(&myrpt->remlock);
04654       if (i < 0) sayfile(mychannel, "rpt/stop"); 
04655       else if (i > 0) saynum(mychannel,i);
04656       imdone = 1;
04657       break;
04658        case TUNE:
04659       ast_mutex_lock(&myrpt->remlock);
04660       if (!strcmp(myrpt->remoterig,remote_rig_ic706))
04661       {
04662          set_mode_ic706(myrpt, REM_MODE_AM);
04663          if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
04664          ast_safe_sleep(mychannel,500);
04665          set_mode_ic706(myrpt, myrpt->remmode);
04666          myrpt->tunerequest = 0;
04667          ast_mutex_unlock(&myrpt->remlock);
04668          imdone = 1;
04669          break;
04670       }
04671       set_mode_ft897(myrpt, REM_MODE_AM);
04672       simple_command_ft897(myrpt, 8);
04673       if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
04674       simple_command_ft897(myrpt, 0x88);
04675       ast_safe_sleep(mychannel,500);
04676       set_mode_ft897(myrpt, myrpt->remmode);
04677       myrpt->tunerequest = 0;
04678       ast_mutex_unlock(&myrpt->remlock);
04679       imdone = 1;
04680       break;
04681        case REMSHORTSTATUS:
04682        case REMLONGSTATUS: 
04683       wait_interval(myrpt, DLY_TELEM, mychannel);
04684       res = saynode(myrpt,mychannel,myrpt->name);
04685       if(!res)
04686          res = sayfile(mychannel,"rpt/frequency");
04687       if(!res)
04688          res = split_freq(mhz, decimals, myrpt->freq);
04689       if (!multimode_capable(myrpt)) decimals[3] = 0;
04690       if(!res){
04691          m = atoi(mhz);
04692          if(m < 100)
04693             res = saynum(mychannel, m);
04694          else
04695             res = saycharstr(mychannel, mhz);
04696       }
04697       if(!res)
04698          res = sayfile(mychannel, "letters/dot");
04699       if(!res)
04700          res = saycharstr(mychannel, decimals);
04701    
04702       if(res)  break;
04703       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
04704          switch(myrpt->offset){
04705    
04706             case REM_MINUS:
04707                res = sayfile(mychannel,"rpt/minus");
04708                break;
04709             
04710             case REM_SIMPLEX:
04711                res = sayfile(mychannel,"rpt/simplex");
04712                break;
04713                
04714             case REM_PLUS:
04715                res = sayfile(mychannel,"rpt/plus");
04716                break;
04717                
04718             default:
04719                break;
04720          }
04721       }
04722       else{ /* Must be USB, LSB, or AM */
04723          switch(myrpt->remmode){
04724 
04725             case REM_MODE_USB:
04726                res = saycharstr(mychannel, "USB");
04727                break;
04728 
04729             case REM_MODE_LSB:
04730                res = saycharstr(mychannel, "LSB");
04731                break;
04732 
04733             case REM_MODE_AM:
04734                res = saycharstr(mychannel, "AM");
04735                break;
04736 
04737 
04738             default:
04739                break;
04740          }
04741       }
04742 
04743       if (res == -1) break;
04744 
04745       if(mytele->mode == REMSHORTSTATUS){ /* Short status? */
04746          wait_interval(myrpt, DLY_COMP, mychannel);
04747          if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04748          break;
04749       }
04750 
04751       if (strcmp(myrpt->remoterig,remote_rig_ic706))
04752       {
04753          switch(myrpt->powerlevel){
04754 
04755             case REM_LOWPWR:
04756                res = sayfile(mychannel,"rpt/lopwr") ;
04757                break;
04758             case REM_MEDPWR:
04759                res = sayfile(mychannel,"rpt/medpwr");
04760                break;
04761             case REM_HIPWR:
04762                res = sayfile(mychannel,"rpt/hipwr"); 
04763                break;
04764             }
04765       }
04766 
04767       rbimode = ((!strncmp(myrpt->remoterig,remote_rig_rbi,3))
04768         || (!strncmp(myrpt->remoterig,remote_rig_ic706,3)));
04769       if (res || (sayfile(mychannel,"rpt/rxpl") == -1)) break;
04770       if (rbimode && (sayfile(mychannel,"rpt/txpl") == -1)) break;
04771       if ((sayfile(mychannel,"rpt/frequency") == -1) ||
04772          (saycharstr(mychannel,myrpt->rxpl) == -1)) break;
04773       if ((!rbimode) && ((sayfile(mychannel,"rpt/txpl") == -1) ||
04774          (sayfile(mychannel,"rpt/frequency") == -1) ||
04775          (saycharstr(mychannel,myrpt->txpl) == -1))) break;
04776       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
04777          if ((sayfile(mychannel,"rpt/rxpl") == -1) ||
04778             (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1) ||
04779             (sayfile(mychannel,"rpt/txpl") == -1) ||
04780             (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1))
04781             {
04782                break;
04783             }
04784       }
04785       wait_interval(myrpt, DLY_COMP, mychannel);
04786       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04787       break;
04788        case STATUS:
04789       /* wait a little bit */
04790       wait_interval(myrpt, DLY_TELEM, mychannel);
04791       hastx = 0;
04792       linkbase.next = &linkbase;
04793       linkbase.prev = &linkbase;
04794       rpt_mutex_lock(&myrpt->lock);
04795       /* make our own list of links */
04796       l = myrpt->links.next;
04797       while(l != &myrpt->links)
04798       {
04799          if (l->name[0] == '0')
04800          {
04801             l = l->next;
04802             continue;
04803          }
04804          l1 = ast_malloc(sizeof(struct rpt_link));
04805          if (!l1)
04806          {
04807             ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
04808             remque((struct qelem *)mytele);
04809             myrpt->active_telem = NULL;
04810             rpt_mutex_unlock(&myrpt->lock);
04811             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04812             ast_free(nodename);
04813             ast_free(ident);
04814             ast_free(mytele);    
04815             ast_hangup(mychannel);
04816             pthread_exit(NULL);
04817          }
04818          memcpy(l1,l,sizeof(struct rpt_link));
04819          l1->next = l1->prev = NULL;
04820          insque((struct qelem *)l1,(struct qelem *)linkbase.next);
04821          l = l->next;
04822       }
04823       rpt_mutex_unlock(&myrpt->lock);
04824       res = saynode(myrpt,mychannel,myrpt->name);
04825       if (myrpt->callmode)
04826       {
04827          hastx = 1;
04828          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
04829          if (!res) 
04830             res = ast_waitstream(mychannel, "");
04831          else
04832              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04833          ast_stopstream(mychannel);
04834       }
04835       l = linkbase.next;
04836       while(l != &linkbase)
04837       {
04838          char *s;
04839 
04840          hastx = 1;
04841          res = saynode(myrpt,mychannel,l->name);
04842          s = "rpt/tranceive";
04843          if (!l->mode) s = "rpt/monitor";
04844          if (!l->thisconnected) s = "rpt/connecting";
04845          res = ast_streamfile(mychannel, s, mychannel->language);
04846          if (!res) 
04847             res = ast_waitstream(mychannel, "");
04848          else
04849             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04850          ast_stopstream(mychannel);
04851          l = l->next;
04852       }        
04853       if (!hastx)
04854       {
04855          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
04856          if (!res) 
04857             res = ast_waitstream(mychannel, "");
04858          else
04859              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04860          ast_stopstream(mychannel);
04861       }
04862       /* destroy our local link queue */
04863       l = linkbase.next;
04864       while(l != &linkbase)
04865       {
04866          l1 = l;
04867          l = l->next;
04868          remque((struct qelem *)l1);
04869          ast_free(l1);
04870       }        
04871       imdone = 1;
04872       break;
04873        case FULLSTATUS:
04874       rpt_mutex_lock(&myrpt->lock);
04875       /* get all the nodes */
04876       __mklinklist(myrpt,NULL,lbuf);
04877       rpt_mutex_unlock(&myrpt->lock);
04878       /* parse em */
04879       ns = finddelim(lbuf,strs,MAXLINKLIST);
04880       /* sort em */
04881       if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
04882       /* wait a little bit */
04883       wait_interval(myrpt, DLY_TELEM, mychannel);
04884       hastx = 0;
04885       res = saynode(myrpt,mychannel,myrpt->name);
04886       if (myrpt->callmode)
04887       {
04888          hastx = 1;
04889          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
04890          if (!res) 
04891             res = ast_waitstream(mychannel, "");
04892          else
04893              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04894          ast_stopstream(mychannel);
04895       }
04896       /* go thru all the nodes in list */
04897       for(i = 0; i < ns; i++)
04898       {
04899          char *s,mode = 'T';
04900 
04901          /* if a mode spec at first, handle it */
04902          if ((*strs[i] < '0') || (*strs[i] > '9'))
04903          {
04904             mode = *strs[i];
04905             strs[i]++;
04906          }
04907 
04908          hastx = 1;
04909          res = saynode(myrpt,mychannel,strs[i]);
04910          s = "rpt/tranceive";
04911          if (mode == 'R') s = "rpt/monitor";
04912          if (mode == 'C') s = "rpt/connecting";
04913          res = ast_streamfile(mychannel, s, mychannel->language);
04914          if (!res) 
04915             res = ast_waitstream(mychannel, "");
04916          else
04917             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04918          ast_stopstream(mychannel);
04919       }        
04920       if (!hastx)
04921       {
04922          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
04923          if (!res) 
04924             res = ast_waitstream(mychannel, "");
04925          else
04926              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04927          ast_stopstream(mychannel);
04928       }
04929       imdone = 1;
04930       break;
04931 
04932        case LASTNODEKEY: /* Identify last node which keyed us up */
04933       rpt_mutex_lock(&myrpt->lock);
04934       if(myrpt->lastnodewhichkeyedusup){
04935          p = ast_strdup(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
04936          if(!p){
04937             ast_log(LOG_WARNING, "ast_strdup failed in telemetery LASTNODEKEY");
04938             imdone = 1;
04939             break;
04940          }
04941       }
04942       else
04943          p = NULL;
04944       rpt_mutex_unlock(&myrpt->lock);
04945       if(!p){
04946          imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
04947          break;
04948       }
04949       wait_interval(myrpt, DLY_TELEM, mychannel);
04950       res = saynode(myrpt,mychannel,p);
04951       ast_free(p);
04952       imdone = 1;
04953       break;      
04954 
04955        case UNAUTHTX: /* Say unauthorized transmit frequency */
04956       wait_interval(myrpt, DLY_TELEM, mychannel);
04957       res = ast_streamfile(mychannel, "rpt/unauthtx", mychannel->language);
04958       if (!res) 
04959          res = ast_waitstream(mychannel, "");
04960       else
04961           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04962       ast_stopstream(mychannel);
04963       imdone = 1;
04964       break;
04965 
04966        case PARROT: /* Repeat stuff */
04967 
04968       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04969       if (ast_fileexists(mystr,NULL,mychannel->language) <= 0)
04970       {
04971          imdone = 1;
04972          myrpt->parrotstate = 0;
04973          break;
04974       }
04975       wait_interval(myrpt, DLY_PARROT, mychannel);
04976       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04977       res = ast_streamfile(mychannel, mystr, mychannel->language);
04978       if (!res) 
04979          res = ast_waitstream(mychannel, "");
04980       else
04981           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04982       ast_stopstream(mychannel);
04983       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04984       strcat(mystr,".wav");
04985       unlink(mystr);       
04986       imdone = 1;
04987       myrpt->parrotstate = 0;
04988       break;
04989 
04990        case TIMEOUT:
04991       res = saynode(myrpt,mychannel,myrpt->name);
04992       if (!res)
04993          res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
04994       break;
04995       
04996        case TIMEOUT_WARNING:
04997       time(&t);
04998       res = saynode(myrpt,mychannel,myrpt->name);
04999       if (!res)
05000          res = ast_streamfile(mychannel, "rpt/timeout-warning", mychannel->language);
05001       if (!res) 
05002          res = ast_waitstream(mychannel, "");
05003       else
05004           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05005       ast_stopstream(mychannel);
05006       if(!res) /* Say number of seconds */
05007          ast_say_number(mychannel, myrpt->p.remotetimeout - 
05008              (t - myrpt->last_activity_time), 
05009             "", mychannel->language, (char *) NULL);
05010       if (!res) 
05011          res = ast_waitstream(mychannel, "");
05012       ast_stopstream(mychannel); 
05013       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
05014       break;
05015 
05016        case ACT_TIMEOUT_WARNING:
05017       time(&t);
05018       res = saynode(myrpt,mychannel,myrpt->name);
05019       if (!res)
05020           res = ast_streamfile(mychannel, "rpt/act-timeout-warning", mychannel->language);
05021       if (!res) 
05022          res = ast_waitstream(mychannel, "");
05023       else
05024           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05025       ast_stopstream(mychannel);
05026       if(!res) /* Say number of seconds */
05027          ast_say_number(mychannel, myrpt->p.remoteinacttimeout - 
05028              (t - myrpt->last_activity_time), 
05029             "", mychannel->language, (char *) NULL);
05030       if (!res) 
05031          res = ast_waitstream(mychannel, "");
05032       ast_stopstream(mychannel); 
05033       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
05034       break;
05035       
05036        case STATS_TIME:
05037             case STATS_TIME_LOCAL:
05038          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05039       t = time(NULL);
05040       rpt_localtime(&t, &localtm);
05041       /* Say the phase of the day is before the time */
05042       if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
05043          p = "rpt/goodmorning";
05044       else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
05045          p = "rpt/goodafternoon";
05046       else
05047          p = "rpt/goodevening";
05048       if (sayfile(mychannel,p) == -1)
05049       {
05050          imdone = 1;
05051          break;
05052       }
05053       /* Say the time is ... */     
05054       if (sayfile(mychannel,"rpt/thetimeis") == -1)
05055       {
05056          imdone = 1;
05057          break;
05058       }
05059       /* Say the time */            
05060          res = ast_say_time(mychannel, t, "", mychannel->language);
05061       if (!res) 
05062          res = ast_waitstream(mychannel, "");
05063       ast_stopstream(mychannel);    
05064       imdone = 1;
05065          break;
05066        case STATS_VERSION:
05067       p = strstr(tdesc, "version"); 
05068       if(!p)
05069          break;   
05070       if(sscanf(p, "version %30d.%30d", &vmajor, &vminor) != 2)
05071          break;
05072          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05073       /* Say "version" */
05074       if (sayfile(mychannel,"rpt/version") == -1)
05075       {
05076          imdone = 1;
05077          break;
05078       }
05079       if(!res) /* Say "X" */
05080          ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
05081       if (!res) 
05082          res = ast_waitstream(mychannel, "");
05083       ast_stopstream(mychannel); 
05084       if (saycharstr(mychannel,".") == -1)
05085       {
05086          imdone = 1;
05087          break;
05088       }
05089       if(!res) /* Say "Y" */
05090          ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
05091       if (!res){
05092          res = ast_waitstream(mychannel, "");
05093          ast_stopstream(mychannel);
05094       }  
05095       else
05096           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05097       imdone = 1;
05098          break;
05099        case ARB_ALPHA:
05100          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05101          if(mytele->param)
05102             saycharstr(mychannel, mytele->param);
05103          imdone = 1;
05104       break;
05105        case REV_PATCH:
05106          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05107          if(mytele->param) {
05108 
05109          /* Parts of this section taken from app_parkandannounce */
05110          char *tpl_working, *tpl_current;
05111          char *tmp[100], *myparm;
05112          int looptemp=0,idx=0, dres = 0;
05113    
05114 
05115          tpl_working = ast_strdup(mytele->param);
05116          myparm = strsep(&tpl_working,",");
05117          tpl_current=strsep(&tpl_working, ":");
05118 
05119          while(tpl_current && looptemp < sizeof(tmp)) {
05120             tmp[looptemp]=tpl_current;
05121             looptemp++;
05122             tpl_current=strsep(&tpl_working,":");
05123          }
05124 
05125          for(idx=0; idx<looptemp; idx++) {
05126             if(!strcmp(tmp[idx], "PARKED")) {
05127                ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
05128             } else if(!strcmp(tmp[idx], "NODE")) {
05129                ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
05130             } else {
05131                dres = ast_streamfile(mychannel, tmp[idx], mychannel->language);
05132                if(!dres) {
05133                   dres = ast_waitstream(mychannel, "");
05134                } else {
05135                   ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[idx], mychannel->name);
05136                   dres = 0;
05137                }
05138             }
05139          }
05140          ast_free(tpl_working);
05141       }
05142          imdone = 1;
05143       break;
05144        case TEST_TONE:
05145       imdone = 1;
05146       if (myrpt->stopgen) break;
05147       myrpt->stopgen = -1;
05148            if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
05149       {
05150          myrpt->stopgen = 0;
05151          break;
05152       }
05153            while(mychannel->generatordata && (myrpt->stopgen <= 0)) {
05154          if (ast_safe_sleep(mychannel,1)) break;
05155             imdone = 1;
05156          }
05157       myrpt->stopgen = 0;
05158       break;
05159        default:
05160          break;
05161    }
05162    if (!imdone)
05163    {
05164       if (!res) 
05165          res = ast_waitstream(mychannel, "");
05166       else {
05167          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05168          res = 0;
05169       }
05170    }
05171    ast_stopstream(mychannel);
05172    rpt_mutex_lock(&myrpt->lock);
05173    if (mytele->mode == TAILMSG)
05174    {
05175       if (!res)
05176       {
05177          myrpt->tailmessagen++;
05178          if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
05179       }
05180       else
05181       {
05182          myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
05183       }
05184    }
05185    remque((struct qelem *)mytele);
05186    myrpt->active_telem = NULL;
05187    rpt_mutex_unlock(&myrpt->lock);
05188    ast_free(nodename);
05189    ast_free(ident);
05190    ast_free(mytele);    
05191    ast_hangup(mychannel);
05192 #ifdef  APP_RPT_LOCK_DEBUG
05193    {
05194       struct lockthread *t;
05195 
05196       sleep(5);
05197       ast_mutex_lock(&locklock);
05198       t = get_lockthread(pthread_self());
05199       if (t) memset(t,0,sizeof(struct lockthread));
05200       ast_mutex_unlock(&locklock);
05201    }        
05202 #endif
05203    pthread_exit(NULL);
05204 }
05205 
05206 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
05207 {
05208 struct rpt_tele *tele;
05209 struct rpt_link *mylink = NULL;
05210 int res;
05211 pthread_attr_t attr;
05212 char *v1, *v2;
05213 
05214    if(debug > 6)
05215       ast_log(LOG_NOTICE,"mode=%i  data=%s\n",mode, (char *)data);
05216 
05217    switch(mode)
05218    {
05219        case UNKEY:
05220       /* if any of the following are defined, go ahead and do it,
05221          otherwise, dont bother */
05222       v1 = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, 
05223          "unlinkedct");
05224       v2 = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, 
05225          "remotect");
05226       if (telem_lookup(myrpt,NULL, myrpt->name, "remotemon") &&
05227         telem_lookup(myrpt,NULL, myrpt->name, "remotetx") &&
05228         telem_lookup(myrpt,NULL, myrpt->name, "cmdmode") &&
05229         (!(v1 && telem_lookup(myrpt,NULL, myrpt->name, v1))) && 
05230         (!(v2 && telem_lookup(myrpt,NULL, myrpt->name, v2)))) return;
05231       break;
05232        case LINKUNKEY:
05233       if (!ast_variable_retrieve(myrpt->cfg, myrpt->name, "linkunkeyct"))
05234          return;
05235       break;
05236        default:
05237       break;
05238    }
05239    tele = ast_malloc(sizeof(struct rpt_tele));
05240    if (!tele)
05241    {
05242       ast_log(LOG_WARNING, "Unable to allocate memory\n");
05243       pthread_exit(NULL);
05244       return;
05245    }
05246    /* zero it out */
05247    memset((char *)tele,0,sizeof(struct rpt_tele));
05248    tele->rpt = myrpt;
05249    tele->mode = mode;
05250    if (mode == PARROT) tele->parrot = (uintptr_t) data;
05251    else mylink = (struct rpt_link *) data;
05252    rpt_mutex_lock(&myrpt->lock);
05253    if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED) ||
05254        (mode == LINKUNKEY)){
05255       memset(&tele->mylink,0,sizeof(struct rpt_link));
05256       if (mylink){
05257          memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
05258       }
05259    }
05260    else if ((mode == ARB_ALPHA) || (mode == REV_PATCH) || (mode == PLAYBACK)) {
05261       strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
05262       tele->param[TELEPARAMSIZE - 1] = 0;
05263    }
05264    if (mode == REMXXX) tele->submode = (intptr_t) data;
05265    insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
05266    rpt_mutex_unlock(&myrpt->lock);
05267         pthread_attr_init(&attr);
05268         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05269    res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
05270    if(res < 0){
05271       rpt_mutex_lock(&myrpt->lock);
05272       remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
05273       rpt_mutex_unlock(&myrpt->lock);  
05274       ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
05275    }
05276    return;
05277 }
05278 
05279 static void *rpt_call(void *this)
05280 {
05281 struct dahdi_confinfo ci;  /* conference info */
05282 struct   rpt *myrpt = (struct rpt *)this;
05283 int   res;
05284 int stopped,congstarted,dialtimer,lastcidx,aborted;
05285 struct ast_channel *mychannel,*genchannel;
05286 
05287    myrpt->mydtmf = 0;
05288    /* allocate a pseudo-channel thru asterisk */
05289    mychannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
05290    if (!mychannel)
05291    {
05292       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
05293       pthread_exit(NULL);
05294    }
05295 #ifdef   AST_CDR_FLAG_POST_DISABLED
05296    if (mychannel->cdr)
05297       ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
05298 #endif
05299    ci.chan = 0;
05300    ci.confno = myrpt->conf; /* use the pseudo conference */
05301 #if   0
05302    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
05303       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
05304 #endif
05305    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
05306    /* first put the channel on the conference */
05307    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05308    {
05309       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05310       ast_hangup(mychannel);
05311       myrpt->callmode = 0;
05312       pthread_exit(NULL);
05313    }
05314    /* allocate a pseudo-channel thru asterisk */
05315    genchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
05316    if (!genchannel)
05317    {
05318       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
05319       ast_hangup(mychannel);
05320       pthread_exit(NULL);
05321    }
05322 #ifdef   AST_CDR_FLAG_POST_DISABLED
05323    if (genchannel->cdr)
05324       ast_set_flag(genchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
05325 #endif
05326    ci.chan = 0;
05327    ci.confno = myrpt->conf;
05328    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
05329       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
05330    /* first put the channel on the conference */
05331    if (ioctl(genchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05332    {
05333       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05334       ast_hangup(mychannel);
05335       ast_hangup(genchannel);
05336       myrpt->callmode = 0;
05337       pthread_exit(NULL);
05338    }
05339    if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
05340    {
05341       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
05342       ast_hangup(mychannel);
05343       ast_hangup(genchannel);
05344       myrpt->callmode = 0;
05345       pthread_exit(NULL);
05346    }
05347    if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
05348    {
05349       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
05350       ast_hangup(mychannel);
05351       ast_hangup(genchannel);
05352       myrpt->callmode = 0;
05353       pthread_exit(NULL);
05354    }
05355    /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
05356    if ((!myrpt->patchquiet) && (tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_DIALTONE) < 0))
05357    {
05358       ast_log(LOG_WARNING, "Cannot start dialtone\n");
05359       ast_hangup(mychannel);
05360       ast_hangup(genchannel);
05361       myrpt->callmode = 0;
05362       pthread_exit(NULL);
05363    }
05364    stopped = 0;
05365    congstarted = 0;
05366    dialtimer = 0;
05367    lastcidx = 0;
05368    myrpt->calldigittimer = 0;
05369    aborted = 0;
05370 
05371    while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
05372    {
05373       if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
05374          dialtimer = 0;
05375          lastcidx = myrpt->cidx;
05376       }     
05377 
05378       if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){ 
05379           if(debug)
05380             ast_log(LOG_NOTICE, "dialtimer %i > patchdialtime %i\n", dialtimer,myrpt->patchdialtime);
05381          rpt_mutex_lock(&myrpt->lock);
05382          aborted = 1;
05383          myrpt->callmode = 0;
05384          rpt_mutex_unlock(&myrpt->lock);
05385          break;
05386       }
05387    
05388       if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
05389       {
05390          stopped = 1;
05391          /* stop dial tone */
05392          tone_zone_play_tone(genchannel->fds[0],-1);
05393       }
05394       if (myrpt->callmode == 1)
05395       {
05396          if(myrpt->calldigittimer > PATCH_DIALPLAN_TIMEOUT)
05397          {
05398             myrpt->callmode = 2;
05399             break;
05400          }
05401          /* bump timer if active */
05402          if (myrpt->calldigittimer) 
05403             myrpt->calldigittimer += MSWAIT;
05404       }
05405       if (myrpt->callmode == 4)
05406       {
05407          if(!congstarted){
05408             congstarted = 1;
05409             /* start congestion tone */
05410             tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
05411          }
05412       }
05413       res = ast_safe_sleep(mychannel, MSWAIT);
05414       if (res < 0)
05415       {
05416           if(debug)
05417             ast_log(LOG_NOTICE, "ast_safe_sleep=%i\n", res);
05418          ast_hangup(mychannel);
05419          ast_hangup(genchannel);
05420          rpt_mutex_lock(&myrpt->lock);
05421          myrpt->callmode = 0;
05422          rpt_mutex_unlock(&myrpt->lock);
05423          pthread_exit(NULL);
05424       }
05425       dialtimer += MSWAIT;
05426    }
05427    /* stop any tone generation */
05428    tone_zone_play_tone(genchannel->fds[0],-1);
05429    /* end if done */
05430    if (!myrpt->callmode)
05431    {
05432       if(debug)
05433          ast_log(LOG_NOTICE, "callmode==0\n");
05434       ast_hangup(mychannel);
05435       ast_hangup(genchannel);
05436       rpt_mutex_lock(&myrpt->lock);
05437       myrpt->callmode = 0;
05438       myrpt->macropatch=0;
05439       channel_revert(myrpt);
05440       rpt_mutex_unlock(&myrpt->lock);
05441       if((!myrpt->patchquiet) && aborted)
05442          rpt_telemetry(myrpt, TERM, NULL);
05443       pthread_exit(NULL);        
05444    }
05445 
05446    if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
05447       char *name, *loc, *instr;
05448       instr = ast_strdup(myrpt->p.ourcallerid);
05449       if(instr){
05450          ast_callerid_parse(instr, &name, &loc);
05451          if(loc){
05452             if(mychannel->cid.cid_num)
05453                ast_free(mychannel->cid.cid_num);
05454             mychannel->cid.cid_num = ast_strdup(loc);
05455          }
05456          if(name){
05457             if(mychannel->cid.cid_name)
05458                ast_free(mychannel->cid.cid_name);
05459             mychannel->cid.cid_name = ast_strdup(name);
05460          }
05461          ast_free(instr);
05462       }
05463    }
05464 
05465    ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
05466    ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
05467    
05468    if (myrpt->p.acctcode)
05469       ast_cdr_setaccount(mychannel,myrpt->p.acctcode);
05470    mychannel->priority = 1;
05471    ast_channel_undefer_dtmf(mychannel);
05472    if (ast_pbx_start(mychannel) < 0)
05473    {
05474       ast_log(LOG_WARNING, "Unable to start PBX!!\n");
05475       ast_hangup(mychannel);
05476       ast_hangup(genchannel);
05477       rpt_mutex_lock(&myrpt->lock);
05478       myrpt->callmode = 0;
05479       rpt_mutex_unlock(&myrpt->lock);
05480       pthread_exit(NULL);
05481    }
05482    usleep(10000);
05483    rpt_mutex_lock(&myrpt->lock);
05484    myrpt->callmode = 3;
05485    /* set appropriate conference for the pseudo */
05486    ci.chan = 0;
05487    ci.confno = myrpt->conf;
05488    ci.confmode = (myrpt->p.duplex == 2) ? DAHDI_CONF_CONFANNMON :
05489       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
05490    /* first put the channel on the conference in announce mode */
05491    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05492    {
05493       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05494       ast_hangup(mychannel);
05495       ast_hangup(genchannel);
05496       myrpt->callmode = 0;
05497       pthread_exit(NULL);
05498    }
05499    /* get its channel number */
05500    if (ioctl(mychannel->fds[0],DAHDI_CHANNO,&res) == -1)
05501    {
05502       ast_log(LOG_WARNING, "Unable to get autopatch channel number\n");
05503       ast_hangup(mychannel);
05504       myrpt->callmode = 0;
05505       pthread_exit(NULL);
05506    }
05507    ci.chan = 0;
05508    ci.confno = res;
05509    ci.confmode = DAHDI_CONF_MONITOR;
05510    /* put vox channel monitoring on the channel  */
05511    if (ioctl(myrpt->voxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05512    {
05513       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05514       ast_hangup(mychannel);
05515       myrpt->callmode = 0;
05516       pthread_exit(NULL);
05517    }
05518    while(myrpt->callmode)
05519    {
05520       if ((!mychannel->pbx) && (myrpt->callmode != 4))
05521       {
05522           /* If patch is setup for far end disconnect */
05523          if(myrpt->patchfarenddisconnect || (myrpt->p.duplex < 2)){ 
05524             if(debug)ast_log(LOG_NOTICE,"callmode=%i, patchfarenddisconnect=%i, duplex=%i\n",\
05525                   myrpt->callmode,myrpt->patchfarenddisconnect,myrpt->p.duplex);
05526             myrpt->callmode = 0;
05527             myrpt->macropatch=0;
05528             if(!myrpt->patchquiet){
05529                rpt_mutex_unlock(&myrpt->lock);
05530                rpt_telemetry(myrpt, TERM, NULL);
05531                rpt_mutex_lock(&myrpt->lock);
05532             }
05533          }
05534          else{ /* Send congestion until patch is downed by command */
05535             myrpt->callmode = 4;
05536             rpt_mutex_unlock(&myrpt->lock);
05537             /* start congestion tone */
05538             tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
05539             rpt_mutex_lock(&myrpt->lock);
05540          }
05541       }
05542       if (myrpt->mydtmf)
05543       {
05544          struct ast_frame wf = {AST_FRAME_DTMF, } ;
05545          wf.subclass = myrpt->mydtmf;
05546          rpt_mutex_unlock(&myrpt->lock);
05547          ast_queue_frame(mychannel,&wf);
05548 #ifdef   NEW_ASTERISK
05549          ast_senddigit(genchannel,myrpt->mydtmf,0);
05550 #else
05551          ast_senddigit(genchannel,myrpt->mydtmf);
05552 #endif
05553          rpt_mutex_lock(&myrpt->lock);
05554          myrpt->mydtmf = 0;
05555       }
05556       rpt_mutex_unlock(&myrpt->lock);
05557       usleep(MSWAIT * 1000);
05558       rpt_mutex_lock(&myrpt->lock);
05559    }
05560    if(debug)
05561       ast_log(LOG_NOTICE, "exit channel loop\n");
05562    rpt_mutex_unlock(&myrpt->lock);
05563    tone_zone_play_tone(genchannel->fds[0],-1);
05564    if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
05565    ast_hangup(genchannel);
05566    rpt_mutex_lock(&myrpt->lock);
05567    myrpt->callmode = 0;
05568    myrpt->macropatch=0;
05569    channel_revert(myrpt);
05570    rpt_mutex_unlock(&myrpt->lock);
05571    /* set appropriate conference for the pseudo */
05572    ci.chan = 0;
05573    ci.confno = myrpt->conf;
05574    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
05575       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
05576    /* first put the channel on the conference in announce mode */
05577    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05578    {
05579       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05580    }
05581    pthread_exit(NULL);
05582 }
05583 
05584 static void send_link_dtmf(struct rpt *myrpt,char c)
05585 {
05586 char  str[300];
05587 struct   ast_frame wf;
05588 struct   rpt_link *l;
05589 
05590    snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
05591    wf.frametype = AST_FRAME_TEXT;
05592    wf.subclass = 0;
05593    wf.offset = 0;
05594    wf.mallocd = 0;
05595    wf.datalen = strlen(str) + 1;
05596    wf.samples = 0;
05597    l = myrpt->links.next;
05598    /* first, see if our dude is there */
05599    while(l != &myrpt->links)
05600    {
05601       if (l->name[0] == '0') 
05602       {
05603          l = l->next;
05604          continue;
05605       }
05606       /* if we found it, write it and were done */
05607       if (!strcmp(l->name,myrpt->cmdnode))
05608       {
05609          wf.data.ptr = str;
05610          if (l->chan) ast_write(l->chan,&wf);
05611          return;
05612       }
05613       l = l->next;
05614    }
05615    l = myrpt->links.next;
05616    /* if not, give it to everyone */
05617    while(l != &myrpt->links)
05618    {
05619       wf.data.ptr = str;
05620       if (l->chan) ast_write(l->chan,&wf);
05621       l = l->next;
05622    }
05623    return;
05624 }
05625 
05626 static void send_link_keyquery(struct rpt *myrpt)
05627 {
05628 char  str[300];
05629 struct   ast_frame wf;
05630 struct   rpt_link *l;
05631 
05632    rpt_mutex_lock(&myrpt->lock);
05633    memset(myrpt->topkey,0,sizeof(myrpt->topkey));
05634    myrpt->topkeystate = 1;
05635    time(&myrpt->topkeytime);
05636    rpt_mutex_unlock(&myrpt->lock);
05637    snprintf(str, sizeof(str), "K? * %s 0 0", myrpt->name);
05638    wf.frametype = AST_FRAME_TEXT;
05639    wf.subclass = 0;
05640    wf.offset = 0;
05641    wf.mallocd = 0;
05642    wf.datalen = strlen(str) + 1;
05643    wf.samples = 0;
05644    l = myrpt->links.next;
05645    /* give it to everyone */
05646    while(l != &myrpt->links)
05647    {
05648       wf.data.ptr = str;
05649       if (l->chan) ast_write(l->chan,&wf);
05650       l = l->next;
05651    }
05652    return;
05653 }
05654 
05655 /* send newkey request */
05656 
05657 static void send_newkey(struct ast_channel *chan)
05658 {
05659 
05660    /* ast_safe_sleep(chan,10); */
05661    ast_sendtext(chan,newkeystr);
05662    return;
05663 }
05664 
05665 
05666 /* 
05667  * Connect a link 
05668  *
05669  * Return values:
05670  * -2: Attempt to connect to self 
05671  * -1: No such node
05672  *  0: Success
05673  *  1: No match yet
05674  *  2: Already connected to this node
05675  */
05676 
05677 static int connect_link(struct rpt *myrpt, char* node, int mode, int perma)
05678 {
05679    char *val, *s, *s1, *s2, *tele;
05680    char lstr[MAXLINKLIST],*strs[MAXLINKLIST];
05681    char tmp[300], deststr[300] = "",modechange = 0;
05682    char sx[320],*sy;
05683    struct rpt_link *l;
05684    int reconnects = 0;
05685    int i,n;
05686    struct dahdi_confinfo ci;  /* conference info */
05687 
05688    val = node_lookup(myrpt,node);
05689    if (!val){
05690       if(strlen(node) >= myrpt->longestnode)
05691          return -1; /* No such node */
05692       return 1; /* No match yet */
05693    }
05694 
05695    if(!strcmp(myrpt->name,node)) /* Do not allow connections to self */
05696       return -2;
05697       
05698    if(debug > 3){
05699       ast_log(LOG_NOTICE,"Connect attempt to node %s\n", node);
05700       ast_log(LOG_NOTICE,"Mode: %s\n",(mode)?"Transceive":"Monitor");
05701       ast_log(LOG_NOTICE,"Connection type: %s\n",(perma)?"Permalink":"Normal");
05702    }
05703 
05704    strncpy(tmp,val,sizeof(tmp) - 1);
05705    s = tmp;
05706    s1 = strsep(&s,",");
05707    if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
05708    {
05709       sy = strchr(s1,'/');    
05710       *sy = 0;
05711       sprintf(sx,"%s:4569/%s",s1,sy + 1);
05712       s1 = sx;
05713    }
05714    s2 = strsep(&s,",");
05715    rpt_mutex_lock(&myrpt->lock);
05716    l = myrpt->links.next;
05717    /* try to find this one in queue */
05718    while(l != &myrpt->links){
05719       if (l->name[0] == '0') 
05720       {
05721          l = l->next;
05722          continue;
05723       }
05724    /* if found matching string */
05725       if (!strcmp(l->name, node))
05726          break;
05727       l = l->next;
05728    }
05729    /* if found */
05730    if (l != &myrpt->links){ 
05731    /* if already in this mode, just ignore */
05732       if ((l->mode) || (!l->chan)) {
05733          rpt_mutex_unlock(&myrpt->lock);
05734          return 2; /* Already linked */
05735       }
05736       reconnects = l->reconnects;
05737       rpt_mutex_unlock(&myrpt->lock);
05738       if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
05739       l->retries = l->max_retries + 1;
05740       l->disced = 2;
05741       modechange = 1;
05742    } else
05743    {
05744       __mklinklist(myrpt,NULL,lstr);
05745       rpt_mutex_unlock(&myrpt->lock);
05746       n = finddelim(lstr,strs,MAXLINKLIST);
05747       for(i = 0; i < n; i++)
05748       {
05749          if ((*strs[i] < '0') || 
05750              (*strs[i] > '9')) strs[i]++;
05751          if (!strcmp(strs[i],node))
05752          {
05753             return 2; /* Already linked */
05754          }
05755       }
05756    }
05757    strncpy(myrpt->lastlinknode,node,MAXNODESTR - 1);
05758    /* establish call */
05759    l = ast_malloc(sizeof(struct rpt_link));
05760    if (!l)
05761    {
05762       ast_log(LOG_WARNING, "Unable to malloc\n");
05763       return -1;
05764    }
05765    /* zero the silly thing */
05766    memset((char *)l,0,sizeof(struct rpt_link));
05767    l->mode = mode;
05768    l->outbound = 1;
05769    l->thisconnected = 0;
05770    voxinit_link(l,1);
05771    strncpy(l->name, node, MAXNODESTR - 1);
05772    l->isremote = (s && ast_true(s));
05773    if (modechange) l->connected = 1;
05774    l->hasconnected = l->perma = perma;
05775 #ifdef ALLOW_LOCAL_CHANNELS
05776    if ((strncasecmp(s1,"iax2/", 5) == 0) || (strncasecmp(s1, "local/", 6) == 0))
05777          strncpy(deststr, s1, sizeof(deststr));
05778    else
05779            snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
05780 #else
05781    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
05782 #endif
05783    tele = strchr(deststr, '/');
05784    if (!tele){
05785       ast_log(LOG_WARNING,"link3:Dial number (%s) must be in format tech/number\n",deststr);
05786       ast_free(l);
05787       return -1;
05788    }
05789    *tele++ = 0;
05790    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
05791    if (l->chan){
05792       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
05793       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
05794 #ifdef   AST_CDR_FLAG_POST_DISABLED
05795       if (l->chan->cdr)
05796          ast_set_flag(l->chan->cdr,AST_CDR_FLAG_POST_DISABLED);
05797 #endif
05798 #ifndef  NEW_ASTERISK
05799       l->chan->whentohangup = 0;
05800 #endif
05801       l->chan->appl = "Apprpt";
05802       l->chan->data = "(Remote Rx)";
05803       if (debug > 3)
05804          ast_log(LOG_NOTICE, "rpt (remote) initiating call to %s/%s on %s\n",
05805       deststr, tele, l->chan->name);
05806       if(l->chan->cid.cid_num)
05807          ast_free(l->chan->cid.cid_num);
05808       l->chan->cid.cid_num = ast_strdup(myrpt->name);
05809       ast_call(l->chan,tele,999);
05810    }
05811    else {
05812       if(debug > 3) 
05813          ast_log(LOG_NOTICE, "Unable to place call to %s/%s on %s\n",
05814       deststr,tele,l->chan->name);
05815       if (myrpt->p.archivedir)
05816       {
05817          char str[100];
05818          sprintf(str,"LINKFAIL,%s",l->name);
05819          donodelog(myrpt,str);
05820       }
05821       ast_free(l);
05822       return -1;
05823    }
05824    /* allocate a pseudo-channel thru asterisk */
05825    l->pchan = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
05826    if (!l->pchan){
05827       ast_log(LOG_WARNING,"rpt connect: Sorry unable to obtain pseudo channel\n");
05828       ast_hangup(l->chan);
05829       ast_free(l);
05830       return -1;
05831    }
05832    ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
05833    ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
05834 #ifdef   AST_CDR_FLAG_POST_DISABLED
05835    if (l->pchan->cdr)
05836       ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
05837 #endif
05838    /* make a conference for the tx */
05839    ci.chan = 0;
05840    ci.confno = myrpt->conf;
05841    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
05842    /* first put the channel on the conference in proper mode */
05843    if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1)
05844    {
05845       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05846       ast_hangup(l->chan);
05847       ast_hangup(l->pchan);
05848       ast_free(l);
05849       return -1;
05850    }
05851    rpt_mutex_lock(&myrpt->lock);
05852    l->reconnects = reconnects;
05853    /* insert at end of queue */
05854    l->max_retries = MAX_RETRIES;
05855    if (perma)
05856       l->max_retries = MAX_RETRIES_PERM;
05857    if (l->isremote) l->retries = l->max_retries + 1;
05858    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
05859    __kickshort(myrpt);
05860    rpt_mutex_unlock(&myrpt->lock);
05861    if (!l->phonemode) send_newkey(l->chan);
05862    return 0;
05863 }
05864 
05865 
05866 
05867 /*
05868 * Internet linking function 
05869 */
05870 
05871 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
05872 {
05873 
05874    char *val, *s, *s1, *s2;
05875    char tmp[300];
05876    char digitbuf[MAXNODESTR],*strs[MAXLINKLIST];
05877    char mode,perma;
05878    char sx[320],*sy;
05879    struct rpt_link *l;
05880    int i,r;
05881 
05882    if(!param)
05883       return DC_ERROR;
05884       
05885          
05886    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable )
05887       return DC_ERROR;
05888 
05889    strncpy(digitbuf,digits,MAXNODESTR - 1);
05890 
05891    if(debug > 6)
05892       printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
05893       
05894    switch(myatoi(param)){
05895       case 11: /* Perm Link off */
05896       case 1: /* Link off */
05897          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
05898             strcpy(digitbuf,myrpt->lastlinknode);
05899          val = node_lookup(myrpt,digitbuf);
05900          if (!val){
05901             if(strlen(digitbuf) >= myrpt->longestnode)
05902                return DC_ERROR;
05903             break;
05904          }
05905          strncpy(tmp,val,sizeof(tmp) - 1);
05906          s = tmp;
05907          s1 = strsep(&s,",");
05908          if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
05909          {
05910             sy = strchr(s1,'/');    
05911             *sy = 0;
05912             sprintf(sx,"%s:4569/%s",s1,sy + 1);
05913             s1 = sx;
05914          }
05915          s2 = strsep(&s,",");
05916          rpt_mutex_lock(&myrpt->lock);
05917          l = myrpt->links.next;
05918          /* try to find this one in queue */
05919          while(l != &myrpt->links){
05920             if (l->name[0] == '0') 
05921             {
05922                l = l->next;
05923                continue;
05924             }
05925             /* if found matching string */
05926             if (!strcmp(l->name, digitbuf))
05927                break;
05928             l = l->next;
05929          }
05930          if (l != &myrpt->links){ /* if found */
05931             struct   ast_frame wf;
05932 
05933             /* must use perm command on perm link */
05934             if ((myatoi(param) < 10) && 
05935                 (l->max_retries > MAX_RETRIES))
05936             {
05937                rpt_mutex_unlock(&myrpt->lock);
05938                return DC_COMPLETE;
05939             }
05940             strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
05941             l->retries = l->max_retries + 1;
05942             l->disced = 1;
05943             rpt_mutex_unlock(&myrpt->lock);
05944             wf.frametype = AST_FRAME_TEXT;
05945             wf.subclass = 0;
05946             wf.offset = 0;
05947             wf.mallocd = 0;
05948             wf.datalen = strlen(discstr) + 1;
05949             wf.samples = 0;
05950             wf.data.ptr = discstr;
05951             if (l->chan)
05952             {
05953                ast_write(l->chan,&wf);
05954                if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
05955                ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
05956             }
05957             rpt_telemetry(myrpt, COMPLETE, NULL);
05958             return DC_COMPLETE;
05959          }
05960          rpt_mutex_unlock(&myrpt->lock);  
05961          return DC_COMPLETE;
05962       case 2: /* Link Monitor */
05963       case 3: /* Link transceive */
05964       case 12: /* Link Monitor permanent */
05965       case 13: /* Link transceive permanent */
05966          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
05967             strcpy(digitbuf,myrpt->lastlinknode);
05968          /* Attempt connection  */
05969          perma = (atoi(param) > 10) ? 1 : 0;
05970          mode = (atoi(param) & 1) ? 1 : 0;
05971          r = connect_link(myrpt, digitbuf, mode, perma);
05972          switch(r){
05973             case -2: /* Attempt to connect to self */
05974                return DC_COMPLETE; /* Silent error */
05975 
05976             case 0:
05977                rpt_telemetry(myrpt, COMPLETE, NULL);
05978                return DC_COMPLETE;
05979 
05980             case 1:
05981                break;
05982             
05983             case 2:
05984                rpt_telemetry(myrpt, REMALREADY, NULL);
05985                return DC_COMPLETE;
05986             
05987             default:
05988                rpt_telemetry(myrpt, CONNFAIL, NULL);
05989                return DC_COMPLETE;
05990          }
05991          break;
05992 
05993       case 4: /* Enter Command Mode */
05994       
05995          /* if doesnt allow link cmd, or no links active, return */
05996          if (((command_source != SOURCE_RPT) && 
05997             (command_source != SOURCE_PHONE) &&
05998             (command_source != SOURCE_ALT) &&
05999             (command_source != SOURCE_DPHONE)) ||
06000              (myrpt->links.next == &myrpt->links))
06001             return DC_COMPLETE;
06002          
06003          /* if already in cmd mode, or selected self, fughetabahtit */
06004          if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
06005          
06006             rpt_telemetry(myrpt, REMALREADY, NULL);
06007             return DC_COMPLETE;
06008          }
06009          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
06010             strcpy(digitbuf,myrpt->lastlinknode);
06011          /* node must at least exist in list */
06012          val = node_lookup(myrpt,digitbuf);
06013          if (!val){
06014             if(strlen(digitbuf) >= myrpt->longestnode)
06015                return DC_ERROR;
06016             break;
06017          
06018          }
06019          rpt_mutex_lock(&myrpt->lock);
06020          strcpy(myrpt->lastlinknode,digitbuf);
06021          strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
06022          rpt_mutex_unlock(&myrpt->lock);
06023          rpt_telemetry(myrpt, REMGO, NULL);  
06024          return DC_COMPLETE;
06025          
06026       case 5: /* Status */
06027          rpt_telemetry(myrpt, STATUS, NULL);
06028          return DC_COMPLETE;
06029 
06030       case 15: /* Full Status */
06031          rpt_telemetry(myrpt, FULLSTATUS, NULL);
06032          return DC_COMPLETE;
06033          
06034          
06035       case 6: /* All Links Off, including permalinks */
06036                        rpt_mutex_lock(&myrpt->lock);
06037          myrpt->savednodes[0] = 0;
06038                         l = myrpt->links.next;
06039                         /* loop through all links */
06040                         while(l != &myrpt->links){
06041             struct   ast_frame wf;
06042                                 if (l->name[0] == '0') /* Skip any IAXRPT monitoring */
06043                                 {
06044                                         l = l->next;
06045                                         continue;
06046                                 }
06047             /* Make a string of disconnected nodes for possible restoration */
06048             sprintf(tmp,"%c%c%s",(l->mode) ? 'X' : 'M',(l->perma) ? 'P':'T',l->name);
06049             if(strlen(tmp) + strlen(myrpt->savednodes) + 1 < MAXNODESTR){ 
06050                if(myrpt->savednodes[0])
06051                   strcat(myrpt->savednodes, ",");
06052                strcat(myrpt->savednodes, tmp);
06053             }
06054                               l->retries = l->max_retries + 1;
06055                                 l->disced = 2; /* Silently disconnect */
06056                                 rpt_mutex_unlock(&myrpt->lock);
06057             /* ast_log(LOG_NOTICE,"dumping link %s\n",l->name); */
06058                                 
06059                                 wf.frametype = AST_FRAME_TEXT;
06060                                 wf.subclass = 0;
06061                                 wf.offset = 0;
06062                                 wf.mallocd = 0;
06063                                 wf.datalen = strlen(discstr) + 1;
06064                                 wf.samples = 0;
06065                                 wf.data.ptr = discstr;
06066                                 if (l->chan)
06067                                 {
06068                                         ast_write(l->chan,&wf);
06069                                         ast_safe_sleep(l->chan,250); /* It's dead already, why check the return value? */
06070                                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
06071                                 }
06072             rpt_mutex_lock(&myrpt->lock);
06073                                 l = l->next;
06074                         }
06075          rpt_mutex_unlock(&myrpt->lock);
06076          if(debug > 3)
06077             ast_log(LOG_NOTICE,"Nodes disconnected: %s\n",myrpt->savednodes);
06078                         rpt_telemetry(myrpt, COMPLETE, NULL);
06079          return DC_COMPLETE;
06080 
06081       case 7: /* Identify last node which keyed us up */
06082          rpt_telemetry(myrpt, LASTNODEKEY, NULL);
06083          break;
06084 
06085 
06086 #ifdef   _MDC_DECODE_H_
06087       case 8:
06088          myrpt->lastunit = 0xd00d; 
06089          mdc1200_notify(myrpt,NULL,myrpt->lastunit);
06090          mdc1200_send(myrpt,myrpt->lastunit);
06091          break;
06092 #endif
06093 
06094       case 16: /* Restore links disconnected with "disconnect all links" command */
06095          strcpy(tmp, myrpt->savednodes); /* Make a copy */
06096          finddelim(tmp, strs, MAXLINKLIST); /* convert into substrings */
06097          for(i = 0; tmp[0] && strs[i] != NULL && i < MAXLINKLIST; i++){
06098             s1 = strs[i];
06099             mode = (s1[0] == 'X') ? 1 : 0;
06100             perma = (s1[1] == 'P') ? 1 : 0;
06101             connect_link(myrpt, s1 + 2, mode, perma); /* Try to reconnect */
06102          }
06103                         rpt_telemetry(myrpt, COMPLETE, NULL);
06104          break;
06105    
06106       case 200:
06107       case 201:
06108       case 202:
06109       case 203:
06110       case 204:
06111       case 205:
06112       case 206:
06113       case 207:
06114       case 208:
06115       case 209:
06116       case 210:
06117       case 211:
06118       case 212:
06119       case 213:
06120       case 214:
06121       case 215:
06122          if (((myrpt->p.propagate_dtmf) && 
06123               (command_source == SOURCE_LNK)) ||
06124              ((myrpt->p.propagate_phonedtmf) &&
06125             ((command_source == SOURCE_PHONE) ||
06126               (command_source == SOURCE_ALT) ||
06127                 (command_source == SOURCE_DPHONE))))
06128                do_dtmf_local(myrpt,
06129                   remdtmfstr[myatoi(param) - 200]);
06130       default:
06131          return DC_ERROR;
06132          
06133    }
06134    
06135    return DC_INDETERMINATE;
06136 }  
06137 
06138 /*
06139 * Autopatch up
06140 */
06141 
06142 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06143 {
06144    pthread_attr_t attr;
06145    int i, idx, paramlength;
06146    char *lparam;
06147    char *value = NULL;
06148    char *paramlist[20];
06149 
06150    static char *keywords[] = {
06151    "context",
06152    "dialtime",
06153    "farenddisconnect",
06154    "noct",
06155    "quiet",
06156    NULL
06157    };
06158       
06159    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
06160       return DC_ERROR;
06161       
06162    if(debug)
06163       printf("@@@@ Autopatch up\n");
06164 
06165    if(!myrpt->callmode){
06166       /* Set defaults */
06167       myrpt->patchnoct = 0;
06168       myrpt->patchdialtime = 0;
06169       myrpt->patchfarenddisconnect = 0;
06170       myrpt->patchquiet = 0;
06171       strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
06172 
06173       if(param){
06174          /* Process parameter list */
06175          lparam = ast_strdup(param);
06176          if(!lparam){
06177             ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
06178             return DC_ERROR;  
06179          }
06180          paramlength = finddelim(lparam, paramlist, 20);          
06181          for(i = 0; i < paramlength; i++){
06182             idx = matchkeyword(paramlist[i], &value, keywords);
06183             if(value)
06184                value = skipchars(value, "= ");
06185             switch(idx){
06186 
06187                case 1: /* context */
06188                   strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ;
06189                   break;
06190                   
06191                case 2: /* dialtime */
06192                   myrpt->patchdialtime = atoi(value);
06193                   break;
06194 
06195                case 3: /* farenddisconnect */
06196                   myrpt->patchfarenddisconnect = atoi(value);
06197                   break;
06198 
06199                case 4:  /* noct */
06200                   myrpt->patchnoct = atoi(value);
06201                   break;
06202 
06203                case 5: /* quiet */
06204                   myrpt->patchquiet = atoi(value);
06205                   break;
06206                            
06207                default:
06208                   break;
06209             }
06210          }
06211       ast_free(lparam);
06212       }
06213    }
06214                
06215    rpt_mutex_lock(&myrpt->lock);
06216 
06217    /* if on call, force * into current audio stream */
06218    
06219    if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
06220       myrpt->mydtmf = myrpt->p.endchar;
06221    }
06222    if (myrpt->callmode){
06223       rpt_mutex_unlock(&myrpt->lock);
06224       return DC_COMPLETE;
06225    }
06226    myrpt->callmode = 1;
06227    myrpt->cidx = 0;
06228    myrpt->exten[myrpt->cidx] = 0;
06229    rpt_mutex_unlock(&myrpt->lock);
06230    pthread_attr_init(&attr);
06231    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
06232    ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
06233    return DC_COMPLETE;
06234 }
06235 
06236 /*
06237 * Autopatch down
06238 */
06239 
06240 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06241 {
06242    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
06243       return DC_ERROR;
06244    
06245    if(debug)
06246       printf("@@@@ Autopatch down\n");
06247       
06248    rpt_mutex_lock(&myrpt->lock);
06249    
06250    myrpt->macropatch=0;
06251 
06252    if (!myrpt->callmode){
06253       rpt_mutex_unlock(&myrpt->lock);
06254       return DC_COMPLETE;
06255    }
06256    
06257    myrpt->callmode = 0;
06258    channel_revert(myrpt);
06259    rpt_mutex_unlock(&myrpt->lock);
06260    rpt_telemetry(myrpt, TERM, NULL);
06261    return DC_COMPLETE;
06262 }
06263 
06264 /*
06265 * Status
06266 */
06267 
06268 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06269 {
06270 
06271    if (!param)
06272       return DC_ERROR;
06273 
06274    if ((myrpt->p.s[myrpt->p.sysstate_cur].txdisable) || (myrpt->p.s[myrpt->p.sysstate_cur].userfundisable))
06275       return DC_ERROR;
06276 
06277    if(debug)
06278       printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06279    
06280    switch(myatoi(param)){
06281       case 1: /* System ID */
06282          rpt_telemetry(myrpt, ID1, NULL);
06283          return DC_COMPLETE;
06284       case 2: /* System Time */
06285          rpt_telemetry(myrpt, STATS_TIME, NULL);
06286          return DC_COMPLETE;
06287       case 3: /* app_rpt.c version */
06288          rpt_telemetry(myrpt, STATS_VERSION, NULL);
06289          return DC_COMPLETE;
06290       case 11: /* System ID (local only)*/
06291           rpt_telemetry(myrpt, ID , NULL);
06292             return DC_COMPLETE;
06293         case 12: /* System Time (local only)*/
06294             rpt_telemetry(myrpt, STATS_TIME_LOCAL, NULL);
06295             return DC_COMPLETE;
06296       default:
06297          return DC_ERROR;
06298    }
06299    return DC_INDETERMINATE;
06300 }
06301 /*
06302 *  Macro-oni (without Salami)
06303 */
06304 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06305 {
06306 char  *val;
06307 int   i;
06308    if (myrpt->remote)
06309       return DC_ERROR;
06310 
06311    if(debug) 
06312       printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06313    
06314    if(strlen(digitbuf) < 1) /* needs 1 digit */
06315       return DC_INDETERMINATE;
06316          
06317    for(i = 0 ; i < digitbuf[i] ; i++) {
06318       if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06319          return DC_ERROR;
06320    }
06321    
06322    if (*digitbuf == '0') val = myrpt->p.startupmacro;
06323    else val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
06324    /* param was 1 for local buf */
06325    if (!val){
06326                 if (strlen(digitbuf) < myrpt->macro_longest)
06327                         return DC_INDETERMINATE;
06328       rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
06329       return DC_COMPLETE;
06330    }        
06331    rpt_mutex_lock(&myrpt->lock);
06332    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
06333    {
06334       rpt_mutex_unlock(&myrpt->lock);
06335       rpt_telemetry(myrpt, MACRO_BUSY, NULL);
06336       return DC_ERROR;
06337    }
06338    myrpt->macrotimer = MACROTIME;
06339    strncat(myrpt->macrobuf,val,MAXMACRO - 1);
06340    rpt_mutex_unlock(&myrpt->lock);
06341    return DC_COMPLETE;  
06342 }
06343 
06344 /*
06345 *  Playback a recording
06346 */
06347 
06348 static int function_playback(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06349 {
06350 
06351    if (myrpt->remote)
06352       return DC_ERROR;
06353 
06354    if(debug) 
06355       printf("@@@@ playback param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06356    
06357    if (ast_fileexists(param,NULL,myrpt->rxchannel->language) <= 0)
06358       return DC_ERROR;
06359 
06360    rpt_telemetry(myrpt,PLAYBACK,param);
06361    return DC_COMPLETE;
06362 }
06363 
06364 /*
06365 * COP - Control operator
06366 */
06367 
06368 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06369 {
06370    char string[16];
06371    int res;
06372 
06373    int i, r;
06374 
06375    if(!param)
06376       return DC_ERROR;
06377    
06378    switch(myatoi(param)){
06379       case 1: /* System reset */
06380          res = system("killall -9 asterisk");
06381          return DC_COMPLETE;
06382 
06383       case 2:
06384          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 0;
06385          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
06386          return DC_COMPLETE;
06387          
06388       case 3:
06389          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 1;
06390          return DC_COMPLETE;
06391          
06392       case 4: /* test tone on */
06393          if (myrpt->stopgen < 0) 
06394          {
06395             myrpt->stopgen = 1;
06396          }
06397          else 
06398          {
06399             myrpt->stopgen = 0;
06400             rpt_telemetry(myrpt, TEST_TONE, NULL);
06401          }
06402          return DC_COMPLETE;
06403 
06404       case 5: /* Disgorge variables to log for debug purposes */
06405          myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
06406          return DC_COMPLETE;
06407 
06408       case 6: /* Simulate COR being activated (phone only) */
06409          if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
06410          return DC_DOKEY;  
06411 
06412 
06413       case 7: /* Time out timer enable */
06414          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 0;
06415          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTENA");
06416          return DC_COMPLETE;
06417          
06418       case 8: /* Time out timer disable */
06419          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 1;
06420          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTDIS");
06421          return DC_COMPLETE;
06422 
06423                 case 9: /* Autopatch enable */
06424                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 0;
06425                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APENA");
06426                         return DC_COMPLETE;
06427 
06428                 case 10: /* Autopatch disable */
06429                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 1;
06430                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APDIS");
06431                         return DC_COMPLETE;
06432 
06433                 case 11: /* Link Enable */
06434                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 0;
06435                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKENA");
06436                         return DC_COMPLETE;
06437 
06438                 case 12: /* Link Disable */
06439                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 1;
06440                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKDIS");
06441                         return DC_COMPLETE;
06442 
06443       case 13: /* Query System State */
06444          string[0] = string[1] = 'S';
06445          string[2] = myrpt->p.sysstate_cur + '0';
06446          string[3] = '\0';
06447          rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
06448          return DC_COMPLETE;
06449 
06450       case 14: /* Change System State */
06451          if(strlen(digitbuf) == 0)
06452             break;
06453          if((digitbuf[0] < '0') || (digitbuf[0] > '9'))
06454             return DC_ERROR;
06455          myrpt->p.sysstate_cur = digitbuf[0] - '0';
06456                         string[0] = string[1] = 'S';
06457                         string[2] = myrpt->p.sysstate_cur + '0';
06458                         string[3] = '\0';
06459                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
06460                         return DC_COMPLETE;
06461 
06462                 case 15: /* Scheduler Enable */
06463                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 0;
06464                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKENA");
06465                         return DC_COMPLETE;
06466 
06467                 case 16: /* Scheduler Disable */
06468                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 1;
06469                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKDIS");
06470                         return DC_COMPLETE;
06471 
06472                 case 17: /* User functions Enable */
06473                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 0;
06474                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFENA");
06475                         return DC_COMPLETE;
06476 
06477                 case 18: /* User Functions Disable */
06478                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 1;
06479                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFDIS");
06480                         return DC_COMPLETE;
06481 
06482                 case 19: /* Alternate Tail Enable */
06483                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 1;
06484                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATENA");
06485                         return DC_COMPLETE;
06486 
06487                 case 20: /* Alternate Tail Disable */
06488                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 0;
06489                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATDIS");
06490                         return DC_COMPLETE;
06491 
06492                 case 21: /* Parrot Mode Disable */
06493          birdbath(myrpt);
06494          if (myrpt->p.parrotmode < 2)
06495          {
06496             myrpt->p.parrotmode = 0;
06497             rpt_telemetry(myrpt,COMPLETE,NULL);
06498             return DC_COMPLETE;
06499          }
06500          break;
06501 
06502                 case 22: /* Parrot Mode Enable */
06503          birdbath(myrpt);
06504          if (myrpt->p.parrotmode < 2)
06505          {
06506             myrpt->p.parrotmode = 1;
06507             rpt_telemetry(myrpt,COMPLETE,NULL);
06508             return DC_COMPLETE;
06509          }
06510          break;
06511       case 23: /* flush parrot in progress */
06512          birdbath(myrpt);
06513          rpt_telemetry(myrpt,COMPLETE,NULL);
06514          return DC_COMPLETE;
06515       case 24: /* flush all telemetry */
06516          flush_telem(myrpt);
06517          rpt_telemetry(myrpt,COMPLETE,NULL);
06518          return DC_COMPLETE;
06519       case 25: /* request keying info (brief) */
06520          send_link_keyquery(myrpt);
06521          myrpt->topkeylong = 0;
06522          rpt_telemetry(myrpt,COMPLETE,NULL);
06523          return DC_COMPLETE;
06524       case 26: /* request keying info (full) */
06525          send_link_keyquery(myrpt);
06526          myrpt->topkeylong = 1;
06527          rpt_telemetry(myrpt,COMPLETE,NULL);
06528          return DC_COMPLETE;
06529 
06530       case 30: /* recall memory location on programmable radio */
06531 
06532          if(strlen(digitbuf) < 2) /* needs 2 digits */
06533             break;
06534          
06535          for(i = 0 ; i < 2 ; i++){
06536             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06537                return DC_ERROR;
06538          }
06539        
06540          r = retreive_memory(myrpt, digitbuf);
06541          if (r < 0){
06542             rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
06543             return DC_COMPLETE;
06544          }
06545          if (r > 0){
06546             return DC_ERROR;
06547          }
06548          if (setrem(myrpt) == -1) return DC_ERROR;
06549          return DC_COMPLETE;  
06550 
06551       case 31: 
06552           /* set channel. note that it's going to change channel 
06553              then confirm on the new channel! */
06554          if(strlen(digitbuf) < 2) /* needs 2 digits */
06555             break;
06556          
06557          for(i = 0 ; i < 2 ; i++){
06558             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06559                return DC_ERROR;
06560          }
06561          channel_steer(myrpt,digitbuf);
06562          return DC_COMPLETE;  
06563 
06564       case 32: /* Touch Tone Pad Test */
06565          i = strlen(digitbuf);
06566          if(!i){
06567             if(debug > 3)
06568             ast_log(LOG_NOTICE,"Padtest entered");
06569             myrpt->inpadtest = 1;
06570          }
06571          else{
06572             if(debug > 3)
06573                ast_log(LOG_NOTICE,"Padtest len= %d digits=%s",i,digitbuf);
06574             if(digitbuf[i-1] != myrpt->p.endchar)
06575                break;
06576             rpt_telemetry(myrpt, ARB_ALPHA, digitbuf);
06577             myrpt->inpadtest = 0;
06578             if(debug > 3)
06579                ast_log(LOG_NOTICE,"Padtest exited");
06580             return DC_COMPLETE;
06581          }
06582    }  
06583    return DC_INDETERMINATE;
06584 }
06585 /*
06586 * Collect digits one by one until something matches
06587 */
06588 static int collect_function_digits(struct rpt *myrpt, char *digits, 
06589    int command_source, struct rpt_link *mylink)
06590 {
06591    int i,rv;
06592    char *stringp,*action,*param,*functiondigits;
06593    char function_table_name[30] = "";
06594    char workstring[200];
06595    
06596    struct ast_variable *vp;
06597    
06598    if (debug > 6) ast_log(LOG_NOTICE,"digits=%s  source=%d\n",digits, command_source);
06599 
06600    //if(debug) 
06601    // printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
06602    
06603    if (command_source == SOURCE_DPHONE) {
06604       if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
06605       strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1);
06606       }
06607    else if (command_source == SOURCE_ALT) {
06608       if (!myrpt->p.alt_functions) return DC_INDETERMINATE;
06609       strncpy(function_table_name, myrpt->p.alt_functions, sizeof(function_table_name) - 1);
06610       }
06611    else if (command_source == SOURCE_PHONE) {
06612       if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
06613       strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1);
06614       }
06615    else if (command_source == SOURCE_LNK)
06616       strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1);
06617    else
06618       strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1);
06619     /* find context for function table in rpt.conf file */
06620    vp = ast_variable_browse(myrpt->cfg, function_table_name);
06621    while(vp) {
06622       if(!strncasecmp(vp->name, digits, strlen(vp->name)))
06623          break;
06624       vp = vp->next;
06625    }  
06626    /* if function context not found */
06627    if(!vp) {
06628       int n;
06629 
06630       n = myrpt->longestfunc;
06631       if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
06632       else 
06633       if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
06634       else 
06635       if (command_source == SOURCE_ALT) n = myrpt->alt_longestfunc;
06636       else 
06637       if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
06638       
06639       if(strlen(digits) >= n)
06640          return DC_ERROR;
06641       else
06642          return DC_INDETERMINATE;
06643    }  
06644    /* Found a match, retrieve value part and parse */
06645    strncpy(workstring, vp->value, sizeof(workstring) - 1 );
06646    stringp = workstring;
06647    action = strsep(&stringp, ",");
06648    param = stringp;
06649    if(debug)
06650       printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
06651    /* Look up the action */
06652    for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
06653       if(!strncasecmp(action, function_table[i].action, strlen(action)))
06654          break;
06655    }
06656    if(debug)
06657       printf("@@@@ table index i = %d\n",i);
06658    if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
06659       /* Error, action not in table */
06660       return DC_ERROR;
06661    }
06662    if(function_table[i].function == NULL){
06663       /* Error, function undefined */
06664       if(debug)
06665          printf("@@@@ NULL for action: %s\n",action);
06666       return DC_ERROR;
06667    }
06668    functiondigits = digits + strlen(vp->name);
06669    rv=(*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
06670    if (debug > 6) ast_log(LOG_NOTICE,"rv=%i\n",rv);
06671    return(rv);
06672 }
06673 
06674 
06675 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
06676    char *str)
06677 {
06678 /* XXX ATTENTION: if you change the size of these arrays you MUST
06679  * change the limits in corresponding sscanf() calls below. */
06680 char  tmp[512],tmp1[512],cmd[300] = "",dest[300],src[300],c;
06681 int   i,seq, res, ts;
06682 struct rpt_link *l;
06683 struct   ast_frame wf;
06684 
06685    wf.frametype = AST_FRAME_TEXT;
06686    wf.subclass = 0;
06687    wf.offset = 0;
06688    wf.mallocd = 0;
06689    wf.datalen = strlen(str) + 1;
06690    wf.samples = 0;
06691    /* put string in our buffer */
06692    strncpy(tmp,str,sizeof(tmp) - 1);
06693 
06694         if (!strcmp(tmp,discstr))
06695         {
06696                 mylink->disced = 1;
06697       mylink->retries = mylink->max_retries + 1;
06698                 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
06699                 return;
06700         }
06701         if (!strcmp(tmp,newkeystr))
06702         {
06703       mylink->newkey = 1;
06704                 return;
06705         }
06706    if (tmp[0] == 'L')
06707    {
06708       rpt_mutex_lock(&myrpt->lock);
06709       strcpy(mylink->linklist,tmp + 2);
06710       time(&mylink->linklistreceived);
06711       rpt_mutex_unlock(&myrpt->lock);
06712       if (debug > 6) ast_log(LOG_NOTICE,"@@@@ node %s received node list %s from node %s\n",
06713          myrpt->name,tmp,mylink->name);
06714       return;
06715    }
06716    if (tmp[0] == 'K')
06717    {
06718       if (sscanf(tmp, "%299s %299s %299s %30d %30d", cmd, dest, src, &seq, &ts) != 5)
06719       {
06720          ast_log(LOG_WARNING, "Unable to parse keying string %s\n",str);
06721          return;
06722       }
06723       if (dest[0] == '0')
06724       {
06725          strcpy(dest,myrpt->name);
06726       }     
06727       /* if not for me, redistribute to all links */
06728       if (strcmp(dest,myrpt->name))
06729       {
06730          l = myrpt->links.next;
06731          /* see if this is one in list */
06732          while(l != &myrpt->links)
06733          {
06734             if (l->name[0] == '0') 
06735             {
06736                l = l->next;
06737                continue;
06738             }
06739             /* dont send back from where it came */
06740             if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06741             {
06742                l = l->next;
06743                continue;
06744             }
06745             /* if it is, send it and we're done */
06746             if (!strcmp(l->name,dest))
06747             {
06748                /* send, but not to src */
06749                if (strcmp(l->name,src)) {
06750                   wf.data.ptr = str;
06751                   if (l->chan) ast_write(l->chan,&wf);
06752                }
06753                return;
06754             }
06755             l = l->next;
06756          }
06757       }
06758       /* if not for me, or is broadcast, redistribute to all links */
06759       if ((strcmp(dest,myrpt->name)) || (dest[0] == '*'))
06760       {
06761          l = myrpt->links.next;
06762          /* otherwise, send it to all of em */
06763          while(l != &myrpt->links)
06764          {
06765             if (l->name[0] == '0') 
06766             {
06767                l = l->next;
06768                continue;
06769             }
06770             /* dont send back from where it came */
06771             if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06772             {
06773                l = l->next;
06774                continue;
06775             }
06776             /* send, but not to src */
06777             if (strcmp(l->name,src)) {
06778                wf.data.ptr = str;
06779                if (l->chan) ast_write(l->chan,&wf); 
06780             }
06781             l = l->next;
06782          }
06783       }
06784       /* if not for me, end here */
06785       if (strcmp(dest,myrpt->name) && (dest[0] != '*')) return;
06786       if (cmd[1] == '?')
06787       {
06788          time_t now;
06789          int n = 0;
06790 
06791          time(&now);
06792          if (myrpt->lastkeyedtime)
06793          {
06794             n = (int)(now - myrpt->lastkeyedtime);
06795          }
06796          sprintf(tmp1,"K %s %s %d %d",src,myrpt->name,myrpt->keyed,n);
06797          wf.data.ptr = tmp1;
06798          wf.datalen = strlen(tmp1) + 1;
06799          if (mylink->chan) ast_write(mylink->chan,&wf); 
06800          return;
06801       }
06802       if (myrpt->topkeystate != 1) return;
06803       rpt_mutex_lock(&myrpt->lock);
06804       for(i = 0; i < TOPKEYN; i++)
06805       {
06806          if (!strcmp(myrpt->topkey[i].node,src)) break;
06807       }
06808       if (i >= TOPKEYN)
06809       {
06810          for(i = 0; i < TOPKEYN; i++)
06811          {
06812             if (!myrpt->topkey[i].node[0]) break;
06813          }
06814       }
06815       if (i < TOPKEYN)
06816       {
06817          strncpy(myrpt->topkey[i].node,src,TOPKEYMAXSTR - 1);
06818          myrpt->topkey[i].timesince = ts;
06819          myrpt->topkey[i].keyed = seq;
06820       }
06821       rpt_mutex_unlock(&myrpt->lock);
06822       return;
06823    }
06824    if (tmp[0] == 'I')
06825    {
06826       /* XXX WARNING: be very careful with the limits on the folowing
06827        * sscanf() call, make sure they match the values defined above */
06828       if (sscanf(tmp,"%299s %299s %30x",cmd,src,&seq) != 3)
06829       {
06830          ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
06831          return;
06832       }
06833       mdc1200_notify(myrpt,src,seq);
06834       strcpy(dest,"*");
06835    }
06836    else
06837    {
06838       /* XXX WARNING: be very careful with the limits on the folowing
06839        * sscanf() call, make sure they match the values defined above */
06840       if (sscanf(tmp,"%299s %299s %299s %30d %1c",cmd,dest,src,&seq,&c) != 5)
06841       {
06842          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
06843          return;
06844       }
06845       if (strcmp(cmd,"D"))
06846       {
06847          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
06848          return;
06849       }
06850    }
06851    if (dest[0] == '0')
06852    {
06853       strcpy(dest,myrpt->name);
06854    }     
06855 
06856    /* if not for me, redistribute to all links */
06857    if (strcmp(dest,myrpt->name))
06858    {
06859       l = myrpt->links.next;
06860       /* see if this is one in list */
06861       while(l != &myrpt->links)
06862       {
06863          if (l->name[0] == '0') 
06864          {
06865             l = l->next;
06866             continue;
06867          }
06868          /* dont send back from where it came */
06869          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06870          {
06871             l = l->next;
06872             continue;
06873          }
06874          /* if it is, send it and we're done */
06875          if (!strcmp(l->name,dest))
06876          {
06877             /* send, but not to src */
06878             if (strcmp(l->name,src)) {
06879                wf.data.ptr = str;
06880                if (l->chan) ast_write(l->chan,&wf);
06881             }
06882             return;
06883          }
06884          l = l->next;
06885       }
06886       l = myrpt->links.next;
06887       /* otherwise, send it to all of em */
06888       while(l != &myrpt->links)
06889       {
06890          if (l->name[0] == '0') 
06891          {
06892             l = l->next;
06893             continue;
06894          }
06895          /* dont send back from where it came */
06896          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06897          {
06898             l = l->next;
06899             continue;
06900          }
06901          /* send, but not to src */
06902          if (strcmp(l->name,src)) {
06903             wf.data.ptr = str;
06904             if (l->chan) ast_write(l->chan,&wf); 
06905          }
06906          l = l->next;
06907       }
06908       return;
06909    }
06910    if (myrpt->p.archivedir)
06911    {
06912       char dtmfstr[100];
06913 
06914       sprintf(dtmfstr,"DTMF,%s,%c",mylink->name,c);
06915       donodelog(myrpt,dtmfstr);
06916    }
06917    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
06918    if (!c) return;
06919    rpt_mutex_lock(&myrpt->lock);
06920    if (c == myrpt->p.endchar) myrpt->stopgen = 1;
06921    if (myrpt->callmode == 1)
06922    {
06923       myrpt->exten[myrpt->cidx++] = c;
06924       myrpt->exten[myrpt->cidx] = 0;
06925       /* if this exists */
06926       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
06927       {
06928          /* if this really it, end now */
06929          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
06930             myrpt->exten,1,NULL)) 
06931          {
06932             myrpt->callmode = 2;
06933             if(!myrpt->patchquiet)
06934             {
06935                rpt_mutex_unlock(&myrpt->lock);
06936                rpt_telemetry(myrpt,PROC,NULL); 
06937                rpt_mutex_lock(&myrpt->lock);
06938             }
06939          }
06940          else /* othewise, reset timer */
06941          {
06942             myrpt->calldigittimer = 1;
06943          }
06944       }
06945       /* if can continue, do so */
06946       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
06947       {
06948          /* call has failed, inform user */
06949          myrpt->callmode = 4;
06950       }
06951    }
06952    if ((!myrpt->inpadtest) &&(c == myrpt->p.funcchar))
06953    {
06954       myrpt->rem_dtmfidx = 0;
06955       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
06956       time(&myrpt->rem_dtmf_time);
06957       rpt_mutex_unlock(&myrpt->lock);
06958       return;
06959    } 
06960    else if (myrpt->rem_dtmfidx < 0)
06961    {
06962       if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
06963       {
06964          myrpt->mydtmf = c;
06965       }
06966       if (myrpt->p.propagate_dtmf) do_dtmf_local(myrpt,c);
06967       if (myrpt->p.propagate_phonedtmf) do_dtmf_phone(myrpt,mylink,c);
06968       rpt_mutex_unlock(&myrpt->lock);
06969       return;
06970    }
06971    else if (((myrpt->inpadtest) || (c != myrpt->p.endchar)) && (myrpt->rem_dtmfidx >= 0))
06972    {
06973       time(&myrpt->rem_dtmf_time);
06974       if (myrpt->rem_dtmfidx < MAXDTMF)
06975       {
06976          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
06977          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
06978          
06979          rpt_mutex_unlock(&myrpt->lock);
06980          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
06981          res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
06982          rpt_mutex_lock(&myrpt->lock);
06983          
06984          switch(res){
06985 
06986             case DC_INDETERMINATE:
06987                break;
06988             
06989             case DC_REQ_FLUSH:
06990                myrpt->rem_dtmfidx = 0;
06991                myrpt->rem_dtmfbuf[0] = 0;
06992                break;
06993             
06994             
06995             case DC_COMPLETE:
06996             case DC_COMPLETEQUIET:
06997                myrpt->totalexecdcommands++;
06998                myrpt->dailyexecdcommands++;
06999                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
07000                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
07001                myrpt->rem_dtmfbuf[0] = 0;
07002                myrpt->rem_dtmfidx = -1;
07003                myrpt->rem_dtmf_time = 0;
07004                break;
07005             
07006             case DC_ERROR:
07007             default:
07008                myrpt->rem_dtmfbuf[0] = 0;
07009                myrpt->rem_dtmfidx = -1;
07010                myrpt->rem_dtmf_time = 0;
07011                break;
07012          }
07013       }
07014 
07015    }
07016    rpt_mutex_unlock(&myrpt->lock);
07017    return;
07018 }
07019 
07020 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
07021    char c)
07022 {
07023 
07024 char  cmd[300];
07025 int   res;
07026 
07027    if (myrpt->p.archivedir)
07028    {
07029       char str[100];
07030 
07031       sprintf(str,"DTMF(P),%s,%c",mylink->name,c);
07032       donodelog(myrpt,str);
07033    }
07034    rpt_mutex_lock(&myrpt->lock);
07035 
07036    if (mylink->phonemode == 3) /*If in simplex dumb phone mode */
07037    {
07038       if(c == myrpt->p.endchar) /* If end char */
07039       {
07040          mylink->lastrealrx = 0; /* Keying state = off */
07041          rpt_mutex_unlock(&myrpt->lock);
07042          return;
07043       }
07044 
07045       if(c == myrpt->p.funcchar) /* If lead-in char */
07046       {
07047          mylink->lastrealrx = !mylink->lastrealrx; /* Toggle keying state */
07048          rpt_mutex_unlock(&myrpt->lock);
07049          return;
07050       }
07051    }
07052    else
07053    {
07054       if (c == myrpt->p.endchar)
07055       {
07056          if (mylink->lastrx)
07057          {
07058             mylink->lastrealrx = 0;
07059             rpt_mutex_unlock(&myrpt->lock);
07060             return;
07061          }
07062          myrpt->stopgen = 1;
07063          if (myrpt->cmdnode[0])
07064          {
07065             myrpt->cmdnode[0] = 0;
07066             myrpt->dtmfidx = -1;
07067             myrpt->dtmfbuf[0] = 0;
07068             rpt_mutex_unlock(&myrpt->lock);
07069             rpt_telemetry(myrpt,COMPLETE,NULL);
07070             return;
07071          }
07072       }
07073    }
07074    if (myrpt->cmdnode[0])
07075    {
07076       rpt_mutex_unlock(&myrpt->lock);
07077       send_link_dtmf(myrpt,c);
07078       return;
07079    }
07080    if (myrpt->callmode == 1)
07081    {
07082       myrpt->exten[myrpt->cidx++] = c;
07083       myrpt->exten[myrpt->cidx] = 0;
07084       /* if this exists */
07085       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
07086       {
07087          /* if this really it, end now */
07088          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
07089             myrpt->exten,1,NULL)) 
07090          {
07091             myrpt->callmode = 2;
07092             if(!myrpt->patchquiet)
07093             {
07094                rpt_mutex_unlock(&myrpt->lock);
07095                rpt_telemetry(myrpt,PROC,NULL); 
07096                rpt_mutex_lock(&myrpt->lock);
07097             }
07098          }
07099          else /* othewise, reset timer */
07100          {
07101             myrpt->calldigittimer = 1;
07102          }
07103       }
07104       /* if can continue, do so */
07105       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
07106       {
07107          /* call has failed, inform user */
07108          myrpt->callmode = 4;
07109       }
07110    }
07111    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
07112    {
07113       myrpt->mydtmf = c;
07114    }
07115    if ((!myrpt->inpadtest) && (c == myrpt->p.funcchar))
07116    {
07117       myrpt->rem_dtmfidx = 0;
07118       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
07119       time(&myrpt->rem_dtmf_time);
07120       rpt_mutex_unlock(&myrpt->lock);
07121       return;
07122    } 
07123    else if (((myrpt->inpadtest) || (c != myrpt->p.endchar)) && (myrpt->rem_dtmfidx >= 0))
07124    {
07125       time(&myrpt->rem_dtmf_time);
07126       if (myrpt->rem_dtmfidx < MAXDTMF)
07127       {
07128          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
07129          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
07130          
07131          rpt_mutex_unlock(&myrpt->lock);
07132          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
07133          switch(mylink->phonemode)
07134          {
07135              case 1:
07136             res = collect_function_digits(myrpt, cmd, 
07137                SOURCE_PHONE, mylink);
07138             break;
07139              case 2:
07140             res = collect_function_digits(myrpt, cmd, 
07141                SOURCE_DPHONE,mylink);
07142             break;
07143              case 4:
07144             res = collect_function_digits(myrpt, cmd, 
07145                SOURCE_ALT,mylink);
07146             break;
07147              default:
07148             res = collect_function_digits(myrpt, cmd, 
07149                SOURCE_LNK, mylink);
07150             break;
07151          }
07152 
07153          rpt_mutex_lock(&myrpt->lock);
07154          
07155          switch(res){
07156 
07157             case DC_INDETERMINATE:
07158                break;
07159             
07160             case DC_DOKEY:
07161                mylink->lastrealrx = 1;
07162                break;
07163             
07164             case DC_REQ_FLUSH:
07165                myrpt->rem_dtmfidx = 0;
07166                myrpt->rem_dtmfbuf[0] = 0;
07167                break;
07168             
07169             
07170             case DC_COMPLETE:
07171             case DC_COMPLETEQUIET:
07172                myrpt->totalexecdcommands++;
07173                myrpt->dailyexecdcommands++;
07174                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
07175                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
07176                myrpt->rem_dtmfbuf[0] = 0;
07177                myrpt->rem_dtmfidx = -1;
07178                myrpt->rem_dtmf_time = 0;
07179                break;
07180             
07181             case DC_ERROR:
07182             default:
07183                myrpt->rem_dtmfbuf[0] = 0;
07184                myrpt->rem_dtmfidx = -1;
07185                myrpt->rem_dtmf_time = 0;
07186                break;
07187          }
07188       }
07189 
07190    }
07191    rpt_mutex_unlock(&myrpt->lock);
07192    return;
07193 }
07194 
07195 /* Doug Hall RBI-1 serial data definitions:
07196  *
07197  * Byte 0: Expansion external outputs 
07198  * Byte 1: 
07199  * Bits 0-3 are BAND as follows:
07200  * Bits 4-5 are POWER bits as follows:
07201  *    00 - Low Power
07202  *    01 - Hi Power
07203  *    02 - Med Power
07204  * Bits 6-7 are always set
07205  * Byte 2:
07206  * Bits 0-3 MHZ in BCD format
07207  * Bits 4-5 are offset as follows:
07208  *    00 - minus
07209  *    01 - plus
07210  *    02 - simplex
07211  *    03 - minus minus (whatever that is)
07212  * Bit 6 is the 0/5 KHZ bit
07213  * Bit 7 is always set
07214  * Byte 3:
07215  * Bits 0-3 are 10 KHZ in BCD format
07216  * Bits 4-7 are 100 KHZ in BCD format
07217  * Byte 4: PL Tone code and encode/decode enable bits
07218  * Bits 0-5 are PL tone code (comspec binary codes)
07219  * Bit 6 is encode enable/disable
07220  * Bit 7 is decode enable/disable
07221  */
07222 
07223 /* take the frequency from the 10 mhz digits (and up) and convert it
07224    to a band number */
07225 
07226 static int rbi_mhztoband(char *str)
07227 {
07228 int   i;
07229 
07230    i = atoi(str) / 10; /* get the 10's of mhz */
07231    switch(i)
07232    {
07233        case 2:
07234       return 10;
07235        case 5:
07236       return 11;
07237        case 14:
07238       return 2;
07239        case 22:
07240       return 3;
07241        case 44:
07242       return 4;
07243        case 124:
07244       return 0;
07245        case 125:
07246       return 1;
07247        case 126:
07248       return 8;
07249        case 127:
07250       return 5;
07251        case 128:
07252       return 6;
07253        case 129:
07254       return 7;
07255        default:
07256       break;
07257    }
07258    return -1;
07259 }
07260 
07261 /* take a PL frequency and turn it into a code */
07262 static int rbi_pltocode(char *str)
07263 {
07264 int i;
07265 char *s;
07266 
07267    s = strchr(str,'.');
07268    i = 0;
07269    if (s) i = atoi(s + 1);
07270    i += atoi(str) * 10;
07271    switch(i)
07272    {
07273        case 670:
07274       return 0;
07275        case 719:
07276       return 1;
07277        case 744:
07278       return 2;
07279        case 770:
07280       return 3;
07281        case 797:
07282       return 4;
07283        case 825:
07284       return 5;
07285        case 854:
07286       return 6;
07287        case 885:
07288       return 7;
07289        case 915:
07290       return 8;
07291        case 948:
07292       return 9;
07293        case 974:
07294       return 10;
07295        case 1000:
07296       return 11;
07297        case 1035:
07298       return 12;
07299        case 1072:
07300       return 13;
07301        case 1109:
07302       return 14;
07303        case 1148:
07304       return 15;
07305        case 1188:
07306       return 16;
07307        case 1230:
07308       return 17;
07309        case 1273:
07310       return 18;
07311        case 1318:
07312       return 19;
07313        case 1365:
07314       return 20;
07315        case 1413:
07316       return 21;
07317        case 1462:
07318       return 22;
07319        case 1514:
07320       return 23;
07321        case 1567:
07322       return 24;
07323        case 1622:
07324       return 25;
07325        case 1679:
07326       return 26;
07327        case 1738:
07328       return 27;
07329        case 1799:
07330       return 28;
07331        case 1862:
07332       return 29;
07333        case 1928:
07334       return 30;
07335        case 2035:
07336       return 31;
07337        case 2107:
07338       return 32;
07339        case 2181:
07340       return 33;
07341        case 2257:
07342       return 34;
07343        case 2336:
07344       return 35;
07345        case 2418:
07346       return 36;
07347        case 2503:
07348       return 37;
07349    }
07350    return -1;
07351 }
07352 
07353 /*
07354 * Shift out a formatted serial bit stream
07355 */
07356 
07357 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
07358     {
07359 #ifdef __i386__
07360     int i,j;
07361     unsigned char od,d;
07362     static volatile long long delayvar;
07363 
07364     for(i = 0 ; i < 5 ; i++){
07365         od = *data++; 
07366         for(j = 0 ; j < 8 ; j++){
07367             d = od & 1;
07368             outb(d,myrpt->p.iobase);
07369        /* >= 15 us */
07370        for(delayvar = 1; delayvar < 15000; delayvar++); 
07371             od >>= 1;
07372             outb(d | 2,myrpt->p.iobase);
07373        /* >= 30 us */
07374        for(delayvar = 1; delayvar < 30000; delayvar++); 
07375             outb(d,myrpt->p.iobase);
07376        /* >= 10 us */
07377        for(delayvar = 1; delayvar < 10000; delayvar++); 
07378             }
07379         }
07380    /* >= 50 us */
07381         for(delayvar = 1; delayvar < 50000; delayvar++); 
07382 #endif
07383     }
07384 
07385 static void rbi_out(struct rpt *myrpt,unsigned char *data)
07386 {
07387 struct dahdi_radio_param r;
07388 
07389    memset(&r,0,sizeof(struct dahdi_radio_param));
07390    r.radpar = DAHDI_RADPAR_REMMODE;
07391    r.data = DAHDI_RADPAR_REM_RBI1;
07392    /* if setparam ioctl fails, its probably not a pciradio card */
07393    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
07394    {
07395       rbi_out_parallel(myrpt,data);
07396       return;
07397    }
07398    r.radpar = DAHDI_RADPAR_REMCOMMAND;
07399    memcpy(&r.data,data,5);
07400    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
07401    {
07402       ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->dahdirxchannel->name);
07403       return;
07404    }
07405 }
07406 
07407 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, 
07408    unsigned char *rxbuf, int rxmaxbytes, int asciiflag)
07409 {
07410    int i,j,idx,oldmode,olddata;
07411    struct dahdi_radio_param prm;
07412    char c;
07413 
07414     if(debug) {
07415        ast_log(LOG_NOTICE, "ioport=%s  iofd=0x%x\n",myrpt->p.ioport,myrpt->iofd);
07416       printf("String output was:\n");
07417       for(i = 0; i < txbytes; i++)
07418          printf("%02X ", (unsigned char ) txbuf[i]);
07419       printf("\n");
07420    }
07421 
07422    if (myrpt->iofd >= 0)  /* if to do out a serial port */
07423    {
07424       if (write(myrpt->iofd,txbuf,txbytes) != txbytes)
07425       {
07426          return -1;
07427       }
07428       if ((!rxmaxbytes) || (rxbuf == NULL)) 
07429       {
07430          return(0);
07431       }
07432       memset(rxbuf,0,rxmaxbytes);
07433       for(i = 0; i < rxmaxbytes; i++)
07434       {
07435          j = read(myrpt->iofd,&c,1);
07436          if (j < 1) 
07437          {
07438             return(i);
07439          }
07440          rxbuf[i] = c;
07441          if (asciiflag & 1)
07442          {
07443             rxbuf[i + 1] = 0;
07444             if (c == '\r') break;
07445          }
07446       }              
07447       if(debug) {
07448          printf("String returned was:\n");
07449          for(j = 0; j < i; j++)
07450             printf("%02X ", (unsigned char ) rxbuf[j]);
07451          printf("\n");
07452       }
07453       return(i);
07454    }
07455 
07456    /* if not a DAHDI channel, cant use pciradio stuff */
07457    if (myrpt->rxchannel != myrpt->dahdirxchannel) return -1;   
07458 
07459    prm.radpar = DAHDI_RADPAR_UIOMODE;
07460    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
07461    oldmode = prm.data;
07462    prm.radpar = DAHDI_RADPAR_UIODATA;
07463    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
07464    olddata = prm.data;
07465         prm.radpar = DAHDI_RADPAR_REMMODE;
07466         if (asciiflag & 1)  prm.data = DAHDI_RADPAR_REM_SERIAL_ASCII;
07467         else prm.data = DAHDI_RADPAR_REM_SERIAL;
07468    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07469    if (asciiflag & 2)
07470    {
07471       i = DAHDI_ONHOOK;
07472       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
07473       usleep(100000);
07474    }
07475         prm.radpar = DAHDI_RADPAR_REMCOMMAND;
07476         prm.data = rxmaxbytes;
07477         memcpy(prm.buf,txbuf,txbytes);
07478         prm.index = txbytes;
07479    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07480         if (rxbuf)
07481         {
07482                 *rxbuf = 0;
07483                 memcpy(rxbuf,prm.buf,prm.index);
07484         }
07485    idx = prm.index;
07486         prm.radpar = DAHDI_RADPAR_REMMODE;
07487         prm.data = DAHDI_RADPAR_REM_NONE;
07488    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07489    if (asciiflag & 2)
07490    {
07491       i = DAHDI_OFFHOOK;
07492       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
07493    }
07494    prm.radpar = DAHDI_RADPAR_UIOMODE;
07495    prm.data = oldmode;
07496    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07497    prm.radpar = DAHDI_RADPAR_UIODATA;
07498    prm.data = olddata;
07499    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07500         return(idx);
07501 }
07502 
07503 static int civ_cmd(struct rpt *myrpt,unsigned char *cmd, int cmdlen)
07504 {
07505 unsigned char rxbuf[100];
07506 int   i,rv ;
07507 
07508    rv = serial_remote_io(myrpt,cmd,cmdlen,rxbuf,cmdlen + 6,0);
07509    if (rv == -1) return(-1);
07510    if (rv != (cmdlen + 6)) return(1);
07511    for(i = 0; i < 6; i++)
07512       if (rxbuf[i] != cmd[i]) return(1);
07513    if (rxbuf[cmdlen] != 0xfe) return(1);
07514    if (rxbuf[cmdlen + 1] != 0xfe) return(1);
07515    if (rxbuf[cmdlen + 4] != 0xfb) return(1);
07516    if (rxbuf[cmdlen + 5] != 0xfd) return(1);
07517    return(0);
07518 }
07519 
07520 static int sendkenwood(struct rpt *myrpt,char *txstr, char *rxstr)
07521 {
07522 int   i;
07523 
07524 ast_log(LOG_NOTICE,"Sent to kenwood: %s\n",txstr);
07525    if (debug) printf("Send to kenwood: %s\n",txstr);
07526    i = serial_remote_io(myrpt, (unsigned char *)txstr, strlen(txstr), 
07527       (unsigned char *)rxstr,RAD_SERIAL_BUFLEN - 1,3);
07528    if (i < 0) return -1;
07529    if ((i > 0) && (rxstr[i - 1] == '\r'))
07530       rxstr[i-- - 1] = 0;
07531    if (debug) printf("Got from kenwood: %s\n",rxstr);
07532 ast_log(LOG_NOTICE,"Got from kenwood: %s\n",rxstr);
07533    return(i);
07534 }
07535 
07536 /* take a PL frequency and turn it into a code */
07537 static int kenwood_pltocode(char *str)
07538 {
07539 int i;
07540 char *s;
07541 
07542    s = strchr(str,'.');
07543    i = 0;
07544    if (s) i = atoi(s + 1);
07545    i += atoi(str) * 10;
07546    switch(i)
07547    {
07548        case 670:
07549       return 1;
07550        case 719:
07551       return 3;
07552        case 744:
07553       return 4;
07554        case 770:
07555       return 5;
07556        case 797:
07557       return 6;
07558        case 825:
07559       return 7;
07560        case 854:
07561       return 8;
07562        case 885:
07563       return 9;
07564        case 915:
07565       return 10;
07566        case 948:
07567       return 11;
07568        case 974:
07569       return 12;
07570        case 1000:
07571       return 13;
07572        case 1035:
07573       return 14;
07574        case 1072:
07575       return 15;
07576        case 1109:
07577       return 16;
07578        case 1148:
07579       return 17;
07580        case 1188:
07581       return 18;
07582        case 1230:
07583       return 19;
07584        case 1273:
07585       return 20;
07586        case 1318:
07587       return 21;
07588        case 1365:
07589       return 22;
07590        case 1413:
07591       return 23;
07592        case 1462:
07593       return 24;
07594        case 1514:
07595       return 25;
07596        case 1567:
07597       return 26;
07598        case 1622:
07599       return 27;
07600        case 1679:
07601       return 28;
07602        case 1738:
07603       return 29;
07604        case 1799:
07605       return 30;
07606        case 1862:
07607       return 31;
07608        case 1928:
07609       return 32;
07610        case 2035:
07611       return 33;
07612        case 2107:
07613       return 34;
07614        case 2181:
07615       return 35;
07616        case 2257:
07617       return 36;
07618        case 2336:
07619       return 37;
07620        case 2418:
07621       return 38;
07622        case 2503:
07623       return 39;
07624    }
07625    return -1;
07626 }
07627 
07628 static int sendrxkenwood(struct rpt *myrpt, char *txstr, char *rxstr, 
07629    char *cmpstr)
07630 {
07631 int   i,j;
07632 
07633    for(i = 0;i < KENWOOD_RETRIES;i++)
07634    {
07635       j = sendkenwood(myrpt,txstr,rxstr);
07636       if (j < 0) return(j);
07637       if (j == 0) continue;
07638       if (!strncmp(rxstr,cmpstr,strlen(cmpstr))) return(0);
07639    }
07640    return(-1);
07641 }     
07642 
07643 static int setkenwood(struct rpt *myrpt)
07644 {
07645 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
07646 char mhz[MAXREMSTR],offset[20],band,decimals[MAXREMSTR],band1,band2;
07647 int myrxpl;
07648    
07649 int offsets[] = {0,2,1};
07650 int powers[] = {2,1,0};
07651 
07652    if (sendrxkenwood(myrpt,"VMC 0,0\r",rxstr,"VMC") < 0) return -1;
07653    split_freq(mhz, decimals, myrpt->freq);
07654    if (atoi(mhz) > 400)
07655    {
07656       band = '6';
07657       band1 = '1';
07658       band2 = '5';
07659       strcpy(offset,"005000000");
07660    }
07661    else
07662    {
07663       band = '2';
07664       band1 = '0';
07665       band2 = '2';
07666       strcpy(offset,"000600000");
07667    }
07668    strcpy(freq,"000000");
07669    strncpy(freq,decimals,strlen(decimals));
07670    myrxpl = myrpt->rxplon;
07671    if (IS_XPMR(myrpt)) myrxpl = 0;
07672    sprintf(txstr,"VW %c,%05d%s,0,%d,0,%d,%d,,%02d,,%02d,%s\r",
07673       band,atoi(mhz),freq,offsets[(int)myrpt->offset],
07674       (myrpt->txplon != 0),myrxpl,
07675       kenwood_pltocode(myrpt->txpl),kenwood_pltocode(myrpt->rxpl),
07676       offset);
07677    if (sendrxkenwood(myrpt,txstr,rxstr,"VW") < 0) return -1;
07678    sprintf(txstr,"RBN %c\r",band2);
07679    if (sendrxkenwood(myrpt,txstr,rxstr,"RBN") < 0) return -1;
07680    sprintf(txstr,"PC %c,%d\r",band1,powers[(int)myrpt->powerlevel]);
07681    if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
07682    return 0;
07683 }
07684 
07685 static int set_tm271(struct rpt *myrpt)
07686 {
07687 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
07688 char mhz[MAXREMSTR],decimals[MAXREMSTR];
07689    
07690 int offsets[] = {0,2,1};
07691 int powers[] = {2,1,0};
07692 
07693    split_freq(mhz, decimals, myrpt->freq);
07694    strcpy(freq,"000000");
07695    strncpy(freq,decimals,strlen(decimals));
07696 
07697    sprintf(txstr,"VF %04d%s,4,%d,0,%d,0,0,%d,%d,000,00600000,0,0\r",
07698       atoi(mhz),freq,offsets[(int)myrpt->offset],
07699       (myrpt->txplon != 0),kenwood_pltocode(myrpt->txpl),
07700       kenwood_pltocode(myrpt->rxpl));
07701 
07702    if (sendrxkenwood(myrpt,txstr,rxstr,"VF") < 0) return -1;
07703    if (sendrxkenwood(myrpt,"VM 0\r",rxstr,"VM") < 0) return -1;
07704    sprintf(txstr,"PC %d\r",powers[(int)myrpt->powerlevel]);
07705    if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
07706    return 0;
07707 }
07708 
07709 static int setrbi(struct rpt *myrpt)
07710 {
07711 char tmp[MAXREMSTR] = "",*s;
07712 unsigned char rbicmd[5];
07713 int   band,txoffset = 0,txpower = 0,rxpl;
07714 
07715    /* must be a remote system */
07716    if (!myrpt->remoterig) return(0);
07717    if (!myrpt->remoterig[0]) return(0);
07718    /* must have rbi hardware */
07719    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
07720    if (setrbi_check(myrpt) == -1) return(-1);
07721    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07722    s = strchr(tmp,'.');
07723    /* if no decimal, is invalid */
07724    
07725    if (s == NULL){
07726       if(debug)
07727          printf("@@@@ Frequency needs a decimal\n");
07728       return -1;
07729    }
07730    
07731    *s++ = 0;
07732    if (strlen(tmp) < 2){
07733       if(debug)
07734          printf("@@@@ Bad MHz digits: %s\n", tmp);
07735       return -1;
07736    }
07737     
07738    if (strlen(s) < 3){
07739       if(debug)
07740          printf("@@@@ Bad KHz digits: %s\n", s);
07741       return -1;
07742    }
07743 
07744    if ((s[2] != '0') && (s[2] != '5')){
07745       if(debug)
07746          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
07747       return -1;
07748    }
07749     
07750    band = rbi_mhztoband(tmp);
07751    if (band == -1){
07752       if(debug)
07753          printf("@@@@ Bad Band: %s\n", tmp);
07754       return -1;
07755    }
07756    
07757    rxpl = rbi_pltocode(myrpt->rxpl);
07758    
07759    if (rxpl == -1){
07760       if(debug)
07761          printf("@@@@ Bad TX PL: %s\n", myrpt->rxpl);
07762       return -1;
07763    }
07764 
07765    
07766    switch(myrpt->offset)
07767    {
07768        case REM_MINUS:
07769       txoffset = 0;
07770       break;
07771        case REM_PLUS:
07772       txoffset = 0x10;
07773       break;
07774        case REM_SIMPLEX:
07775       txoffset = 0x20;
07776       break;
07777    }
07778    switch(myrpt->powerlevel)
07779    {
07780        case REM_LOWPWR:
07781       txpower = 0;
07782       break;
07783        case REM_MEDPWR:
07784       txpower = 0x20;
07785       break;
07786        case REM_HIPWR:
07787       txpower = 0x10;
07788       break;
07789    }
07790    rbicmd[0] = 0;
07791    rbicmd[1] = band | txpower | 0xc0;
07792    rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
07793    if (s[2] == '5') rbicmd[2] |= 0x40;
07794    rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
07795    rbicmd[4] = rxpl;
07796    if (myrpt->txplon) rbicmd[4] |= 0x40;
07797    if (myrpt->rxplon) rbicmd[4] |= 0x80;
07798    rbi_out(myrpt,rbicmd);
07799    return 0;
07800 }
07801 
07802 static int setrtx(struct rpt *myrpt)
07803 {
07804 char tmp[MAXREMSTR] = "",*s,rigstr[200],pwr,res = 0;
07805 int   band,txoffset = 0,txpower = 0,rxpl,txpl;
07806 float ofac;
07807 double txfreq;
07808 
07809    /* must be a remote system */
07810    if (!myrpt->remoterig) return(0);
07811    if (!myrpt->remoterig[0]) return(0);
07812    /* must have rtx hardware */
07813    if (!ISRIG_RTX(myrpt->remoterig)) return(0);
07814    /* must be a usbradio interface type */
07815    if (!IS_XPMR(myrpt)) return(0);
07816    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07817    s = strchr(tmp,'.');
07818    /* if no decimal, is invalid */
07819    
07820    if(debug)printf("setrtx() %s %s\n",myrpt->name,myrpt->remoterig);
07821 
07822    if (s == NULL){
07823       if(debug)
07824          printf("@@@@ Frequency needs a decimal\n");
07825       return -1;
07826    }
07827    *s++ = 0;
07828    if (strlen(tmp) < 2){
07829       if(debug)
07830          printf("@@@@ Bad MHz digits: %s\n", tmp);
07831       return -1;
07832    }
07833     
07834    if (strlen(s) < 3){
07835       if(debug)
07836          printf("@@@@ Bad KHz digits: %s\n", s);
07837       return -1;
07838    }
07839 
07840    if ((s[2] != '0') && (s[2] != '5')){
07841       if(debug)
07842          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
07843       return -1;
07844    }
07845     
07846    band = rbi_mhztoband(tmp);
07847    if (band == -1){
07848       if(debug)
07849          printf("@@@@ Bad Band: %s\n", tmp);
07850       return -1;
07851    }
07852    
07853    rxpl = rbi_pltocode(myrpt->rxpl);
07854    
07855    if (rxpl == -1){
07856       if(debug)
07857          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
07858       return -1;
07859    }
07860 
07861    txpl = rbi_pltocode(myrpt->txpl);
07862    
07863    if (txpl == -1){
07864       if(debug)
07865          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
07866       return -1;
07867    }
07868    
07869    switch(myrpt->offset)
07870    {
07871        case REM_MINUS:
07872       txoffset = 0;
07873       break;
07874        case REM_PLUS:
07875       txoffset = 0x10;
07876       break;
07877        case REM_SIMPLEX:
07878       txoffset = 0x20;
07879       break;
07880    }
07881    switch(myrpt->powerlevel)
07882    {
07883        case REM_LOWPWR:
07884       txpower = 0;
07885       break;
07886        case REM_MEDPWR:
07887       txpower = 0x20;
07888       break;
07889        case REM_HIPWR:
07890       txpower = 0x10;
07891       break;
07892    }
07893 
07894    res = setrtx_check(myrpt);
07895    if (res < 0) return res;
07896    ofac = 0.0;
07897    if (myrpt->offset == REM_MINUS) ofac = -1.0;
07898    if (myrpt->offset == REM_PLUS) ofac = 1.0;
07899 
07900    if (!strcmp(myrpt->remoterig,remote_rig_rtx450))
07901       txfreq = atof(myrpt->freq) +  (ofac * 5.0);
07902    else
07903       txfreq = atof(myrpt->freq) +  (ofac * 0.6);
07904 
07905    pwr = 'L';
07906    if (myrpt->powerlevel == REM_HIPWR) pwr = 'H';
07907    if (!res)
07908    {
07909       sprintf(rigstr,"SETFREQ %s %f %s %s %c",myrpt->freq,txfreq,
07910          (myrpt->rxplon) ? myrpt->rxpl : "0.0",
07911          (myrpt->txplon) ? myrpt->txpl : "0.0",pwr);
07912       send_usb_txt(myrpt,rigstr);
07913       rpt_telemetry(myrpt,COMPLETE,NULL);
07914       res = 0;
07915    }
07916    return 0;
07917 }
07918 #if 0
07919 /*
07920    sets current signaling code for xpmr routines
07921    under development for new radios.
07922 */
07923 static int setxpmr(struct rpt *myrpt)
07924 {
07925    char rigstr[200];
07926    int rxpl,txpl;
07927 
07928    /* must be a remote system */
07929    if (!myrpt->remoterig) return(0);
07930    if (!myrpt->remoterig[0]) return(0);
07931    /* must not have rtx hardware */
07932    if (ISRIG_RTX(myrpt->remoterig)) return(0);
07933    /* must be a usbradio interface type */
07934    if (!IS_XPMR(myrpt)) return(0);
07935    
07936    if(debug)printf("setxpmr() %s %s\n",myrpt->name,myrpt->remoterig );
07937 
07938    rxpl = rbi_pltocode(myrpt->rxpl);
07939    
07940    if (rxpl == -1){
07941       if(debug)
07942          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
07943       return -1;
07944    }
07945 
07946    txpl = rbi_pltocode(myrpt->txpl);
07947    if (txpl == -1){
07948       if(debug)
07949          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
07950       return -1;
07951    }
07952    sprintf(rigstr,"SETFREQ 0.0 0.0 %s %s L",
07953       (myrpt->rxplon) ? myrpt->rxpl : "0.0",
07954       (myrpt->txplon) ? myrpt->txpl : "0.0");
07955    send_usb_txt(myrpt,rigstr);
07956    return 0;
07957 }
07958 #endif
07959 
07960 static int setrbi_check(struct rpt *myrpt)
07961 {
07962 char tmp[MAXREMSTR] = "",*s;
07963 int   band,txpl;
07964 
07965    /* must be a remote system */
07966    if (!myrpt->remote) return(0);
07967    /* must have rbi hardware */
07968    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
07969    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07970    s = strchr(tmp,'.');
07971    /* if no decimal, is invalid */
07972    
07973    if (s == NULL){
07974       if(debug)
07975          printf("@@@@ Frequency needs a decimal\n");
07976       return -1;
07977    }
07978    
07979    *s++ = 0;
07980    if (strlen(tmp) < 2){
07981       if(debug)
07982          printf("@@@@ Bad MHz digits: %s\n", tmp);
07983       return -1;
07984    }
07985     
07986    if (strlen(s) < 3){
07987       if(debug)
07988          printf("@@@@ Bad KHz digits: %s\n", s);
07989       return -1;
07990    }
07991 
07992    if ((s[2] != '0') && (s[2] != '5')){
07993       if(debug)
07994          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
07995       return -1;
07996    }
07997     
07998    band = rbi_mhztoband(tmp);
07999    if (band == -1){
08000       if(debug)
08001          printf("@@@@ Bad Band: %s\n", tmp);
08002       return -1;
08003    }
08004    
08005    txpl = rbi_pltocode(myrpt->txpl);
08006    
08007    if (txpl == -1){
08008       if(debug)
08009          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
08010       return -1;
08011    }
08012    return 0;
08013 }
08014 
08015 static int setrtx_check(struct rpt *myrpt)
08016 {
08017 char tmp[MAXREMSTR] = "",*s;
08018 int   band,txpl,rxpl;
08019 
08020    /* must be a remote system */
08021    if (!myrpt->remote) return(0);
08022    /* must have rbi hardware */
08023    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
08024    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
08025    s = strchr(tmp,'.');
08026    /* if no decimal, is invalid */
08027    
08028    if (s == NULL){
08029       if(debug)
08030          printf("@@@@ Frequency needs a decimal\n");
08031       return -1;
08032    }
08033    
08034    *s++ = 0;
08035    if (strlen(tmp) < 2){
08036       if(debug)
08037          printf("@@@@ Bad MHz digits: %s\n", tmp);
08038       return -1;
08039    }
08040     
08041    if (strlen(s) < 3){
08042       if(debug)
08043          printf("@@@@ Bad KHz digits: %s\n", s);
08044       return -1;
08045    }
08046 
08047    if ((s[2] != '0') && (s[2] != '5')){
08048       if(debug)
08049          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
08050       return -1;
08051    }
08052     
08053    band = rbi_mhztoband(tmp);
08054    if (band == -1){
08055       if(debug)
08056          printf("@@@@ Bad Band: %s\n", tmp);
08057       return -1;
08058    }
08059    
08060    txpl = rbi_pltocode(myrpt->txpl);
08061    
08062    if (txpl == -1){
08063       if(debug)
08064          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
08065       return -1;
08066    }
08067 
08068    rxpl = rbi_pltocode(myrpt->rxpl);
08069    
08070    if (rxpl == -1){
08071       if(debug)
08072          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
08073       return -1;
08074    }
08075    return 0;
08076 }
08077 
08078 static int check_freq_kenwood(int m, int d, int *defmode)
08079 {
08080    int dflmd = REM_MODE_FM;
08081 
08082    if (m == 144){ /* 2 meters */
08083       if(d < 10100)
08084          return -1;
08085    }
08086    else if((m >= 145) && (m < 148)){
08087       ;
08088    }
08089    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08090       ;
08091    }
08092    else
08093       return -1;
08094    
08095    if(defmode)
08096       *defmode = dflmd; 
08097 
08098 
08099    return 0;
08100 }
08101 
08102 
08103 static int check_freq_tm271(int m, int d, int *defmode)
08104 {
08105    int dflmd = REM_MODE_FM;
08106 
08107    if (m == 144){ /* 2 meters */
08108       if(d < 10100)
08109          return -1;
08110    }
08111    else if((m >= 145) && (m < 148)){
08112       ;
08113    }
08114       return -1;
08115    
08116    if(defmode)
08117       *defmode = dflmd; 
08118 
08119 
08120    return 0;
08121 }
08122 
08123 
08124 /* Check for valid rbi frequency */
08125 /* Hard coded limits now, configurable later, maybe? */
08126 
08127 static int check_freq_rbi(int m, int d, int *defmode)
08128 {
08129    int dflmd = REM_MODE_FM;
08130 
08131    if(m == 50){ /* 6 meters */
08132       if(d < 10100)
08133          return -1;
08134    }
08135    else if((m >= 51) && ( m < 54)){
08136                 ;
08137    }
08138    else if(m == 144){ /* 2 meters */
08139       if(d < 10100)
08140          return -1;
08141    }
08142    else if((m >= 145) && (m < 148)){
08143       ;
08144    }
08145    else if((m >= 222) && (m < 225)){ /* 1.25 meters */
08146       ;
08147    }
08148    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08149       ;
08150    }
08151    else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
08152       ;
08153    }
08154    else
08155       return -1;
08156    
08157    if(defmode)
08158       *defmode = dflmd; 
08159 
08160 
08161    return 0;
08162 }
08163 
08164 /* Check for valid rtx frequency */
08165 /* Hard coded limits now, configurable later, maybe? */
08166 
08167 static int check_freq_rtx(int m, int d, int *defmode, struct rpt *myrpt)
08168 {
08169    int dflmd = REM_MODE_FM;
08170 
08171    if (!strcmp(myrpt->remoterig,remote_rig_rtx150))
08172    {
08173 
08174       if(m == 144){ /* 2 meters */
08175          if(d < 10100)
08176             return -1;
08177       }
08178       else if((m >= 145) && (m < 148)){
08179          ;
08180       }
08181       else
08182          return -1;
08183    }
08184    else 
08185    {
08186       if((m >= 430) && (m < 450)){ /* 70 centimeters */
08187          ;
08188       }
08189       else
08190          return -1;
08191    }
08192    if(defmode)
08193       *defmode = dflmd; 
08194 
08195 
08196    return 0;
08197 }
08198 
08199 /*
08200  * Convert decimals of frequency to int
08201  */
08202 
08203 static int decimals2int(char *fraction)
08204 {
08205    int i;
08206    char len = strlen(fraction);
08207    int multiplier = 100000;
08208    int res = 0;
08209 
08210    if(!len)
08211       return 0;
08212    for( i = 0 ; i < len ; i++, multiplier /= 10)
08213       res += (fraction[i] - '0') * multiplier;
08214    return res;
08215 }
08216 
08217 
08218 /*
08219 * Split frequency into mhz and decimals
08220 */
08221  
08222 static int split_freq(char *mhz, char *decimals, char *freq)
08223 {
08224    char freq_copy[MAXREMSTR];
08225    char *decp;
08226 
08227    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
08228    if(decp){
08229       *decp++ = 0;
08230       strncpy(mhz, freq_copy, MAXREMSTR);
08231       strcpy(decimals, "00000");
08232       strncpy(decimals, decp, strlen(decp));
08233       decimals[5] = 0;
08234       return 0;
08235    }
08236    else
08237       return -1;
08238 
08239 }
08240    
08241 /*
08242 * Split ctcss frequency into hertz and decimal
08243 */
08244  
08245 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
08246 {
08247    char freq_copy[MAXREMSTR];
08248    char *decp;
08249 
08250    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
08251    if(decp){
08252       *decp++ = 0;
08253       strncpy(hertz, freq_copy, MAXREMSTR);
08254       strncpy(decimal, decp, strlen(decp));
08255       decimal[strlen(decp)] = '\0';
08256       return 0;
08257    }
08258    else
08259       return -1;
08260 }
08261 
08262 
08263 
08264 /*
08265 * FT-897 I/O handlers
08266 */
08267 
08268 /* Check to see that the frequency is valid */
08269 /* Hard coded limits now, configurable later, maybe? */
08270 
08271 
08272 static int check_freq_ft897(int m, int d, int *defmode)
08273 {
08274    int dflmd = REM_MODE_FM;
08275 
08276    if(m == 1){ /* 160 meters */
08277       dflmd =  REM_MODE_LSB; 
08278       if(d < 80000)
08279          return -1;
08280    }
08281    else if(m == 3){ /* 80 meters */
08282       dflmd = REM_MODE_LSB;
08283       if(d < 50000)
08284          return -1;
08285    }
08286    else if(m == 7){ /* 40 meters */
08287       dflmd = REM_MODE_LSB;
08288       if(d > 30000)
08289          return -1;
08290    }
08291    else if(m == 14){ /* 20 meters */
08292       dflmd = REM_MODE_USB;
08293       if(d > 35000)
08294          return -1;
08295    }
08296    else if(m == 18){ /* 17 meters */
08297       dflmd = REM_MODE_USB;
08298       if((d < 6800) || (d > 16800))
08299          return -1;
08300    }
08301    else if(m == 21){ /* 15 meters */
08302       dflmd = REM_MODE_USB;
08303       if((d < 20000) || (d > 45000))
08304          return -1;
08305    }
08306    else if(m == 24){ /* 12 meters */
08307       dflmd = REM_MODE_USB;
08308       if((d < 89000) || (d > 99000))
08309          return -1;
08310    }
08311    else if(m == 28){ /* 10 meters */
08312       dflmd = REM_MODE_USB;
08313    }
08314    else if(m == 29){ 
08315       if(d >= 51000)
08316          dflmd = REM_MODE_FM;
08317       else
08318          dflmd = REM_MODE_USB;
08319       if(d > 70000)
08320          return -1;
08321    }
08322    else if(m == 50){ /* 6 meters */
08323       if(d >= 30000)
08324          dflmd = REM_MODE_FM;
08325       else
08326          dflmd = REM_MODE_USB;
08327 
08328    }
08329    else if((m >= 51) && ( m < 54)){
08330       dflmd = REM_MODE_FM;
08331    }
08332    else if(m == 144){ /* 2 meters */
08333       if(d >= 30000)
08334          dflmd = REM_MODE_FM;
08335       else
08336          dflmd = REM_MODE_USB;
08337    }
08338    else if((m >= 145) && (m < 148)){
08339       dflmd = REM_MODE_FM;
08340    }
08341    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08342       if(m  < 438)
08343          dflmd = REM_MODE_USB;
08344       else
08345          dflmd = REM_MODE_FM;
08346       ;
08347    }
08348    else
08349       return -1;
08350 
08351    if(defmode)
08352       *defmode = dflmd;
08353 
08354    return 0;
08355 }
08356 
08357 /*
08358 * Set a new frequency for the FT897
08359 */
08360 
08361 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
08362 {
08363    unsigned char cmdstr[5];
08364    int fd,m,d;
08365    char mhz[MAXREMSTR];
08366    char decimals[MAXREMSTR];
08367 
08368    fd = 0;
08369    if(debug) 
08370       printf("New frequency: %s\n",newfreq);
08371 
08372    if(split_freq(mhz, decimals, newfreq))
08373       return -1; 
08374 
08375    m = atoi(mhz);
08376    d = atoi(decimals);
08377 
08378    /* The FT-897 likes packed BCD frequencies */
08379 
08380    cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10);        /* 100MHz 10Mhz */
08381    cmdstr[1] = ((m % 10) << 4) + (d / 10000);         /* 1MHz 100KHz */
08382    cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100);  /* 10KHz 1KHz */
08383    cmdstr[3] = (((d % 100)/10) << 4) + (d % 10);         /* 100Hz 10Hz */
08384    cmdstr[4] = 0x01;                /* command */
08385 
08386    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08387 
08388 }
08389 
08390 /* ft-897 simple commands */
08391 
08392 static int simple_command_ft897(struct rpt *myrpt, char command)
08393 {
08394    unsigned char cmdstr[5];
08395    
08396    memset(cmdstr, 0, 5);
08397 
08398    cmdstr[4] = command; 
08399 
08400    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08401 
08402 }
08403 
08404 /* ft-897 offset */
08405 
08406 static int set_offset_ft897(struct rpt *myrpt, char offset)
08407 {
08408    unsigned char cmdstr[5];
08409    
08410    memset(cmdstr, 0, 5);
08411 
08412    switch(offset){
08413       case  REM_SIMPLEX:
08414          cmdstr[0] = 0x89;
08415          break;
08416 
08417       case  REM_MINUS:
08418          cmdstr[0] = 0x09;
08419          break;
08420       
08421       case  REM_PLUS:
08422          cmdstr[0] = 0x49;
08423          break;   
08424 
08425       default:
08426          return -1;
08427    }
08428 
08429    cmdstr[4] = 0x09; 
08430 
08431    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08432 }
08433 
08434 /* ft-897 mode */
08435 
08436 static int set_mode_ft897(struct rpt *myrpt, char newmode)
08437 {
08438    unsigned char cmdstr[5];
08439    
08440    memset(cmdstr, 0, 5);
08441    
08442    switch(newmode){
08443       case  REM_MODE_FM:
08444          cmdstr[0] = 0x08;
08445          break;
08446 
08447       case  REM_MODE_USB:
08448          cmdstr[0] = 0x01;
08449          break;
08450 
08451       case  REM_MODE_LSB:
08452          cmdstr[0] = 0x00;
08453          break;
08454 
08455       case  REM_MODE_AM:
08456          cmdstr[0] = 0x04;
08457          break;
08458       
08459       default:
08460          return -1;
08461    }
08462    cmdstr[4] = 0x07; 
08463 
08464    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08465 }
08466 
08467 /* Set tone encode and decode modes */
08468 
08469 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
08470 {
08471    unsigned char cmdstr[5];
08472    
08473    memset(cmdstr, 0, 5);
08474    
08475    if(rxplon && txplon)
08476       cmdstr[0] = 0x2A; /* Encode and Decode */
08477    else if (!rxplon && txplon)
08478       cmdstr[0] = 0x4A; /* Encode only */
08479    else if (rxplon && !txplon)
08480       cmdstr[0] = 0x3A; /* Encode only */
08481    else
08482       cmdstr[0] = 0x8A; /* OFF */
08483 
08484    cmdstr[4] = 0x0A; 
08485 
08486    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08487 }
08488 
08489 
08490 /* Set transmit and receive ctcss tone frequencies */
08491 
08492 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
08493 {
08494    unsigned char cmdstr[5];
08495    char hertz[MAXREMSTR],decimal[MAXREMSTR];
08496    int h,d; 
08497 
08498    memset(cmdstr, 0, 5);
08499 
08500    if(split_ctcss_freq(hertz, decimal, txtone))
08501       return -1; 
08502 
08503    h = atoi(hertz);
08504    d = atoi(decimal);
08505    
08506    cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
08507    cmdstr[1] = ((h % 10) << 4) + (d % 10);
08508    
08509    if(rxtone){
08510    
08511       if(split_ctcss_freq(hertz, decimal, rxtone))
08512          return -1; 
08513 
08514       h = atoi(hertz);
08515       d = atoi(decimal);
08516    
08517       cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
08518       cmdstr[3] = ((h % 10) << 4) + (d % 10);
08519    }
08520    cmdstr[4] = 0x0B; 
08521 
08522    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08523 }  
08524 
08525 
08526 
08527 static int set_ft897(struct rpt *myrpt)
08528 {
08529    int res;
08530    
08531    if(debug)
08532       printf("@@@@ lock on\n");
08533 
08534    res = simple_command_ft897(myrpt, 0x00);  /* LOCK on */  
08535 
08536    if(debug)
08537       printf("@@@@ ptt off\n");
08538 
08539    if(!res)
08540       res = simple_command_ft897(myrpt, 0x88);     /* PTT off */
08541 
08542    if(debug)
08543       printf("Modulation mode\n");
08544 
08545    if(!res)
08546       res = set_mode_ft897(myrpt, myrpt->remmode);    /* Modulation mode */
08547 
08548    if(debug)
08549       printf("Split off\n");
08550 
08551    if(!res)
08552       simple_command_ft897(myrpt, 0x82);        /* Split off */
08553 
08554    if(debug)
08555       printf("Frequency\n");
08556 
08557    if(!res)
08558       res = set_freq_ft897(myrpt, myrpt->freq);    /* Frequency */
08559    if((myrpt->remmode == REM_MODE_FM)){
08560       if(debug)
08561          printf("Offset\n");
08562       if(!res)
08563          res = set_offset_ft897(myrpt, myrpt->offset);   /* Offset if FM */
08564       if((!res)&&(myrpt->rxplon || myrpt->txplon)){
08565          if(debug)
08566             printf("CTCSS tone freqs.\n");
08567          res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
08568       }
08569       if(!res){
08570          if(debug)
08571             printf("CTCSS mode\n");
08572          res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
08573       }
08574    }
08575    if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
08576       if(debug)
08577          printf("Clarifier off\n");
08578       simple_command_ft897(myrpt, 0x85);        /* Clarifier off if LSB or USB */
08579    }
08580    return res;
08581 }
08582 
08583 static int closerem_ft897(struct rpt *myrpt)
08584 {
08585    simple_command_ft897(myrpt, 0x88); /* PTT off */
08586    return 0;
08587 }  
08588 
08589 /*
08590 * Bump frequency up or down by a small amount 
08591 * Return 0 if the new frequnecy is valid, or -1 if invalid
08592 * Interval is in Hz, resolution is 10Hz 
08593 */
08594 
08595 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
08596 {
08597    int m,d;
08598    char mhz[MAXREMSTR], decimals[MAXREMSTR];
08599 
08600    if(debug)
08601       printf("Before bump: %s\n", myrpt->freq);
08602 
08603    if(split_freq(mhz, decimals, myrpt->freq))
08604       return -1;
08605    
08606    m = atoi(mhz);
08607    d = atoi(decimals);
08608 
08609    d += (interval / 10); /* 10Hz resolution */
08610    if(d < 0){
08611       m--;
08612       d += 100000;
08613    }
08614    else if(d >= 100000){
08615       m++;
08616       d -= 100000;
08617    }
08618 
08619    if(check_freq_ft897(m, d, NULL)){
08620       if(debug)
08621          printf("Bump freq invalid\n");
08622       return -1;
08623    }
08624 
08625    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
08626 
08627    if(debug)
08628       printf("After bump: %s\n", myrpt->freq);
08629 
08630    return set_freq_ft897(myrpt, myrpt->freq);   
08631 }
08632 
08633 
08634 
08635 /*
08636 * IC-706 I/O handlers
08637 */
08638 
08639 /* Check to see that the frequency is valid */
08640 /* returns 0 if frequency is valid          */
08641 
08642 static int check_freq_ic706(int m, int d, int *defmode, char mars)
08643 {
08644    int dflmd = REM_MODE_FM;
08645    int rv=0;
08646 
08647    if(debug > 6)
08648       ast_log(LOG_NOTICE,"(%i,%i,%i,%i)\n",m,d,*defmode,mars);
08649 
08650    /* first test for standard amateur radio bands */
08651 
08652    if(m == 1){                /* 160 meters */
08653       dflmd =  REM_MODE_LSB; 
08654       if(d < 80000)rv=-1;
08655    }
08656    else if(m == 3){           /* 80 meters */
08657       dflmd = REM_MODE_LSB;
08658       if(d < 50000)rv=-1;
08659    }
08660    else if(m == 7){           /* 40 meters */
08661       dflmd = REM_MODE_LSB;
08662       if(d > 30000)rv=-1;
08663    }
08664    else if(m == 14){             /* 20 meters */
08665       dflmd = REM_MODE_USB;
08666       if(d > 35000)rv=-1;
08667    }
08668    else if(m == 18){                      /* 17 meters */
08669       dflmd = REM_MODE_USB;
08670       if((d < 6800) || (d > 16800))rv=-1;
08671    }
08672    else if(m == 21){ /* 15 meters */
08673       dflmd = REM_MODE_USB;
08674       if((d < 20000) || (d > 45000))rv=-1;
08675    }
08676    else if(m == 24){ /* 12 meters */
08677       dflmd = REM_MODE_USB;
08678       if((d < 89000) || (d > 99000))rv=-1;
08679    }
08680    else if(m == 28){                      /* 10 meters */
08681       dflmd = REM_MODE_USB;
08682    }
08683    else if(m == 29){ 
08684       if(d >= 51000)
08685          dflmd = REM_MODE_FM;
08686       else
08687          dflmd = REM_MODE_USB;
08688       if(d > 70000)rv=-1;
08689    }
08690    else if(m == 50){                      /* 6 meters */
08691       if(d >= 30000)
08692          dflmd = REM_MODE_FM;
08693       else
08694          dflmd = REM_MODE_USB;
08695    }
08696    else if((m >= 51) && ( m < 54)){
08697       dflmd = REM_MODE_FM;
08698    }
08699    else if(m == 144){ /* 2 meters */
08700       if(d >= 30000)
08701          dflmd = REM_MODE_FM;
08702       else
08703          dflmd = REM_MODE_USB;
08704    }
08705    else if((m >= 145) && (m < 148)){
08706       dflmd = REM_MODE_FM;
08707    }
08708    else if((m >= 430) && (m < 450)){         /* 70 centimeters */
08709       if(m  < 438)
08710          dflmd = REM_MODE_USB;
08711       else
08712          dflmd = REM_MODE_FM;
08713    }
08714 
08715    /* check expanded coverage */
08716    if(mars && rv<0){
08717       if((m >= 450) && (m < 470)){        /* LMR */
08718          dflmd = REM_MODE_FM;
08719          rv=0;
08720       }
08721       else if((m >= 148) && (m < 174)){      /* LMR */
08722          dflmd = REM_MODE_FM;
08723          rv=0;
08724       }
08725       else if((m >= 138) && (m < 144)){      /* VHF-AM AIRCRAFT */
08726          dflmd = REM_MODE_AM;
08727          rv=0;
08728       }
08729       else if((m >= 108) && (m < 138)){      /* VHF-AM AIRCRAFT */
08730          dflmd = REM_MODE_AM;
08731          rv=0;
08732       }
08733       else if( (m==0 && d>=55000) || (m==1 && d<=75000) ){  /* AM BCB*/
08734          dflmd = REM_MODE_AM;
08735          rv=0;
08736       }
08737       else if( (m == 1 && d>75000) || (m>1 && m<30) ){      /* HF SWL*/
08738          dflmd = REM_MODE_AM;
08739          rv=0;
08740       }
08741    }
08742 
08743    if(defmode)
08744       *defmode = dflmd;
08745 
08746    if(debug > 1)
08747       ast_log(LOG_NOTICE,"(%i,%i,%i,%i) returning %i\n",m,d,*defmode,mars,rv);
08748 
08749    return rv;
08750 }
08751 
08752 /* take a PL frequency and turn it into a code */
08753 static int ic706_pltocode(char *str)
08754 {
08755    int i;
08756    char *s;
08757    int rv=-1;
08758 
08759    s = strchr(str,'.');
08760    i = 0;
08761    if (s) i = atoi(s + 1);
08762    i += atoi(str) * 10;
08763    switch(i)
08764    {
08765        case 670:
08766          rv=0;
08767        case 693:
08768          rv=1;
08769        case 719:
08770          rv=2;
08771        case 744:
08772          rv=3;
08773        case 770:
08774          rv=4;
08775        case 797:
08776          rv=5;
08777        case 825:
08778          rv=6;
08779        case 854:
08780          rv=7;
08781        case 885:
08782          rv=8;
08783        case 915:
08784          rv=9;
08785        case 948:
08786          rv=10;
08787        case 974:
08788          rv=11;
08789        case 1000:
08790          rv=12;
08791        case 1035:
08792          rv=13;
08793        case 1072:
08794          rv=14;
08795        case 1109:
08796          rv=15;
08797        case 1148:
08798          rv=16;
08799        case 1188:
08800          rv=17;
08801        case 1230:
08802          rv=18;
08803        case 1273:
08804          rv=19;
08805        case 1318:
08806          rv=20;
08807        case 1365:
08808          rv=21;
08809        case 1413:
08810          rv=22;
08811        case 1462:
08812          rv=23;
08813        case 1514:
08814          rv=24;
08815        case 1567:
08816          rv=25;
08817        case 1598:
08818          rv=26;
08819        case 1622:
08820          rv=27;
08821        case 1655:
08822          rv=28;      
08823        case 1679:
08824          rv=29;
08825        case 1713:
08826          rv=30;
08827        case 1738:
08828          rv=31;
08829        case 1773:
08830          rv=32;
08831        case 1799:
08832          rv=33;
08833         case 1835:
08834          rv=34;
08835        case 1862:
08836          rv=35;
08837        case 1899:
08838          rv=36;
08839        case 1928:
08840          rv=37;
08841        case 1966:
08842          rv=38;
08843        case 1995:
08844          rv=39;
08845        case 2035:
08846          rv=40;
08847        case 2065:
08848          rv=41;
08849        case 2107:
08850          rv=42;
08851        case 2181:
08852          rv=43;
08853        case 2257:
08854          rv=44;
08855        case 2291:
08856          rv=45;
08857        case 2336:
08858          rv=46;
08859        case 2418:
08860          rv=47;
08861        case 2503:
08862          rv=48;
08863        case 2541:
08864          rv=49;
08865    }
08866    if(debug > 1)
08867       ast_log(LOG_NOTICE,"%i  rv=%i\n",i, rv);
08868 
08869    return rv;
08870 }
08871 
08872 /* ic-706 simple commands */
08873 
08874 static int simple_command_ic706(struct rpt *myrpt, char command, char subcommand)
08875 {
08876    unsigned char cmdstr[10];
08877    
08878    cmdstr[0] = cmdstr[1] = 0xfe;
08879    cmdstr[2] = myrpt->p.civaddr;
08880    cmdstr[3] = 0xe0;
08881    cmdstr[4] = command;
08882    cmdstr[5] = subcommand;
08883    cmdstr[6] = 0xfd;
08884 
08885    return(civ_cmd(myrpt,cmdstr,7));
08886 }
08887 
08888 /*
08889 * Set a new frequency for the ic706
08890 */
08891 
08892 static int set_freq_ic706(struct rpt *myrpt, char *newfreq)
08893 {
08894    unsigned char cmdstr[20];
08895    char mhz[MAXREMSTR], decimals[MAXREMSTR];
08896    int fd,m,d;
08897 
08898    fd = 0;
08899    if(debug) 
08900       ast_log(LOG_NOTICE,"newfreq:%s\n",newfreq);        
08901 
08902    if(split_freq(mhz, decimals, newfreq))
08903       return -1; 
08904 
08905    m = atoi(mhz);
08906    d = atoi(decimals);
08907 
08908    /* The ic-706 likes packed BCD frequencies */
08909 
08910    cmdstr[0] = cmdstr[1] = 0xfe;
08911    cmdstr[2] = myrpt->p.civaddr;
08912    cmdstr[3] = 0xe0;
08913    cmdstr[4] = 5;
08914    cmdstr[5] = ((d % 10) << 4);
08915    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
08916    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
08917    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
08918    cmdstr[9] = (m / 100);
08919    cmdstr[10] = 0xfd;
08920 
08921    return(civ_cmd(myrpt,cmdstr,11));
08922 }
08923 
08924 /* ic-706 offset */
08925 
08926 static int set_offset_ic706(struct rpt *myrpt, char offset)
08927 {
08928    unsigned char c;
08929 
08930    if(debug > 6)
08931       ast_log(LOG_NOTICE,"offset=%i\n",offset);
08932 
08933    switch(offset){
08934       case  REM_SIMPLEX:
08935          c = 0x10;
08936          break;
08937 
08938       case  REM_MINUS:
08939          c = 0x11;
08940          break;
08941       
08942       case  REM_PLUS:
08943          c = 0x12;
08944          break;   
08945 
08946       default:
08947          return -1;
08948    }
08949 
08950    return simple_command_ic706(myrpt,0x0f,c);
08951 
08952 }
08953 
08954 /* ic-706 mode */
08955 
08956 static int set_mode_ic706(struct rpt *myrpt, char newmode)
08957 {
08958    unsigned char c;
08959    
08960    if(debug > 6)
08961       ast_log(LOG_NOTICE,"newmode=%i\n",newmode);
08962 
08963    switch(newmode){
08964       case  REM_MODE_FM:
08965          c = 5;
08966          break;
08967 
08968       case  REM_MODE_USB:
08969          c = 1;
08970          break;
08971 
08972       case  REM_MODE_LSB:
08973          c = 0;
08974          break;
08975 
08976       case  REM_MODE_AM:
08977          c = 2;
08978          break;
08979       
08980       default:
08981          return -1;
08982    }
08983    return simple_command_ic706(myrpt,6,c);
08984 }
08985 
08986 /* Set tone encode and decode modes */
08987 
08988 static int set_ctcss_mode_ic706(struct rpt *myrpt, char txplon, char rxplon)
08989 {
08990    unsigned char cmdstr[10];
08991    int rv;
08992 
08993    if(debug > 6)
08994       ast_log(LOG_NOTICE,"txplon=%i  rxplon=%i \n",txplon,rxplon);
08995 
08996    cmdstr[0] = cmdstr[1] = 0xfe;
08997    cmdstr[2] = myrpt->p.civaddr;
08998    cmdstr[3] = 0xe0;
08999    cmdstr[4] = 0x16;
09000    cmdstr[5] = 0x42;
09001    cmdstr[6] = (txplon != 0);
09002    cmdstr[7] = 0xfd;
09003 
09004    rv = civ_cmd(myrpt,cmdstr,8);
09005    if (rv) return(-1);
09006 
09007    cmdstr[0] = cmdstr[1] = 0xfe;
09008    cmdstr[2] = myrpt->p.civaddr;
09009    cmdstr[3] = 0xe0;
09010    cmdstr[4] = 0x16;
09011    cmdstr[5] = 0x43;
09012    cmdstr[6] = (rxplon != 0);
09013    cmdstr[7] = 0xfd;
09014 
09015    return(civ_cmd(myrpt,cmdstr,8));
09016 }
09017 
09018 #if 0
09019 /* Set transmit and receive ctcss tone frequencies */
09020 
09021 static int set_ctcss_freq_ic706(struct rpt *myrpt, char *txtone, char *rxtone)
09022 {
09023    unsigned char cmdstr[10];
09024    char hertz[MAXREMSTR],decimal[MAXREMSTR];
09025    int h,d,rv;
09026 
09027    memset(cmdstr, 0, 5);
09028 
09029    if(debug > 6)
09030       ast_log(LOG_NOTICE,"txtone=%s  rxtone=%s \n",txtone,rxtone);
09031 
09032    if(split_ctcss_freq(hertz, decimal, txtone))
09033       return -1; 
09034 
09035    h = atoi(hertz);
09036    d = atoi(decimal);
09037    
09038    cmdstr[0] = cmdstr[1] = 0xfe;
09039    cmdstr[2] = myrpt->p.civaddr;
09040    cmdstr[3] = 0xe0;
09041    cmdstr[4] = 0x1b;
09042    cmdstr[5] = 0;
09043    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
09044    cmdstr[7] = ((h % 10) << 4) + (d % 10);
09045    cmdstr[8] = 0xfd;
09046 
09047    rv = civ_cmd(myrpt,cmdstr,9);
09048    if (rv) return(-1);
09049 
09050    if (!rxtone) return(0);
09051 
09052    if(split_ctcss_freq(hertz, decimal, rxtone))
09053       return -1; 
09054 
09055    h = atoi(hertz);
09056    d = atoi(decimal);
09057 
09058    cmdstr[0] = cmdstr[1] = 0xfe;
09059    cmdstr[2] = myrpt->p.civaddr;
09060    cmdstr[3] = 0xe0;
09061    cmdstr[4] = 0x1b;
09062    cmdstr[5] = 1;
09063    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
09064    cmdstr[7] = ((h % 10) << 4) + (d % 10);
09065    cmdstr[8] = 0xfd;
09066    return(civ_cmd(myrpt,cmdstr,9));
09067 }  
09068 #endif
09069 
09070 static int vfo_ic706(struct rpt *myrpt)
09071 {
09072    unsigned char cmdstr[10];
09073    
09074    cmdstr[0] = cmdstr[1] = 0xfe;
09075    cmdstr[2] = myrpt->p.civaddr;
09076    cmdstr[3] = 0xe0;
09077    cmdstr[4] = 7;
09078    cmdstr[5] = 0xfd;
09079 
09080    return(civ_cmd(myrpt,cmdstr,6));
09081 }
09082 
09083 static int mem2vfo_ic706(struct rpt *myrpt)
09084 {
09085    unsigned char cmdstr[10];
09086    
09087    cmdstr[0] = cmdstr[1] = 0xfe;
09088    cmdstr[2] = myrpt->p.civaddr;
09089    cmdstr[3] = 0xe0;
09090    cmdstr[4] = 0x0a;
09091    cmdstr[5] = 0xfd;
09092 
09093    return(civ_cmd(myrpt,cmdstr,6));
09094 }
09095 
09096 static int select_mem_ic706(struct rpt *myrpt, int slot)
09097 {
09098    unsigned char cmdstr[10];
09099    
09100    cmdstr[0] = cmdstr[1] = 0xfe;
09101    cmdstr[2] = myrpt->p.civaddr;
09102    cmdstr[3] = 0xe0;
09103    cmdstr[4] = 8;
09104    cmdstr[5] = 0;
09105    cmdstr[6] = ((slot / 10) << 4) + (slot % 10);
09106    cmdstr[7] = 0xfd;
09107 
09108    return(civ_cmd(myrpt,cmdstr,8));
09109 }
09110 
09111 static int set_ic706(struct rpt *myrpt)
09112 {
09113    int res = 0,i;
09114    
09115    if(debug)ast_log(LOG_NOTICE, "Set to VFO A iobase=%i\n",myrpt->p.iobase);
09116 
09117    if (!res)
09118       res = simple_command_ic706(myrpt,7,0);
09119 
09120    if((myrpt->remmode == REM_MODE_FM))
09121    {
09122       i = ic706_pltocode(myrpt->rxpl);
09123       if (i == -1) return -1;
09124       if(debug)
09125          printf("Select memory number\n");
09126       if (!res)
09127          res = select_mem_ic706(myrpt,i + IC706_PL_MEMORY_OFFSET);
09128       if(debug)
09129          printf("Transfer memory to VFO\n");
09130       if (!res)
09131          res = mem2vfo_ic706(myrpt);
09132    }
09133       
09134    if(debug)
09135       printf("Set to VFO\n");
09136 
09137    if (!res)
09138       res = vfo_ic706(myrpt);
09139 
09140    if(debug)
09141       printf("Modulation mode\n");
09142 
09143    if (!res)
09144       res = set_mode_ic706(myrpt, myrpt->remmode);    /* Modulation mode */
09145 
09146    if(debug)
09147       printf("Split off\n");
09148 
09149    if(!res)
09150       simple_command_ic706(myrpt, 0x82,0);         /* Split off */
09151 
09152    if(debug)
09153       printf("Frequency\n");
09154 
09155    if(!res)
09156       res = set_freq_ic706(myrpt, myrpt->freq);    /* Frequency */
09157    if((myrpt->remmode == REM_MODE_FM)){
09158       if(debug)
09159          printf("Offset\n");
09160       if(!res)
09161          res = set_offset_ic706(myrpt, myrpt->offset);   /* Offset if FM */
09162       if(!res){
09163          if(debug)
09164             printf("CTCSS mode\n");
09165          res = set_ctcss_mode_ic706(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
09166       }
09167    }
09168    return res;
09169 }
09170 
09171 /*
09172 * Bump frequency up or down by a small amount 
09173 * Return 0 if the new frequnecy is valid, or -1 if invalid
09174 * Interval is in Hz, resolution is 10Hz 
09175 */
09176 
09177 static int multimode_bump_freq_ic706(struct rpt *myrpt, int interval)
09178 {
09179    int m,d;
09180    char mhz[MAXREMSTR], decimals[MAXREMSTR];
09181    unsigned char cmdstr[20];
09182 
09183    if(debug)
09184       printf("Before bump: %s\n", myrpt->freq);
09185 
09186    if(split_freq(mhz, decimals, myrpt->freq))
09187       return -1;
09188    
09189    m = atoi(mhz);
09190    d = atoi(decimals);
09191 
09192    d += (interval / 10); /* 10Hz resolution */
09193    if(d < 0){
09194       m--;
09195       d += 100000;
09196    }
09197    else if(d >= 100000){
09198       m++;
09199       d -= 100000;
09200    }
09201 
09202    if(check_freq_ic706(m, d, NULL,myrpt->p.remote_mars)){
09203       if(debug)
09204          printf("Bump freq invalid\n");
09205       return -1;
09206    }
09207 
09208    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
09209 
09210    if(debug)
09211       printf("After bump: %s\n", myrpt->freq);
09212 
09213    /* The ic-706 likes packed BCD frequencies */
09214 
09215    cmdstr[0] = cmdstr[1] = 0xfe;
09216    cmdstr[2] = myrpt->p.civaddr;
09217    cmdstr[3] = 0xe0;
09218    cmdstr[4] = 0;
09219    cmdstr[5] = ((d % 10) << 4);
09220    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
09221    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
09222    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
09223    cmdstr[9] = (m / 100);
09224    cmdstr[10] = 0xfd;
09225 
09226    return(serial_remote_io(myrpt,cmdstr,11,NULL,0,0));
09227 }
09228 
09229 
09230 
09231 /*
09232 * Dispatch to correct I/O handler 
09233 */
09234 static int setrem(struct rpt *myrpt)
09235 {
09236 char  str[300];
09237 char  *offsets[] = {"SIMPLEX","MINUS","PLUS"};
09238 char  *powerlevels[] = {"LOW","MEDIUM","HIGH"};
09239 char  *modes[] = {"FM","USB","LSB","AM"};
09240 int   res = -1;
09241 
09242 #if   0
09243 printf("FREQ,%s,%s,%s,%s,%s,%s,%d,%d\n",myrpt->freq,
09244    modes[(int)myrpt->remmode],
09245    myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
09246    powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
09247    myrpt->rxplon);
09248 #endif
09249    if (myrpt->p.archivedir)
09250    {
09251       sprintf(str,"FREQ,%s,%s,%s,%s,%s,%s,%d,%d",myrpt->freq,
09252          modes[(int)myrpt->remmode],
09253          myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
09254          powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
09255          myrpt->rxplon);
09256       donodelog(myrpt,str);
09257    }
09258    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09259    {
09260       rpt_telemetry(myrpt,SETREMOTE,NULL);
09261       res = 0;
09262    }
09263    if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09264    {
09265       rpt_telemetry(myrpt,SETREMOTE,NULL);
09266       res = 0;
09267    }
09268    if(!strcmp(myrpt->remoterig, remote_rig_tm271))
09269    {
09270       rpt_telemetry(myrpt,SETREMOTE,NULL);
09271       res = 0;
09272    }
09273    else if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09274    {
09275       res = setrbi_check(myrpt);
09276       if (!res)
09277       {
09278          rpt_telemetry(myrpt,SETREMOTE,NULL);
09279          res = 0;
09280       }
09281    }
09282    else if(ISRIG_RTX(myrpt->remoterig))
09283    {
09284       setrtx(myrpt);
09285       res = 0;
09286    }
09287    else if(!strcmp(myrpt->remoterig, remote_rig_kenwood)) {
09288       rpt_telemetry(myrpt,SETREMOTE,NULL);
09289       res = 0;
09290    }
09291    else
09292       res = 0;
09293 
09294    if (res < 0) ast_log(LOG_ERROR,"Unable to send remote command on node %s\n",myrpt->name);
09295 
09296    return res;
09297 }
09298 
09299 static int closerem(struct rpt *myrpt)
09300 {
09301    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09302       return closerem_ft897(myrpt);
09303    else
09304       return 0;
09305 }
09306 
09307 /*
09308 * Dispatch to correct RX frequency checker
09309 */
09310 
09311 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
09312 {
09313    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09314       return check_freq_ft897(m, d, defmode);
09315    else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09316       return check_freq_ic706(m, d, defmode,myrpt->p.remote_mars);
09317    else if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09318       return check_freq_rbi(m, d, defmode);
09319    else if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
09320       return check_freq_kenwood(m, d, defmode);
09321    else if(!strcmp(myrpt->remoterig, remote_rig_tm271))
09322       return check_freq_tm271(m, d, defmode);
09323    else if(ISRIG_RTX(myrpt->remoterig))
09324       return check_freq_rtx(m, d, defmode, myrpt);
09325    else
09326       return -1;
09327 }
09328 
09329 /*
09330  * Check TX frequency before transmitting
09331    rv=1 if tx frequency in ok.
09332 */
09333 
09334 static char check_tx_freq(struct rpt *myrpt)
09335 {
09336    int i,rv=0;
09337    int radio_mhz, radio_decimals, ulimit_mhz, ulimit_decimals, llimit_mhz, llimit_decimals;
09338    char radio_mhz_char[MAXREMSTR];
09339    char radio_decimals_char[MAXREMSTR];
09340    char limit_mhz_char[MAXREMSTR];
09341    char limit_decimals_char[MAXREMSTR];
09342    char limits[256];
09343    char *limit_ranges[40];
09344    struct ast_variable *limitlist;
09345    
09346    if(debug > 3){
09347       ast_log(LOG_NOTICE, "myrpt->freq = %s\n", myrpt->freq);
09348    }
09349 
09350    /* Must have user logged in and tx_limits defined */
09351 
09352    if(!myrpt->p.txlimitsstanzaname || !myrpt->loginuser[0] || !myrpt->loginlevel[0]){
09353       if(debug > 3){
09354          ast_log(LOG_NOTICE, "No tx band table defined, or no user logged in. rv=1\n");
09355       }
09356       rv=1;
09357       return 1; /* Assume it's ok otherwise */
09358    }
09359 
09360    /* Retrieve the band table for the loginlevel */
09361    limitlist = ast_variable_browse(myrpt->cfg, myrpt->p.txlimitsstanzaname);
09362 
09363    if(!limitlist){
09364       ast_log(LOG_WARNING, "No entries in %s band table stanza. rv=0\n", myrpt->p.txlimitsstanzaname);
09365       rv=0;
09366       return 0;
09367    }
09368 
09369    split_freq(radio_mhz_char, radio_decimals_char, myrpt->freq);
09370    radio_mhz = atoi(radio_mhz_char);
09371    radio_decimals = decimals2int(radio_decimals_char);
09372 
09373    if(debug > 3){
09374       ast_log(LOG_NOTICE, "Login User = %s, login level = %s\n", myrpt->loginuser, myrpt->loginlevel);
09375    }
09376 
09377    /* Find our entry */
09378 
09379    for(;limitlist; limitlist=limitlist->next){
09380       if(!strcmp(limitlist->name, myrpt->loginlevel))
09381          break;
09382    }
09383 
09384    if(!limitlist){
09385       ast_log(LOG_WARNING, "Can't find %s entry in band table stanza %s. rv=0\n", myrpt->loginlevel, myrpt->p.txlimitsstanzaname);
09386       rv=0;
09387        return 0;
09388    }
09389    
09390    if(debug > 3){
09391       ast_log(LOG_NOTICE, "Auth: %s = %s\n", limitlist->name, limitlist->value);
09392    }
09393 
09394    /* Parse the limits */
09395 
09396    strncpy(limits, limitlist->value, 256);
09397    limits[255] = 0;
09398    finddelim(limits, limit_ranges, 40);
09399    for(i = 0; i < 40 && limit_ranges[i] ; i++){
09400       char range[40];
09401       char *r,*s;
09402       strncpy(range, limit_ranges[i], 40);
09403       range[39] = 0;
09404         if(debug > 3) 
09405          ast_log(LOG_NOTICE, "Check %s within %s\n", myrpt->freq, range);
09406    
09407       r = strchr(range, '-');
09408       if(!r){
09409          ast_log(LOG_WARNING, "Malformed range in %s tx band table entry. rv=0\n", limitlist->name);
09410          rv=0;
09411          break;
09412       }
09413       *r++ = 0;
09414       s = eatwhite(range);
09415       r = eatwhite(r);
09416       split_freq(limit_mhz_char, limit_decimals_char, s);
09417       llimit_mhz = atoi(limit_mhz_char);
09418       llimit_decimals = decimals2int(limit_decimals_char);
09419       split_freq(limit_mhz_char, limit_decimals_char, r);
09420       ulimit_mhz = atoi(limit_mhz_char);
09421       ulimit_decimals = decimals2int(limit_decimals_char);
09422          
09423       if((radio_mhz >= llimit_mhz) && (radio_mhz <= ulimit_mhz)){
09424          if(radio_mhz == llimit_mhz){ /* CASE 1: TX freq is in llimit mhz portion of band */
09425             if(radio_decimals >= llimit_decimals){ /* Cannot be below llimit decimals */
09426                if(llimit_mhz == ulimit_mhz){ /* If bandwidth < 1Mhz, check ulimit decimals */
09427                   if(radio_decimals <= ulimit_decimals){
09428                      rv=1;
09429                      break;
09430                   }
09431                   else{
09432                      if(debug > 3)
09433                         ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 1\n");
09434                      rv=0;
09435                      break;
09436                   }
09437                }
09438                else{
09439                   rv=1;
09440                   break;
09441                }
09442             }
09443             else{ /* Is below llimit decimals */
09444                if(debug > 3)
09445                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 2\n");
09446                rv=0;
09447                break;
09448             }
09449          }
09450          else if(radio_mhz == ulimit_mhz){ /* CASE 2: TX freq not in llimit mhz portion of band */
09451             if(radio_decimals <= ulimit_decimals){
09452                if(debug > 3)
09453                   ast_log(LOG_NOTICE, "radio_decimals <= ulimit_decimals\n");
09454                rv=1;
09455                break;
09456             }
09457             else{ /* Is above ulimit decimals */
09458                if(debug > 3)
09459                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 3\n");
09460                rv=0;
09461                break;
09462             }
09463          }
09464          else /* CASE 3: TX freq within a multi-Mhz band and ok */
09465             if(debug > 3)
09466                   ast_log(LOG_NOTICE, "Valid TX freq within a multi-Mhz band and ok.\n");
09467             rv=1;
09468             break;
09469       }
09470    }
09471    if(debug > 3)  
09472       ast_log(LOG_NOTICE, "rv=%i\n",rv);
09473 
09474    return rv;
09475 }
09476 
09477 
09478 /*
09479 * Dispatch to correct frequency bumping function
09480 */
09481 
09482 static int multimode_bump_freq(struct rpt *myrpt, int interval)
09483 {
09484    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09485       return multimode_bump_freq_ft897(myrpt, interval);
09486    else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09487       return multimode_bump_freq_ic706(myrpt, interval);
09488    else
09489       return -1;
09490 }
09491 
09492 
09493 /*
09494 * Queue announcment that scan has been stopped 
09495 */
09496 
09497 static void stop_scan(struct rpt *myrpt)
09498 {
09499    myrpt->hfscanstop = 1;
09500    rpt_telemetry(myrpt,SCAN,0);
09501 }
09502 
09503 /*
09504 * This is called periodically when in scan mode
09505 */
09506 
09507 
09508 static int service_scan(struct rpt *myrpt)
09509 {
09510    int res, interval;
09511    char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
09512 
09513    switch(myrpt->hfscanmode){
09514 
09515       case HF_SCAN_DOWN_SLOW:
09516          interval = -10; /* 100Hz /sec */
09517          break;
09518 
09519       case HF_SCAN_DOWN_QUICK:
09520          interval = -50; /* 500Hz /sec */
09521          break;
09522 
09523       case HF_SCAN_DOWN_FAST:
09524          interval = -200; /* 2KHz /sec */
09525          break;
09526 
09527       case HF_SCAN_UP_SLOW:
09528          interval = 10; /* 100Hz /sec */
09529          break;
09530 
09531       case HF_SCAN_UP_QUICK:
09532          interval = 50; /* 500 Hz/sec */
09533          break;
09534 
09535       case HF_SCAN_UP_FAST:
09536          interval = 200; /* 2KHz /sec */
09537          break;
09538 
09539       default:
09540          myrpt->hfscanmode = 0; /* Huh? */
09541          return -1;
09542    }
09543 
09544    res = split_freq(mhz, decimals, myrpt->freq);
09545       
09546    if(!res){
09547       k100 =decimals[0];
09548       k10 = decimals[1];
09549       res = multimode_bump_freq(myrpt, interval);
09550    }
09551 
09552    if(!res)
09553       res = split_freq(mhz, decimals, myrpt->freq);
09554 
09555 
09556    if(res){
09557       myrpt->hfscanmode = 0;
09558       myrpt->hfscanstatus = -2;
09559       return -1;
09560    }
09561 
09562    /* Announce 10KHz boundaries */
09563    if(k10 != decimals[1]){
09564       int myhund = (interval < 0) ? k100 : decimals[0];
09565       int myten = (interval < 0) ? k10 : decimals[1];
09566       myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
09567    } else myrpt->hfscanstatus = 0;
09568    return res;
09569 
09570 }
09571 /*
09572    retrieve memory setting and set radio
09573 */
09574 static int get_mem_set(struct rpt *myrpt, char *digitbuf)
09575 {
09576    int res=0;
09577    if(debug)ast_log(LOG_NOTICE," digitbuf=%s\n", digitbuf);
09578    res = retreive_memory(myrpt, digitbuf);
09579    if(!res)res=setrem(myrpt); 
09580    if(debug)ast_log(LOG_NOTICE," freq=%s  res=%i\n", myrpt->freq, res);
09581    return res;
09582 }
09583 /*
09584    steer the radio selected channel to either one programmed into the radio
09585    or if the radio is VFO agile, to an rpt.conf memory location.
09586 */
09587 static int channel_steer(struct rpt *myrpt, char *data)
09588 {
09589    int res=0;
09590 
09591    if(debug)ast_log(LOG_NOTICE,"remoterig=%s, data=%s\n",myrpt->remoterig,data);
09592    if (!myrpt->remoterig) return(0);
09593    if(data<=0)
09594    {
09595       res=-1;
09596    }
09597    else
09598    {
09599       myrpt->nowchan=strtod(data,NULL);
09600       if(!strcmp(myrpt->remoterig, remote_rig_ppp16))
09601       {
09602          char string[16];
09603          sprintf(string,"SETCHAN %d ",myrpt->nowchan);
09604          send_usb_txt(myrpt,string);   
09605       }
09606       else
09607       {
09608          if(get_mem_set(myrpt, data))res=-1;
09609       }
09610    }
09611    if(debug)ast_log(LOG_NOTICE,"nowchan=%i  res=%i\n",myrpt->nowchan, res);
09612    return res;
09613 }
09614 /*
09615 */
09616 static int channel_revert(struct rpt *myrpt)
09617 {
09618    int res=0;
09619    if(debug)ast_log(LOG_NOTICE,"remoterig=%s, nowchan=%02d, waschan=%02d\n",myrpt->remoterig,myrpt->nowchan,myrpt->waschan);
09620    if (!myrpt->remoterig) return(0);
09621    if(myrpt->nowchan!=myrpt->waschan)
09622    {
09623       char data[8];
09624         if(debug)ast_log(LOG_NOTICE,"reverting.\n");
09625       sprintf(data,"%02d",myrpt->waschan);
09626       myrpt->nowchan=myrpt->waschan;
09627       channel_steer(myrpt,data);
09628       res=1;
09629    }
09630    return(res);
09631 }
09632 /*
09633 * Remote base function
09634 */
09635 
09636 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
09637 {
09638    char *s,*s1,*s2;
09639    int i,j,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode=0;
09640    intptr_t p;
09641    char multimode = 0;
09642    char oc,*cp,*cp1,*cp2;
09643    char tmp[20], freq[20] = "", savestr[20] = "";
09644    char mhz[MAXREMSTR], decimals[MAXREMSTR];
09645 
09646     if(debug > 6) {
09647       ast_log(LOG_NOTICE,"%s param=%s digitbuf=%s source=%i\n",myrpt->name,param,digitbuf,command_source);
09648    }
09649 
09650    if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
09651       return DC_ERROR;
09652       
09653    p = myatoi(param);
09654 
09655    if ((p != 99) && (p != 5) && (p != 140) && myrpt->p.authlevel && 
09656       (!myrpt->loginlevel[0])) return DC_ERROR;
09657    multimode = multimode_capable(myrpt);
09658 
09659    switch(p){
09660 
09661       case 1:  /* retrieve memory */
09662          if(strlen(digitbuf) < 2) /* needs 2 digits */
09663             break;
09664          
09665          for(i = 0 ; i < 2 ; i++){
09666             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09667                return DC_ERROR;
09668          }
09669          r=get_mem_set(myrpt, digitbuf);
09670          if (r < 0){
09671             rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
09672             return DC_COMPLETE;
09673          }
09674          else if (r > 0){
09675             return DC_ERROR;
09676          }
09677          return DC_COMPLETE;  
09678          
09679       case 2:  /* set freq and offset */
09680       
09681          
09682             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
09683             if(digitbuf[i] == '*'){
09684                j++;
09685                continue;
09686             }
09687             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09688                goto invalid_freq;
09689             else{
09690                if(j == 0)
09691                   l++; /* # of digits before first * */
09692                if(j == 1)
09693                   k++; /* # of digits after first * */
09694             }
09695          }
09696       
09697          i = strlen(digitbuf) - 1;
09698          if(multimode){
09699             if((j > 2) || (l > 3) || (k > 6))
09700                goto invalid_freq; /* &^@#! */
09701          }
09702          else{
09703             if((j > 2) || (l > 4) || (k > 3))
09704                goto invalid_freq; /* &^@#! */
09705          }
09706 
09707          /* Wait for M+*K+* */
09708 
09709          if(j < 2)
09710             break; /* Not yet */
09711 
09712          /* We have a frequency */
09713 
09714          strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
09715          
09716          s = tmp;
09717          s1 = strsep(&s, "*"); /* Pick off MHz */
09718          s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
09719          ls2 = strlen(s2); 
09720          
09721          switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
09722             case 1:
09723                ht = 0;
09724                k = 100 * atoi(s2);
09725                break;
09726             
09727             case 2:
09728                ht = 0;
09729                k = 10 * atoi(s2);
09730                break;
09731                
09732             case 3:
09733                if(!multimode){
09734                   if((s2[2] != '0')&&(s2[2] != '5'))
09735                      goto invalid_freq;
09736                }
09737                ht = 0;
09738                k = atoi(s2);
09739                   break;
09740             case 4:
09741                k = atoi(s2)/10;
09742                ht = 10 * (atoi(s2+(ls2-1)));
09743                break;
09744 
09745             case 5:
09746                k = atoi(s2)/100;
09747                ht = (atoi(s2+(ls2-2)));
09748                break;
09749                
09750             default:
09751                goto invalid_freq;
09752          }
09753 
09754          /* Check frequency for validity and establish a default mode */
09755          
09756          snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
09757 
09758          if(debug)
09759             ast_log(LOG_NOTICE, "New frequency: %s\n", freq);
09760    
09761          split_freq(mhz, decimals, freq);
09762          m = atoi(mhz);
09763          d = atoi(decimals);
09764 
09765          if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
09766                  goto invalid_freq;
09767 
09768 
09769          if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
09770             break; /* Not yet */
09771 
09772 
09773          offset = REM_SIMPLEX; /* Assume simplex */
09774 
09775          if(defmode == REM_MODE_FM){
09776             oc = *s; /* Pick off offset */
09777          
09778             if (oc){
09779                switch(oc){
09780                   case '1':
09781                      offset = REM_MINUS;
09782                      break;
09783                   
09784                   case '2':
09785                      offset = REM_SIMPLEX;
09786                   break;
09787                   
09788                   case '3':
09789                      offset = REM_PLUS;
09790                      break;
09791                   
09792                   default:
09793                      goto invalid_freq;
09794                } 
09795             } 
09796          }  
09797          offsave = myrpt->offset;
09798          modesave = myrpt->remmode;
09799          strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
09800          strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
09801          myrpt->offset = offset;
09802          myrpt->remmode = defmode;
09803 
09804          if (setrem(myrpt) == -1){
09805             myrpt->offset = offsave;
09806             myrpt->remmode = modesave;
09807             strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
09808             goto invalid_freq;
09809          }
09810 
09811          return DC_COMPLETE;
09812 
09813 invalid_freq:
09814          rpt_telemetry(myrpt,INVFREQ,NULL);
09815          return DC_ERROR; 
09816       
09817       case 3: /* set rx PL tone */
09818             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
09819             if(digitbuf[i] == '*'){
09820                j++;
09821                continue;
09822             }
09823             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09824                return DC_ERROR;
09825             else{
09826                if(j)
09827                   l++;
09828                else
09829                   k++;
09830             }
09831          }
09832          if((j > 1) || (k > 3) || (l > 1))
09833             return DC_ERROR; /* &$@^! */
09834          i = strlen(digitbuf) - 1;
09835          if((j != 1) || (k < 2)|| (l != 1))
09836             break; /* Not yet */
09837          if(debug)
09838             printf("PL digits entered %s\n", digitbuf);
09839             
09840          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
09841          /* see if we have at least 1 */
09842          s = strchr(tmp,'*');
09843          if(s)
09844             *s = '.';
09845          strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
09846          strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
09847          if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09848          {
09849             strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
09850          }
09851          if (setrem(myrpt) == -1){
09852             strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
09853             return DC_ERROR;
09854          }
09855          return DC_COMPLETE;
09856       
09857       case 4: /* set tx PL tone */
09858          /* cant set tx tone on RBI (rx tone does both) */
09859          if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09860             return DC_ERROR;
09861          /*  eventually for the ic706 instead of just throwing the exception
09862             we can check if we are in encode only mode and allow the tx
09863             ctcss code to be changed. but at least the warning message is
09864             issued for now.
09865          */
09866          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09867          {
09868             if(debug)
09869                ast_log(LOG_WARNING,"Setting IC706 Tx CTCSS Code Not Supported. Set Rx Code for both.\n");
09870             return DC_ERROR;
09871          }
09872          for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
09873             if(digitbuf[i] == '*'){
09874                j++;
09875                continue;
09876             }
09877             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09878                return DC_ERROR;
09879             else{
09880                if(j)
09881                   l++;
09882                else
09883                   k++;
09884             }
09885          }
09886          if((j > 1) || (k > 3) || (l > 1))
09887             return DC_ERROR; /* &$@^! */
09888          i = strlen(digitbuf) - 1;
09889          if((j != 1) || (k < 2)|| (l != 1))
09890             break; /* Not yet */
09891          if(debug)
09892             printf("PL digits entered %s\n", digitbuf);
09893             
09894          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
09895          /* see if we have at least 1 */
09896          s = strchr(tmp,'*');
09897          if(s)
09898             *s = '.';
09899          strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1);
09900          strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
09901          
09902          if (setrem(myrpt) == -1){
09903             strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
09904             return DC_ERROR;
09905          }
09906          return DC_COMPLETE;
09907       
09908 
09909       case 6: /* MODE (FM,USB,LSB,AM) */
09910          if(strlen(digitbuf) < 1)
09911             break;
09912 
09913          if(!multimode)
09914             return DC_ERROR; /* Multimode radios only */
09915 
09916          switch(*digitbuf){
09917             case '1':
09918                split_freq(mhz, decimals, myrpt->freq); 
09919                m=atoi(mhz);
09920                if(m < 29) /* No FM allowed below 29MHz! */
09921                   return DC_ERROR;
09922                myrpt->remmode = REM_MODE_FM;
09923                
09924                rpt_telemetry(myrpt,REMMODE,NULL);
09925                break;
09926 
09927             case '2':
09928                myrpt->remmode = REM_MODE_USB;
09929                rpt_telemetry(myrpt,REMMODE,NULL);
09930                break;   
09931 
09932             case '3':
09933                myrpt->remmode = REM_MODE_LSB;
09934                rpt_telemetry(myrpt,REMMODE,NULL);
09935                break;
09936             
09937             case '4':
09938                myrpt->remmode = REM_MODE_AM;
09939                rpt_telemetry(myrpt,REMMODE,NULL);
09940                break;
09941       
09942             default:
09943                return DC_ERROR;
09944          }
09945 
09946          if(setrem(myrpt))
09947             return DC_ERROR;
09948          return DC_COMPLETEQUIET;
09949       case 99:
09950          /* cant log in when logged in */
09951          if (myrpt->loginlevel[0]) 
09952             return DC_ERROR;
09953          *myrpt->loginuser = 0;
09954          myrpt->loginlevel[0] = 0;
09955          cp = ast_strdup(param);
09956          cp1 = strchr(cp,',');
09957          ast_mutex_lock(&myrpt->lock);
09958          if (cp1) 
09959          {
09960             *cp1 = 0;
09961             cp2 = strchr(cp1 + 1,',');
09962             if (cp2) 
09963             {
09964                *cp2 = 0;
09965                strncpy(myrpt->loginlevel,cp2 + 1,
09966                   sizeof(myrpt->loginlevel) - 1);
09967             }
09968             strncpy(myrpt->loginuser,cp1 + 1,sizeof(myrpt->loginuser));
09969             ast_mutex_unlock(&myrpt->lock);
09970             if (myrpt->p.archivedir)
09971             {
09972                char str[100];
09973 
09974                sprintf(str,"LOGIN,%s,%s",
09975                    myrpt->loginuser,myrpt->loginlevel);
09976                donodelog(myrpt,str);
09977             }
09978             if (debug) 
09979                printf("loginuser %s level %s\n",myrpt->loginuser,myrpt->loginlevel);
09980             rpt_telemetry(myrpt,REMLOGIN,NULL);
09981          }
09982          ast_free(cp);
09983          return DC_COMPLETEQUIET;
09984       case 100: /* RX PL Off */
09985          myrpt->rxplon = 0;
09986          setrem(myrpt);
09987          rpt_telemetry(myrpt,REMXXX,(void *)p);
09988          return DC_COMPLETEQUIET;
09989       case 101: /* RX PL On */
09990          myrpt->rxplon = 1;
09991          setrem(myrpt);
09992          rpt_telemetry(myrpt,REMXXX,(void *)p);
09993          return DC_COMPLETEQUIET;
09994       case 102: /* TX PL Off */
09995          myrpt->txplon = 0;
09996          setrem(myrpt);
09997          rpt_telemetry(myrpt,REMXXX,(void *)p);
09998          return DC_COMPLETEQUIET;
09999       case 103: /* TX PL On */
10000          myrpt->txplon = 1;
10001          setrem(myrpt);
10002          rpt_telemetry(myrpt,REMXXX,(void *)p);
10003          return DC_COMPLETEQUIET;
10004       case 104: /* Low Power */
10005          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10006             return DC_ERROR;
10007          myrpt->powerlevel = REM_LOWPWR;
10008          setrem(myrpt);
10009          rpt_telemetry(myrpt,REMXXX,(void *)p);
10010          return DC_COMPLETEQUIET;
10011       case 105: /* Medium Power */
10012          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10013             return DC_ERROR;
10014          if (ISRIG_RTX(myrpt->remoterig)) return DC_ERROR;
10015          myrpt->powerlevel = REM_MEDPWR;
10016          setrem(myrpt);
10017          rpt_telemetry(myrpt,REMXXX,(void *)p);
10018          return DC_COMPLETEQUIET;
10019       case 106: /* Hi Power */
10020          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10021             return DC_ERROR;
10022          myrpt->powerlevel = REM_HIPWR;
10023          setrem(myrpt);
10024          rpt_telemetry(myrpt,REMXXX,(void *)p);
10025          return DC_COMPLETEQUIET;
10026       case 107: /* Bump down 20Hz */
10027          multimode_bump_freq(myrpt, -20);
10028          return DC_COMPLETE;
10029       case 108: /* Bump down 100Hz */
10030          multimode_bump_freq(myrpt, -100);
10031          return DC_COMPLETE;
10032       case 109: /* Bump down 500Hz */
10033          multimode_bump_freq(myrpt, -500);
10034          return DC_COMPLETE;
10035       case 110: /* Bump up 20Hz */
10036          multimode_bump_freq(myrpt, 20);
10037          return DC_COMPLETE;
10038       case 111: /* Bump up 100Hz */
10039          multimode_bump_freq(myrpt, 100);
10040          return DC_COMPLETE;
10041       case 112: /* Bump up 500Hz */
10042          multimode_bump_freq(myrpt, 500);
10043          return DC_COMPLETE;
10044       case 113: /* Scan down slow */
10045          myrpt->scantimer = REM_SCANTIME;
10046          myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
10047          rpt_telemetry(myrpt,REMXXX,(void *)p);
10048          return DC_COMPLETEQUIET;
10049       case 114: /* Scan down quick */
10050          myrpt->scantimer = REM_SCANTIME;
10051          myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
10052          rpt_telemetry(myrpt,REMXXX,(void *)p);
10053          return DC_COMPLETEQUIET;
10054       case 115: /* Scan down fast */
10055          myrpt->scantimer = REM_SCANTIME;
10056          myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
10057          rpt_telemetry(myrpt,REMXXX,(void *)p);
10058          return DC_COMPLETEQUIET;
10059       case 116: /* Scan up slow */
10060          myrpt->scantimer = REM_SCANTIME;
10061          myrpt->hfscanmode = HF_SCAN_UP_SLOW;
10062          rpt_telemetry(myrpt,REMXXX,(void *)p);
10063          return DC_COMPLETEQUIET;
10064       case 117: /* Scan up quick */
10065          myrpt->scantimer = REM_SCANTIME;
10066          myrpt->hfscanmode = HF_SCAN_UP_QUICK;
10067          rpt_telemetry(myrpt,REMXXX,(void *)p);
10068          return DC_COMPLETEQUIET;
10069       case 118: /* Scan up fast */
10070          myrpt->scantimer = REM_SCANTIME;
10071          myrpt->hfscanmode = HF_SCAN_UP_FAST;
10072          rpt_telemetry(myrpt,REMXXX,(void *)p);
10073          return DC_COMPLETEQUIET;
10074       case 119: /* Tune Request */
10075          if(debug > 3)
10076             ast_log(LOG_NOTICE,"TUNE REQUEST\n");
10077          /* if not currently going, and valid to do */
10078          if((!myrpt->tunerequest) && 
10079              ((!strcmp(myrpt->remoterig, remote_rig_ft897) || 
10080             !strcmp(myrpt->remoterig, remote_rig_ic706)) )) { 
10081             myrpt->remotetx = 0;
10082             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
10083             myrpt->tunerequest = 1;
10084             rpt_telemetry(myrpt,TUNE,NULL);
10085             return DC_COMPLETEQUIET;
10086          }
10087          return DC_ERROR;        
10088       case 5: /* Long Status */
10089          rpt_telemetry(myrpt,REMLONGSTATUS,NULL);
10090          return DC_COMPLETEQUIET;
10091       case 140: /* Short Status */
10092          rpt_telemetry(myrpt,REMSHORTSTATUS,NULL);
10093          return DC_COMPLETEQUIET;
10094       case 200:
10095       case 201:
10096       case 202:
10097       case 203:
10098       case 204:
10099       case 205:
10100       case 206:
10101       case 207:
10102       case 208:
10103       case 209:
10104       case 210:
10105       case 211:
10106       case 212:
10107       case 213:
10108       case 214:
10109       case 215:
10110          do_dtmf_local(myrpt,remdtmfstr[p - 200]);
10111          return DC_COMPLETEQUIET;
10112       default:
10113          break;
10114    }
10115    return DC_INDETERMINATE;
10116 }
10117 
10118 
10119 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode)
10120 {
10121 time_t   now;
10122 int   ret,res = 0,src;
10123 
10124    if(debug > 6)
10125       ast_log(LOG_NOTICE,"c=%c  phonemode=%i  dtmfidx=%i\n",c,phonemode,myrpt->dtmfidx);
10126 
10127    time(&myrpt->last_activity_time);
10128    /* Stop scan mode if in scan mode */
10129    if(myrpt->hfscanmode){
10130       stop_scan(myrpt);
10131       return 0;
10132    }
10133 
10134    time(&now);
10135    /* if timed-out */
10136    if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
10137    {
10138       myrpt->dtmfidx = -1;
10139       myrpt->dtmfbuf[0] = 0;
10140       myrpt->dtmf_time_rem = 0;
10141    }
10142    /* if decode not active */
10143    if (myrpt->dtmfidx == -1)
10144    {
10145       /* if not lead-in digit, dont worry */
10146       if (c != myrpt->p.funcchar)
10147       {
10148          if (!myrpt->p.propagate_dtmf)
10149          {
10150             rpt_mutex_lock(&myrpt->lock);
10151             do_dtmf_local(myrpt,c);
10152             rpt_mutex_unlock(&myrpt->lock);
10153          }
10154          return 0;
10155       }
10156       myrpt->dtmfidx = 0;
10157       myrpt->dtmfbuf[0] = 0;
10158       myrpt->dtmf_time_rem = now;
10159       return 0;
10160    }
10161    /* if too many in buffer, start over */
10162    if (myrpt->dtmfidx >= MAXDTMF)
10163    {
10164       myrpt->dtmfidx = 0;
10165       myrpt->dtmfbuf[0] = 0;
10166       myrpt->dtmf_time_rem = now;
10167    }
10168    if (c == myrpt->p.funcchar)
10169    {
10170       /* if star at beginning, or 2 together, erase buffer */
10171       if ((myrpt->dtmfidx < 1) || 
10172          (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
10173       {
10174          myrpt->dtmfidx = 0;
10175          myrpt->dtmfbuf[0] = 0;
10176          myrpt->dtmf_time_rem = now;
10177          return 0;
10178       }
10179    }
10180    myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
10181    myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10182    myrpt->dtmf_time_rem = now;
10183    
10184    
10185    src = SOURCE_RMT;
10186    if (phonemode == 2) src = SOURCE_DPHONE;
10187    else if (phonemode) src = SOURCE_PHONE;
10188    else if (phonemode == 4) src = SOURCE_ALT;
10189    ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
10190    
10191    switch(ret){
10192    
10193       case DC_INDETERMINATE:
10194          res = 0;
10195          break;
10196             
10197       case DC_DOKEY:
10198          if (keyed) *keyed = 1;
10199          res = 0;
10200          break;
10201             
10202       case DC_REQ_FLUSH:
10203          myrpt->dtmfidx = 0;
10204          myrpt->dtmfbuf[0] = 0;
10205          res = 0;
10206          break;
10207             
10208             
10209       case DC_COMPLETE:
10210          res = 1;
10211       case DC_COMPLETEQUIET:
10212          myrpt->totalexecdcommands++;
10213          myrpt->dailyexecdcommands++;
10214          strncpy(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF-1);
10215          myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
10216          myrpt->dtmfbuf[0] = 0;
10217          myrpt->dtmfidx = -1;
10218          myrpt->dtmf_time_rem = 0;
10219          break;
10220             
10221       case DC_ERROR:
10222       default:
10223          myrpt->dtmfbuf[0] = 0;
10224          myrpt->dtmfidx = -1;
10225          myrpt->dtmf_time_rem = 0;
10226          res = 0;
10227          break;
10228    }
10229 
10230    return res;
10231 }
10232 
10233 static int handle_remote_data(struct rpt *myrpt, char *str)
10234 {
10235 /* XXX ATTENTION: if you change the size of these arrays you MUST
10236  * change the limits in corresponding sscanf() calls below. */
10237 char  tmp[300],cmd[300],dest[300],src[300],c;
10238 int   seq,res;
10239 
10240    /* put string in our buffer */
10241    strncpy(tmp,str,sizeof(tmp) - 1);
10242    if (!strcmp(tmp,discstr)) return 0;
10243         if (!strcmp(tmp,newkeystr))
10244         {
10245       myrpt->newkey = 1;
10246                 return 0;
10247         }
10248 
10249 #ifndef  DO_NOT_NOTIFY_MDC1200_ON_REMOTE_BASES
10250    if (tmp[0] == 'I')
10251    {
10252       /* XXX WARNING: be very careful with the limits on the folowing
10253        * sscanf() call, make sure they match the values defined above */
10254       if (sscanf(tmp,"%299s %299s %30x",cmd,src,&seq) != 3)
10255       {
10256          ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
10257          return 0;
10258       }
10259       mdc1200_notify(myrpt,src,seq);
10260       return 0;
10261    }
10262 #endif
10263    /* XXX WARNING: be very careful with the limits on the folowing
10264     * sscanf() call, make sure they match the values defined above */
10265    if (sscanf(tmp,"%299s %299s %299s %30d %1c",cmd,dest,src,&seq,&c) != 5)
10266    {
10267       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
10268       return 0;
10269    }
10270    if (strcmp(cmd,"D"))
10271    {
10272       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
10273       return 0;
10274    }
10275    /* if not for me, ignore */
10276    if (strcmp(dest,myrpt->name)) return 0;
10277    if (myrpt->p.archivedir)
10278    {
10279       char dtmfstr[100];
10280 
10281       sprintf(dtmfstr,"DTMF,%c",c);
10282       donodelog(myrpt,dtmfstr);
10283    }
10284    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
10285    if (!c) return(0);
10286    res = handle_remote_dtmf_digit(myrpt,c, NULL, 0);
10287    if (res != 1)
10288       return res;
10289    rpt_telemetry(myrpt,COMPLETE,NULL);
10290    return 0;
10291 }
10292 
10293 static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode)
10294 {
10295 int   res;
10296 
10297 
10298    if(phonemode == 3) /* simplex phonemode, funcchar key/unkey toggle */
10299    {
10300       if (keyed && *keyed && ((c == myrpt->p.funcchar) || (c == myrpt->p.endchar)))
10301       {
10302          *keyed = 0; /* UNKEY */
10303          return 0;
10304       }
10305       else if (keyed && !*keyed && (c = myrpt->p.funcchar))
10306       {
10307          *keyed = 1; /* KEY */
10308          return 0;
10309       }
10310    }
10311    else /* endchar unkey */
10312    {
10313 
10314       if (keyed && *keyed && (c == myrpt->p.endchar))
10315       {
10316          *keyed = 0;
10317          return DC_INDETERMINATE;
10318       }
10319    }
10320    if (myrpt->p.archivedir)
10321    {
10322       char str[100];
10323 
10324       sprintf(str,"DTMF(P),%c",c);
10325       donodelog(myrpt,str);
10326    }
10327    res = handle_remote_dtmf_digit(myrpt,c,keyed, phonemode);
10328    if (res != 1)
10329       return res;
10330    rpt_telemetry(myrpt,COMPLETE,NULL);
10331    return 0;
10332 }
10333 
10334 static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
10335 {
10336    char *val, *s, *s1, *s2, *tele;
10337    char tmp[300], deststr[300] = "";
10338    char sx[320],*sy;
10339 
10340 
10341    val = node_lookup(myrpt,l->name);
10342    if (!val)
10343    {
10344       fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
10345       return -1;
10346    }
10347 
10348    rpt_mutex_lock(&myrpt->lock);
10349    /* remove from queue */
10350    remque((struct qelem *) l);
10351    rpt_mutex_unlock(&myrpt->lock);
10352    strncpy(tmp,val,sizeof(tmp) - 1);
10353    s = tmp;
10354    s1 = strsep(&s,",");
10355    if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
10356    {
10357       sy = strchr(s1,'/');    
10358       *sy = 0;
10359       sprintf(sx,"%s:4569/%s",s1,sy + 1);
10360       s1 = sx;
10361    }
10362    s2 = strsep(&s,",");
10363    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
10364    tele = strchr(deststr, '/');
10365    if (!tele) {
10366       fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
10367       return -1;
10368    }
10369    *tele++ = 0;
10370    l->elaptime = 0;
10371    l->connecttime = 0;
10372    l->thisconnected = 0;
10373    l->newkey = 0;
10374    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
10375    if (l->chan){
10376       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
10377       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
10378 #ifndef  NEW_ASTERISK
10379       l->chan->whentohangup = 0;
10380 #endif
10381       l->chan->appl = "Apprpt";
10382       l->chan->data = "(Remote Rx)";
10383       if (option_verbose > 2)
10384          ast_verbose(VERBOSE_PREFIX_3 "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
10385             deststr, tele, l->chan->name);
10386       if(l->chan->cid.cid_num)
10387          ast_free(l->chan->cid.cid_num);
10388       l->chan->cid.cid_num = ast_strdup(myrpt->name);
10389                 ast_call(l->chan,tele,999); 
10390 
10391    }
10392    else 
10393    {
10394       if (option_verbose > 2)
10395          ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
10396             deststr,tele,l->chan->name);
10397       return -1;
10398    }
10399    rpt_mutex_lock(&myrpt->lock);
10400    /* put back in queue */
10401    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
10402    rpt_mutex_unlock(&myrpt->lock);
10403    ast_log(LOG_WARNING,"Reconnect Attempt to %s in process\n",l->name);
10404    if (!l->phonemode) send_newkey(l->chan);
10405    return 0;
10406 }
10407 
10408 /* 0 return=continue, 1 return = break, -1 return = error */
10409 static void local_dtmf_helper(struct rpt *myrpt,char c_in)
10410 {
10411 int   res;
10412 pthread_attr_t attr;
10413 char  cmd[MAXDTMF+1] = "",c;
10414 
10415 
10416    c = c_in & 0x7f;
10417    if (myrpt->p.archivedir)
10418    {
10419       char str[100];
10420 
10421       sprintf(str,"DTMF,MAIN,%c",c);
10422       donodelog(myrpt,str);
10423    }
10424    if (c == myrpt->p.endchar)
10425    {
10426    /* if in simple mode, kill autopatch */
10427       if (myrpt->p.simple && myrpt->callmode)
10428       {   
10429          if(debug)
10430             ast_log(LOG_WARNING, "simple mode autopatch kill\n");
10431          rpt_mutex_lock(&myrpt->lock);
10432          myrpt->callmode = 0;
10433          myrpt->macropatch=0;
10434          channel_revert(myrpt);
10435          rpt_mutex_unlock(&myrpt->lock);
10436          rpt_telemetry(myrpt,TERM,NULL);
10437          return;
10438       }
10439       rpt_mutex_lock(&myrpt->lock);
10440       myrpt->stopgen = 1;
10441       if (myrpt->cmdnode[0])
10442       {
10443          myrpt->cmdnode[0] = 0;
10444          myrpt->dtmfidx = -1;
10445          myrpt->dtmfbuf[0] = 0;
10446          rpt_mutex_unlock(&myrpt->lock);
10447          rpt_telemetry(myrpt,COMPLETE,NULL);
10448          return;
10449       } 
10450       else if(!myrpt->inpadtest)
10451                 {
10452                         rpt_mutex_unlock(&myrpt->lock);
10453                         if (myrpt->p.propagate_phonedtmf)
10454                                do_dtmf_phone(myrpt,NULL,c);
10455          return;
10456                 }
10457       else
10458          rpt_mutex_unlock(&myrpt->lock);
10459    }
10460    rpt_mutex_lock(&myrpt->lock);
10461    if (myrpt->cmdnode[0])
10462    {
10463       rpt_mutex_unlock(&myrpt->lock);
10464       send_link_dtmf(myrpt,c);
10465       return;
10466    }
10467    if (!myrpt->p.simple)
10468    {
10469       if ((!myrpt->inpadtest)&&(c == myrpt->p.funcchar))
10470       {
10471          myrpt->dtmfidx = 0;
10472          myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10473          rpt_mutex_unlock(&myrpt->lock);
10474          time(&myrpt->dtmf_time);
10475          return;
10476       } 
10477       else if (((myrpt->inpadtest)||(c != myrpt->p.endchar)) && (myrpt->dtmfidx >= 0))
10478       {
10479          time(&myrpt->dtmf_time);
10480          
10481          if (myrpt->dtmfidx < MAXDTMF)
10482          {
10483             int src;
10484 
10485             myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
10486             myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10487             
10488             strncpy(cmd, myrpt->dtmfbuf, sizeof(cmd) - 1);
10489             
10490             rpt_mutex_unlock(&myrpt->lock);
10491             src = SOURCE_RPT;
10492             if (c_in & 0x80) src = SOURCE_ALT;
10493             res = collect_function_digits(myrpt, cmd, src, NULL);
10494             rpt_mutex_lock(&myrpt->lock);
10495             switch(res){
10496                 case DC_INDETERMINATE:
10497                break;
10498                 case DC_REQ_FLUSH:
10499                myrpt->dtmfidx = 0;
10500                myrpt->dtmfbuf[0] = 0;
10501                break;
10502                 case DC_COMPLETE:
10503                 case DC_COMPLETEQUIET:
10504                myrpt->totalexecdcommands++;
10505                myrpt->dailyexecdcommands++;
10506                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
10507                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
10508                myrpt->dtmfbuf[0] = 0;
10509                myrpt->dtmfidx = -1;
10510                myrpt->dtmf_time = 0;
10511                break;
10512 
10513                 case DC_ERROR:
10514                 default:
10515                myrpt->dtmfbuf[0] = 0;
10516                myrpt->dtmfidx = -1;
10517                myrpt->dtmf_time = 0;
10518                break;
10519             }
10520             if(res != DC_INDETERMINATE) {
10521                rpt_mutex_unlock(&myrpt->lock);
10522                return;
10523             }
10524          } 
10525       }
10526    }
10527    else /* if simple */
10528    {
10529       if ((!myrpt->callmode) && (c == myrpt->p.funcchar))
10530       {
10531          myrpt->callmode = 1;
10532          myrpt->patchnoct = 0;
10533          myrpt->patchquiet = 0;
10534          myrpt->patchfarenddisconnect = 0;
10535          myrpt->patchdialtime = 0;
10536          strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
10537          myrpt->cidx = 0;
10538          myrpt->exten[myrpt->cidx] = 0;
10539          rpt_mutex_unlock(&myrpt->lock);
10540               pthread_attr_init(&attr);
10541               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10542          ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
10543          return;
10544       }
10545    }
10546    if (myrpt->callmode == 1)
10547    {
10548       myrpt->exten[myrpt->cidx++] = c;
10549       myrpt->exten[myrpt->cidx] = 0;
10550       /* if this exists */
10551       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
10552       {
10553          /* if this really it, end now */
10554          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
10555             myrpt->exten,1,NULL)) 
10556          {
10557             myrpt->callmode = 2;
10558             rpt_mutex_unlock(&myrpt->lock);
10559             if(!myrpt->patchquiet)
10560                rpt_telemetry(myrpt,PROC,NULL); 
10561             return;
10562          }
10563          else /* othewise, reset timer */
10564          {
10565             myrpt->calldigittimer = 1;
10566          }
10567       }
10568       /* if can continue, do so */
10569       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
10570       {
10571          /* call has failed, inform user */
10572          myrpt->callmode = 4;
10573       }
10574       rpt_mutex_unlock(&myrpt->lock);
10575       return;
10576    }
10577    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
10578    {
10579       myrpt->mydtmf = c;
10580    }
10581    rpt_mutex_unlock(&myrpt->lock);
10582    if ((myrpt->dtmfidx < 0) && myrpt->p.propagate_phonedtmf)
10583       do_dtmf_phone(myrpt,NULL,c);
10584    return;
10585 }
10586 
10587 
10588 /* place an ID event in the telemetry queue */
10589 
10590 static void queue_id(struct rpt *myrpt)
10591 {
10592    if(myrpt->p.idtime){ /* ID time must be non-zero */
10593       myrpt->mustid = myrpt->tailid = 0;
10594       myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
10595       rpt_mutex_unlock(&myrpt->lock);
10596       rpt_telemetry(myrpt,ID,NULL);
10597       rpt_mutex_lock(&myrpt->lock);
10598    }
10599 }
10600 
10601 /* Scheduler */
10602 /* must be called locked */
10603 
10604 static void do_scheduler(struct rpt *myrpt)
10605 {
10606    int i,res;
10607 
10608 #ifdef   NEW_ASTERISK
10609    struct ast_tm tmnow;
10610 #else
10611    struct tm tmnow;
10612 #endif
10613    struct ast_variable *skedlist;
10614    char *strs[5],*vp,*val,value[100];
10615 
10616    memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
10617    
10618    if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
10619       ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
10620 
10621    /* Try to get close to a 1 second resolution */
10622    
10623    if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
10624       return;
10625 
10626    rpt_localtime(&myrpt->curtv.tv_sec, &tmnow);
10627 
10628    /* If midnight, then reset all daily statistics */
10629    
10630    if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
10631       myrpt->dailykeyups = 0;
10632       myrpt->dailytxtime = 0;
10633       myrpt->dailykerchunks = 0;
10634       myrpt->dailyexecdcommands = 0;
10635    }
10636 
10637    if(tmnow.tm_sec != 0)
10638       return;
10639 
10640    /* Code below only executes once per minute */
10641 
10642 
10643    /* Don't schedule if remote */
10644 
10645         if (myrpt->remote)
10646                 return;
10647 
10648    /* Don't schedule if disabled */
10649 
10650         if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable){
10651       if(debug > 6)
10652          ast_log(LOG_NOTICE, "Scheduler disabled\n");
10653       return;
10654    }
10655 
10656    if(!myrpt->p.skedstanzaname){ /* No stanza means we do nothing */
10657       if(debug > 6)
10658          ast_log(LOG_NOTICE,"No stanza for scheduler in rpt.conf\n");
10659       return;
10660    }
10661 
10662     /* get pointer to linked list of scheduler entries */
10663     skedlist = ast_variable_browse(myrpt->cfg, myrpt->p.skedstanzaname);
10664 
10665    if(debug > 6){
10666       ast_log(LOG_NOTICE, "Time now: %02d:%02d %02d %02d %02d\n",
10667          tmnow.tm_hour,tmnow.tm_min,tmnow.tm_mday,tmnow.tm_mon + 1, tmnow.tm_wday); 
10668    }
10669    /* walk the list */
10670    for(; skedlist; skedlist = skedlist->next){
10671       if(debug > 6)
10672          ast_log(LOG_NOTICE, "Scheduler entry %s = %s being considered\n",skedlist->name, skedlist->value);
10673       strncpy(value,skedlist->value,99);
10674       value[99] = 0;
10675       /* point to the substrings for minute, hour, dom, month, and dow */
10676       for( i = 0, vp = value ; i < 5; i++){
10677          if(!*vp)
10678             break;
10679          while((*vp == ' ') || (*vp == 0x09)) /* get rid of any leading white space */
10680             vp++;
10681          strs[i] = vp; /* save pointer to beginning of substring */
10682          while((*vp != ' ') && (*vp != 0x09) && (*vp != 0)) /* skip over substring */
10683             vp++;
10684          if(*vp)
10685             *vp++ = 0; /* mark end of substring */
10686       }
10687       if(debug > 6)
10688          ast_log(LOG_NOTICE, "i = %d, min = %s, hour = %s, mday=%s, mon=%s, wday=%s\n",i,
10689             strs[0], strs[1], strs[2], strs[3], strs[4]); 
10690       if(i == 5){
10691          if((*strs[0] != '*')&&(atoi(strs[0]) != tmnow.tm_min))
10692             continue;
10693          if((*strs[1] != '*')&&(atoi(strs[1]) != tmnow.tm_hour))
10694             continue;
10695          if((*strs[2] != '*')&&(atoi(strs[2]) != tmnow.tm_mday))
10696             continue;
10697          if((*strs[3] != '*')&&(atoi(strs[3]) != tmnow.tm_mon + 1))
10698             continue;
10699          if(atoi(strs[4]) == 7)
10700             strs[4] = "0";
10701          if((*strs[4] != '*')&&(atoi(strs[4]) != tmnow.tm_wday))
10702             continue;
10703          if(debug)
10704             ast_log(LOG_NOTICE, "Executing scheduler entry %s = %s\n", skedlist->name, skedlist->value);
10705          if(atoi(skedlist->name) == 0)
10706             return; /* Zero is reserved for the startup macro */
10707          val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, skedlist->name);
10708          if (!val){
10709             ast_log(LOG_WARNING,"Scheduler could not find macro %s\n",skedlist->name);
10710             return; /* Macro not found */
10711          }
10712          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)){
10713             ast_log(LOG_WARNING, "Scheduler could not execute macro %s: Macro buffer full\n",
10714                skedlist->name);
10715             return; /* Macro buffer full */
10716          }
10717          myrpt->macrotimer = MACROTIME;
10718          strncat(myrpt->macrobuf,val,MAXMACRO - 1);
10719       }
10720       else{
10721          ast_log(LOG_WARNING,"Malformed scheduler entry in rpt.conf: %s = %s\n",
10722             skedlist->name, skedlist->value);
10723       }
10724    }
10725 
10726 }
10727 
10728 /* single thread with one file (request) to dial */
10729 static void *rpt(void *this)
10730 {
10731 struct   rpt *myrpt = (struct rpt *)this;
10732 char *tele,*idtalkover,c,myfirst,*p;
10733 int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued;
10734 int tailmessagequeued,ctqueued,dtmfed,lastmyrx,localmsgqueued;
10735 struct ast_channel *who;
10736 struct dahdi_confinfo ci;  /* conference info */
10737 time_t   t;
10738 struct rpt_link *l,*m;
10739 struct rpt_tele *telem;
10740 char tmpstr[300],lstr[MAXLINKLIST];
10741 
10742 
10743    if (myrpt->p.archivedir) mkdir(myrpt->p.archivedir,0600);
10744    sprintf(tmpstr,"%s/%s",myrpt->p.archivedir,myrpt->name);
10745    mkdir(tmpstr,0600);
10746    rpt_mutex_lock(&myrpt->lock);
10747 
10748    telem = myrpt->tele.next;
10749    while(telem != &myrpt->tele)
10750    {
10751       ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
10752       telem = telem->next;
10753    }
10754    rpt_mutex_unlock(&myrpt->lock);
10755    /* find our index, and load the vars initially */
10756    for(i = 0; i < nrpts; i++)
10757    {
10758       if (&rpt_vars[i] == myrpt)
10759       {
10760          load_rpt_vars(i,0);
10761          break;
10762       }
10763    }
10764 
10765    rpt_mutex_lock(&myrpt->lock);
10766    while(myrpt->xlink)
10767    {
10768       myrpt->xlink = 3;
10769       rpt_mutex_unlock(&myrpt->lock);
10770       usleep(100000);
10771       rpt_mutex_lock(&myrpt->lock);
10772    }
10773 #ifdef HAVE_IOPERM
10774    if ((!strcmp(myrpt->remoterig, remote_rig_rbi)) &&
10775      (ioperm(myrpt->p.iobase,1,1) == -1))
10776    {
10777       rpt_mutex_unlock(&myrpt->lock);
10778       ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
10779       myrpt->rpt_thread = AST_PTHREADT_STOP;
10780       pthread_exit(NULL);
10781    }
10782 #endif
10783    strncpy(tmpstr,myrpt->rxchanname,sizeof(tmpstr) - 1);
10784    tele = strchr(tmpstr,'/');
10785    if (!tele)
10786    {
10787       fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
10788       rpt_mutex_unlock(&myrpt->lock);
10789       myrpt->rpt_thread = AST_PTHREADT_STOP;
10790       pthread_exit(NULL);
10791    }
10792    *tele++ = 0;
10793    myrpt->rxchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
10794    myrpt->dahdirxchannel = NULL;
10795    if (!strcasecmp(tmpstr,"DAHDI"))
10796       myrpt->dahdirxchannel = myrpt->rxchannel;
10797    if (myrpt->rxchannel)
10798    {
10799       if (myrpt->rxchannel->_state == AST_STATE_BUSY)
10800       {
10801          fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
10802          rpt_mutex_unlock(&myrpt->lock);
10803          ast_hangup(myrpt->rxchannel);
10804          myrpt->rpt_thread = AST_PTHREADT_STOP;
10805          pthread_exit(NULL);
10806       }
10807       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10808       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10809 #ifdef   AST_CDR_FLAG_POST_DISABLED
10810       if (myrpt->rxchannel->cdr)
10811          ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10812 #endif
10813 #ifndef  NEW_ASTERISK
10814       myrpt->rxchannel->whentohangup = 0;
10815 #endif
10816       myrpt->rxchannel->appl = "Apprpt";
10817       myrpt->rxchannel->data = "(Repeater Rx)";
10818       if (option_verbose > 2)
10819          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
10820             tmpstr,tele,myrpt->rxchannel->name);
10821       ast_call(myrpt->rxchannel,tele,999);
10822       if (myrpt->rxchannel->_state != AST_STATE_UP)
10823       {
10824          rpt_mutex_unlock(&myrpt->lock);
10825          ast_hangup(myrpt->rxchannel);
10826          myrpt->rpt_thread = AST_PTHREADT_STOP;
10827          pthread_exit(NULL);
10828       }
10829    }
10830    else
10831    {
10832       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
10833       rpt_mutex_unlock(&myrpt->lock);
10834       myrpt->rpt_thread = AST_PTHREADT_STOP;
10835       pthread_exit(NULL);
10836    }
10837    myrpt->dahditxchannel = NULL;
10838    if (myrpt->txchanname)
10839    {
10840       strncpy(tmpstr,myrpt->txchanname,sizeof(tmpstr) - 1);
10841       tele = strchr(tmpstr,'/');
10842       if (!tele)
10843       {
10844          fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
10845          rpt_mutex_unlock(&myrpt->lock);
10846          ast_hangup(myrpt->rxchannel);
10847          myrpt->rpt_thread = AST_PTHREADT_STOP;
10848          pthread_exit(NULL);
10849       }
10850       *tele++ = 0;
10851       myrpt->txchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
10852       if (!strcasecmp(tmpstr,"DAHDI"))
10853          myrpt->dahditxchannel = myrpt->txchannel;
10854       if (myrpt->txchannel)
10855       {
10856          if (myrpt->txchannel->_state == AST_STATE_BUSY)
10857          {
10858             fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
10859             rpt_mutex_unlock(&myrpt->lock);
10860             ast_hangup(myrpt->txchannel);
10861             ast_hangup(myrpt->rxchannel);
10862             myrpt->rpt_thread = AST_PTHREADT_STOP;
10863             pthread_exit(NULL);
10864          }        
10865          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
10866          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
10867 #ifdef   AST_CDR_FLAG_POST_DISABLED
10868          if (myrpt->txchannel->cdr)
10869             ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10870 #endif
10871 #ifndef  NEW_ASTERISK
10872          myrpt->txchannel->whentohangup = 0;
10873 #endif
10874          myrpt->txchannel->appl = "Apprpt";
10875          myrpt->txchannel->data = "(Repeater Tx)";
10876          if (option_verbose > 2)
10877             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
10878                tmpstr,tele,myrpt->txchannel->name);
10879          ast_call(myrpt->txchannel,tele,999);
10880          if (myrpt->rxchannel->_state != AST_STATE_UP)
10881          {
10882             rpt_mutex_unlock(&myrpt->lock);
10883             ast_hangup(myrpt->rxchannel);
10884             ast_hangup(myrpt->txchannel);
10885             myrpt->rpt_thread = AST_PTHREADT_STOP;
10886             pthread_exit(NULL);
10887          }
10888       }
10889       else
10890       {
10891          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
10892          rpt_mutex_unlock(&myrpt->lock);
10893          ast_hangup(myrpt->rxchannel);
10894          myrpt->rpt_thread = AST_PTHREADT_STOP;
10895          pthread_exit(NULL);
10896       }
10897    }
10898    else
10899    {
10900       myrpt->txchannel = myrpt->rxchannel;
10901       if (!strncasecmp(myrpt->rxchanname,"DAHDI",3))
10902          myrpt->dahditxchannel = myrpt->txchannel;
10903    }
10904    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
10905    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
10906    /* allocate a pseudo-channel thru asterisk */
10907    myrpt->pchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
10908    if (!myrpt->pchannel)
10909    {
10910       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10911       rpt_mutex_unlock(&myrpt->lock);
10912       if (myrpt->txchannel != myrpt->rxchannel) 
10913          ast_hangup(myrpt->txchannel);
10914       ast_hangup(myrpt->rxchannel);
10915       myrpt->rpt_thread = AST_PTHREADT_STOP;
10916       pthread_exit(NULL);
10917    }
10918 #ifdef   AST_CDR_FLAG_POST_DISABLED
10919    if (myrpt->pchannel->cdr)
10920       ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10921 #endif
10922    if (!myrpt->dahdirxchannel) myrpt->dahdirxchannel = myrpt->pchannel;
10923    if (!myrpt->dahditxchannel)
10924    {
10925       /* allocate a pseudo-channel thru asterisk */
10926       myrpt->dahditxchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
10927       if (!myrpt->dahditxchannel)
10928       {
10929          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10930          rpt_mutex_unlock(&myrpt->lock);
10931          if (myrpt->txchannel != myrpt->rxchannel) 
10932             ast_hangup(myrpt->txchannel);
10933          ast_hangup(myrpt->rxchannel);
10934          myrpt->rpt_thread = AST_PTHREADT_STOP;
10935          pthread_exit(NULL);
10936       }
10937       ast_set_read_format(myrpt->dahditxchannel,AST_FORMAT_SLINEAR);
10938       ast_set_write_format(myrpt->dahditxchannel,AST_FORMAT_SLINEAR);
10939 #ifdef   AST_CDR_FLAG_POST_DISABLED
10940       if (myrpt->dahditxchannel->cdr)
10941          ast_set_flag(myrpt->dahditxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10942 #endif
10943    }
10944    /* allocate a pseudo-channel thru asterisk */
10945    myrpt->monchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
10946    if (!myrpt->monchannel)
10947    {
10948       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10949       rpt_mutex_unlock(&myrpt->lock);
10950       if (myrpt->txchannel != myrpt->rxchannel) 
10951          ast_hangup(myrpt->txchannel);
10952       ast_hangup(myrpt->rxchannel);
10953       myrpt->rpt_thread = AST_PTHREADT_STOP;
10954       pthread_exit(NULL);
10955    }
10956    ast_set_read_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
10957    ast_set_write_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
10958 #ifdef   AST_CDR_FLAG_POST_DISABLED
10959    if (myrpt->monchannel->cdr)
10960       ast_set_flag(myrpt->monchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10961 #endif
10962    /* make a conference for the tx */
10963    ci.chan = 0;
10964    ci.confno = -1; /* make a new conf */
10965    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER;
10966    /* first put the channel on the conference in proper mode */
10967    if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
10968    {
10969       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10970       rpt_mutex_unlock(&myrpt->lock);
10971       ast_hangup(myrpt->pchannel);
10972       ast_hangup(myrpt->monchannel);
10973       if (myrpt->txchannel != myrpt->rxchannel) 
10974          ast_hangup(myrpt->txchannel);
10975       ast_hangup(myrpt->rxchannel);
10976       myrpt->rpt_thread = AST_PTHREADT_STOP;
10977       pthread_exit(NULL);
10978    }
10979    /* save tx conference number */
10980    myrpt->txconf = ci.confno;
10981    /* make a conference for the pseudo */
10982    ci.chan = 0;
10983    ci.confno = -1; /* make a new conf */
10984    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
10985       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
10986    /* first put the channel on the conference in announce mode */
10987    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
10988    {
10989       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10990       rpt_mutex_unlock(&myrpt->lock);
10991       ast_hangup(myrpt->pchannel);
10992       ast_hangup(myrpt->monchannel);
10993       if (myrpt->txchannel != myrpt->rxchannel) 
10994          ast_hangup(myrpt->txchannel);
10995       ast_hangup(myrpt->rxchannel);
10996       myrpt->rpt_thread = AST_PTHREADT_STOP;
10997       pthread_exit(NULL);
10998    }
10999    /* save pseudo channel conference number */
11000    myrpt->conf = ci.confno;
11001    /* make a conference for the pseudo */
11002    ci.chan = 0;
11003    if ((strstr(myrpt->txchannel->name,"pseudo") == NULL) &&
11004       (myrpt->dahditxchannel == myrpt->txchannel))
11005    {
11006       /* get tx channel's port number */
11007       if (ioctl(myrpt->txchannel->fds[0],DAHDI_CHANNO,&ci.confno) == -1)
11008       {
11009          ast_log(LOG_WARNING, "Unable to set tx channel's chan number\n");
11010          rpt_mutex_unlock(&myrpt->lock);
11011          ast_hangup(myrpt->pchannel);
11012          ast_hangup(myrpt->monchannel);
11013          if (myrpt->txchannel != myrpt->rxchannel) 
11014             ast_hangup(myrpt->txchannel);
11015          ast_hangup(myrpt->rxchannel);
11016          myrpt->rpt_thread = AST_PTHREADT_STOP;
11017          pthread_exit(NULL);
11018       }
11019       ci.confmode = DAHDI_CONF_MONITORTX;
11020    }
11021    else
11022    {
11023       ci.confno = myrpt->txconf;
11024       ci.confmode = DAHDI_CONF_CONFANNMON;
11025    }
11026    /* first put the channel on the conference in announce mode */
11027    if (ioctl(myrpt->monchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11028    {
11029       ast_log(LOG_WARNING, "Unable to set conference mode for monitor\n");
11030       rpt_mutex_unlock(&myrpt->lock);
11031       ast_hangup(myrpt->pchannel);
11032       ast_hangup(myrpt->monchannel);
11033       if (myrpt->txchannel != myrpt->rxchannel) 
11034          ast_hangup(myrpt->txchannel);
11035       ast_hangup(myrpt->rxchannel);
11036       myrpt->rpt_thread = AST_PTHREADT_STOP;
11037       pthread_exit(NULL);
11038    }
11039    /* allocate a pseudo-channel thru asterisk */
11040    myrpt->parrotchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
11041    if (!myrpt->parrotchannel)
11042    {
11043       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11044       rpt_mutex_unlock(&myrpt->lock);
11045       if (myrpt->txchannel != myrpt->rxchannel) 
11046          ast_hangup(myrpt->txchannel);
11047       ast_hangup(myrpt->rxchannel);
11048       myrpt->rpt_thread = AST_PTHREADT_STOP;
11049       pthread_exit(NULL);
11050    }
11051    ast_set_read_format(myrpt->parrotchannel,AST_FORMAT_SLINEAR);
11052    ast_set_write_format(myrpt->parrotchannel,AST_FORMAT_SLINEAR);
11053 #ifdef   AST_CDR_FLAG_POST_DISABLED
11054    if (myrpt->parrotchannel->cdr)
11055       ast_set_flag(myrpt->parrotchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11056 #endif
11057    /* allocate a pseudo-channel thru asterisk */
11058    myrpt->voxchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
11059    if (!myrpt->voxchannel)
11060    {
11061       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11062       rpt_mutex_unlock(&myrpt->lock);
11063       if (myrpt->txchannel != myrpt->rxchannel) 
11064          ast_hangup(myrpt->txchannel);
11065       ast_hangup(myrpt->rxchannel);
11066       myrpt->rpt_thread = AST_PTHREADT_STOP;
11067       pthread_exit(NULL);
11068    }
11069    ast_set_read_format(myrpt->voxchannel,AST_FORMAT_SLINEAR);
11070    ast_set_write_format(myrpt->voxchannel,AST_FORMAT_SLINEAR);
11071 #ifdef   AST_CDR_FLAG_POST_DISABLED
11072    if (myrpt->voxchannel->cdr)
11073       ast_set_flag(myrpt->voxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11074 #endif
11075    /* allocate a pseudo-channel thru asterisk */
11076    myrpt->txpchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
11077    if (!myrpt->txpchannel)
11078    {
11079       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11080       rpt_mutex_unlock(&myrpt->lock);
11081       ast_hangup(myrpt->pchannel);
11082       ast_hangup(myrpt->monchannel);
11083       if (myrpt->txchannel != myrpt->rxchannel) 
11084          ast_hangup(myrpt->txchannel);
11085       ast_hangup(myrpt->rxchannel);
11086       myrpt->rpt_thread = AST_PTHREADT_STOP;
11087       pthread_exit(NULL);
11088    }
11089 #ifdef   AST_CDR_FLAG_POST_DISABLED
11090    if (myrpt->txpchannel->cdr)
11091       ast_set_flag(myrpt->txpchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11092 #endif
11093    /* make a conference for the tx */
11094    ci.chan = 0;
11095    ci.confno = myrpt->txconf;
11096    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER ;
11097    /* first put the channel on the conference in proper mode */
11098    if (ioctl(myrpt->txpchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11099    {
11100       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
11101       rpt_mutex_unlock(&myrpt->lock);
11102       ast_hangup(myrpt->txpchannel);
11103       ast_hangup(myrpt->monchannel);
11104       if (myrpt->txchannel != myrpt->rxchannel) 
11105          ast_hangup(myrpt->txchannel);
11106       ast_hangup(myrpt->rxchannel);
11107       myrpt->rpt_thread = AST_PTHREADT_STOP;
11108       pthread_exit(NULL);
11109    }
11110    /* if serial io port, open it */
11111    myrpt->iofd = -1;
11112    if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt,myrpt->p.ioport)) == -1))
11113    {
11114       ast_log(LOG_ERROR, "Unable to open %s\n",myrpt->p.ioport);
11115       rpt_mutex_unlock(&myrpt->lock);
11116       ast_hangup(myrpt->pchannel);
11117       if (myrpt->txchannel != myrpt->rxchannel) 
11118          ast_hangup(myrpt->txchannel);
11119       ast_hangup(myrpt->rxchannel);
11120       pthread_exit(NULL);
11121    }
11122    /* Now, the idea here is to copy from the physical rx channel buffer
11123       into the pseudo tx buffer, and from the pseudo rx buffer into the 
11124       tx channel buffer */
11125    myrpt->links.next = &myrpt->links;
11126    myrpt->links.prev = &myrpt->links;
11127    myrpt->tailtimer = 0;
11128    myrpt->totimer = 0;
11129    myrpt->tmsgtimer = myrpt->p.tailmessagetime;
11130    myrpt->idtimer = myrpt->p.politeid;
11131    myrpt->mustid = myrpt->tailid = 0;
11132    myrpt->callmode = 0;
11133    myrpt->tounkeyed = 0;
11134    myrpt->tonotify = 0;
11135    myrpt->retxtimer = 0;
11136    myrpt->rerxtimer = 0;
11137    myrpt->skedtimer = 0;
11138    myrpt->tailevent = 0;
11139    lasttx = 0;
11140    myrpt->keyed = 0;
11141    myrpt->txkeyed = 0;
11142    time(&myrpt->lastkeyedtime);
11143    myrpt->lastkeyedtime -= RPT_LOCKOUT_SECS;
11144    time(&myrpt->lasttxkeyedtime);
11145    myrpt->lasttxkeyedtime -= RPT_LOCKOUT_SECS;
11146    idtalkover = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
11147    myrpt->dtmfidx = -1;
11148    myrpt->dtmfbuf[0] = 0;
11149    myrpt->rem_dtmfidx = -1;
11150    myrpt->rem_dtmfbuf[0] = 0;
11151    myrpt->dtmf_time = 0;
11152    myrpt->rem_dtmf_time = 0;
11153    myrpt->inpadtest = 0;
11154    myrpt->disgorgetime = 0;
11155    myrpt->lastnodewhichkeyedusup[0] = '\0';
11156    myrpt->dailytxtime = 0;
11157    myrpt->totaltxtime = 0;
11158    myrpt->dailykeyups = 0;
11159    myrpt->totalkeyups = 0;
11160    myrpt->dailykerchunks = 0;
11161    myrpt->totalkerchunks = 0;
11162    myrpt->dailyexecdcommands = 0;
11163    myrpt->totalexecdcommands = 0;
11164    myrpt->timeouts = 0;
11165    myrpt->exten[0] = '\0';
11166    myrpt->lastdtmfcommand[0] = '\0';
11167    voxinit_rpt(myrpt,1);
11168    myrpt->wasvox = 0;
11169    if (myrpt->p.startupmacro)
11170    {
11171       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
11172    }
11173    rpt_mutex_unlock(&myrpt->lock);
11174    val = 1;
11175    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
11176    val = 1;
11177    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
11178    if (myrpt->p.archivedir) donodelog(myrpt,"STARTUP");
11179    dtmfed = 0;
11180    if (myrpt->remoterig && !ISRIG_RTX(myrpt->remoterig)) setrem(myrpt);
11181    lastmyrx = 0;
11182    myfirst = 0;
11183    while (ms >= 0)
11184    {
11185       struct ast_frame *f,*f1,*f2;
11186       struct ast_channel *cs[300],*cs1[300];
11187       int totx=0,elap=0,n,x,toexit=0;
11188 
11189       /* DEBUG Dump */
11190       if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){
11191          struct rpt_link *dl;
11192          struct rpt_tele *dt;
11193 
11194          myrpt->disgorgetime = 0;
11195          ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n");
11196          ast_log(LOG_NOTICE,"totx = %d\n",totx);
11197          ast_log(LOG_NOTICE,"remrx = %d\n",remrx);
11198          ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx);
11199          ast_log(LOG_NOTICE,"elap = %d\n",elap);
11200          ast_log(LOG_NOTICE,"toexit = %d\n",toexit);
11201 
11202          ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed);
11203          ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx);
11204          ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode);
11205          ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
11206          ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed);
11207          ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify);
11208          ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
11209          ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
11210          ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
11211          ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
11212 
11213          dl = myrpt->links.next;
11214                   while(dl != &myrpt->links){
11215             ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",dl->name);
11216             ast_log(LOG_NOTICE,"        link->lasttx %d\n",dl->lasttx);
11217             ast_log(LOG_NOTICE,"        link->lastrx %d\n",dl->lastrx);
11218             ast_log(LOG_NOTICE,"        link->connected %d\n",dl->connected);
11219             ast_log(LOG_NOTICE,"        link->hasconnected %d\n",dl->hasconnected);
11220             ast_log(LOG_NOTICE,"        link->outbound %d\n",dl->outbound);
11221             ast_log(LOG_NOTICE,"        link->disced %d\n",dl->disced);
11222             ast_log(LOG_NOTICE,"        link->killme %d\n",dl->killme);
11223             ast_log(LOG_NOTICE,"        link->disctime %ld\n",dl->disctime);
11224             ast_log(LOG_NOTICE,"        link->retrytimer %ld\n",dl->retrytimer);
11225             ast_log(LOG_NOTICE,"        link->retries = %d\n",dl->retries);
11226             ast_log(LOG_NOTICE,"        link->reconnects = %d\n",dl->reconnects);
11227             ast_log(LOG_NOTICE,"        link->newkey = %d\n",dl->newkey);
11228                            dl = dl->next;
11229                   }
11230                                                                                                                                
11231          dt = myrpt->tele.next;
11232          if(dt != &myrpt->tele)
11233             ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n");
11234                   while(dt != &myrpt->tele){
11235             ast_log(LOG_NOTICE,"        Telemetry mode: %d\n",dt->mode);
11236                            dt = dt->next;
11237                   }
11238          ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n");
11239 
11240       }  
11241 
11242 
11243       if (myrpt->reload)
11244       {
11245          struct rpt_tele *inner_telem;
11246 
11247          rpt_mutex_lock(&myrpt->lock);
11248          inner_telem = myrpt->tele.next;
11249          while(inner_telem != &myrpt->tele)
11250          {
11251             ast_softhangup(inner_telem->chan,AST_SOFTHANGUP_DEV);
11252             inner_telem = inner_telem->next;
11253          }
11254          myrpt->reload = 0;
11255          rpt_mutex_unlock(&myrpt->lock);
11256          usleep(10000);
11257          /* find our index, and load the vars */
11258          for(i = 0; i < nrpts; i++)
11259          {
11260             if (&rpt_vars[i] == myrpt)
11261             {
11262                load_rpt_vars(i,0);
11263                break;
11264             }
11265          }
11266       }
11267 
11268       rpt_mutex_lock(&myrpt->lock);
11269       if (ast_check_hangup(myrpt->rxchannel)) break;
11270       if (ast_check_hangup(myrpt->txchannel)) break;
11271       if (ast_check_hangup(myrpt->pchannel)) break;
11272       if (ast_check_hangup(myrpt->monchannel)) break;
11273       if (myrpt->parrotchannel && 
11274          ast_check_hangup(myrpt->parrotchannel)) break;
11275       if (myrpt->voxchannel && 
11276          ast_check_hangup(myrpt->voxchannel)) break;
11277       if (ast_check_hangup(myrpt->txpchannel)) break;
11278       if (myrpt->dahditxchannel && ast_check_hangup(myrpt->dahditxchannel)) break;
11279 
11280       /* Set local tx with keyed */
11281       myrpt->localtx = myrpt->keyed;
11282       /* If someone's connected, and they're transmitting from their end to us, set remrx true */
11283       l = myrpt->links.next;
11284       remrx = 0;
11285       while(l != &myrpt->links)
11286       {
11287          if (l->lastrx){
11288             remrx = 1;
11289             if(l->name[0] != '0') /* Ignore '0' nodes */
11290                strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
11291          }
11292          l = l->next;
11293       }
11294       /* Create a "must_id" flag for the cleanup ID */      
11295       if(myrpt->p.idtime) /* ID time must be non-zero */
11296          myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
11297       /* Build a fresh totx from myrpt->keyed and autopatch activated */
11298       /* If full duplex, add local tx to totx */
11299       if (myrpt->p.duplex > 1) 
11300       {
11301          totx = myrpt->callmode;
11302          totx = totx || myrpt->localtx;
11303       }
11304       else
11305       {
11306          int myrx = myrpt->localtx || remrx || (!myrpt->callmode);
11307 
11308          if (lastmyrx != myrx)
11309          {
11310             voxinit_rpt(myrpt,!myrx);
11311             lastmyrx = myrx;
11312          }
11313          totx = 0;
11314          if (myrpt->callmode && (myrpt->voxtotimer <= 0))
11315          {
11316             if (myrpt->voxtostate)
11317             {
11318                myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
11319                myrpt->voxtostate = 0;
11320             }           
11321             else
11322             {
11323                myrpt->voxtotimer = myrpt->p.voxrecover_ms;
11324                myrpt->voxtostate = 1;
11325             }
11326          }
11327          if (!myrpt->voxtostate)
11328             totx = myrpt->callmode && myrpt->wasvox;
11329       }
11330       /* Traverse the telemetry list to see what's queued */
11331       identqueued = 0;
11332       localmsgqueued = 0;
11333       othertelemqueued = 0;
11334       tailmessagequeued = 0;
11335       ctqueued = 0;
11336       telem = myrpt->tele.next;
11337       while(telem != &myrpt->tele)
11338       {
11339          if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
11340             identqueued = 1; /* Identification telemetry */
11341          }
11342          else if(telem->mode == TAILMSG)
11343          {
11344             tailmessagequeued = 1; /* Tail message telemetry */
11345          }
11346          else if(telem->mode == STATS_TIME_LOCAL) 
11347          {
11348             localmsgqueued = 1; /* Local message */
11349          }
11350          else
11351          {
11352             if ((telem->mode != UNKEY) && (telem->mode != LINKUNKEY))
11353                othertelemqueued = 1;  /* Other telemetry */
11354             else
11355                ctqueued = 1; /* Courtesy tone telemetry */
11356          }
11357          telem = telem->next;
11358       }
11359    
11360       /* Add in any "other" telemetry, unless specified otherwise */
11361       if (!myrpt->p.notelemtx) totx = totx || othertelemqueued;
11362       /* Update external (to links) transmitter PTT state with everything but */
11363       /* ID, CT, local messages, and tailmessage telemetry */
11364       myrpt->exttx = totx;
11365       totx = totx || myrpt->dtmf_local_timer;
11366       /* If half or 3/4 duplex, add localtx to external link tx */
11367       if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
11368       /* Add in ID telemetry to local transmitter */
11369       totx = totx || remrx;
11370       /* If 3/4 or full duplex, add in ident, CT telemetry, and local messages */
11371       if (myrpt->p.duplex > 0)
11372          totx = totx || identqueued || ctqueued || localmsgqueued;
11373       /* If full duplex, add local dtmf stuff active */
11374       if (myrpt->p.duplex > 1) 
11375       {
11376          totx = totx || (myrpt->dtmfidx > -1) ||
11377             myrpt->cmdnode[0];
11378       }
11379       /* add in parrot stuff */
11380       totx = totx || (myrpt->parrotstate > 1);
11381       /* Reset time out timer variables if there is no activity */
11382       if (!totx) 
11383       {
11384          myrpt->totimer = myrpt->p.totime;
11385          myrpt->tounkeyed = 0;
11386          myrpt->tonotify = 0;
11387       }
11388       else{
11389          myrpt->tailtimer = myrpt->p.s[myrpt->p.sysstate_cur].alternatetail ?
11390             myrpt->p.althangtime : /* Initialize tail timer */
11391             myrpt->p.hangtime;
11392       }
11393       /* Disable the local transmitter if we are timed out */
11394       totx = totx && myrpt->totimer;
11395       /* if timed-out and not said already, say it */
11396       if ((!myrpt->totimer) && (!myrpt->tonotify))
11397       {
11398          myrpt->tonotify = 1;
11399          myrpt->timeouts++;
11400          rpt_mutex_unlock(&myrpt->lock);
11401          rpt_telemetry(myrpt,TIMEOUT,NULL);
11402          rpt_mutex_lock(&myrpt->lock);
11403       }
11404 
11405       /* If unkey and re-key, reset time out timer */
11406       if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
11407       {
11408          myrpt->tounkeyed = 1;
11409       }
11410       if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
11411       {
11412          myrpt->totimer = myrpt->p.totime;
11413          myrpt->tounkeyed = 0;
11414          myrpt->tonotify = 0;
11415          rpt_mutex_unlock(&myrpt->lock);
11416          continue;
11417       }
11418       /* if timed-out and in circuit busy after call */
11419       if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
11420       {
11421           if(debug)
11422             ast_log(LOG_NOTICE, "timed-out and in circuit busy after call\n");
11423          myrpt->callmode = 0;
11424          myrpt->macropatch=0;
11425          channel_revert(myrpt);
11426       }
11427       /* get rid of tail if timed out */
11428       if (!myrpt->totimer) myrpt->tailtimer = 0;
11429       /* if not timed-out, add in tail */
11430       if (myrpt->totimer) totx = totx || myrpt->tailtimer;
11431       /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
11432       /* If tail message, kill the message if someone keys up over it */ 
11433       if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
11434          int hasid = 0,hastalkover = 0;
11435 
11436          telem = myrpt->tele.next;
11437          while(telem != &myrpt->tele){
11438             if(telem->mode == ID){
11439                if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
11440                hasid = 1;
11441             }
11442             if(telem->mode == TAILMSG){
11443                                         if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
11444                                 }
11445             if (telem->mode == IDTALKOVER) hastalkover = 1;
11446             telem = telem->next;
11447          }
11448          rpt_mutex_unlock(&myrpt->lock);
11449          if (hasid && (!hastalkover)) rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
11450          rpt_mutex_lock(&myrpt->lock);
11451       }
11452       /* Try to be polite */
11453       /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
11454       /* If within 30 seconds of the time to ID, try do it in the tail */
11455       /* else if at ID time limit, do it right over the top of them */
11456       /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
11457       if(myrpt->mustid && (!myrpt->idtimer))
11458          queue_id(myrpt);
11459 
11460       if ((myrpt->p.idtime && totx && (!myrpt->exttx) &&
11461           (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) /* ID time must be non-zero */ 
11462          {
11463             myrpt->tailid = 1;
11464          }
11465 
11466       /* If tail timer expires, then check for tail messages */
11467 
11468       if(myrpt->tailevent){
11469          myrpt->tailevent = 0;
11470          if(myrpt->tailid){
11471             totx = 1;
11472             queue_id(myrpt);
11473          }
11474          else if ((myrpt->p.tailmessages[0]) &&
11475             (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
11476                totx = 1;
11477                myrpt->tmsgtimer = myrpt->p.tailmessagetime; 
11478                rpt_mutex_unlock(&myrpt->lock);
11479                rpt_telemetry(myrpt, TAILMSG, NULL);
11480                rpt_mutex_lock(&myrpt->lock);
11481          }  
11482       }
11483 
11484       /* Main TX control */
11485 
11486       /* let telemetry transmit anyway (regardless of timeout) */
11487       if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
11488       totx = totx && !myrpt->p.s[myrpt->p.sysstate_cur].txdisable;
11489       myrpt->txrealkeyed = totx;
11490       totx = totx || (!AST_LIST_EMPTY(&myrpt->txq));
11491       if (totx && (!lasttx))
11492       {
11493          char mydate[100],myfname[100];
11494          time_t myt;
11495 
11496          if (myrpt->monstream) ast_closestream(myrpt->monstream);
11497          if (myrpt->p.archivedir)
11498          {
11499             long blocksleft;
11500 
11501             time(&myt);
11502             strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
11503                localtime(&myt));
11504             sprintf(myfname,"%s/%s/%s",myrpt->p.archivedir,
11505                myrpt->name,mydate);
11506             myrpt->monstream = ast_writefile(myfname,"wav49",
11507                "app_rpt Air Archive",O_CREAT | O_APPEND,0,0600);
11508             if (myrpt->p.monminblocks)
11509             {
11510                blocksleft = diskavail(myrpt);
11511                if (blocksleft >= myrpt->p.monminblocks)
11512                   donodelog(myrpt,"TXKEY,MAIN");
11513             } else donodelog(myrpt,"TXKEY,MAIN");
11514          }
11515          lasttx = 1;
11516          myrpt->txkeyed = 1;
11517          time(&myrpt->lasttxkeyedtime);
11518          myrpt->dailykeyups++;
11519          myrpt->totalkeyups++;
11520          rpt_mutex_unlock(&myrpt->lock);
11521          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
11522          rpt_mutex_lock(&myrpt->lock);
11523       }
11524       if ((!totx) && lasttx)
11525       {
11526          if (myrpt->monstream) ast_closestream(myrpt->monstream);
11527          myrpt->monstream = NULL;
11528 
11529          lasttx = 0;
11530          myrpt->txkeyed = 0;
11531          time(&myrpt->lasttxkeyedtime);
11532          rpt_mutex_unlock(&myrpt->lock);
11533          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
11534          rpt_mutex_lock(&myrpt->lock);
11535          donodelog(myrpt,"TXUNKEY,MAIN");
11536       }
11537       time(&t);
11538       /* if DTMF timeout */
11539       if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t))
11540       {
11541          myrpt->inpadtest = 0;
11542          myrpt->dtmfidx = -1;
11543          myrpt->dtmfbuf[0] = 0;
11544       }        
11545       /* if remote DTMF timeout */
11546       if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
11547       {
11548          myrpt->inpadtest = 0;
11549          myrpt->rem_dtmfidx = -1;
11550          myrpt->rem_dtmfbuf[0] = 0;
11551       }  
11552 
11553       if (myrpt->exttx && myrpt->parrotchannel && 
11554          myrpt->p.parrotmode && (!myrpt->parrotstate))
11555       {
11556          char myfname[300];
11557 
11558          ci.confno = myrpt->conf;
11559          ci.confmode = DAHDI_CONF_CONFANNMON;
11560          ci.chan = 0;
11561 
11562          /* first put the channel on the conference in announce mode */
11563          if (ioctl(myrpt->parrotchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11564          {
11565             ast_log(LOG_WARNING, "Unable to set conference mode for parrot\n");
11566             break;
11567          }
11568 
11569          sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
11570          strcat(myfname,".wav");
11571          unlink(myfname);        
11572          sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
11573          myrpt->parrotstate = 1;
11574          myrpt->parrottimer = myrpt->p.parrottime;
11575          if (myrpt->parrotstream) 
11576             ast_closestream(myrpt->parrotstream);
11577          myrpt->parrotstream = NULL;
11578          myrpt->parrotstream = ast_writefile(myfname,"wav",
11579             "app_rpt Parrot",O_CREAT | O_TRUNC,0,0600);
11580       }
11581 
11582       /* Reconnect */
11583    
11584       l = myrpt->links.next;
11585       while(l != &myrpt->links)
11586       {
11587          if (l->killme)
11588          {
11589             /* remove from queue */
11590             remque((struct qelem *) l);
11591             if (!strcmp(myrpt->cmdnode,l->name))
11592                myrpt->cmdnode[0] = 0;
11593             rpt_mutex_unlock(&myrpt->lock);
11594             /* hang-up on call to device */
11595             if (l->chan) ast_hangup(l->chan);
11596             ast_hangup(l->pchan);
11597             ast_free(l);
11598             rpt_mutex_lock(&myrpt->lock);
11599             /* re-start link traversal */
11600             l = myrpt->links.next;
11601             continue;
11602          }
11603          l = l->next;
11604       }
11605       n = 0;
11606       cs[n++] = myrpt->rxchannel;
11607       cs[n++] = myrpt->pchannel;
11608       cs[n++] = myrpt->monchannel;
11609       if (myrpt->parrotchannel) cs[n++] = myrpt->parrotchannel;
11610       if (myrpt->voxchannel) cs[n++] = myrpt->voxchannel;
11611       cs[n++] = myrpt->txpchannel;
11612       if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
11613       if (myrpt->dahditxchannel != myrpt->txchannel)
11614          cs[n++] = myrpt->dahditxchannel;
11615       l = myrpt->links.next;
11616       while(l != &myrpt->links)
11617       {
11618          if ((!l->killme) && (!l->disctime) && l->chan)
11619          {
11620             cs[n++] = l->chan;
11621             cs[n++] = l->pchan;
11622          }
11623          l = l->next;
11624       }
11625       if ((myrpt->topkeystate == 1) && 
11626           ((t - myrpt->topkeytime) > TOPKEYWAIT))
11627       {
11628          myrpt->topkeystate = 2;
11629          qsort(myrpt->topkey,TOPKEYN,sizeof(struct rpt_topkey),
11630             topcompar);
11631       }
11632       rpt_mutex_unlock(&myrpt->lock);
11633 
11634       if (myrpt->topkeystate == 2)
11635       {
11636          rpt_telemetry(myrpt,TOPKEY,NULL);
11637          myrpt->topkeystate = 3;
11638       }
11639       ms = MSWAIT;
11640       for(x = 0; x < n; x++)
11641       {
11642          int s = -(-x - myrpt->scram - 1) % n;
11643          cs1[x] = cs[s];
11644       }
11645       myrpt->scram++;
11646       who = ast_waitfor_n(cs1,n,&ms);
11647       if (who == NULL) ms = 0;
11648       elap = MSWAIT - ms;
11649       rpt_mutex_lock(&myrpt->lock);
11650       l = myrpt->links.next;
11651       while(l != &myrpt->links)
11652       {
11653          int myrx;
11654 
11655          if (l->voxtotimer) l->voxtotimer -= elap;
11656          if (l->voxtotimer < 0) l->voxtotimer = 0;
11657 
11658          if (l->lasttx != l->lasttx1)
11659          {
11660             voxinit_link(l,!l->lasttx);
11661             l->lasttx1 = l->lasttx;
11662          }
11663          myrx = l->lastrealrx;
11664          if ((l->phonemode) && (l->phonevox))
11665          {
11666             myrx = myrx || (!AST_LIST_EMPTY(&l->rxq));
11667             if (l->voxtotimer <= 0)
11668             {
11669                if (l->voxtostate)
11670                {
11671                   l->voxtotimer = myrpt->p.voxtimeout_ms;
11672                   l->voxtostate = 0;
11673                }           
11674                else
11675                {
11676                   l->voxtotimer = myrpt->p.voxrecover_ms;
11677                   l->voxtostate = 1;
11678                }
11679             }
11680             if (!l->voxtostate)
11681                myrx = myrx || l->wasvox ;
11682          }
11683          l->lastrx = myrx;
11684          if (l->linklisttimer)
11685          {
11686             l->linklisttimer -= elap;
11687             if (l->linklisttimer < 0) l->linklisttimer = 0;
11688          }
11689          if ((!l->linklisttimer) && (l->name[0] != '0') && (!l->isremote))
11690          {
11691             struct   ast_frame lf;
11692 
11693             memset(&lf,0,sizeof(lf));
11694             lf.frametype = AST_FRAME_TEXT;
11695             lf.subclass = 0;
11696             lf.offset = 0;
11697             lf.mallocd = 0;
11698             lf.samples = 0;
11699             l->linklisttimer = LINKLISTTIME;
11700             strcpy(lstr,"L ");
11701             __mklinklist(myrpt,l,lstr + 2);
11702             if (l->chan)
11703             {
11704                lf.datalen = strlen(lstr) + 1;
11705                lf.data.ptr = lstr;
11706                ast_write(l->chan,&lf);
11707                if (debug > 6) ast_log(LOG_NOTICE,
11708                   "@@@@ node %s sent node string %s to node %s\n",
11709                      myrpt->name,lstr,l->name);
11710             }
11711          }
11712          if (l->newkey)
11713          {
11714             if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
11715             {
11716                l->retxtimer = 0;
11717                if (l->chan && l->phonemode == 0) 
11718                {
11719                   if (l->lasttx)
11720                      ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
11721                   else
11722                      ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
11723                }
11724             }
11725             if ((l->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 5))
11726             {
11727                if (debug == 7) printf("@@@@ rx un-key\n");
11728                l->lastrealrx = 0;
11729                l->rerxtimer = 0;
11730                if (l->lastrx1)
11731                {
11732                   if (myrpt->p.archivedir)
11733                   {
11734                      char str[100];
11735    
11736                      sprintf(str,"RXUNKEY(T),%s",l->name);
11737                      donodelog(myrpt,str);
11738                   }
11739                   if(myrpt->p.duplex) 
11740                      rpt_telemetry(myrpt,LINKUNKEY,l);
11741                   l->lastrx1 = 0;
11742                }
11743             }
11744          }
11745          if (l->disctime) /* Disconnect timer active on a channel ? */
11746          {
11747             l->disctime -= elap;
11748             if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
11749                l->disctime = 0; /* Yep */
11750          }
11751 
11752          if (l->retrytimer)
11753          {
11754             l->retrytimer -= elap;
11755             if (l->retrytimer < 0) l->retrytimer = 0;
11756          }
11757 
11758          /* Tally connect time */
11759          l->connecttime += elap;
11760 
11761          /* ignore non-timing channels */
11762          if (l->elaptime < 0)
11763          {
11764             l = l->next;
11765             continue;
11766          }
11767          l->elaptime += elap;
11768          /* if connection has taken too long */
11769          if ((l->elaptime > MAXCONNECTTIME) && 
11770             ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
11771          {
11772             l->elaptime = 0;
11773             rpt_mutex_unlock(&myrpt->lock);
11774             if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
11775             rpt_mutex_lock(&myrpt->lock);
11776             break;
11777          }
11778          if ((!l->chan) && (!l->retrytimer) && l->outbound && 
11779             (l->retries++ < l->max_retries) && (l->hasconnected))
11780          {
11781             if (l->chan) ast_hangup(l->chan);
11782             l->chan = 0;
11783             rpt_mutex_unlock(&myrpt->lock);
11784             if ((l->name[0] != '0') && (!l->isremote))
11785             {
11786                if (attempt_reconnect(myrpt,l) == -1)
11787                {
11788                   l->retrytimer = RETRY_TIMER_MS;
11789                } 
11790             }
11791             else 
11792             {
11793                l->retrytimer = l->max_retries + 1;
11794             }
11795 
11796             rpt_mutex_lock(&myrpt->lock);
11797             break;
11798          }
11799          if ((!l->chan) && (!l->retrytimer) && l->outbound &&
11800             (l->retries >= l->max_retries))
11801          {
11802             /* remove from queue */
11803             remque((struct qelem *) l);
11804             if (!strcmp(myrpt->cmdnode,l->name))
11805                myrpt->cmdnode[0] = 0;
11806             rpt_mutex_unlock(&myrpt->lock);
11807             if (l->name[0] != '0')
11808             {
11809                if (!l->hasconnected)
11810                   rpt_telemetry(myrpt,CONNFAIL,l);
11811                else rpt_telemetry(myrpt,REMDISC,l);
11812             }
11813             if (myrpt->p.archivedir)
11814             {
11815                char str[100];
11816 
11817                if (!l->hasconnected)
11818                   sprintf(str,"LINKFAIL,%s",l->name);
11819                else
11820                   sprintf(str,"LINKDISC,%s",l->name);
11821                donodelog(myrpt,str);
11822             }
11823             /* hang-up on call to device */
11824             ast_hangup(l->pchan);
11825             ast_free(l);
11826                                 rpt_mutex_lock(&myrpt->lock);
11827             break;
11828          }
11829             if ((!l->chan) && (!l->disctime) && (!l->outbound))
11830             {
11831             if(debug)ast_log(LOG_NOTICE, "LINKDISC AA\n");
11832                 /* remove from queue */
11833                 remque((struct qelem *) l);
11834             if(myrpt->links.next==&myrpt->links)channel_revert(myrpt);
11835                 if (!strcmp(myrpt->cmdnode,l->name))myrpt->cmdnode[0] = 0;
11836                 rpt_mutex_unlock(&myrpt->lock);
11837             if (l->name[0] != '0') 
11838             {
11839                   rpt_telemetry(myrpt,REMDISC,l);
11840             }
11841             if (myrpt->p.archivedir)
11842             {
11843                char str[100];
11844                sprintf(str,"LINKDISC,%s",l->name);
11845                donodelog(myrpt,str);
11846             }
11847                 /* hang-up on call to device */
11848                 ast_hangup(l->pchan);
11849                 ast_free(l);
11850                 rpt_mutex_lock(&myrpt->lock);
11851                 break;
11852             }
11853          l = l->next;
11854       }
11855       if (myrpt->linkposttimer)
11856       {
11857          myrpt->linkposttimer -= elap;
11858          if (myrpt->linkposttimer < 0) myrpt->linkposttimer = 0;
11859       }
11860       if (myrpt->linkposttimer <= 0)
11861       {
11862          int nstr;
11863          char lst,*str;
11864          time_t now;
11865 
11866          myrpt->linkposttimer = LINKPOSTTIME;
11867          nstr = 0;
11868          for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
11869          {
11870             /* if is not a real link, ignore it */
11871             if (l->name[0] == '0') continue;
11872             nstr += strlen(l->name) + 1;
11873          }
11874          str = ast_malloc(nstr + 256);
11875          if (!str)
11876          {
11877             ast_log(LOG_NOTICE,"Cannot ast_malloc()\n");
11878             break;
11879          }
11880          nstr = 0;
11881          strcpy(str,"nodes=");
11882          for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
11883          {
11884             /* if is not a real link, ignore it */
11885             if (l->name[0] == '0') continue;
11886             lst = 'T';
11887             if (!l->mode) lst = 'R';
11888             if (!l->thisconnected) lst = 'C';
11889             if (nstr) strcat(str,",");
11890             sprintf(str + strlen(str),"%c%s",lst,l->name);
11891             nstr = 1;
11892          }
11893                   p = strstr(tdesc, "version");
11894                   if(p){
11895             int vmajor,vminor;
11896             if(sscanf(p, "version %30d.%30d", &vmajor, &vminor) == 2)
11897                sprintf(str + strlen(str),"&apprptvers=%d.%d",vmajor,vminor);
11898          }
11899          time(&now);
11900          sprintf(str + strlen(str),"&apprptuptime=%d",(int)(now-starttime));
11901          sprintf(str + strlen(str),
11902          "&totalkerchunks=%d&totalkeyups=%d&totaltxtime=%d&timeouts=%d&totalexecdcommands=%d",
11903          myrpt->totalkerchunks,myrpt->totalkeyups,(int) myrpt->totaltxtime/1000,
11904          myrpt->timeouts,myrpt->totalexecdcommands);
11905          rpt_mutex_unlock(&myrpt->lock);
11906          statpost(myrpt,str);
11907          rpt_mutex_lock(&myrpt->lock);
11908          ast_free(str);
11909       }
11910       if (myrpt->keyposttimer)
11911       {
11912          myrpt->keyposttimer -= elap;
11913          if (myrpt->keyposttimer < 0) myrpt->keyposttimer = 0;
11914       }
11915       if (myrpt->keyposttimer <= 0)
11916       {
11917          char str[100];
11918          int diff = 0;
11919          time_t now;
11920 
11921          myrpt->keyposttimer = KEYPOSTTIME;
11922          time(&now);
11923          if (myrpt->lastkeyedtime)
11924          {
11925             diff = (int)(now - myrpt->lastkeyedtime);
11926          }
11927          sprintf(str,"keyed=%d&keytime=%d",myrpt->keyed,diff);
11928          rpt_mutex_unlock(&myrpt->lock);
11929          statpost(myrpt,str);
11930          rpt_mutex_lock(&myrpt->lock);
11931       }
11932       if(totx){
11933          myrpt->dailytxtime += elap;
11934          myrpt->totaltxtime += elap;
11935       }
11936       i = myrpt->tailtimer;
11937       if (myrpt->tailtimer) myrpt->tailtimer -= elap;
11938       if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
11939       if((i) && (myrpt->tailtimer == 0))
11940          myrpt->tailevent = 1;
11941       if ((!myrpt->p.s[myrpt->p.sysstate_cur].totdisable) && myrpt->totimer) myrpt->totimer -= elap;
11942       if (myrpt->totimer < 0) myrpt->totimer = 0;
11943       if (myrpt->idtimer) myrpt->idtimer -= elap;
11944       if (myrpt->idtimer < 0) myrpt->idtimer = 0;
11945       if (myrpt->tmsgtimer) myrpt->tmsgtimer -= elap;
11946       if (myrpt->tmsgtimer < 0) myrpt->tmsgtimer = 0;
11947       if (myrpt->voxtotimer) myrpt->voxtotimer -= elap;
11948       if (myrpt->voxtotimer < 0) myrpt->voxtotimer = 0;
11949       if (myrpt->exttx)
11950       {
11951          myrpt->parrottimer = myrpt->p.parrottime;
11952       }
11953       else
11954       {
11955          if (myrpt->parrottimer) myrpt->parrottimer -= elap;
11956          if (myrpt->parrottimer < 0) myrpt->parrottimer = 0;
11957       }
11958       /* do macro timers */
11959       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
11960       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
11961       /* do local dtmf timer */
11962       if (myrpt->dtmf_local_timer)
11963       {
11964          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
11965          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
11966       }
11967       do_dtmf_local(myrpt,0);
11968       /* Execute scheduler appx. every 2 tenths of a second */
11969       if (myrpt->skedtimer <= 0){
11970          myrpt->skedtimer = 200;
11971          do_scheduler(myrpt);
11972       }
11973       else
11974          myrpt->skedtimer -=elap;
11975       if (!ms) 
11976       {
11977          rpt_mutex_unlock(&myrpt->lock);
11978          continue;
11979       }
11980       if (myrpt->p.parrotmode && (myrpt->parrotstate == 1) &&
11981          (myrpt->parrottimer <= 0))
11982       {
11983 
11984          ci.confno = 0;
11985          ci.confmode = 0;
11986          ci.chan = 0;
11987 
11988          /* first put the channel on the conference in announce mode */
11989          if (ioctl(myrpt->parrotchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11990          {
11991             ast_log(LOG_WARNING, "Unable to set conference mode for parrot\n");
11992             break;
11993          }
11994          if (myrpt->parrotstream) 
11995             ast_closestream(myrpt->parrotstream);
11996          myrpt->parrotstream = NULL;
11997          myrpt->parrotstate = 2;
11998          rpt_telemetry(myrpt,PARROT,(void *) ((intptr_t)myrpt->parrotcnt++)); 
11999       }        
12000       if (myrpt->cmdAction.state == CMD_STATE_READY)
12001       { /* there is a command waiting to be processed */
12002          int status;
12003          myrpt->cmdAction.state = CMD_STATE_EXECUTING;
12004          // lose the lock
12005          rpt_mutex_unlock(&myrpt->lock);
12006          // do the function
12007          status = (*function_table[myrpt->cmdAction.functionNumber].function)(myrpt,myrpt->cmdAction.param, myrpt->cmdAction.digits, myrpt->cmdAction.command_source, NULL);
12008          // get the lock again
12009          rpt_mutex_lock(&myrpt->lock);
12010          myrpt->cmdAction.state = CMD_STATE_IDLE;
12011       } /* if myrpt->cmdAction.state == CMD_STATE_READY */
12012       
12013       c = myrpt->macrobuf[0];
12014       time(&t);
12015       if (c && (!myrpt->macrotimer) && 
12016          starttime && (t > (starttime + START_DELAY)))
12017       {
12018          char cin = c & 0x7f;
12019          myrpt->macrotimer = MACROTIME;
12020          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
12021          if ((cin == 'p') || (cin == 'P'))
12022             myrpt->macrotimer = MACROPTIME;
12023          rpt_mutex_unlock(&myrpt->lock);
12024          if (myrpt->p.archivedir)
12025          {
12026             char str[100];
12027 
12028             sprintf(str,"DTMF(M),MAIN,%c",cin);
12029             donodelog(myrpt,str);
12030          }
12031          local_dtmf_helper(myrpt,c);
12032       } else rpt_mutex_unlock(&myrpt->lock);
12033       if (who == myrpt->rxchannel) /* if it was a read from rx */
12034       {
12035          int ismuted;
12036 
12037          f = ast_read(myrpt->rxchannel);
12038          if (!f)
12039          {
12040             if (debug) printf("@@@@ rpt:Hung Up\n");
12041             break;
12042          }
12043          if (f->frametype == AST_FRAME_VOICE)
12044          {
12045 #ifdef   _MDC_DECODE_H_
12046             unsigned char ubuf[2560];
12047             short *sp;
12048             int n;
12049 #endif
12050 
12051             if ((!myrpt->localtx) && (!myrpt->p.linktolink)) {
12052                memset(f->data.ptr,0,f->datalen);
12053             }
12054 
12055 #ifdef   _MDC_DECODE_H_
12056             sp = (short *) f->data;
12057             /* convert block to unsigned char */
12058             for(n = 0; n < f->datalen / 2; n++)
12059             {
12060                ubuf[n] = (*sp++ >> 8) + 128;
12061             }
12062             n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
12063             if (n == 1)
12064             {
12065                   unsigned char op,arg;
12066                   unsigned short unitID;
12067 
12068                   mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
12069                   if (debug > 2)
12070                   {
12071                      ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
12072                      ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
12073                         op & 255,arg & 255,unitID);
12074                   }
12075                   if ((op == 1) && (arg == 0))
12076                   {
12077                      myrpt->lastunit = unitID;
12078                      mdc1200_notify(myrpt,NULL,myrpt->lastunit);
12079                      mdc1200_send(myrpt,myrpt->lastunit);
12080                   }
12081             }
12082             if ((debug > 2) && (i == 2))
12083             {
12084                unsigned char op,arg,ex1,ex2,ex3,ex4;
12085                unsigned short unitID;
12086 
12087                mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
12088                   &ex1,&ex2,&ex3,&ex4);
12089                ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
12090                ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
12091                   op & 255,arg & 255,unitID);
12092                ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
12093                   ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
12094             }
12095 #endif
12096 #ifdef   __RPT_NOTCH
12097             /* apply inbound filters, if any */
12098             rpt_filter(myrpt,f->data,f->datalen / 2);
12099 #endif
12100             if (ioctl(myrpt->dahdirxchannel->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
12101             {
12102                ismuted = 0;
12103             }
12104             if (dtmfed) ismuted = 1;
12105             dtmfed = 0;
12106             if (ismuted)
12107             {
12108                memset(f->data.ptr,0,f->datalen);
12109                if (myrpt->lastf1)
12110                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12111                if (myrpt->lastf2)
12112                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12113             } 
12114             if (f) f2 = ast_frdup(f);
12115             else f2 = NULL;
12116             f1 = myrpt->lastf2;
12117             myrpt->lastf2 = myrpt->lastf1;
12118             myrpt->lastf1 = f2;
12119             if (ismuted)
12120             {
12121                if (myrpt->lastf1)
12122                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12123                if (myrpt->lastf2)
12124                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12125             }
12126             if (f1)
12127             {
12128                ast_write(myrpt->pchannel,f1);
12129                ast_frfree(f1);
12130             }
12131          }
12132 #ifndef  OLD_ASTERISK
12133          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
12134          {
12135             if (myrpt->lastf1)
12136                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12137             if (myrpt->lastf2)
12138                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12139             dtmfed = 1;
12140          }
12141 #endif
12142          else if (f->frametype == AST_FRAME_DTMF)
12143          {
12144             c = (char) f->subclass; /* get DTMF char */
12145             ast_frfree(f);
12146             if (myrpt->lastf1)
12147                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12148             if (myrpt->lastf2)
12149                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12150             dtmfed = 1;
12151             if (!myrpt->keyed) continue;
12152             c = func_xlat(myrpt,c,&myrpt->p.inxlat);
12153             if (c) local_dtmf_helper(myrpt,c);
12154             continue;
12155          }                 
12156          else if (f->frametype == AST_FRAME_CONTROL)
12157          {
12158             if (f->subclass == AST_CONTROL_HANGUP)
12159             {
12160                if (debug) printf("@@@@ rpt:Hung Up\n");
12161                ast_frfree(f);
12162                break;
12163             }
12164             /* if RX key */
12165             if (f->subclass == AST_CONTROL_RADIO_KEY)
12166             {
12167                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink)) 
12168                {
12169                   if (debug == 7) printf("@@@@ rx key\n");
12170                   myrpt->keyed = 1;
12171                   time(&myrpt->lastkeyedtime);
12172                   myrpt->keyposttimer = KEYPOSTSHORTTIME;
12173                }
12174                if (myrpt->p.archivedir)
12175                {
12176                   donodelog(myrpt,"RXKEY,MAIN");
12177                }
12178                if (f->datalen && f->data.ptr)
12179                {
12180                   char busy = 0;
12181 
12182                   if (debug) ast_log(LOG_NOTICE,"Got PL %s on node %s\n",(char *)f->data.ptr,myrpt->name);
12183                   // ctcss code autopatch initiate
12184                   if (strstr((char *)f->data.ptr,"/M/")&& !myrpt->macropatch)
12185                   {
12186                       char value[16];
12187                      strcat(value,"*6");
12188                      myrpt->macropatch=1;
12189                      rpt_mutex_lock(&myrpt->lock);
12190                      if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(value)){
12191                         rpt_mutex_unlock(&myrpt->lock);
12192                         busy=1;
12193                      }
12194                      if(!busy){
12195                         myrpt->macrotimer = MACROTIME;
12196                         strncat(myrpt->macrobuf,value,MAXMACRO - 1);
12197                         if (!busy) strcpy(myrpt->lasttone,(char*)f->data.ptr);
12198                      }
12199                      rpt_mutex_unlock(&myrpt->lock);
12200                   }
12201                   else if (strcmp((char *)f->data.ptr,myrpt->lasttone))
12202                   {
12203                      char *value = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.tonemacro, (char *)f->data.ptr);
12204                      if (value)
12205                      {
12206                         if (debug) ast_log(LOG_NOTICE,"Tone %s doing %s on node %s\n",(char *) f->data.ptr,value,myrpt->name);
12207                         rpt_mutex_lock(&myrpt->lock);
12208                         if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(value)){
12209                            rpt_mutex_unlock(&myrpt->lock);
12210                            busy=1;
12211                         }
12212                         if(!busy){
12213                            myrpt->macrotimer = MACROTIME;
12214                            strncat(myrpt->macrobuf,value,MAXMACRO - 1);
12215                         }
12216                         rpt_mutex_unlock(&myrpt->lock);
12217                      }
12218                      if (!busy) strcpy(myrpt->lasttone,(char*)f->data.ptr);
12219                   }
12220                } else myrpt->lasttone[0] = 0;
12221             }
12222             /* if RX un-key */
12223             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
12224             {
12225                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
12226                {
12227                   if (debug == 7) printf("@@@@ rx un-key\n");
12228                   if(myrpt->p.duplex && myrpt->keyed) {
12229                      rpt_telemetry(myrpt,UNKEY,NULL);
12230                   }
12231                }
12232                myrpt->keyed = 0;
12233                time(&myrpt->lastkeyedtime);
12234                myrpt->keyposttimer = KEYPOSTSHORTTIME;
12235                if (myrpt->p.archivedir)
12236                {
12237                   donodelog(myrpt,"RXUNKEY,MAIN");
12238                }
12239             }
12240          }
12241          ast_frfree(f);
12242          continue;
12243       }
12244       if (who == myrpt->pchannel) /* if it was a read from pseudo */
12245       {
12246          f = ast_read(myrpt->pchannel);
12247          if (!f)
12248          {
12249             if (debug) printf("@@@@ rpt:Hung Up\n");
12250             break;
12251          }
12252          if (f->frametype == AST_FRAME_VOICE)
12253          {
12254             ast_write(myrpt->txpchannel,f);
12255          }
12256          if (f->frametype == AST_FRAME_CONTROL)
12257          {
12258             if (f->subclass == AST_CONTROL_HANGUP)
12259             {
12260                if (debug) printf("@@@@ rpt:Hung Up\n");
12261                ast_frfree(f);
12262                break;
12263             }
12264          }
12265          ast_frfree(f);
12266          continue;
12267       }
12268       if (who == myrpt->txchannel) /* if it was a read from tx */
12269       {
12270          f = ast_read(myrpt->txchannel);
12271          if (!f)
12272          {
12273             if (debug) printf("@@@@ rpt:Hung Up\n");
12274             break;
12275          }
12276          if (f->frametype == AST_FRAME_CONTROL)
12277          {
12278             if (f->subclass == AST_CONTROL_HANGUP)
12279             {
12280                if (debug) printf("@@@@ rpt:Hung Up\n");
12281                ast_frfree(f);
12282                break;
12283             }
12284          }
12285          ast_frfree(f);
12286          continue;
12287       }
12288       if (who == myrpt->dahditxchannel) /* if it was a read from pseudo-tx */
12289       {
12290          f = ast_read(myrpt->dahditxchannel);
12291          if (!f)
12292          {
12293             if (debug) printf("@@@@ rpt:Hung Up\n");
12294             break;
12295          }
12296          if (f->frametype == AST_FRAME_VOICE)
12297          {
12298             struct ast_frame *vframe;
12299 
12300             if (myrpt->p.duplex < 2)
12301             {
12302                if (myrpt->txrealkeyed) 
12303                {
12304                   if ((!myfirst) && myrpt->callmode)
12305                   {
12306                       x = 0;
12307                       AST_LIST_TRAVERSE(&myrpt->txq, vframe,
12308                      frame_list) x++;
12309                       for(;x < myrpt->p.simplexpatchdelay; x++)
12310                       {
12311                         vframe = ast_frdup(f);
12312                         memset(vframe->data.ptr,0,vframe->datalen);
12313                         AST_LIST_INSERT_TAIL(&myrpt->txq,vframe,frame_list);
12314                       }
12315                       myfirst = 1;
12316                   }
12317                   vframe = ast_frdup(f);
12318                   AST_LIST_INSERT_TAIL(&myrpt->txq,
12319                      vframe,frame_list);
12320                } else myfirst = 0;
12321                x = 0;
12322                AST_LIST_TRAVERSE(&myrpt->txq, vframe,
12323                   frame_list) x++;
12324                if (!x)
12325                {
12326                   memset(f->data.ptr,0,f->datalen);
12327                }
12328                else
12329                {
12330                   ast_frfree(f);
12331                   f = AST_LIST_REMOVE_HEAD(&myrpt->txq,
12332                      frame_list);
12333                }
12334             }
12335             else
12336             {
12337                while((vframe = AST_LIST_REMOVE_HEAD(&myrpt->txq,
12338                   frame_list))) ast_frfree(vframe);
12339             }
12340             ast_write(myrpt->txchannel,f);
12341          }
12342          if (f->frametype == AST_FRAME_CONTROL)
12343          {
12344             if (f->subclass == AST_CONTROL_HANGUP)
12345             {
12346                if (debug) printf("@@@@ rpt:Hung Up\n");
12347                ast_frfree(f);
12348                break;
12349             }
12350          }
12351          ast_frfree(f);
12352          continue;
12353       }
12354       toexit = 0;
12355       rpt_mutex_lock(&myrpt->lock);
12356       l = myrpt->links.next;
12357       while(l != &myrpt->links)
12358       {
12359          int remnomute;
12360          struct timeval now;
12361 
12362          if (l->disctime)
12363          {
12364             l = l->next;
12365             continue;
12366          }
12367 
12368          remrx = 0;
12369          /* see if any other links are receiving */
12370          m = myrpt->links.next;
12371          while(m != &myrpt->links)
12372          {
12373             /* if not us, count it */
12374             if ((m != l) && (m->lastrx)) remrx = 1;
12375             m = m->next;
12376          }
12377          rpt_mutex_unlock(&myrpt->lock);
12378          now = ast_tvnow();
12379          if ((who == l->chan) || (!l->lastlinktv.tv_sec) ||
12380             (ast_tvdiff_ms(now,l->lastlinktv) >= 19))
12381          {
12382             l->lastlinktv = now;
12383             remnomute = myrpt->localtx && 
12384                 (!(myrpt->cmdnode[0] || 
12385                (myrpt->dtmfidx > -1)));
12386             totx = (((l->isremote) ? (remnomute) : 
12387                myrpt->exttx) || remrx) && l->mode;
12388             if (l->phonemode == 0 && l->chan && (l->lasttx != totx))
12389             {
12390                if (totx)
12391                {
12392                   ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
12393                }
12394                else
12395                {
12396                   ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
12397                }
12398                if (myrpt->p.archivedir)
12399                {
12400                   char str[100];
12401 
12402                   if (totx)
12403                      sprintf(str,"TXKEY,%s",l->name);
12404                   else
12405                      sprintf(str,"TXUNKEY,%s",l->name);
12406                   donodelog(myrpt,str);
12407                }
12408             }
12409             l->lasttx = totx;
12410          }
12411          rpt_mutex_lock(&myrpt->lock);
12412          if (who == l->chan) /* if it was a read from rx */
12413          {
12414             rpt_mutex_unlock(&myrpt->lock);
12415             f = ast_read(l->chan);
12416             if (!f)
12417             {
12418                rpt_mutex_lock(&myrpt->lock);
12419                __kickshort(myrpt);
12420                rpt_mutex_unlock(&myrpt->lock);
12421                if ((!l->disced) && (!l->outbound))
12422                {
12423                   if ((l->name[0] == '0') || l->isremote)
12424                      l->disctime = 1;
12425                   else
12426                      l->disctime = DISC_TIME;
12427                   rpt_mutex_lock(&myrpt->lock);
12428                   ast_hangup(l->chan);
12429                   l->chan = 0;
12430                   break;
12431                }
12432 
12433                if (l->retrytimer) 
12434                {
12435                   ast_hangup(l->chan);
12436                   l->chan = 0;
12437                   rpt_mutex_lock(&myrpt->lock);
12438                   break; 
12439                }
12440                if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
12441                {
12442                   rpt_mutex_lock(&myrpt->lock);
12443                   if (l->chan) ast_hangup(l->chan);
12444                   l->chan = 0;
12445                   l->hasconnected = 1;
12446                   l->retrytimer = RETRY_TIMER_MS;
12447                   l->elaptime = 0;
12448                   l->connecttime = 0;
12449                   l->thisconnected = 0;
12450                   break;
12451                }
12452                rpt_mutex_lock(&myrpt->lock);
12453                /* remove from queue */
12454                remque((struct qelem *) l);
12455                if (!strcmp(myrpt->cmdnode,l->name))
12456                   myrpt->cmdnode[0] = 0;
12457                __kickshort(myrpt);
12458                rpt_mutex_unlock(&myrpt->lock);
12459                if (!l->hasconnected)
12460                   rpt_telemetry(myrpt,CONNFAIL,l);
12461                else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
12462                if (myrpt->p.archivedir)
12463                {
12464                   char str[100];
12465 
12466                   if (!l->hasconnected)
12467                      sprintf(str,"LINKFAIL,%s",l->name);
12468                   else
12469                      sprintf(str,"LINKDISC,%s",l->name);
12470                   donodelog(myrpt,str);
12471                }
12472                if (l->lastf1) ast_frfree(l->lastf1);
12473                l->lastf1 = NULL;
12474                if (l->lastf2) ast_frfree(l->lastf2);
12475                l->lastf2 = NULL;
12476                /* hang-up on call to device */
12477                ast_hangup(l->chan);
12478                ast_hangup(l->pchan);
12479                ast_free(l);
12480                rpt_mutex_lock(&myrpt->lock);
12481                break;
12482             }
12483             if (f->frametype == AST_FRAME_VOICE)
12484             {
12485                int ismuted,n1;
12486 
12487                if ((l->phonemode) && (l->phonevox))
12488                {
12489                   n1 = dovox(&l->vox,
12490                      f->data.ptr,f->datalen / 2);
12491                   if (n1 != l->wasvox)
12492                   {
12493                      if (debug)ast_log(LOG_DEBUG,"Link Node %s, vox %d\n",l->name,n1);
12494                      l->wasvox = n1;
12495                      l->voxtostate = 0;
12496                      if (n1) l->voxtotimer = myrpt->p.voxtimeout_ms;
12497                      else l->voxtotimer = 0;
12498                   }
12499                   if (l->lastrealrx || n1)
12500                   {
12501                      if (!myfirst)
12502                      {
12503                          x = 0;
12504                          AST_LIST_TRAVERSE(&l->rxq, f1,
12505                         frame_list) x++;
12506                          for(;x < myrpt->p.simplexphonedelay; x++)
12507                         {
12508                            f1 = ast_frdup(f);
12509                            memset(f1->data.ptr,0,f1->datalen);
12510                            AST_LIST_INSERT_TAIL(&l->rxq,
12511                               f1,frame_list);
12512                          }
12513                          myfirst = 1;
12514                      }
12515                      f1 = ast_frdup(f);
12516                      AST_LIST_INSERT_TAIL(&l->rxq,f1,frame_list);
12517                   } else myfirst = 0; 
12518                   x = 0;
12519                   AST_LIST_TRAVERSE(&l->rxq, f1,frame_list) x++;
12520                   if (!x)
12521                   {
12522                      memset(f->data.ptr,0,f->datalen);
12523                   }
12524                   else
12525                   {
12526                      ast_frfree(f);
12527                      f = AST_LIST_REMOVE_HEAD(&l->rxq,frame_list);
12528                   }
12529                   if (ioctl(l->chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
12530                   {
12531                      ismuted = 0;
12532                   }
12533                   /* if not receiving, zero-out audio */
12534                   ismuted |= (!l->lastrx);
12535                   if (l->dtmfed && l->phonemode) ismuted = 1;
12536                   l->dtmfed = 0;
12537                   if (ismuted)
12538                   {
12539                      memset(f->data.ptr,0,f->datalen);
12540                      if (l->lastf1)
12541                         memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12542                      if (l->lastf2)
12543                         memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12544                   } 
12545                   if (f) f2 = ast_frdup(f);
12546                   else f2 = NULL;
12547                   f1 = l->lastf2;
12548                   l->lastf2 = l->lastf1;
12549                   l->lastf1 = f2;
12550                   if (ismuted)
12551                   {
12552                      if (l->lastf1)
12553                         memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12554                      if (l->lastf2)
12555                         memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12556                   }
12557                   if (f1)
12558                   {
12559                      ast_write(l->pchan,f1);
12560                      ast_frfree(f1);
12561                   }
12562                }
12563                else
12564                {
12565                   if (!l->lastrx)
12566                      memset(f->data.ptr,0,f->datalen);
12567                   ast_write(l->pchan,f);
12568                }
12569             }
12570 #ifndef  OLD_ASTERISK
12571             else if (f->frametype == AST_FRAME_DTMF_BEGIN)
12572             {
12573                if (l->lastf1)
12574                   memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12575                if (l->lastf2)
12576                   memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12577                l->dtmfed = 1;
12578             }
12579 #endif
12580             if (f->frametype == AST_FRAME_TEXT)
12581             {
12582                handle_link_data(myrpt,l,f->data.ptr);
12583             }
12584             if (f->frametype == AST_FRAME_DTMF)
12585             {
12586                if (l->lastf1)
12587                   memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12588                if (l->lastf2)
12589                   memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12590                l->dtmfed = 1;
12591                handle_link_phone_dtmf(myrpt,l,f->subclass);
12592             }
12593             if (f->frametype == AST_FRAME_CONTROL)
12594             {
12595                if (f->subclass == AST_CONTROL_ANSWER)
12596                {
12597                   char lconnected = l->connected;
12598 
12599                   __kickshort(myrpt);
12600                   l->connected = 1;
12601                   l->hasconnected = 1;
12602                   l->thisconnected = 1;
12603                   l->elaptime = -1;
12604                   if (!l->phonemode) send_newkey(l->chan);
12605                   if (!l->isremote) l->retries = 0;
12606                   if (!lconnected) 
12607                   {
12608                      rpt_telemetry(myrpt,CONNECTED,l);
12609                      if (myrpt->p.archivedir)
12610                      {
12611                         char str[100];
12612 
12613                         if (l->mode)
12614                            sprintf(str,"LINKTRX,%s",l->name);
12615                         else
12616                            sprintf(str,"LINKMONITOR,%s",l->name);
12617                         donodelog(myrpt,str);
12618                      }
12619                   }     
12620                   else
12621                      l->reconnects++;
12622                }
12623                /* if RX key */
12624                if (f->subclass == AST_CONTROL_RADIO_KEY)
12625                {
12626                   if (debug == 7 ) printf("@@@@ rx key\n");
12627                   l->lastrealrx = 1;
12628                   l->rerxtimer = 0;
12629                   if (!l->lastrx1)
12630                   {
12631                      if (myrpt->p.archivedir)
12632                      {
12633                         char str[100];
12634 
12635                         sprintf(str,"RXKEY,%s",l->name);
12636                         donodelog(myrpt,str);
12637                      }
12638                      l->lastrx1 = 1;
12639                   }
12640                }
12641                /* if RX un-key */
12642                if (f->subclass == AST_CONTROL_RADIO_UNKEY)
12643                {
12644                   if (debug == 7) printf("@@@@ rx un-key\n");
12645                   l->lastrealrx = 0;
12646                   l->rerxtimer = 0;
12647                   if (l->lastrx1)
12648                   {
12649                      if (myrpt->p.archivedir)
12650                      {
12651                         char str[100];
12652 
12653                         sprintf(str,"RXUNKEY,%s",l->name);
12654                         donodelog(myrpt,str);
12655                      }
12656                      l->lastrx1 = 0;
12657                      if(myrpt->p.duplex) 
12658                         rpt_telemetry(myrpt,LINKUNKEY,l);
12659                   }
12660                }
12661                if (f->subclass == AST_CONTROL_HANGUP)
12662                {
12663                   ast_frfree(f);
12664                   rpt_mutex_lock(&myrpt->lock);
12665                   __kickshort(myrpt);
12666                   rpt_mutex_unlock(&myrpt->lock);
12667                   if ((!l->outbound) && (!l->disced))
12668                   {
12669                      if ((l->name[0] == '0') || l->isremote)
12670                         l->disctime = 1;
12671                      else
12672                         l->disctime = DISC_TIME;
12673                      rpt_mutex_lock(&myrpt->lock);
12674                      ast_hangup(l->chan);
12675                      l->chan = 0;
12676                      break;
12677                   }
12678                   if (l->retrytimer) 
12679                   {
12680                      if (l->chan) ast_hangup(l->chan);
12681                      l->chan = 0;
12682                      rpt_mutex_lock(&myrpt->lock);
12683                      break;
12684                   }
12685                   if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
12686                   {
12687                      rpt_mutex_lock(&myrpt->lock);
12688                      if (l->chan) ast_hangup(l->chan);
12689                      l->chan = 0;
12690                      l->hasconnected = 1;
12691                      l->elaptime = 0;
12692                      l->retrytimer = RETRY_TIMER_MS;
12693                      l->connecttime = 0;
12694                      l->thisconnected = 0;
12695                      break;
12696                   }
12697                   rpt_mutex_lock(&myrpt->lock);
12698                   /* remove from queue */
12699                   remque((struct qelem *) l);
12700                   if (!strcmp(myrpt->cmdnode,l->name))
12701                      myrpt->cmdnode[0] = 0;
12702                   __kickshort(myrpt);
12703                   rpt_mutex_unlock(&myrpt->lock);
12704                   if (!l->hasconnected)
12705                      rpt_telemetry(myrpt,CONNFAIL,l);
12706                   else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
12707                   if (myrpt->p.archivedir)
12708                   {
12709                      char str[100];
12710 
12711                      if (!l->hasconnected)
12712                         sprintf(str,"LINKFAIL,%s",l->name);
12713                      else
12714                         sprintf(str,"LINKDISC,%s",l->name);
12715                      donodelog(myrpt,str);
12716                   }
12717                   if (l->lastf1) ast_frfree(l->lastf1);
12718                   l->lastf1 = NULL;
12719                   if (l->lastf2) ast_frfree(l->lastf2);
12720                   l->lastf2 = NULL;
12721                   /* hang-up on call to device */
12722                   ast_hangup(l->chan);
12723                   ast_hangup(l->pchan);
12724                   ast_free(l);
12725                   rpt_mutex_lock(&myrpt->lock);
12726                   break;
12727                }
12728             }
12729             ast_frfree(f);
12730             rpt_mutex_lock(&myrpt->lock);
12731             break;
12732          }
12733          if (who == l->pchan) 
12734          {
12735             rpt_mutex_unlock(&myrpt->lock);
12736             f = ast_read(l->pchan);
12737             if (!f)
12738             {
12739                if (debug) printf("@@@@ rpt:Hung Up\n");
12740                toexit = 1;
12741                rpt_mutex_lock(&myrpt->lock);
12742                break;
12743             }
12744             if (f->frametype == AST_FRAME_VOICE)
12745             {
12746                if (l->chan) ast_write(l->chan,f);
12747             }
12748             if (f->frametype == AST_FRAME_CONTROL)
12749             {
12750                if (f->subclass == AST_CONTROL_HANGUP)
12751                {
12752                   if (debug) printf("@@@@ rpt:Hung Up\n");
12753                   ast_frfree(f);
12754                   toexit = 1;
12755                   rpt_mutex_lock(&myrpt->lock);
12756                   break;
12757                }
12758             }
12759             ast_frfree(f);
12760             rpt_mutex_lock(&myrpt->lock);
12761             break;
12762          }
12763          l = l->next;
12764       }
12765       rpt_mutex_unlock(&myrpt->lock);
12766       if (toexit) break;
12767       if (who == myrpt->monchannel) 
12768       {
12769          f = ast_read(myrpt->monchannel);
12770          if (!f)
12771          {
12772             if (debug) printf("@@@@ rpt:Hung Up\n");
12773             break;
12774          }
12775          if (f->frametype == AST_FRAME_VOICE)
12776          {
12777             if (myrpt->monstream) 
12778                ast_writestream(myrpt->monstream,f);
12779          }
12780          if (f->frametype == AST_FRAME_CONTROL)
12781          {
12782             if (f->subclass == AST_CONTROL_HANGUP)
12783             {
12784                if (debug) printf("@@@@ rpt:Hung Up\n");
12785                ast_frfree(f);
12786                break;
12787             }
12788          }
12789          ast_frfree(f);
12790          continue;
12791       }
12792       if (myrpt->parrotchannel && (who == myrpt->parrotchannel))
12793       {
12794          f = ast_read(myrpt->parrotchannel);
12795          if (!f)
12796          {
12797             if (debug) printf("@@@@ rpt:Hung Up\n");
12798             break;
12799          }
12800          if (!myrpt->p.parrotmode)
12801          {
12802             char myfname[300];
12803 
12804             if (myrpt->parrotstream)
12805             {
12806                ast_closestream(myrpt->parrotstream);
12807                myrpt->parrotstream = 0;
12808             }
12809             sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
12810             strcat(myfname,".wav");
12811             unlink(myfname);        
12812          } else if (f->frametype == AST_FRAME_VOICE)
12813          {
12814             if (myrpt->parrotstream) 
12815                ast_writestream(myrpt->parrotstream,f);
12816          }
12817          if (f->frametype == AST_FRAME_CONTROL)
12818          {
12819             if (f->subclass == AST_CONTROL_HANGUP)
12820             {
12821                if (debug) printf("@@@@ rpt:Hung Up\n");
12822                ast_frfree(f);
12823                break;
12824             }
12825          }
12826          ast_frfree(f);
12827          continue;
12828       }
12829       if (myrpt->voxchannel && (who == myrpt->voxchannel))
12830       {
12831          f = ast_read(myrpt->voxchannel);
12832          if (!f)
12833          {
12834             if (debug) printf("@@@@ rpt:Hung Up\n");
12835             break;
12836          }
12837          if (f->frametype == AST_FRAME_VOICE)
12838          {
12839             n = dovox(&myrpt->vox,f->data.ptr,f->datalen / 2);
12840             if (n != myrpt->wasvox)
12841             {
12842                if (debug) ast_log(LOG_DEBUG,"Node %s, vox %d\n",myrpt->name,n);
12843                myrpt->wasvox = n;
12844                myrpt->voxtostate = 0;
12845                if (n) myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
12846                else myrpt->voxtotimer = 0;
12847             }
12848          }
12849          if (f->frametype == AST_FRAME_CONTROL)
12850          {
12851             if (f->subclass == AST_CONTROL_HANGUP)
12852             {
12853                if (debug) printf("@@@@ rpt:Hung Up\n");
12854                ast_frfree(f);
12855                break;
12856             }
12857          }
12858          ast_frfree(f);
12859          continue;
12860       }
12861       if (who == myrpt->txpchannel) /* if it was a read from remote tx */
12862       {
12863          f = ast_read(myrpt->txpchannel);
12864          if (!f)
12865          {
12866             if (debug) printf("@@@@ rpt:Hung Up\n");
12867             break;
12868          }
12869          if (f->frametype == AST_FRAME_CONTROL)
12870          {
12871             if (f->subclass == AST_CONTROL_HANGUP)
12872             {
12873                if (debug) printf("@@@@ rpt:Hung Up\n");
12874                ast_frfree(f);
12875                break;
12876             }
12877          }
12878          ast_frfree(f);
12879          continue;
12880       }
12881    }
12882    usleep(100000);
12883    ast_hangup(myrpt->pchannel);
12884    ast_hangup(myrpt->monchannel);
12885    if (myrpt->parrotchannel) ast_hangup(myrpt->parrotchannel);
12886    myrpt->parrotstate = 0;
12887    if (myrpt->voxchannel) ast_hangup(myrpt->voxchannel);
12888    ast_hangup(myrpt->txpchannel);
12889    if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
12890    if (myrpt->dahditxchannel != myrpt->txchannel) ast_hangup(myrpt->dahditxchannel);
12891    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
12892    myrpt->lastf1 = NULL;
12893    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
12894    myrpt->lastf2 = NULL;
12895    ast_hangup(myrpt->rxchannel);
12896    rpt_mutex_lock(&myrpt->lock);
12897    l = myrpt->links.next;
12898    while(l != &myrpt->links)
12899    {
12900       struct rpt_link *ll = l;
12901       /* remove from queue */
12902       remque((struct qelem *) l);
12903       /* hang-up on call to device */
12904       if (l->chan) ast_hangup(l->chan);
12905       ast_hangup(l->pchan);
12906       l = l->next;
12907       ast_free(ll);
12908    }
12909    if (myrpt->xlink  == 1) myrpt->xlink = 2;
12910    rpt_mutex_unlock(&myrpt->lock);
12911    if (debug) printf("@@@@ rpt:Hung up channel\n");
12912    myrpt->rpt_thread = AST_PTHREADT_STOP;
12913    pthread_exit(NULL); 
12914    return NULL;
12915 }
12916 
12917    
12918 static void *rpt_master(void *ignore)
12919 {
12920 int   i,n;
12921 pthread_attr_t attr;
12922 struct ast_config *cfg;
12923 char *this,*val;
12924 
12925    /* init nodelog queue */
12926    nodelog.next = nodelog.prev = &nodelog;
12927    /* go thru all the specified repeaters */
12928    this = NULL;
12929    n = 0;
12930 #ifndef OLD_ASTERISK
12931    /* wait until asterisk starts */
12932         while(!ast_test_flag(&ast_options,AST_OPT_FLAG_FULLY_BOOTED))
12933                 usleep(250000);
12934 #endif
12935 #ifdef   NEW_ASTERISK
12936    rpt_vars[n].cfg = ast_config_load("rpt.conf",config_flags);
12937 #else
12938    rpt_vars[n].cfg = ast_config_load("rpt.conf");
12939 #endif
12940    cfg = rpt_vars[n].cfg;
12941    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
12942       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
12943       pthread_exit(NULL);
12944    }
12945    while((this = ast_category_browse(cfg,this)) != NULL)
12946    {
12947       for(i = 0 ; i < strlen(this) ; i++){
12948          if((this[i] < '0') || (this[i] > '9'))
12949             break;
12950       }
12951       if(i != strlen(this)) continue; /* Not a node defn */
12952       memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
12953       rpt_vars[n].name = ast_strdup(this);
12954       val = (char *) ast_variable_retrieve(cfg,this,"rxchannel");
12955       if (val) rpt_vars[n].rxchanname = ast_strdup(val);
12956       val = (char *) ast_variable_retrieve(cfg,this,"txchannel");
12957       if (val) rpt_vars[n].txchanname = ast_strdup(val);
12958       rpt_vars[n].remote = 0;
12959       rpt_vars[n].remoterig = "";
12960       val = (char *) ast_variable_retrieve(cfg,this,"remote");
12961       if (val) 
12962       {
12963          rpt_vars[n].remoterig = ast_strdup(val);
12964          rpt_vars[n].remote = 1;
12965       }
12966       val = (char *) ast_variable_retrieve(cfg,this,"radiotype");
12967       if (val) rpt_vars[n].remoterig = ast_strdup(val);
12968       ast_mutex_init(&rpt_vars[n].lock);
12969       ast_mutex_init(&rpt_vars[n].remlock);
12970       ast_mutex_init(&rpt_vars[n].statpost_lock);
12971       rpt_vars[n].tele.next = &rpt_vars[n].tele;
12972       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
12973       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
12974       rpt_vars[n].tailmessagen = 0;
12975 #ifdef   _MDC_DECODE_H_
12976       rpt_vars[n].mdc = mdc_decoder_new(8000);
12977 #endif
12978       n++;
12979    }
12980    nrpts = n;
12981    ast_config_destroy(cfg);
12982 
12983    /* start em all */
12984    for(i = 0; i < n; i++)
12985    {
12986       load_rpt_vars(i,1);
12987 
12988       /* if is a remote, dont start one for it */
12989       if (rpt_vars[i].remote)
12990       {
12991          if(retreive_memory(&rpt_vars[i],"init")){ /* Try to retreive initial memory channel */
12992             if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx450))
12993                strncpy(rpt_vars[i].freq, "446.500", sizeof(rpt_vars[i].freq) - 1);
12994             else
12995                strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
12996             strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
12997 
12998             strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
12999             rpt_vars[i].remmode = REM_MODE_FM;
13000             rpt_vars[i].offset = REM_SIMPLEX;
13001             rpt_vars[i].powerlevel = REM_LOWPWR;
13002          }
13003          continue;
13004       }
13005       else /* is a normal repeater */
13006       {
13007           rpt_vars[i].p.memory = rpt_vars[i].name;
13008          if(retreive_memory(&rpt_vars[i],"radiofreq")){ /* Try to retreive initial memory channel */
13009             if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx450))
13010                strncpy(rpt_vars[i].freq, "446.500", sizeof(rpt_vars[i].freq) - 1);
13011             else if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx150))
13012                strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
13013             strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
13014 
13015             strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
13016             rpt_vars[i].remmode = REM_MODE_FM;
13017             rpt_vars[i].offset = REM_SIMPLEX;
13018             rpt_vars[i].powerlevel = REM_LOWPWR;
13019          }
13020          ast_log(LOG_NOTICE,"Normal Repeater Init  %s  %s  %s\n",rpt_vars[i].name, rpt_vars[i].remoterig, rpt_vars[i].freq);
13021       }
13022       if (!rpt_vars[i].p.ident)
13023       {
13024          ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
13025          ast_config_destroy(cfg);
13026          pthread_exit(NULL);
13027       }
13028            pthread_attr_init(&attr);
13029            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13030       ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
13031    }
13032    usleep(500000);
13033    time(&starttime);
13034    for(;;)
13035    {
13036       /* Now monitor each thread, and restart it if necessary */
13037       for(i = 0; i < n; i++)
13038       { 
13039          int rv;
13040          if (rpt_vars[i].remote) continue;
13041          if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP) 
13042             rv = -1;
13043          else
13044             rv = pthread_kill(rpt_vars[i].rpt_thread,0);
13045          if (rv)
13046          {
13047             if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15)
13048             {
13049                if(rpt_vars[i].threadrestarts >= 5)
13050                {
13051                   ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n");
13052                   exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
13053                }
13054                else
13055                {
13056                   ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name);
13057                   rpt_vars[i].threadrestarts++;
13058                }
13059             }
13060             else
13061                rpt_vars[i].threadrestarts = 0;
13062 
13063             rpt_vars[i].lastthreadrestarttime = time(NULL);
13064                  pthread_attr_init(&attr);
13065                  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13066             ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
13067             /* if (!rpt_vars[i].xlink) */
13068                ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
13069          }
13070 
13071       }
13072       for(;;)
13073       {
13074          struct nodelog *nodep;
13075          char *space,datestr[100],fname[300];
13076          int fd;
13077 
13078          ast_mutex_lock(&nodeloglock);
13079          nodep = nodelog.next;
13080          if(nodep == &nodelog) /* if nothing in queue */
13081          {
13082             ast_mutex_unlock(&nodeloglock);
13083             break;
13084          }
13085          remque((struct qelem *)nodep);
13086          ast_mutex_unlock(&nodeloglock);
13087          space = strchr(nodep->str,' ');
13088          if (!space) 
13089          {
13090             ast_free(nodep);
13091             continue;
13092          }
13093          *space = 0;
13094          strftime(datestr,sizeof(datestr) - 1,"%Y%m%d",
13095             localtime(&nodep->timestamp));
13096          sprintf(fname,"%s/%s/%s.txt",nodep->archivedir,
13097             nodep->str,datestr);
13098          fd = open(fname,O_WRONLY | O_CREAT | O_APPEND,0600);
13099          if (fd == -1)
13100          {
13101             ast_log(LOG_ERROR,"Cannot open node log file %s for write",space + 1);
13102             ast_free(nodep);
13103             continue;
13104          }
13105          if (write(fd,space + 1,strlen(space + 1)) !=
13106             strlen(space + 1))
13107          {
13108             ast_log(LOG_ERROR,"Cannot write node log file %s for write",space + 1);
13109             ast_free(nodep);
13110             continue;
13111          }
13112          close(fd);
13113          ast_free(nodep);
13114       }
13115       sleep(2);
13116    }
13117    ast_config_destroy(cfg);
13118    pthread_exit(NULL);
13119 }
13120 
13121 static int rpt_exec(struct ast_channel *chan, void *data)
13122 {
13123    int res=-1,i,rem_totx,rem_rx,remkeyed,n,phone_mode = 0;
13124    int iskenwood_pci4,authtold,authreq,setting,notremming,reming;
13125    int ismuted,dtmfed,phone_vox = 0;
13126 #ifdef   OLD_ASTERISK
13127    struct localuser *u;
13128 #endif
13129    char tmp[256], keyed = 0,keyed1 = 0;
13130    char *options,*stringp,*tele,c,*altp,*memp;
13131    char sx[320],*sy;
13132    struct   rpt *myrpt;
13133    struct ast_frame *f,*f1,*f2;
13134    struct ast_channel *who;
13135    struct ast_channel *cs[20];
13136    struct   rpt_link *l;
13137    struct dahdi_confinfo ci;  /* conference info */
13138    struct dahdi_params par;
13139    int ms,elap,nullfd;
13140    time_t t,last_timeout_warning;
13141    struct   dahdi_radio_param z;
13142    struct rpt_tele *telem;
13143    int   numlinks;
13144 
13145    nullfd = open("/dev/null",O_RDWR);
13146    if (ast_strlen_zero(data)) {
13147       ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
13148       return -1;
13149    }
13150 
13151    strncpy(tmp, (char *)data, sizeof(tmp)-1);
13152    time(&t);
13153    /* if time has externally shifted negative, screw it */
13154    if (t < starttime) t = starttime + START_DELAY;
13155    if ((!starttime) || (t < (starttime + START_DELAY)))
13156    {
13157       ast_log(LOG_NOTICE,"Node %s rejecting call: too soon!\n",tmp);
13158       ast_safe_sleep(chan,3000);
13159       return -1;
13160    }
13161 
13162    ast_log(LOG_NOTICE,"parsing argument=%s \n",tmp);
13163 
13164    altp=strstr(tmp, "|*");
13165    if(altp){
13166       altp[0]=0;
13167       altp++;
13168     }
13169 
13170    memp=strstr(tmp, "|M");
13171    if(memp){
13172       memp[0]=0;
13173       memp+=2;
13174     }
13175 
13176    stringp=tmp;
13177    strsep(&stringp, "|");
13178    options = stringp;
13179 
13180    ast_log(LOG_NOTICE,"options=%s \n",options);
13181    if(memp>0)ast_log(LOG_NOTICE,"memp=%s \n",memp);
13182    if(altp>0)ast_log(LOG_NOTICE,"altp=%s \n",altp);
13183 
13184    myrpt = NULL;
13185    /* see if we can find our specified one */
13186    for(i = 0; i < nrpts; i++)
13187    {
13188       /* if name matches, assign it and exit loop */
13189       if (!strcmp(tmp,rpt_vars[i].name))
13190       {
13191          myrpt = &rpt_vars[i];
13192          break;
13193       }
13194    }
13195 
13196    pbx_builtin_setvar_helper(chan, "RPT_STAT_ERR", "");
13197 
13198    if (myrpt == NULL)
13199    {
13200       pbx_builtin_setvar_helper(chan, "RPT_STAT_ERR", "NODE_NOT_FOUND");
13201       ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
13202       return (priority_jump(NULL,chan));
13203    }
13204 
13205    numlinks=linkcount(myrpt);
13206 
13207    if(options && *options == 'q')
13208    {
13209       char buf2[128];
13210 
13211       if(myrpt->keyed)
13212          pbx_builtin_setvar_helper(chan, "RPT_STAT_RXKEYED", "1");
13213       else
13214          pbx_builtin_setvar_helper(chan, "RPT_STAT_RXKEYED", "0");   
13215 
13216       if(myrpt->txkeyed)
13217          pbx_builtin_setvar_helper(chan, "RPT_STAT_TXKEYED", "1");
13218       else
13219          pbx_builtin_setvar_helper(chan, "RPT_STAT_TXKEYED", "0");   
13220 
13221       snprintf(buf2,sizeof(buf2),"%s=%i", "RPT_STAT_XLINK", myrpt->xlink);
13222       pbx_builtin_setvar(chan, buf2);
13223       snprintf(buf2,sizeof(buf2),"%s=%i", "RPT_STAT_LINKS", numlinks);
13224       pbx_builtin_setvar(chan, buf2);
13225       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_WASCHAN", myrpt->waschan);
13226       pbx_builtin_setvar(chan, buf2);
13227       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_NOWCHAN", myrpt->nowchan);
13228       pbx_builtin_setvar(chan, buf2);
13229       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_DUPLEX", myrpt->p.duplex);
13230       pbx_builtin_setvar(chan, buf2);
13231       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_PARROT", myrpt->p.parrotmode);
13232       pbx_builtin_setvar(chan, buf2);
13233       //snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_PHONEVOX", myrpt->phonevox);
13234       //pbx_builtin_setvar(chan, buf2);
13235       //snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_CONNECTED", myrpt->connected);
13236       //pbx_builtin_setvar(chan, buf2);
13237       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_CALLMODE", myrpt->callmode);
13238       pbx_builtin_setvar(chan, buf2);
13239       snprintf(buf2,sizeof(buf2),"%s=%s", "RPT_STAT_LASTTONE", myrpt->lasttone);
13240       pbx_builtin_setvar(chan, buf2);
13241 
13242       return priority_jump(myrpt,chan);
13243    }
13244 
13245    if(options && *options == 'o')
13246    {
13247       return(channel_revert(myrpt));
13248    }
13249 
13250    #if 0
13251    if((altp)&&(*options == 'Z'))
13252    {
13253       rpt_push_alt_macro(myrpt,altp);
13254       return 0;
13255    }
13256    #endif
13257 
13258 
13259    /* if not phone access, must be an IAX connection */
13260    if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R') || (*options == 'S')))
13261    {
13262       int val;
13263 
13264       pbx_builtin_setvar_helper(chan, "RPT_STAT_BUSY", "0");
13265        
13266       myrpt->bargechan=0;
13267       if(options && strstr(options, "f")>0)
13268       {
13269          myrpt->bargechan=1;     
13270       }
13271 
13272       if(memp>0)
13273       {
13274          char radiochan;
13275          radiochan=strtod(data,NULL);
13276          // if(myrpt->nowchan!=0 && radiochan!=myrpt->nowchan && !myrpt->bargechan)
13277 
13278          if(numlinks>0 && radiochan!=myrpt->nowchan && !myrpt->bargechan)
13279          {
13280             pbx_builtin_setvar_helper(chan, "RPT_STAT_BUSY", "1");
13281             ast_log(LOG_NOTICE, "Radio Channel Busy.\n");
13282             return (priority_jump(myrpt,chan));
13283          }
13284          else if(radiochan!=myrpt->nowchan || myrpt->bargechan)
13285          {
13286             channel_steer(myrpt,memp); 
13287          }
13288       }
13289       if(altp)rpt_push_alt_macro(myrpt,altp);
13290       phone_mode = 1;
13291       if (*options == 'D') phone_mode = 2;
13292       if (*options == 'S') phone_mode = 3;
13293       ast_set_callerid(chan,"0","app_rpt user","0");
13294       val = 1;
13295       ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
13296       if ((*(options + 1) == 'V') || (*(options + 1) == 'v')) phone_vox = 1;
13297    }
13298    else
13299    {
13300 #ifdef ALLOW_LOCAL_CHANNELS
13301            /* Check to insure the connection is IAX2 or Local*/
13302            if ( (strncmp(chan->name,"IAX2",4)) && (strncmp(chan->name,"Local",5)) ) {
13303                ast_log(LOG_WARNING, "We only accept links via IAX2 or Local!!\n");
13304                return -1;
13305            }
13306 #else
13307       if (strncmp(chan->name,"IAX2",4))
13308       {
13309          ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
13310          return -1;
13311       }
13312 #endif
13313            if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable){ /* Do not allow incoming radio connections if disabled */
13314                  ast_log(LOG_NOTICE, "Connect attempt to node %s  with tx disabled", myrpt->name);
13315                   return -1;
13316          }  
13317    }
13318    if (options && (*options == 'R'))
13319    {
13320       /* Parts of this section taken from app_parkandannounce */
13321       char *return_context;
13322       int length, m, lot, timeout = 0;
13323       char buffer[256],*template;
13324       char *working, *context, *exten, *priority;
13325       char *s,*orig_s;
13326 
13327       rpt_mutex_lock(&myrpt->lock);
13328       m = myrpt->callmode;
13329       rpt_mutex_unlock(&myrpt->lock);
13330 
13331       if ((!myrpt->p.nobusyout) && m)
13332       {
13333          if (chan->_state != AST_STATE_UP)
13334          {
13335             ast_indicate(chan,AST_CONTROL_BUSY);
13336          }
13337          while(ast_safe_sleep(chan,10000) != -1);
13338          return -1;
13339       }
13340 
13341       if (chan->_state != AST_STATE_UP)
13342       {
13343          ast_answer(chan);
13344          if (!phone_mode) send_newkey(chan);
13345       }
13346 
13347       length=strlen(options)+2;
13348       orig_s=ast_malloc(length);
13349       if(!orig_s) {
13350          ast_log(LOG_WARNING, "Out of memory\n");
13351          return -1;
13352       }
13353       s=orig_s;
13354       strncpy(s,options,length);
13355 
13356       template=strsep(&s,"|");
13357       if(!template) {
13358          ast_log(LOG_WARNING, "An announce template must be defined\n");
13359          ast_free(orig_s);
13360          return -1;
13361       } 
13362   
13363       if(s) {
13364          timeout = atoi(strsep(&s, "|"));
13365          timeout *= 1000;
13366       }
13367    
13368       return_context = s;
13369   
13370       if(return_context != NULL) {
13371          /* set the return context. Code borrowed from the Goto builtin */
13372     
13373          working = return_context;
13374          context = strsep(&working, "|");
13375          exten = strsep(&working, "|");
13376          if(!exten) {
13377             /* Only a priority in this one */
13378             priority = context;
13379             exten = NULL;
13380             context = NULL;
13381          } else {
13382             priority = strsep(&working, "|");
13383             if(!priority) {
13384                /* Only an extension and priority in this one */
13385                priority = exten;
13386                exten = context;
13387                context = NULL;
13388          }
13389       }
13390       if(atoi(priority) < 0) {
13391          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
13392          ast_free(orig_s);
13393          return -1;
13394       }
13395       /* At this point we have a priority and maybe an extension and a context */
13396       chan->priority = atoi(priority);
13397 #ifdef OLD_ASTERISK
13398       if(exten && strcasecmp(exten, "BYEXTENSION"))
13399 #else
13400       if(exten)
13401 #endif
13402          strncpy(chan->exten, exten, sizeof(chan->exten)-1);
13403       if(context)
13404          strncpy(chan->context, context, sizeof(chan->context)-1);
13405       } else {  /* increment the priority by default*/
13406          chan->priority++;
13407       }
13408 
13409       if(option_verbose > 2) {
13410          ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
13411          if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
13412             ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
13413          }
13414       }
13415   
13416       /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
13417       before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
13418 
13419       ast_masq_park_call(chan, NULL, timeout, &lot);
13420 
13421       if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
13422 
13423       snprintf(buffer, sizeof(buffer) - 1, "%d,%s", lot, template + 1);
13424 
13425       rpt_telemetry(myrpt,REV_PATCH,buffer);
13426 
13427       ast_free(orig_s);
13428 
13429       return 0;
13430 
13431    }
13432 
13433    if (!options)
13434    {
13435         struct ast_hostent ahp;
13436         struct hostent *hp;
13437         struct in_addr ia;
13438         char hisip[100],nodeip[100],*val, *s, *s1, *s2, *s3, *b,*b1;
13439 
13440       /* look at callerid to see what node this comes from */
13441       if (!chan->cid.cid_num) /* if doesn't have caller id */
13442       {
13443          ast_log(LOG_WARNING, "Does not have callerid on %s\n",tmp);
13444          return -1;
13445       }
13446       /* get his IP from IAX2 module */
13447       memset(hisip,0,sizeof(hisip));
13448 #ifdef ALLOW_LOCAL_CHANNELS
13449         /* set IP address if this is a local connection*/
13450         if (strncmp(chan->name,"Local",5)==0) {
13451             strcpy(hisip,"127.0.0.1");
13452         } else {
13453          pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
13454       }
13455 #else
13456       pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
13457 #endif
13458 
13459       if (!hisip[0])
13460       {
13461          ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
13462          return -1;
13463       }
13464       
13465       ast_callerid_parse(chan->cid.cid_num,&b,&b1);
13466       ast_shrink_phone_number(b1);
13467       if (!strcmp(myrpt->name,b1))
13468       {
13469          ast_log(LOG_WARNING, "Trying to link to self!!\n");
13470          return -1;
13471       }
13472 
13473       if (*b1 < '1')
13474       {
13475          ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n",b1);
13476          return -1;
13477       }
13478 
13479 
13480       /* look for his reported node string */
13481       val = node_lookup(myrpt,b1);
13482       if (!val)
13483       {
13484          ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
13485          return -1;
13486       }
13487       strncpy(tmp,val,sizeof(tmp) - 1);
13488       s = tmp;
13489       s1 = strsep(&s,",");
13490       if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
13491       {
13492          sy = strchr(s1,'/');    
13493          *sy = 0;
13494          sprintf(sx,"%s:4569/%s",s1,sy + 1);
13495          s1 = sx;
13496       }
13497       s2 = strsep(&s,",");
13498       if (!s2)
13499       {
13500          ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n",b1);
13501          return -1;
13502       }
13503                 if (strcmp(s2,"NONE")) {
13504          hp = ast_gethostbyname(s2, &ahp);
13505          if (!hp)
13506          {
13507             ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s2);
13508             return -1;
13509          }
13510          memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
13511 #ifdef   OLD_ASTERISK
13512          ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
13513 #else
13514          strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
13515 #endif
13516          s3 = strchr(hisip,':');
13517          if (s3) *s3 = 0;
13518          if (strcmp(hisip,nodeip))
13519          {
13520             s3 = strchr(s1,'@');
13521             if (s3) s1 = s3 + 1;
13522             s3 = strchr(s1,'/');
13523             if (s3) *s3 = 0;
13524             s3 = strchr(s1,':');
13525             if (s3) *s3 = 0;
13526             hp = ast_gethostbyname(s1, &ahp);
13527             if (!hp)
13528             {
13529                ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s1);
13530                return -1;
13531             }
13532             memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
13533 #ifdef   OLD_ASTERISK
13534             ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
13535 #else
13536             strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
13537 #endif
13538             if (strcmp(hisip,nodeip))
13539             {
13540                ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip);
13541                return -1;
13542             }
13543          }
13544       }
13545    }
13546 
13547    /* if is not a remote */
13548    if (!myrpt->remote)
13549    {
13550       char *b,*b1;
13551       int reconnects = 0;
13552 
13553       rpt_mutex_lock(&myrpt->lock);
13554       i = myrpt->xlink;
13555       rpt_mutex_unlock(&myrpt->lock);
13556       if (i)
13557       {
13558          ast_log(LOG_WARNING, "Cannot connect to node %s, system busy\n",myrpt->name);
13559          return -1;
13560       }
13561       /* look at callerid to see what node this comes from */
13562       if (!chan->cid.cid_num) /* if doesn't have caller id */
13563       {
13564          ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
13565          return -1;
13566       }
13567 
13568       ast_callerid_parse(chan->cid.cid_num,&b,&b1);
13569       ast_shrink_phone_number(b1);
13570       if (!strcmp(myrpt->name,b1))
13571       {
13572          ast_log(LOG_WARNING, "Trying to link to self!!\n");
13573          return -1;
13574       }
13575       rpt_mutex_lock(&myrpt->lock);
13576       l = myrpt->links.next;
13577       /* try to find this one in queue */
13578       while(l != &myrpt->links)
13579       {
13580          if (l->name[0] == '0') 
13581          {
13582             l = l->next;
13583             continue;
13584          }
13585          /* if found matching string */
13586          if (!strcmp(l->name,b1)) break;
13587          l = l->next;
13588       }
13589       /* if found */
13590       if (l != &myrpt->links) 
13591       {
13592          l->killme = 1;
13593          l->retries = l->max_retries + 1;
13594          l->disced = 2;
13595          reconnects = l->reconnects;
13596          reconnects++;
13597                         rpt_mutex_unlock(&myrpt->lock);
13598          usleep(500000);   
13599       } else 
13600          rpt_mutex_unlock(&myrpt->lock);
13601       /* establish call in tranceive mode */
13602       l = ast_malloc(sizeof(struct rpt_link));
13603       if (!l)
13604       {
13605          ast_log(LOG_WARNING, "Unable to malloc\n");
13606          pthread_exit(NULL);
13607       }
13608       /* zero the silly thing */
13609       memset((char *)l,0,sizeof(struct rpt_link));
13610       l->mode = 1;
13611       strncpy(l->name,b1,MAXNODESTR - 1);
13612       l->isremote = 0;
13613       l->chan = chan;
13614       l->connected = 1;
13615       l->thisconnected = 1;
13616       l->hasconnected = 1;
13617       l->reconnects = reconnects;
13618       l->phonemode = phone_mode;
13619       l->phonevox = phone_vox;
13620       l->lastf1 = NULL;
13621       l->lastf2 = NULL;
13622       l->dtmfed = 0;
13623       voxinit_link(l,1);
13624       ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
13625       ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
13626       /* allocate a pseudo-channel thru asterisk */
13627       l->pchan = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
13628       if (!l->pchan)
13629       {
13630          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
13631          pthread_exit(NULL);
13632       }
13633       ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
13634       ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
13635 #ifdef   AST_CDR_FLAG_POST_DISABLED
13636       if (l->pchan->cdr)
13637          ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
13638 #endif
13639       /* make a conference for the tx */
13640       ci.chan = 0;
13641       ci.confno = myrpt->conf;
13642       ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
13643       /* first put the channel on the conference in proper mode */
13644       if (ioctl(l->pchan->fds[0],DAHDI_SETCONF,&ci) == -1)
13645       {
13646          ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
13647          pthread_exit(NULL);
13648       }
13649       rpt_mutex_lock(&myrpt->lock);
13650       if ((phone_mode == 2) && (!phone_vox)) l->lastrealrx = 1;
13651       l->max_retries = MAX_RETRIES;
13652       /* insert at end of queue */
13653       insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
13654       __kickshort(myrpt);
13655       rpt_mutex_unlock(&myrpt->lock);
13656       if (chan->_state != AST_STATE_UP) {
13657          ast_answer(chan);
13658          if (!phone_mode) send_newkey(chan);
13659       }
13660       if (myrpt->p.archivedir)
13661       {
13662          char str[100];
13663 
13664          if (l->phonemode)
13665             sprintf(str,"LINK(P),%s",l->name);
13666          else
13667             sprintf(str,"LINK,%s",l->name);
13668          donodelog(myrpt,str);
13669       }
13670       if (!phone_mode) send_newkey(chan);
13671       return 0;
13672    }
13673    /* well, then it is a remote */
13674    rpt_mutex_lock(&myrpt->lock);
13675    /* if remote, error if anyone else already linked */
13676    if (myrpt->remoteon)
13677    {
13678       rpt_mutex_unlock(&myrpt->lock);
13679       usleep(500000);
13680       if (myrpt->remoteon)
13681       {
13682          ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
13683 #ifdef   AST_CDR_FLAG_POST_DISABLED
13684          if (chan->cdr)
13685             ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13686 #endif
13687          return -1;
13688       }     
13689       rpt_mutex_lock(&myrpt->lock);
13690    }
13691    if (myrpt->p.rptnode)
13692    {
13693       char killedit = 0;
13694       time_t now;
13695 
13696       time(&now);
13697       for(i = 0; i < nrpts; i++)
13698       {
13699          if (!strcasecmp(rpt_vars[i].name,myrpt->p.rptnode))
13700          {
13701             if ((rpt_vars[i].links.next != &rpt_vars[i].links) ||
13702                rpt_vars[i].keyed ||
13703                 ((rpt_vars[i].lastkeyedtime + RPT_LOCKOUT_SECS) > now) ||
13704                  rpt_vars[i].txkeyed ||
13705                   ((rpt_vars[i].lasttxkeyedtime + RPT_LOCKOUT_SECS) > now))
13706             {
13707                rpt_mutex_unlock(&myrpt->lock);
13708                ast_log(LOG_WARNING, "Trying to use busy link (repeater node %s) on %s\n",rpt_vars[i].name,tmp);
13709 #ifdef   AST_CDR_FLAG_POST_DISABLED
13710                if (chan->cdr)
13711                   ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13712 #endif
13713                return -1;
13714             }
13715             while(rpt_vars[i].xlink != 3)
13716             {
13717                if (!killedit)
13718                {
13719                   ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
13720                   rpt_vars[i].xlink = 1;
13721                   killedit = 1;
13722                }
13723                rpt_mutex_unlock(&myrpt->lock);
13724                if (ast_safe_sleep(chan,500) == -1)
13725                {
13726 #ifdef   AST_CDR_FLAG_POST_DISABLED
13727                   if (chan->cdr)
13728                      ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13729 #endif
13730                   return -1;
13731                }
13732                rpt_mutex_lock(&myrpt->lock);
13733             }
13734             break;
13735          }
13736       }
13737    }
13738 
13739 #ifdef HAVE_IOPERM
13740    if ( (!strcmp(myrpt->remoterig, remote_rig_rbi)||!strcmp(myrpt->remoterig, remote_rig_ppp16)) &&
13741      (ioperm(myrpt->p.iobase,1,1) == -1))
13742    {
13743       rpt_mutex_unlock(&myrpt->lock);
13744       ast_log(LOG_WARNING, "Can't get io permission on IO port %x hex\n",myrpt->p.iobase);
13745       return -1;
13746    }
13747 #endif
13748    myrpt->remoteon = 1;
13749 #ifdef   OLD_ASTERISK
13750    LOCAL_USER_ADD(u);
13751 #endif
13752    rpt_mutex_unlock(&myrpt->lock);
13753    /* find our index, and load the vars initially */
13754    for(i = 0; i < nrpts; i++)
13755    {
13756       if (&rpt_vars[i] == myrpt)
13757       {
13758          load_rpt_vars(i,0);
13759          break;
13760       }
13761    }
13762    rpt_mutex_lock(&myrpt->lock);
13763    tele = strchr(myrpt->rxchanname,'/');
13764    if (!tele)
13765    {
13766       fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
13767       rpt_mutex_unlock(&myrpt->lock);
13768       pthread_exit(NULL);
13769    }
13770    *tele++ = 0;
13771    myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele,NULL);
13772    myrpt->dahdirxchannel = NULL;
13773    if (!strcasecmp(myrpt->rxchanname,"DAHDI"))
13774       myrpt->dahdirxchannel = myrpt->rxchannel;
13775    if (myrpt->rxchannel)
13776    {
13777       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
13778       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
13779 #ifdef   AST_CDR_FLAG_POST_DISABLED
13780       if (myrpt->rxchannel->cdr)
13781          ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13782 #endif
13783 #ifndef  NEW_ASTERISK
13784       myrpt->rxchannel->whentohangup = 0;
13785 #endif
13786       myrpt->rxchannel->appl = "Apprpt";
13787       myrpt->rxchannel->data = "(Link Rx)";
13788       if (option_verbose > 2)
13789          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
13790             myrpt->rxchanname,tele,myrpt->rxchannel->name);
13791       rpt_mutex_unlock(&myrpt->lock);
13792       ast_call(myrpt->rxchannel,tele,999);
13793       rpt_mutex_lock(&myrpt->lock);
13794    }
13795    else
13796    {
13797       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
13798       rpt_mutex_unlock(&myrpt->lock);
13799       pthread_exit(NULL);
13800    }
13801    *--tele = '/';
13802    myrpt->dahditxchannel = NULL;
13803    if (myrpt->txchanname)
13804    {
13805       tele = strchr(myrpt->txchanname,'/');
13806       if (!tele)
13807       {
13808          fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
13809          rpt_mutex_unlock(&myrpt->lock);
13810          ast_hangup(myrpt->rxchannel);
13811          pthread_exit(NULL);
13812       }
13813       *tele++ = 0;
13814       myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele,NULL);
13815       if (!strncasecmp(myrpt->txchanname,"DAHDI",3))
13816          myrpt->dahditxchannel = myrpt->txchannel;
13817       if (myrpt->txchannel)
13818       {
13819          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
13820          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
13821 #ifdef   AST_CDR_FLAG_POST_DISABLED
13822          if (myrpt->txchannel->cdr)
13823             ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13824 #endif
13825 #ifndef  NEW_ASTERISK
13826          myrpt->txchannel->whentohangup = 0;
13827 #endif
13828          myrpt->txchannel->appl = "Apprpt";
13829          myrpt->txchannel->data = "(Link Tx)";
13830          if (option_verbose > 2)
13831             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
13832                myrpt->txchanname,tele,myrpt->txchannel->name);
13833          rpt_mutex_unlock(&myrpt->lock);
13834          ast_call(myrpt->txchannel,tele,999);
13835          rpt_mutex_lock(&myrpt->lock);
13836       }
13837       else
13838       {
13839          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
13840          rpt_mutex_unlock(&myrpt->lock);
13841          ast_hangup(myrpt->rxchannel);
13842          pthread_exit(NULL);
13843       }
13844       *--tele = '/';
13845    }
13846    else
13847    {
13848       myrpt->txchannel = myrpt->rxchannel;
13849       if (!strncasecmp(myrpt->rxchanname,"DAHDI",3))
13850          myrpt->dahditxchannel = myrpt->rxchannel;
13851    }
13852    /* allocate a pseudo-channel thru asterisk */
13853    myrpt->pchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
13854    if (!myrpt->pchannel)
13855    {
13856       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
13857       rpt_mutex_unlock(&myrpt->lock);
13858       if (myrpt->txchannel != myrpt->rxchannel) 
13859          ast_hangup(myrpt->txchannel);
13860       ast_hangup(myrpt->rxchannel);
13861       pthread_exit(NULL);
13862    }
13863    ast_set_read_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
13864    ast_set_write_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
13865 #ifdef   AST_CDR_FLAG_POST_DISABLED
13866    if (myrpt->pchannel->cdr)
13867       ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13868 #endif
13869    if (!myrpt->dahdirxchannel) myrpt->dahdirxchannel = myrpt->pchannel;
13870    if (!myrpt->dahditxchannel) myrpt->dahditxchannel = myrpt->pchannel;
13871    /* make a conference for the pseudo */
13872    ci.chan = 0;
13873    ci.confno = -1; /* make a new conf */
13874    ci.confmode = DAHDI_CONF_CONFANNMON ;
13875    /* first put the channel on the conference in announce/monitor mode */
13876    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
13877    {
13878       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
13879       rpt_mutex_unlock(&myrpt->lock);
13880       ast_hangup(myrpt->pchannel);
13881       if (myrpt->txchannel != myrpt->rxchannel) 
13882          ast_hangup(myrpt->txchannel);
13883       ast_hangup(myrpt->rxchannel);
13884       pthread_exit(NULL);
13885    }
13886    /* save pseudo channel conference number */
13887    myrpt->conf = myrpt->txconf = ci.confno;
13888    /* if serial io port, open it */
13889    myrpt->iofd = -1;
13890    if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt,myrpt->p.ioport)) == -1))
13891    {
13892       rpt_mutex_unlock(&myrpt->lock);
13893       ast_hangup(myrpt->pchannel);
13894       if (myrpt->txchannel != myrpt->rxchannel) 
13895          ast_hangup(myrpt->txchannel);
13896       ast_hangup(myrpt->rxchannel);
13897       pthread_exit(NULL);
13898    }
13899    iskenwood_pci4 = 0;
13900    memset(&z,0,sizeof(z));
13901    if ((myrpt->iofd < 1) && (myrpt->txchannel == myrpt->dahditxchannel))
13902    {
13903       z.radpar = DAHDI_RADPAR_REMMODE;
13904       z.data = DAHDI_RADPAR_REM_NONE;
13905       res = ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z);
13906       /* if PCIRADIO and kenwood selected */
13907       if ((!res) && (!strcmp(myrpt->remoterig,remote_rig_kenwood)))
13908       {
13909          z.radpar = DAHDI_RADPAR_UIOMODE;
13910          z.data = 1;
13911          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13912          {
13913             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
13914             return -1;
13915          }
13916          z.radpar = DAHDI_RADPAR_UIODATA;
13917          z.data = 3;
13918          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13919          {
13920             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
13921             return -1;
13922          }
13923          i = DAHDI_OFFHOOK;
13924          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i) == -1)
13925          {
13926             ast_log(LOG_ERROR,"Cannot set hook\n");
13927             return -1;
13928          }
13929          iskenwood_pci4 = 1;
13930       }
13931    }
13932    if (myrpt->txchannel == myrpt->dahditxchannel)
13933    {
13934       i = DAHDI_ONHOOK;
13935       ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i);
13936       /* if PCIRADIO and Yaesu ft897/ICOM IC-706 selected */
13937       if ((myrpt->iofd < 1) && (!res) &&
13938          ((!strcmp(myrpt->remoterig,remote_rig_ft897)) ||
13939             (!strcmp(myrpt->remoterig,remote_rig_ic706)) ||
13940                (!strcmp(myrpt->remoterig,remote_rig_tm271))))
13941       {
13942          z.radpar = DAHDI_RADPAR_UIOMODE;
13943          z.data = 1;
13944          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13945          {
13946             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
13947             return -1;
13948          }
13949          z.radpar = DAHDI_RADPAR_UIODATA;
13950          z.data = 3;
13951          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13952          {
13953             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
13954             return -1;
13955          }
13956       }
13957    }
13958    myrpt->remoterx = 0;
13959    myrpt->remotetx = 0;
13960    myrpt->retxtimer = 0;
13961    myrpt->rerxtimer = 0;
13962    myrpt->remoteon = 1;
13963    myrpt->dtmfidx = -1;
13964    myrpt->dtmfbuf[0] = 0;
13965    myrpt->dtmf_time_rem = 0;
13966    myrpt->hfscanmode = 0;
13967    myrpt->hfscanstatus = 0;
13968    if (myrpt->p.startupmacro)
13969    {
13970       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
13971    }
13972    time(&myrpt->start_time);
13973    myrpt->last_activity_time = myrpt->start_time;
13974    last_timeout_warning = 0;
13975    myrpt->reload = 0;
13976    myrpt->tele.next = &myrpt->tele;
13977    myrpt->tele.prev = &myrpt->tele;
13978    myrpt->newkey = 0;
13979    rpt_mutex_unlock(&myrpt->lock);
13980    ast_set_write_format(chan, AST_FORMAT_SLINEAR);
13981    ast_set_read_format(chan, AST_FORMAT_SLINEAR);
13982    rem_rx = 0;
13983    remkeyed = 0;
13984    /* if we are on 2w loop and are a remote, turn EC on */
13985    if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
13986    {
13987       i = 128;
13988       ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_ECHOCANCEL,&i);
13989    }
13990    if (chan->_state != AST_STATE_UP) {
13991       ast_answer(chan);
13992       if (!phone_mode) send_newkey(chan);
13993    }
13994 
13995    if (myrpt->rxchannel == myrpt->dahdirxchannel)
13996    {
13997       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_GET_PARAMS,&par) != -1)
13998       {
13999          if (par.rxisoffhook)
14000          {
14001             ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14002             myrpt->remoterx = 1;
14003             remkeyed = 1;
14004          }
14005       }
14006    }
14007    if (myrpt->p.archivedir)
14008    {
14009       char mycmd[100],mydate[100],*b,*b1;
14010       time_t myt;
14011       long blocksleft;
14012 
14013 
14014       mkdir(myrpt->p.archivedir,0600);
14015       sprintf(mycmd,"%s/%s",myrpt->p.archivedir,myrpt->name);
14016       mkdir(mycmd,0600);
14017       time(&myt);
14018       strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
14019          localtime(&myt));
14020       sprintf(mycmd,"mixmonitor start %s %s/%s/%s.wav49 a",chan->name,
14021          myrpt->p.archivedir,myrpt->name,mydate);
14022       if (myrpt->p.monminblocks)
14023       {
14024          blocksleft = diskavail(myrpt);
14025          if (myrpt->p.remotetimeout)
14026          {
14027             blocksleft -= (myrpt->p.remotetimeout *
14028                MONITOR_DISK_BLOCKS_PER_MINUTE) / 60;
14029          }
14030          if (blocksleft >= myrpt->p.monminblocks)
14031             ast_cli_command(nullfd,mycmd);
14032       } else ast_cli_command(nullfd,mycmd);
14033       /* look at callerid to see what node this comes from */
14034       if (!chan->cid.cid_num) /* if doesn't have caller id */
14035       {
14036          b1 = "0";
14037       } else {
14038          ast_callerid_parse(chan->cid.cid_num,&b,&b1);
14039          ast_shrink_phone_number(b1);
14040       }
14041       sprintf(mycmd,"CONNECT,%s",b1);
14042       donodelog(myrpt,mycmd);
14043    }
14044    myrpt->loginuser[0] = 0;
14045    myrpt->loginlevel[0] = 0;
14046    myrpt->authtelltimer = 0;
14047    myrpt->authtimer = 0;
14048    authtold = 0;
14049    authreq = 0;
14050    if (myrpt->p.authlevel > 1) authreq = 1;
14051    setrem(myrpt); 
14052    n = 0;
14053    dtmfed = 0;
14054    cs[n++] = chan;
14055    cs[n++] = myrpt->rxchannel;
14056    cs[n++] = myrpt->pchannel;
14057    if (myrpt->rxchannel != myrpt->txchannel)
14058       cs[n++] = myrpt->txchannel;
14059    if (!phone_mode) send_newkey(chan);
14060    /* start un-locked */
14061    for(;;) 
14062    {
14063       if (ast_check_hangup(chan)) break;
14064       if (ast_check_hangup(myrpt->rxchannel)) break;
14065       notremming = 0;
14066       setting = 0;
14067       reming = 0;
14068       telem = myrpt->tele.next;
14069       while(telem != &myrpt->tele)
14070       {
14071          if (telem->mode == SETREMOTE) setting = 1;
14072          if ((telem->mode == SETREMOTE) ||
14073              (telem->mode == SCAN) ||
14074             (telem->mode == TUNE))  reming = 1;
14075          else notremming = 1;
14076          telem = telem->next;
14077       }
14078       if (myrpt->reload)
14079       {
14080          myrpt->reload = 0;
14081          /* find our index, and load the vars */
14082          for(i = 0; i < nrpts; i++)
14083          {
14084             if (&rpt_vars[i] == myrpt)
14085             {
14086                load_rpt_vars(i,0);
14087                break;
14088             }
14089          }
14090       }
14091       time(&t);
14092       if (myrpt->p.remotetimeout)
14093       { 
14094          time_t r;
14095 
14096          r = (t - myrpt->start_time);
14097          if (r >= myrpt->p.remotetimeout)
14098          {
14099             saynode(myrpt,chan,myrpt->name);
14100             sayfile(chan,"rpt/timeout");
14101             ast_safe_sleep(chan,1000);
14102             break;
14103          }
14104          if ((myrpt->p.remotetimeoutwarning) && 
14105              (r >= (myrpt->p.remotetimeout -
14106             myrpt->p.remotetimeoutwarning)) &&
14107                 (r <= (myrpt->p.remotetimeout - 
14108                   myrpt->p.remotetimeoutwarningfreq)))
14109          {
14110             if (myrpt->p.remotetimeoutwarningfreq)
14111             {
14112                 if ((t - last_timeout_warning) >=
14113                myrpt->p.remotetimeoutwarningfreq)
14114                 {
14115                time(&last_timeout_warning);
14116                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
14117                 }
14118             }
14119             else
14120             {
14121                 if (!last_timeout_warning)
14122                 {
14123                time(&last_timeout_warning);
14124                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
14125                 }
14126             }
14127          }
14128       }
14129       if (myrpt->p.remoteinacttimeout && myrpt->last_activity_time)
14130       { 
14131          time_t r;
14132 
14133          r = (t - myrpt->last_activity_time);
14134          if (r >= myrpt->p.remoteinacttimeout)
14135          {
14136             saynode(myrpt,chan,myrpt->name);
14137             ast_safe_sleep(chan,1000);
14138             break;
14139          }
14140          if ((myrpt->p.remotetimeoutwarning) && 
14141              (r >= (myrpt->p.remoteinacttimeout -
14142             myrpt->p.remotetimeoutwarning)) &&
14143                 (r <= (myrpt->p.remoteinacttimeout - 
14144                   myrpt->p.remotetimeoutwarningfreq)))
14145          {
14146             if (myrpt->p.remotetimeoutwarningfreq)
14147             {
14148                 if ((t - last_timeout_warning) >=
14149                myrpt->p.remotetimeoutwarningfreq)
14150                 {
14151                time(&last_timeout_warning);
14152                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
14153                 }
14154             }
14155             else
14156             {
14157                 if (!last_timeout_warning)
14158                 {
14159                time(&last_timeout_warning);
14160                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
14161                 }
14162             }
14163          }
14164       }
14165       ms = MSWAIT;
14166       who = ast_waitfor_n(cs,n,&ms);
14167       if (who == NULL) ms = 0;
14168       elap = MSWAIT - ms;
14169       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
14170       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
14171       if (!ms) continue;
14172       /* do local dtmf timer */
14173       if (myrpt->dtmf_local_timer)
14174       {
14175          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
14176          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
14177       }
14178       rpt_mutex_lock(&myrpt->lock);
14179       do_dtmf_local(myrpt,0);
14180       rpt_mutex_unlock(&myrpt->lock);
14181       //
14182       rem_totx =  myrpt->dtmf_local_timer && (!phone_mode);
14183       rem_totx |= keyed && (!myrpt->tunerequest);
14184       rem_rx = (remkeyed && (!setting)) || (myrpt->tele.next != &myrpt->tele);
14185       if(!strcmp(myrpt->remoterig, remote_rig_ic706))
14186          rem_totx |= myrpt->tunerequest;
14187       //
14188        if((debug > 6) && rem_totx) {
14189          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);
14190       }
14191       if (keyed && (!keyed1))
14192       {
14193          keyed1 = 1;
14194       }
14195 
14196       if (!keyed && (keyed1))
14197       {
14198          time_t myt;
14199 
14200          keyed1 = 0;
14201          time(&myt);
14202          /* if login necessary, and not too soon */
14203          if ((myrpt->p.authlevel) && 
14204              (!myrpt->loginlevel[0]) &&
14205             (myt > (t + 3)))
14206          {
14207             authreq = 1;
14208             authtold = 0;
14209             myrpt->authtelltimer = AUTHTELLTIME - AUTHTXTIME;
14210          }
14211       }
14212 
14213       if (rem_rx && (!myrpt->remoterx))
14214       {
14215          myrpt->remoterx = 1;
14216          ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14217       }
14218       if ((!rem_rx) && (myrpt->remoterx))
14219       {
14220          myrpt->remoterx = 0;
14221          ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
14222       }
14223       /* if auth requested, and not authed yet */
14224       if (authreq && (!myrpt->loginlevel[0]))
14225       {
14226          if ((!authtold) && ((myrpt->authtelltimer += elap)
14227              >= AUTHTELLTIME))
14228          {
14229             authtold = 1;
14230             rpt_telemetry(myrpt,LOGINREQ,NULL);
14231          }
14232          if ((myrpt->authtimer += elap) >= AUTHLOGOUTTIME)
14233          {
14234             break; /* if not logged in, hang up after a time */
14235          }
14236       }
14237       if (myrpt->newkey)
14238       {
14239          if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
14240          {
14241             myrpt->retxtimer = 0;
14242             if ((myrpt->remoterx) && (!myrpt->remotetx))
14243                ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14244             else
14245                ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
14246          }
14247 
14248          if ((myrpt->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 2))
14249          {
14250             keyed = 0;
14251             myrpt->rerxtimer = 0;
14252          }
14253       }
14254       if (rem_totx && (!myrpt->remotetx))
14255       {
14256          /* if not authed, and needed, do not transmit */
14257          if ((!myrpt->p.authlevel) || myrpt->loginlevel[0])
14258          {
14259             if(debug > 6)
14260                ast_log(LOG_NOTICE,"Handle rem_totx=%i.  dtmf_local_timer=%i  tunerequest=%i\n",rem_totx,myrpt->dtmf_local_timer,myrpt->tunerequest);
14261 
14262             myrpt->remotetx = 1;
14263             /* asdf maw ??? is this really what you want? Doesn't it always get executed? */
14264             if((myrpt->remtxfreqok = check_tx_freq(myrpt)))
14265             {
14266                time(&myrpt->last_activity_time);
14267                if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14268                {
14269                   z.radpar = DAHDI_RADPAR_UIODATA;
14270                   z.data = 1;
14271                   if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14272                   {
14273                      ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14274                      return -1;
14275                   }
14276                }
14277                else
14278                {
14279                   ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
14280                }
14281                if (myrpt->p.archivedir) donodelog(myrpt,"TXKEY");
14282             }
14283          }
14284       }
14285       if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
14286       {
14287          myrpt->remotetx = 0;
14288          if(!myrpt->remtxfreqok){
14289             rpt_telemetry(myrpt,UNAUTHTX,NULL);
14290          }
14291          if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14292          {
14293             z.radpar = DAHDI_RADPAR_UIODATA;
14294             z.data = 3;
14295             if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14296             {
14297                ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14298                return -1;
14299             }
14300          }
14301          else
14302          {
14303             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
14304          }
14305          if (myrpt->p.archivedir) donodelog(myrpt,"TXUNKEY");
14306       }
14307       if (myrpt->hfscanmode){
14308          myrpt->scantimer -= elap;
14309          if(myrpt->scantimer <= 0){
14310             if (!reming)
14311             {
14312                myrpt->scantimer = REM_SCANTIME;
14313                rpt_telemetry(myrpt,SCAN,0);
14314             } else myrpt->scantimer = 1;
14315          }
14316       }
14317       rpt_mutex_lock(&myrpt->lock);
14318       c = myrpt->macrobuf[0];
14319       if (c && (!myrpt->macrotimer))
14320       {
14321          myrpt->macrotimer = MACROTIME;
14322          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
14323          if ((c == 'p') || (c == 'P'))
14324             myrpt->macrotimer = MACROPTIME;
14325          rpt_mutex_unlock(&myrpt->lock);
14326          if (myrpt->p.archivedir)
14327          {
14328             char str[100];
14329                sprintf(str,"DTMF(M),%c",c);
14330             donodelog(myrpt,str);
14331          }
14332          if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
14333          continue;
14334       } else rpt_mutex_unlock(&myrpt->lock);
14335       if (who == chan) /* if it was a read from incomming */
14336       {
14337          f = ast_read(chan);
14338          if (!f)
14339          {
14340             if (debug) printf("@@@@ link:Hung Up\n");
14341             break;
14342          }
14343          if (f->frametype == AST_FRAME_VOICE)
14344          {
14345             if (ioctl(chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
14346             {
14347                ismuted = 0;
14348             }
14349             /* if not transmitting, zero-out audio */
14350             ismuted |= (!myrpt->remotetx);
14351             if (dtmfed && phone_mode) ismuted = 1;
14352             dtmfed = 0;
14353             if (ismuted)
14354             {
14355                memset(f->data.ptr,0,f->datalen);
14356                if (myrpt->lastf1)
14357                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14358                if (myrpt->lastf2)
14359                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14360             } 
14361             if (f) f2 = ast_frdup(f);
14362             else f2 = NULL;
14363             f1 = myrpt->lastf2;
14364             myrpt->lastf2 = myrpt->lastf1;
14365             myrpt->lastf1 = f2;
14366             if (ismuted)
14367             {
14368                if (myrpt->lastf1)
14369                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14370                if (myrpt->lastf2)
14371                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14372             }
14373             if (f1)
14374             {
14375                if (phone_mode)
14376                   ast_write(myrpt->txchannel,f1);
14377                else
14378                   ast_write(myrpt->txchannel,f);
14379                ast_frfree(f1);
14380             }
14381          }
14382 #ifndef  OLD_ASTERISK
14383          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
14384          {
14385             if (myrpt->lastf1)
14386                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14387             if (myrpt->lastf2)
14388                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14389             dtmfed = 1;
14390          }
14391 #endif
14392          if (f->frametype == AST_FRAME_DTMF)
14393          {
14394             if (myrpt->lastf1)
14395                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14396             if (myrpt->lastf2)
14397                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14398             dtmfed = 1;
14399             if (handle_remote_phone_dtmf(myrpt,f->subclass,&keyed,phone_mode) == -1)
14400             {
14401                if (debug) printf("@@@@ rpt:Hung Up\n");
14402                ast_frfree(f);
14403                break;
14404             }
14405          }
14406          if (f->frametype == AST_FRAME_TEXT)
14407          {
14408             if (handle_remote_data(myrpt,f->data.ptr) == -1)
14409             {
14410                if (debug) printf("@@@@ rpt:Hung Up\n");
14411                ast_frfree(f);
14412                break;
14413             }
14414          }
14415          if (f->frametype == AST_FRAME_CONTROL)
14416          {
14417             if (f->subclass == AST_CONTROL_HANGUP)
14418             {
14419                if (debug) printf("@@@@ rpt:Hung Up\n");
14420                ast_frfree(f);
14421                break;
14422             }
14423             /* if RX key */
14424             if (f->subclass == AST_CONTROL_RADIO_KEY)
14425             {
14426                if (debug == 7) printf("@@@@ rx key\n");
14427                keyed = 1;
14428                myrpt->rerxtimer = 0;
14429             }
14430             /* if RX un-key */
14431             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
14432             {
14433                myrpt->rerxtimer = 0;
14434                if (debug == 7) printf("@@@@ rx un-key\n");
14435                keyed = 0;
14436             }
14437          }
14438          ast_frfree(f);
14439          continue;
14440       }
14441       if (who == myrpt->rxchannel) /* if it was a read from radio */
14442       {
14443          f = ast_read(myrpt->rxchannel);
14444          if (!f)
14445          {
14446             if (debug) printf("@@@@ link:Hung Up\n");
14447             break;
14448          }
14449          if (f->frametype == AST_FRAME_VOICE)
14450          {
14451             int myreming = 0;
14452 
14453             if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
14454                myreming = reming;
14455 
14456             if (myreming || (!remkeyed) ||
14457             ((myrpt->remote) && (myrpt->remotetx)) ||
14458               ((myrpt->remmode != REM_MODE_FM) &&
14459                 notremming))
14460                memset(f->data.ptr,0,f->datalen); 
14461              ast_write(myrpt->pchannel,f);
14462          }
14463          else if (f->frametype == AST_FRAME_CONTROL)
14464          {
14465             if (f->subclass == AST_CONTROL_HANGUP)
14466             {
14467                if (debug) printf("@@@@ rpt:Hung Up\n");
14468                ast_frfree(f);
14469                break;
14470             }
14471             /* if RX key */
14472             if (f->subclass == AST_CONTROL_RADIO_KEY)
14473             {
14474                if (debug == 7) printf("@@@@ remote rx key\n");
14475                if (!myrpt->remotetx)
14476                {
14477                   remkeyed = 1;
14478                }
14479             }
14480             /* if RX un-key */
14481             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
14482             {
14483                if (debug == 7) printf("@@@@ remote rx un-key\n");
14484                if (!myrpt->remotetx) 
14485                {
14486                   remkeyed = 0;
14487                }
14488             }
14489          }
14490          ast_frfree(f);
14491          continue;
14492       }
14493       if (who == myrpt->pchannel) /* if is remote mix output */
14494       {
14495          f = ast_read(myrpt->pchannel);
14496          if (!f)
14497          {
14498             if (debug) printf("@@@@ link:Hung Up\n");
14499             break;
14500          }
14501          if (f->frametype == AST_FRAME_VOICE)
14502          {
14503             ast_write(chan,f);
14504          }
14505          if (f->frametype == AST_FRAME_CONTROL)
14506          {
14507             if (f->subclass == AST_CONTROL_HANGUP)
14508             {
14509                if (debug) printf("@@@@ rpt:Hung Up\n");
14510                ast_frfree(f);
14511                break;
14512             }
14513          }
14514          ast_frfree(f);
14515          continue;
14516       }
14517       if ((myrpt->rxchannel != myrpt->txchannel) && 
14518          (who == myrpt->txchannel)) /* do this cuz you have to */
14519       {
14520          f = ast_read(myrpt->txchannel);
14521          if (!f)
14522          {
14523             if (debug) printf("@@@@ link:Hung Up\n");
14524             break;
14525          }
14526          if (f->frametype == AST_FRAME_CONTROL)
14527          {
14528             if (f->subclass == AST_CONTROL_HANGUP)
14529             {
14530                if (debug) printf("@@@@ rpt:Hung Up\n");
14531                ast_frfree(f);
14532                break;
14533             }
14534          }
14535          ast_frfree(f);
14536          continue;
14537       }
14538    }
14539    if (myrpt->p.archivedir)
14540    {
14541       char mycmd[100],*b,*b1;
14542 
14543       /* look at callerid to see what node this comes from */
14544       if (!chan->cid.cid_num) /* if doesn't have caller id */
14545       {
14546          b1 = "0";
14547       } else {
14548          ast_callerid_parse(chan->cid.cid_num,&b,&b1);
14549          ast_shrink_phone_number(b1);
14550       }
14551       sprintf(mycmd,"DISCONNECT,%s",b1);
14552       donodelog(myrpt,mycmd);
14553    }
14554    /* wait for telem to be done */
14555    while(myrpt->tele.next != &myrpt->tele) usleep(100000);
14556    sprintf(tmp,"mixmonitor stop %s",chan->name);
14557    ast_cli_command(nullfd,tmp);
14558    close(nullfd);
14559    rpt_mutex_lock(&myrpt->lock);
14560    myrpt->hfscanmode = 0;
14561    myrpt->hfscanstatus = 0;
14562    myrpt->remoteon = 0;
14563    rpt_mutex_unlock(&myrpt->lock);
14564    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
14565    myrpt->lastf1 = NULL;
14566    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
14567    myrpt->lastf2 = NULL;
14568    if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14569    {
14570       z.radpar = DAHDI_RADPAR_UIOMODE;
14571       z.data = 3;
14572       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14573       {
14574          ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
14575          return -1;
14576       }
14577       z.radpar = DAHDI_RADPAR_UIODATA;
14578       z.data = 3;
14579       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14580       {
14581          ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14582          return -1;
14583       }
14584       i = DAHDI_OFFHOOK;
14585       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i) == -1)
14586       {
14587          ast_log(LOG_ERROR,"Cannot set hook\n");
14588          return -1;
14589       }
14590    }
14591    if (myrpt->iofd) close(myrpt->iofd);
14592    myrpt->iofd = -1;
14593    ast_hangup(myrpt->pchannel);
14594    if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
14595    ast_hangup(myrpt->rxchannel);
14596    closerem(myrpt);
14597    if (myrpt->p.rptnode)
14598    {
14599       rpt_mutex_lock(&myrpt->lock);
14600       for(i = 0; i < nrpts; i++)
14601       {
14602          if (!strcasecmp(rpt_vars[i].name,myrpt->p.rptnode))
14603          {
14604             rpt_vars[i].xlink = 0;
14605             break;
14606          }
14607       }
14608       rpt_mutex_unlock(&myrpt->lock);
14609    }
14610 #ifdef   OLD_ASTERISK
14611    LOCAL_USER_REMOVE(u);
14612 #endif
14613    return res;
14614 }
14615 
14616 #ifndef OLD_ASTERISK
14617 /*!\brief callback to display list of locally configured nodes
14618    \addtogroup Group_AMI
14619  */
14620 static int manager_rpt_local_nodes(struct mansession *s, const struct message *m)
14621 {
14622     int i;
14623     astman_append(s, "<?xml version=\"1.0\"?>\r\n");
14624     astman_append(s, "<nodes>\r\n");
14625     for (i=0; i< nrpts; i++)
14626     {
14627         astman_append(s, "  <node>%s</node>\r\n", rpt_vars[i].name);        
14628     } /* for i */
14629     astman_append(s, "</nodes>\r\n");
14630     astman_append(s, "\r\n"); /* Properly terminate Manager output */
14631     return RESULT_SUCCESS;
14632 } /* manager_rpt_local_nodes() */
14633 
14634 
14635 
14636 /*
14637  * Append Success and ActionID to manager response message
14638  */
14639 
14640 static void rpt_manager_success(struct mansession *s, const struct message *m)
14641 {
14642    const char *id = astman_get_header(m, "ActionID");
14643    if (!ast_strlen_zero(id))
14644       astman_append(s, "ActionID: %s\r\n", id);
14645    astman_append(s, "Response: Success\r\n");
14646 }
14647 
14648 /*
14649 * Dump statistics to manager session
14650 */
14651 
14652 static int rpt_manager_do_stats(struct mansession *s, const struct message *m, char *str)
14653 {
14654    int i,j,numoflinks;
14655    int dailytxtime, dailykerchunks;
14656    time_t now;
14657    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
14658    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
14659    long long totaltxtime;
14660    struct   rpt_link *l;
14661    char *listoflinks[MAX_STAT_LINKS];  
14662    char *lastdtmfcommand,*parrot_ena;
14663    char *tot_state, *ider_state, *patch_state;
14664    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
14665    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
14666    char *transmitterkeyed;
14667    const char *node = astman_get_header(m, "Node");
14668    struct rpt *myrpt;
14669 
14670    static char *not_applicable = "N/A";
14671 
14672    tot_state = ider_state = 
14673    patch_state = reverse_patch_state = 
14674    input_signal = not_applicable;
14675    called_number = lastdtmfcommand = transmitterkeyed = NULL;
14676 
14677    time(&now);
14678    for(i = 0; i < nrpts; i++)
14679    {
14680       if ((node)&&(!strcmp(node,rpt_vars[i].name))){
14681          rpt_manager_success(s,m);
14682 
14683          myrpt = &rpt_vars[i];
14684 
14685          if(myrpt->remote){ /* Remote base ? */
14686             char *loginuser, *loginlevel, *freq, *rxpl, *txpl, *modestr;
14687             char offset = 0, powerlevel = 0, rxplon = 0, txplon = 0, remoteon, remmode = 0, reportfmstuff;
14688             char offsetc,powerlevelc;
14689 
14690             loginuser = loginlevel = freq = rxpl = txpl = NULL;
14691             /* Make a copy of all stat variables while locked */
14692             rpt_mutex_lock(&myrpt->lock); /* LOCK */
14693             if((remoteon = myrpt->remoteon)){
14694                if(!ast_strlen_zero(myrpt->loginuser))
14695                   loginuser = ast_strdup(myrpt->loginuser);
14696                if(!ast_strlen_zero(myrpt->loginlevel))
14697                   loginlevel = ast_strdup(myrpt->loginlevel);
14698                if(!ast_strlen_zero(myrpt->freq))
14699                   freq = ast_strdup(myrpt->freq);
14700                if(!ast_strlen_zero(myrpt->rxpl))
14701                   rxpl = ast_strdup(myrpt->rxpl);
14702                if(!ast_strlen_zero(myrpt->txpl))
14703                   txpl = ast_strdup(myrpt->txpl);
14704                remmode = myrpt->remmode;
14705                offset = myrpt->offset;
14706                powerlevel = myrpt->powerlevel;
14707                rxplon = myrpt->rxplon;
14708                txplon = myrpt->txplon;       
14709             }
14710             rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
14711             astman_append(s, "IsRemoteBase: YES\r\n");
14712             astman_append(s, "RemoteOn: %s\r\n",(remoteon) ? "YES": "NO");
14713             if(remoteon){
14714                if(loginuser){
14715                   astman_append(s, "LogInUser: %s\r\n", loginuser);
14716                   ast_free(loginuser);
14717                }
14718                if(loginlevel){
14719                   astman_append(s, "LogInLevel: %s\r\n", loginlevel);
14720                   ast_free(loginlevel);
14721                }
14722                if(freq){
14723                   astman_append(s, "Freq: %s\r\n", freq);
14724                   ast_free(freq);
14725                }
14726                reportfmstuff = 0;
14727                switch(remmode){
14728                   case REM_MODE_FM:
14729                      modestr = "FM";   
14730                      reportfmstuff = 1;
14731                      break;
14732                   case REM_MODE_AM:
14733                      modestr = "AM";
14734                      break;
14735                   case REM_MODE_USB:
14736                      modestr = "USB";
14737                      break;
14738                   default:
14739                      modestr = "LSB";
14740                      break;
14741                }
14742                astman_append(s, "RemMode: %s\r\n", modestr);
14743                if(reportfmstuff){
14744                   switch(offset){
14745                      case REM_SIMPLEX:
14746                         offsetc = 'S';
14747                         break;
14748                      case REM_MINUS:
14749                         offsetc = '-';
14750                         break;
14751                      default:
14752                         offsetc = '+';
14753                         break;
14754                   }
14755                   astman_append(s, "RemOffset: %c\r\n", offsetc);
14756                   if(rxplon && rxpl){
14757                      astman_append(s, "RxPl: %s\r\n",rxpl);
14758                      ast_free(rxpl);
14759                   }
14760                   if(txplon && txpl){
14761                      astman_append(s, "TxPl: %s\r\n",txpl);
14762                      ast_free(txpl);
14763                   }
14764                }
14765                switch(powerlevel){
14766                   case REM_LOWPWR:
14767                      powerlevelc = 'L';
14768                      break;
14769                   case REM_MEDPWR:
14770                      powerlevelc = 'M';
14771                      break;
14772                   default:
14773                      powerlevelc = 'H';
14774                      break;
14775                }
14776                astman_append(s,"PowerLevel: %c\r\n", powerlevelc);
14777             }
14778             astman_append(s, "\r\n");
14779             return 0; /* End of remote base status reporting */
14780          }  
14781 
14782          /* ELSE Process as a repeater node */
14783          /* Make a copy of all stat variables while locked */
14784          rpt_mutex_lock(&myrpt->lock); /* LOCK */
14785          dailytxtime = myrpt->dailytxtime;
14786          totaltxtime = myrpt->totaltxtime;
14787          dailykeyups = myrpt->dailykeyups;
14788          totalkeyups = myrpt->totalkeyups;
14789          dailykerchunks = myrpt->dailykerchunks;
14790          totalkerchunks = myrpt->totalkerchunks;
14791          dailyexecdcommands = myrpt->dailyexecdcommands;
14792          totalexecdcommands = myrpt->totalexecdcommands;
14793          timeouts = myrpt->timeouts;
14794 
14795 
14796          /* Traverse the list of connected nodes */
14797          reverse_patch_state = "DOWN";
14798          numoflinks = 0;
14799          l = myrpt->links.next;
14800          while(l && (l != &myrpt->links)){
14801             if(numoflinks >= MAX_STAT_LINKS){
14802                ast_log(LOG_NOTICE,
14803                "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
14804                break;
14805             }
14806             if (l->name[0] == '0'){ /* Skip '0' nodes */
14807                reverse_patch_state = "UP";
14808                l = l->next;
14809                continue;
14810             }
14811             listoflinks[numoflinks] = ast_strdup(l->name);
14812             if(listoflinks[numoflinks] == NULL){
14813                break;
14814             }
14815             else{
14816                numoflinks++;
14817             }
14818             l = l->next;
14819          }
14820 
14821          if(myrpt->keyed)
14822             input_signal = "YES";
14823          else
14824             input_signal = "NO";
14825          
14826          if(myrpt->txkeyed)
14827             transmitterkeyed = "YES";
14828          else
14829             transmitterkeyed = "NO";
14830 
14831          if(myrpt->p.parrotmode)
14832             parrot_ena = "ENABLED";
14833          else
14834             parrot_ena = "DISABLED";
14835 
14836          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
14837             sys_ena = "DISABLED";
14838          else
14839             sys_ena = "ENABLED";
14840 
14841          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
14842             tot_ena = "DISABLED";
14843          else
14844             tot_ena = "ENABLED";
14845 
14846          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
14847             link_ena = "DISABLED";
14848          else
14849             link_ena = "ENABLED";
14850 
14851          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
14852             patch_ena = "DISABLED";
14853          else
14854             patch_ena = "ENABLED";
14855 
14856          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
14857             sch_ena = "DISABLED";
14858          else
14859             sch_ena = "ENABLED";
14860 
14861          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
14862             user_funs = "DISABLED";
14863          else
14864             user_funs = "ENABLED";
14865 
14866          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
14867             tail_type = "ALTERNATE";
14868          else
14869             tail_type = "STANDARD";
14870 
14871          if(!myrpt->totimer)
14872             tot_state = "TIMED OUT!";
14873          else if(myrpt->totimer != myrpt->p.totime)
14874             tot_state = "ARMED";
14875          else
14876             tot_state = "RESET";
14877 
14878          if(myrpt->tailid)
14879             ider_state = "QUEUED IN TAIL";
14880          else if(myrpt->mustid)
14881             ider_state = "QUEUED FOR CLEANUP";
14882          else
14883             ider_state = "CLEAN";
14884 
14885          switch(myrpt->callmode){
14886             case 1:
14887                patch_state = "DIALING";
14888                break;
14889             case 2:
14890                patch_state = "CONNECTING";
14891                break;
14892             case 3:
14893                patch_state = "UP";
14894                break;
14895 
14896             case 4:
14897                patch_state = "CALL FAILED";
14898                break;
14899 
14900             default:
14901                patch_state = "DOWN";
14902          }
14903 
14904          if(strlen(myrpt->exten)){
14905             called_number = ast_strdup(myrpt->exten);
14906          }
14907 
14908          if(strlen(myrpt->lastdtmfcommand)){
14909             lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
14910          }
14911          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
14912 
14913          astman_append(s, "IsRemoteBase: NO\r\n");
14914          astman_append(s, "NodeState: %d\r\n", myrpt->p.sysstate_cur);
14915          astman_append(s, "SignalOnInput: %s\r\n", input_signal);
14916          astman_append(s, "TransmitterKeyed: %s\r\n", transmitterkeyed);
14917          astman_append(s, "Transmitter: %s\r\n", sys_ena);
14918          astman_append(s, "Parrot: %s\r\n", parrot_ena);
14919          astman_append(s, "Scheduler: %s\r\n", sch_ena);
14920          astman_append(s, "TailLength: %s\r\n", tail_type);
14921          astman_append(s, "TimeOutTimer: %s\r\n", tot_ena);
14922          astman_append(s, "TimeOutTimerState: %s\r\n", tot_state);
14923          astman_append(s, "TimeOutsSinceSystemInitialization: %d\r\n", timeouts);
14924          astman_append(s, "IdentifierState: %s\r\n", ider_state);
14925          astman_append(s, "KerchunksToday: %d\r\n", dailykerchunks);
14926          astman_append(s, "KerchunksSinceSystemInitialization: %d\r\n", totalkerchunks);
14927          astman_append(s, "KeyupsToday: %d\r\n", dailykeyups);
14928          astman_append(s, "KeyupsSinceSystemInitialization: %d\r\n", totalkeyups);
14929          astman_append(s, "DtmfCommandsToday: %d\r\n", dailyexecdcommands);
14930          astman_append(s, "DtmfCommandsSinceSystemInitialization: %d\r\n", totalexecdcommands);
14931          astman_append(s, "LastDtmfCommandExecuted: %s\r\n", 
14932          (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
14933          hours = dailytxtime/3600000;
14934          dailytxtime %= 3600000;
14935          minutes = dailytxtime/60000;
14936          dailytxtime %= 60000;
14937          seconds = dailytxtime/1000;
14938          dailytxtime %= 1000;
14939 
14940          astman_append(s, "TxTimeToday: %02d:%02d:%02d.%d\r\n",
14941             hours, minutes, seconds, dailytxtime);
14942 
14943          hours = (int) totaltxtime/3600000;
14944          totaltxtime %= 3600000;
14945          minutes = (int) totaltxtime/60000;
14946          totaltxtime %= 60000;
14947          seconds = (int)  totaltxtime/1000;
14948          totaltxtime %= 1000;
14949 
14950          astman_append(s, "TxTimeSinceSystemInitialization: %02d:%02d:%02d.%d\r\n",
14951              hours, minutes, seconds, (int) totaltxtime);
14952 
14953          sprintf(str, "NodesCurrentlyConnectedToUs: ");
14954                         if(!numoflinks){
14955                          strcat(str,"<NONE>");
14956                         }
14957          else{
14958             for(j = 0 ;j < numoflinks; j++){
14959                sprintf(str+strlen(str), "%s", listoflinks[j]);
14960                if(j < numoflinks - 1)
14961                   strcat(str,",");
14962             }
14963          }
14964          astman_append(s,"%s\r\n", str);
14965 
14966          astman_append(s, "Autopatch: %s\r\n", patch_ena);
14967          astman_append(s, "AutopatchState: %s\r\n", patch_state);
14968          astman_append(s, "AutopatchCalledNumber: %s\r\n",
14969          (called_number && strlen(called_number)) ? called_number : not_applicable);
14970          astman_append(s, "ReversePatchIaxrptConnected: %s\r\n", reverse_patch_state);
14971          astman_append(s, "UserLinkingCommands: %s\r\n", link_ena);
14972          astman_append(s, "UserFunctions: %s\r\n", user_funs);
14973 
14974          for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
14975             ast_free(listoflinks[j]);
14976          }
14977          if(called_number){
14978             ast_free(called_number);
14979          }
14980          if(lastdtmfcommand){
14981             ast_free(lastdtmfcommand);
14982          }
14983          astman_append(s, "\r\n"); /* We're Done! */
14984               return 0;
14985       }
14986    }
14987    astman_send_error(s, m, "RptStatus unknown or missing node");
14988    return -1;
14989 }
14990 
14991 
14992 
14993 /*
14994  * Implement the RptStatus Manager Interface
14995  */
14996 
14997 static int manager_rpt_status(struct mansession *s, const struct message *m)
14998 {
14999    int i,res,len,idx;
15000    int uptime,hours,minutes;
15001    time_t now;
15002    const char *cmd = astman_get_header(m, "Command");
15003    char *str;
15004    enum {MGRCMD_RPTSTAT,MGRCMD_NODESTAT};
15005    struct mgrcmdtbl{
15006       const char *cmd;
15007       int index;
15008    };
15009    static struct mgrcmdtbl mct[] = {
15010       {"RptStat",MGRCMD_RPTSTAT},
15011       {"NodeStat",MGRCMD_NODESTAT},
15012       {NULL,0} /* NULL marks end of command table */
15013    };
15014 
15015    time(&now);
15016 
15017    len = 1024; /* Allocate a working buffer */
15018    if(!(str = ast_malloc(len)))
15019       return -1;
15020 
15021    /* Check for Command */
15022    if(ast_strlen_zero(cmd)){
15023       astman_send_error(s, m, "RptStatus missing command");
15024       ast_free(str);
15025       return 0;
15026    }
15027    /* Try to find the command in the table */
15028    for(i = 0 ; mct[i].cmd ; i++){
15029       if(!strcmp(mct[i].cmd, cmd))
15030          break;
15031    }
15032 
15033    if(!mct[i].cmd){ /* Found or not found ? */
15034       astman_send_error(s, m, "RptStatus unknown command");
15035       ast_free(str);
15036       return 0;
15037    }
15038    else
15039       idx = mct[i].index;
15040 
15041    switch(idx){ /* Use the index to go to the correct command */
15042 
15043       case MGRCMD_RPTSTAT:
15044          /* Return Nodes: and a comma separated list of nodes */
15045          if((res = snprintf(str, len, "Nodes: ")) > -1)
15046             len -= res;
15047          else{
15048             ast_free(str);
15049             return 0;
15050          }
15051          for(i = 0; i < nrpts; i++){
15052             if(i < nrpts - 1){
15053                if((res = snprintf(str+strlen(str), len, "%s,",rpt_vars[i].name)) < 0){
15054                   ast_free(str);
15055                   return 0;
15056                }
15057             }
15058             else{
15059                if((res = snprintf(str+strlen(str), len, "%s",rpt_vars[i].name)) < 0){
15060                   ast_free(str);
15061                   return 0;
15062                }
15063             }
15064             len -= res;
15065          }
15066 
15067          rpt_manager_success(s,m);
15068          
15069          if(!nrpts)
15070             astman_append(s, "<NONE>\r\n");
15071          else
15072             astman_append(s, "%s\r\n", str);
15073 
15074          uptime = (int)(now - starttime);
15075                         hours = uptime/3600;
15076                         uptime %= 3600;
15077                         minutes = uptime/60;
15078                         uptime %= 60;
15079 
15080                         astman_append(s, "RptUptime: %02d:%02d:%02d\r\n",
15081                                 hours, minutes, uptime);
15082 
15083          astman_append(s, "\r\n");
15084          break;      
15085 
15086       case  MGRCMD_NODESTAT:
15087          res = rpt_manager_do_stats(s,m,str);
15088          ast_free(str);
15089          return res;
15090 
15091       default:
15092          astman_send_error(s, m, "RptStatus invalid command");
15093          break;
15094    }
15095    ast_free(str);
15096    return 0;
15097 }
15098 
15099 #endif
15100 
15101 #ifdef   OLD_ASTERISK
15102 int unload_module()
15103 #else
15104 static int unload_module(void)
15105 #endif
15106 {
15107    int i, res;
15108 
15109 #ifdef   OLD_ASTERISK
15110    STANDARD_HANGUP_LOCALUSERS;
15111 #endif
15112    for(i = 0; i < nrpts; i++) {
15113       if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
15114                 ast_mutex_destroy(&rpt_vars[i].lock);
15115                 ast_mutex_destroy(&rpt_vars[i].remlock);
15116    }
15117    res = ast_unregister_application(app);
15118 
15119 #ifdef   NEW_ASTERISK
15120    ast_cli_unregister_multiple(rpt_cli, ARRAY_LEN(rpt_cli));
15121 #else
15122    /* Unregister cli extensions */
15123    ast_cli_unregister(&cli_debug);
15124    ast_cli_unregister(&cli_dump);
15125    ast_cli_unregister(&cli_stats);
15126    ast_cli_unregister(&cli_lstats);
15127    ast_cli_unregister(&cli_nodes);
15128    ast_cli_unregister(&cli_local_nodes);
15129    ast_cli_unregister(&cli_reload);
15130    ast_cli_unregister(&cli_restart);
15131    ast_cli_unregister(&cli_fun);
15132    ast_cli_unregister(&cli_fun1);
15133    res |= ast_cli_unregister(&cli_cmd);
15134 #endif
15135 #ifndef OLD_ASTERISK
15136    res |= ast_manager_unregister("RptLocalNodes");
15137    res |= ast_manager_unregister("RptStatus");
15138 #endif
15139    return res;
15140 }
15141 
15142 #ifdef   OLD_ASTERISK
15143 int load_module()
15144 #else
15145 static int load_module(void)
15146 #endif
15147 {
15148    int res;
15149    ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
15150 
15151 #ifdef   NEW_ASTERISK
15152    ast_cli_register_multiple(rpt_cli, ARRAY_LEN(rpt_cli));
15153    res = 0;
15154 #else
15155    /* Register cli extensions */
15156    ast_cli_register(&cli_debug);
15157    ast_cli_register(&cli_dump);
15158    ast_cli_register(&cli_stats);
15159    ast_cli_register(&cli_lstats);
15160    ast_cli_register(&cli_nodes);
15161    ast_cli_register(&cli_local_nodes);
15162    ast_cli_register(&cli_reload);
15163    ast_cli_register(&cli_restart);
15164    ast_cli_register(&cli_fun);
15165    ast_cli_register(&cli_fun1);
15166    res = ast_cli_register(&cli_cmd);
15167 #endif
15168 #ifndef OLD_ASTERISK
15169    res |= ast_manager_register("RptLocalNodes", 0, manager_rpt_local_nodes, "List local node numbers");
15170    res |= ast_manager_register("RptStatus", 0, manager_rpt_status, "Return Rpt Status for CGI");
15171 
15172 #endif
15173    res |= ast_register_application(app, rpt_exec, synopsis, descrip);
15174    return res;
15175 }
15176 
15177 #ifdef   OLD_ASTERISK
15178 char *description()
15179 {
15180    return tdesc;
15181 }
15182 int usecount(void)
15183 {
15184    int res;
15185    STANDARD_USECOUNT(res);
15186    return res;
15187 }
15188 
15189 char *key()
15190 {
15191    return ASTERISK_GPL_KEY;
15192 }
15193 #endif
15194 
15195 #ifdef   OLD_ASTERISK
15196 int reload()
15197 #else
15198 static int reload(void)
15199 #endif
15200 {
15201 int   n;
15202 
15203    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
15204    return(0);
15205 }
15206 
15207 
15208 #ifndef  OLD_ASTERISK
15209 /* STD_MOD(MOD_1, reload, NULL, NULL); */
15210 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application",
15211       .load = load_module,
15212       .unload = unload_module,
15213       .reload = reload,
15214           );
15215 #endif
15216