Mon Jun 27 16:50:47 2011

Asterisk developer's documentation


app_rpt.c

Go to the documentation of this file.
00001 #define  NEW_ASTERISK
00002 /* #define OLD_ASTERISK */
00003 /*
00004  * Asterisk -- An open source telephony toolkit.
00005  *
00006  * Copyright (C) 2002-2008, Jim Dixon, WB6NIL
00007  *
00008  * Jim Dixon, WB6NIL <jim@lambdatel.com>
00009  * Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
00010  *
00011  * See http://www.asterisk.org for more information about
00012  * the Asterisk project. Please do not directly contact
00013  * any of the maintainers of this project for assistance;
00014  * the project provides a web site, mailing lists and IRC
00015  * channels for your use.
00016  *
00017  * This program is free software, distributed under the terms of
00018  * the GNU General Public License Version 2. See the LICENSE file
00019  * at the top of the source tree.
00020  */
00021 /*! \file
00022  *
00023  * \brief Radio Repeater / Remote Base program 
00024  *  version 0.115 5/12/08 2055 EDT
00025  * 
00026  * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
00027  *
00028  * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
00029  * \note Steven Henke, W9SH, <w9sh@arrl.net> added a few features here and there.
00030  *
00031  * See http://www.zapatatelephony.org/app_rpt.html
00032  *
00033  *
00034  * Repeater / Remote Functions:
00035  * "Simple" Mode:  * - autopatch access, # - autopatch hangup
00036  * Normal mode:
00037  * See the function list in rpt.conf (autopatchup, autopatchdn)
00038  * autopatchup can optionally take comma delimited setting=value pairs:
00039  *  
00040  *
00041  * context=string    :  Override default context with "string"
00042  * dialtime=ms       :  Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
00043  * farenddisconnect=1      :  Automatically disconnect when called party hangs up
00044  * noct=1         :  Don't send repeater courtesy tone during autopatch calls
00045  * quiet=1        :  Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
00046  *
00047  *
00048  * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
00049  *
00050  *  To send an asterisk (*) while dialing or talking on phone,
00051  *  use the autopatch acess code.
00052  *
00053  *
00054  * status cmds:
00055  *
00056  *  1 - Force ID (global)
00057  *  2 - Give Time of Day (global)
00058  *  3 - Give software Version (global)
00059  *  11 - Force ID (local only)
00060  *  12 - Give Time of Day (local only)
00061  *
00062  * cop (control operator) cmds:
00063  *
00064  *  1 - System warm boot
00065  *  2 - System enable
00066  *  3 - System disable
00067  *  4 - Test Tone On/Off
00068  *  5 - Dump System Variables on Console (debug)
00069  *  6 - PTT (phone mode only)
00070  *  7 - Time out timer enable
00071  *  8 - Time out timer disable
00072  *  9 - Autopatch enable
00073  *  10 - Autopatch disable
00074  *  11 - Link enable
00075  *  12 - Link disable
00076  *  13 - Query System State
00077  *  14 - Change System State
00078  *  15 - Scheduler Enable
00079  *  16 - Scheduler Disable
00080  *  17 - User functions (time, id, etc) enable
00081  *  18 - User functions (time, id, etc) disable
00082  *  19 - Select alternate hang timer
00083  *  20 - Select standard hang timer 
00084  *  21 - Enable Parrot Mode
00085  *  22 - Disable Parrot Mode
00086  *  23 - Birdbath (Current Parrot Cleanup/Flush)
00087  *  24 - Flush all telemetry
00088  *  25 - Query last node un-keyed
00089  *  26 - Query all nodes keyed/unkeyed
00090  *  30 - Recall Memory Setting in Attached Xcvr
00091  *  31 - Channel Selector for Parallel Programmed Xcvr
00092  *  32 - Touchtone pad test: command + Digit string + # to playback all digits pressed
00093  *
00094  * ilink cmds:
00095  *
00096  *  1 - Disconnect specified link
00097  *  2 - Connect specified link -- monitor only
00098  *  3 - Connect specified link -- tranceive
00099  *  4 - Enter command mode on specified link
00100  *  5 - System status
00101  *  6 - Disconnect all links
00102  *  11 - Disconnect a previously permanently connected link
00103  *  12 - Permanently connect specified link -- monitor only
00104  *  13 - Permanently connect specified link -- tranceive
00105  *  15 - Full system status (all nodes)
00106  *  16 - Reconnect links disconnected with "disconnect all links"
00107  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
00108  *
00109  * remote cmds:
00110  *
00111  *  1 - Recall Memory MM  (*000-*099) (Gets memory from rpt.conf)
00112  *  2 - Set VFO MMMMM*KKK*O   (Mhz digits, Khz digits, Offset)
00113  *  3 - Set Rx PL Tone HHH*D*
00114  *  4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
00115  *  5 - Link Status (long)
00116  *  6 - Set operating mode M (FM, USB, LSB, AM, etc)
00117  *  100 - RX PL off (Default)
00118  *  101 - RX PL On
00119  *  102 - TX PL Off (Default)
00120  *  103 - TX PL On
00121  *  104 - Low Power
00122  *  105 - Med Power
00123  *  106 - Hi Power
00124  *  107 - Bump Down 20 Hz
00125  *  108 - Bump Down 100 Hz
00126  *  109 - Bump Down 500 Hz
00127  *  110 - Bump Up 20 Hz
00128  *  111 - Bump Up 100 Hz
00129  *  112 - Bump Up 500 Hz
00130  *  113 - Scan Down Slow
00131  *  114 - Scan Down Medium
00132  *  115 - Scan Down Fast
00133  *  116 - Scan Up Slow
00134  *  117 - Scan Up Medium
00135  *  118 - Scan Up Fast
00136  *  119 - Transmit allowing auto-tune
00137  *  140 - Link Status (brief)
00138  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
00139  *
00140  * playback cmds:
00141  *  specify the name of the file to be played (for example, 25=rpt/foo)
00142  *
00143  *
00144  * 'duplex' modes:  (defaults to duplex=2)
00145  *
00146  * 0 - Only remote links key Tx and no main repeat audio.
00147  * 1 - Everything other then main Rx keys Tx, no main repeat audio.
00148  * 2 - Normal mode
00149  * 3 - Normal except no main repeat audio.
00150  * 4 - Normal except no main repeat audio during autopatch only
00151  *
00152 */
00153 
00154 /*** MODULEINFO
00155    <depend>dahdi</depend>
00156    <depend>tonezone</depend>
00157    <defaultenabled>no</defaultenabled>
00158  ***/
00159 
00160 /* Un-comment the following to include support for MDC-1200 digital tone
00161    signalling protocol (using KA6SQG's GPL'ed implementation) */
00162 /* #include "mdc_decode.c" */
00163 
00164 /* Un-comment the following to include support for notch filters in the
00165    rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
00166 /* #include "rpt_notch.c" */
00167 
00168 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
00169 
00170 #ifdef OLD_ASTERISK
00171 #define ast_free free
00172 #define ast_malloc malloc
00173 #define ast_strdup strdup
00174 #endif
00175 
00176 
00177 #define  MAXDTMF 32
00178 #define  MAXMACRO 2048
00179 #define  MAXLINKLIST 512
00180 #define  LINKLISTTIME 10000
00181 #define  LINKLISTSHORTTIME 200
00182 #define  LINKPOSTTIME 30000
00183 #define  LINKPOSTSHORTTIME 200
00184 #define  KEYPOSTTIME 30000
00185 #define  KEYPOSTSHORTTIME 200
00186 #define  MACROTIME 100
00187 #define  MACROPTIME 500
00188 #define  DTMF_TIMEOUT 3
00189 #define  KENWOOD_RETRIES 5
00190 #define  TOPKEYN 32
00191 #define  TOPKEYWAIT 3
00192 #define  TOPKEYMAXSTR 30
00193 
00194 #define  AUTHTELLTIME 7000
00195 #define  AUTHTXTIME 1000
00196 #define  AUTHLOGOUTTIME 25000
00197 
00198 #ifdef   __RPT_NOTCH
00199 #define  MAXFILTERS 10
00200 #endif
00201 
00202 #define  DISC_TIME 10000  /* report disc after 10 seconds of no connect */
00203 #define  MAX_RETRIES 5
00204 #define  MAX_RETRIES_PERM 1000000000
00205 
00206 #define  REDUNDANT_TX_TIME 2000
00207 
00208 #define  RETRY_TIMER_MS 5000
00209 
00210 #define  PATCH_DIALPLAN_TIMEOUT 1500
00211 
00212 #ifdef OLD_ASTERISK
00213 #define  START_DELAY 10
00214 #else
00215 #define  START_DELAY 2
00216 #endif
00217 
00218 #define  RPT_LOCKOUT_SECS 10
00219 
00220 #define MAXPEERSTR 31
00221 #define  MAXREMSTR 15
00222 
00223 #define  DELIMCHR ','
00224 #define  QUOTECHR 34
00225 
00226 #define  MONITOR_DISK_BLOCKS_PER_MINUTE 38
00227 
00228 #define  DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000
00229 #define  DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60)
00230 #define  DEFAULT_REMOTE_TIMEOUT (60 * 60)
00231 #define  DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60)
00232 #define  DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30
00233 
00234 #define  NODES "nodes"
00235 #define  EXTNODES "extnodes"
00236 #define MEMORY "memory"
00237 #define MACRO "macro"
00238 #define  FUNCTIONS "functions"
00239 #define TELEMETRY "telemetry"
00240 #define MORSE "morse"
00241 #define  TONEMACRO "tonemacro"
00242 #define  FUNCCHAR '*'
00243 #define  ENDCHAR '#'
00244 #define  EXTNODEFILE "/var/lib/asterisk/rpt_extnodes"
00245 #define  NODENAMES "rpt/nodenames"
00246 #define  PARROTFILE "/tmp/parrot_%s_%u"
00247 
00248 #define  PARROTTIME 1000
00249 
00250 #define  DEFAULT_IOBASE 0x378
00251 
00252 #define  DEFAULT_CIV_ADDR 0x58
00253 
00254 #define  MAXCONNECTTIME 5000
00255 
00256 #define MAXNODESTR 300
00257 
00258 #define MAXNODELEN 16
00259 
00260 #define MAXIDENTLEN 32
00261 
00262 #define MAXPATCHCONTEXT 100
00263 
00264 #define ACTIONSIZE 32
00265 
00266 #define TELEPARAMSIZE 256
00267 
00268 #define REM_SCANTIME 100
00269 
00270 #define  DTMF_LOCAL_TIME 250
00271 #define  DTMF_LOCAL_STARTTIME 500
00272 
00273 #define  IC706_PL_MEMORY_OFFSET 50
00274 
00275 #define  VOX_ON_DEBOUNCE_COUNT 3
00276 #define  VOX_OFF_DEBOUNCE_COUNT 20
00277 #define  VOX_MAX_THRESHOLD 10000.0
00278 #define  VOX_MIN_THRESHOLD 3000.0
00279 #define  VOX_TIMEOUT_MS 5000
00280 #define  VOX_RECOVER_MS 500
00281 #define  SIMPLEX_PATCH_DELAY 25
00282 #define  SIMPLEX_PHONE_DELAY 25
00283 
00284 #define  STATPOST_PROGRAM "/usr/bin/wget,-q,--output-document=/dev/null,--no-check-certificate"
00285 
00286 #define  ALLOW_LOCAL_CHANNELS
00287 
00288 enum {REM_OFF,REM_MONITOR,REM_TX};
00289 
00290 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
00291    CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME, PLAYBACK,
00292    STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
00293    TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS,
00294    MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS,
00295    REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE, TOPKEY,
00296    TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX, PARROT,
00297    STATS_TIME_LOCAL};
00298 
00299 
00300 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
00301 
00302 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
00303 
00304 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY};
00305 
00306 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE, SOURCE_ALT};
00307 
00308 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY, DLY_PARROT};
00309 
00310 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
00311 
00312 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
00313       HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
00314 
00315 #include "asterisk.h"
00316 
00317 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 276347 $")
00318 
00319 #include <signal.h>
00320 #include <stdio.h>
00321 #include <stdint.h>
00322 #include <unistd.h>
00323 #include <string.h>
00324 #include <stdlib.h>
00325 #include <search.h>
00326 #include <sys/types.h>
00327 #include <sys/stat.h>
00328 #include <errno.h>
00329 #include <dirent.h>
00330 #include <ctype.h>
00331 #include <sys/stat.h>
00332 #include <sys/time.h>
00333 #include <sys/file.h>
00334 #include <sys/ioctl.h>
00335 #ifdef HAVE_SYS_IO_H
00336 #include <sys/io.h>
00337 #endif
00338 #include <sys/vfs.h>
00339 #include <math.h>
00340 #include <dahdi/user.h>
00341 #include <dahdi/tonezone.h>
00342 #include <netinet/in.h>
00343 #include <arpa/inet.h>
00344 
00345 #include "asterisk/utils.h"
00346 #include "asterisk/lock.h"
00347 #include "asterisk/file.h"
00348 #include "asterisk/logger.h"
00349 #include "asterisk/channel.h"
00350 #include "asterisk/callerid.h"
00351 #include "asterisk/pbx.h"
00352 #include "asterisk/module.h"
00353 #include "asterisk/translate.h"
00354 #include "asterisk/features.h"
00355 #include "asterisk/options.h"
00356 #include "asterisk/cli.h"
00357 #include "asterisk/config.h"
00358 #include "asterisk/say.h"
00359 #include "asterisk/localtime.h"
00360 #include "asterisk/cdr.h"
00361 #include "asterisk/options.h"
00362 #include "asterisk/manager.h"
00363 #include "asterisk/app.h"
00364 
00365 #include <termios.h>
00366 
00367 #ifdef   NEW_ASTERISK
00368 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
00369 #endif
00370 
00371 
00372 /* Start a tone-list going */
00373 int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
00374 /*! Stop the tones from playing */
00375 void ast_playtones_stop(struct ast_channel *chan);
00376 
00377 static  char *tdesc = "Radio Repeater / Remote Base  version 0.115  5/12/2008";
00378 
00379 static char *app = "Rpt";
00380 
00381 static char *synopsis = "Radio Repeater/Remote Base Control System";
00382 
00383 static char *descrip = 
00384 "  Rpt(nodename[|options][|M][|*]):  \n"
00385 "    Radio Remote Link or Remote Base Link Endpoint Process.\n"
00386 "\n"
00387 "    Not specifying an option puts it in normal endpoint mode (where source\n"
00388 "    IP and nodename are verified).\n"
00389 "\n"
00390 "    Options are as follows:\n"
00391 "\n"
00392 "        X - Normal endpoint mode WITHOUT security check. Only specify\n"
00393 "            this if you have checked security already (like with an IAX2\n"
00394 "            user/password or something).\n"
00395 "\n"
00396 "        Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
00397 "            Reverse Autopatch. Caller is put on hold, and announcement (as\n"
00398 "            specified by the 'announce-string') is played on radio system.\n"
00399 "            Users of radio system can access autopatch, dial specified\n"
00400 "            code, and pick up call. Announce-string is list of names of\n"
00401 "            recordings, or \"PARKED\" to substitute code for un-parking,\n"
00402 "            or \"NODE\" to substitute node number.\n"
00403 "\n"
00404 "        P - Phone Control mode. This allows a regular phone user to have\n"
00405 "            full control and audio access to the radio system. For the\n"
00406 "            user to have DTMF control, the 'phone_functions' parameter\n"
00407 "            must be specified for the node in 'rpt.conf'. An additional\n"
00408 "            function (cop,6) must be listed so that PTT control is available.\n"
00409 "\n"
00410 "        D - Dumb Phone Control mode. This allows a regular phone user to\n"
00411 "            have full control and audio access to the radio system. In this\n"
00412 "            mode, the PTT is activated for the entire length of the call.\n"
00413 "            For the user to have DTMF control (not generally recomended in\n"
00414 "            this mode), the 'dphone_functions' parameter must be specified\n"
00415 "            for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
00416 "            available to the phone user.\n"
00417 "\n"
00418 "        S - Simplex Dumb Phone Control mode. This allows a regular phone user\n"
00419 "            audio-only access to the radio system. In this mode, the\n"
00420 "            transmitter is toggled on and off when the phone user presses the\n"
00421 "            funcchar (*) key on the telephone set. In addition, the transmitter\n"
00422 "            will turn off if the endchar (#) key is pressed. When a user first\n"
00423 "            calls in, the transmitter will be off, and the user can listen for\n"
00424 "            radio traffic. When the user wants to transmit, they press the *\n" 
00425 "            key, start talking, then press the * key again or the # key to turn\n"
00426 "            the transmitter off.  No other functions can be executed by the\n"
00427 "            user on the phone when this mode is selected. Note: If your\n"
00428 "            radio system is full-duplex, we recommend using either P or D\n"
00429 "            modes as they provide more flexibility.\n"
00430 "\n"
00431 "        q - Query Status. Sets channel variables and returns + 101 in plan.\n"
00432 "\n"
00433 "        M - Memory Channel Steer as MXX where XX is the memory channel number.\n"
00434 "\n"
00435 "        * - Alt Macro to execute (e.g. *7 for status)\n"
00436 "\n";
00437 ;
00438 
00439 static int debug = 0;  /* Set this >0 for extra debug output */
00440 static int nrpts = 0;
00441 
00442 static const char remdtmfstr[] = "0123456789*#ABCD";
00443 
00444 enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
00445 
00446 int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
00447 
00448 #define NRPTSTAT 7
00449 
00450 struct rpt_chan_stat
00451 {
00452    struct timeval last;
00453    long long total;
00454    unsigned long count;
00455    unsigned long largest;
00456    struct timeval largest_time;
00457 };
00458 
00459 char *discstr = "!!DISCONNECT!!";
00460 char *newkeystr = "!NEWKEY!";
00461 static char *remote_rig_ft897="ft897";
00462 static char *remote_rig_rbi="rbi";
00463 static char *remote_rig_kenwood="kenwood";
00464 static char *remote_rig_tm271="tm271";
00465 static char *remote_rig_ic706="ic706";
00466 static char *remote_rig_rtx150="rtx150";
00467 static char *remote_rig_rtx450="rtx450";
00468 static char *remote_rig_ppp16="ppp16";       // parallel port programmable 16 channels
00469 
00470 #define ISRIG_RTX(x) ((!strcmp(x,remote_rig_rtx150)) || (!strcmp(x,remote_rig_rtx450)))
00471 #define  IS_XPMR(x) (!strncasecmp(x->rxchanname,"rad",3))
00472 
00473 #ifdef   OLD_ASTERISK
00474 STANDARD_LOCAL_USER;
00475 LOCAL_USER_DECL;
00476 #endif
00477 
00478 #define  MSWAIT 200
00479 #define  HANGTIME 5000
00480 #define  TOTIME 180000
00481 #define  IDTIME 300000
00482 #define  MAXRPTS 20
00483 #define MAX_STAT_LINKS 32
00484 #define POLITEID 30000
00485 #define FUNCTDELAY 1500
00486 
00487 #define  MAXXLAT 20
00488 #define  MAXXLATTIME 3
00489 
00490 #define MAX_SYSSTATES 10
00491 
00492 struct vox {
00493    float speech_energy;
00494    float noise_energy;
00495    int   enacount;
00496    char  voxena;
00497    char  lastvox;
00498    int   offdebcnt;
00499    int   ondebcnt;
00500 } ;
00501 
00502 #define  mymax(x,y) ((x > y) ? x : y)
00503 #define  mymin(x,y) ((x < y) ? x : y)
00504 
00505 struct rpt_topkey
00506 {
00507 char  node[TOPKEYMAXSTR];
00508 int   timesince;
00509 int   keyed;
00510 } ;
00511 
00512 struct rpt_xlat
00513 {
00514 char  funccharseq[MAXXLAT];
00515 char  endcharseq[MAXXLAT];
00516 char  passchars[MAXXLAT];
00517 int   funcindex;
00518 int   endindex;
00519 time_t   lastone;
00520 } ;
00521 
00522 static time_t  starttime = 0;
00523 
00524 static  pthread_t rpt_master_thread;
00525 
00526 struct rpt;
00527 
00528 struct rpt_link
00529 {
00530    struct rpt_link *next;
00531    struct rpt_link *prev;
00532    char  mode;       /* 1 if in tx mode */
00533    char  isremote;
00534    char  phonemode;
00535    char  phonevox;      /* vox the phone */
00536    char  name[MAXNODESTR]; /* identifier (routing) string */
00537    char  lasttx;
00538    char  lasttx1;
00539    char  lastrx;
00540    char  lastrealrx;
00541    char  lastrx1;
00542    char  connected;
00543    char  hasconnected;
00544    char  perma;
00545    char  thisconnected;
00546    char  outbound;
00547    char  disced;
00548    char  killme;
00549    long  elaptime;
00550    long  disctime;
00551    long  retrytimer;
00552    long  retxtimer;
00553    long  rerxtimer;
00554    int   retries;
00555    int   max_retries;
00556    int   reconnects;
00557    long long connecttime;
00558    struct ast_channel *chan;  
00559    struct ast_channel *pchan; 
00560    char  linklist[MAXLINKLIST];
00561    time_t   linklistreceived;
00562    long  linklisttimer;
00563    int   dtmfed;
00564    int linkunkeytocttimer;
00565    struct timeval lastlinktv;
00566    struct   ast_frame *lastf1,*lastf2;
00567    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00568    struct vox vox;
00569    char wasvox;
00570    int voxtotimer;
00571    char voxtostate;
00572    char newkey;
00573 #ifdef OLD_ASTERISK
00574         AST_LIST_HEAD(, ast_frame) rxq;
00575 #else
00576    AST_LIST_HEAD_NOLOCK(, ast_frame) rxq;
00577 #endif
00578 } ;
00579 
00580 struct rpt_lstat
00581 {
00582    struct   rpt_lstat *next;
00583    struct   rpt_lstat *prev;
00584    char  peer[MAXPEERSTR];
00585    char  name[MAXNODESTR];
00586    char  mode;
00587    char  outbound;
00588    char  reconnects;
00589    char  thisconnected;
00590    long long   connecttime;
00591    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00592 } ;
00593 
00594 struct rpt_tele
00595 {
00596    struct rpt_tele *next;
00597    struct rpt_tele *prev;
00598    struct rpt *rpt;
00599    struct ast_channel *chan;
00600    int   mode;
00601    struct rpt_link mylink;
00602    char param[TELEPARAMSIZE];
00603    intptr_t submode;
00604    uintptr_t  parrot;
00605    pthread_t threadid;
00606 } ;
00607 
00608 struct function_table_tag
00609 {
00610    char action[ACTIONSIZE];
00611    int (*function)(struct rpt *myrpt, char *param, char *digitbuf, 
00612       int command_source, struct rpt_link *mylink);
00613 } ;
00614 
00615 /* Used to store the morse code patterns */
00616 
00617 struct morse_bits
00618 {       
00619    int len;
00620    int ddcomb;
00621 } ;
00622 
00623 struct telem_defaults
00624 {
00625    char name[20];
00626    char value[80];
00627 } ;
00628 
00629 
00630 struct sysstate
00631 {
00632    char txdisable;
00633    char totdisable;
00634    char linkfundisable;
00635    char autopatchdisable;
00636    char schedulerdisable;
00637    char userfundisable;
00638    char alternatetail;
00639 };
00640 
00641 /* rpt cmd support */
00642 #define CMD_DEPTH 1
00643 #define CMD_STATE_IDLE 0
00644 #define CMD_STATE_BUSY 1
00645 #define CMD_STATE_READY 2
00646 #define CMD_STATE_EXECUTING 3
00647 
00648 struct rpt_cmd_struct
00649 {
00650     int state;
00651     int functionNumber;
00652     char param[MAXDTMF];
00653     char digits[MAXDTMF];
00654     int command_source;
00655 };
00656 
00657 static struct rpt
00658 {
00659    ast_mutex_t lock;
00660    ast_mutex_t remlock;
00661    ast_mutex_t statpost_lock;
00662    struct ast_config *cfg;
00663    char reload;
00664    char xlink;                         // cross link state of a share repeater/remote radio
00665    unsigned int statpost_seqno;
00666 
00667    char *name;
00668    char *rxchanname;
00669    char *txchanname;
00670    char remote;
00671    char *remoterig;
00672    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00673    unsigned int scram;
00674 
00675    struct {
00676       char *ourcontext;
00677       char *ourcallerid;
00678       char *acctcode;
00679       char *ident;
00680       char *tonezone;
00681       char simple;
00682       char *functions;
00683       char *link_functions;
00684       char *phone_functions;
00685       char *dphone_functions;
00686       char *alt_functions;
00687       char *nodes;
00688       char *extnodes;
00689       char *extnodefile;
00690       int hangtime;
00691       int althangtime;
00692       int totime;
00693       int idtime;
00694       int tailmessagetime;
00695       int tailsquashedtime;
00696       int duplex;
00697       int politeid;
00698       char *tailmessages[500];
00699       int tailmessagemax;
00700       char  *memory;
00701       char  *macro;
00702       char  *tonemacro;
00703       char  *startupmacro;
00704       int iobase;
00705       char *ioport;
00706       char funcchar;
00707       char endchar;
00708       char nobusyout;
00709       char notelemtx;
00710       char propagate_dtmf;
00711       char propagate_phonedtmf;
00712       char linktolink;
00713       unsigned char civaddr;
00714       struct rpt_xlat inxlat;
00715       struct rpt_xlat outxlat;
00716       char *archivedir;
00717       int authlevel;
00718       char *csstanzaname;
00719       char *skedstanzaname;
00720       char *txlimitsstanzaname;
00721       long monminblocks;
00722       int remoteinacttimeout;
00723       int remotetimeout;
00724       int remotetimeoutwarning;
00725       int remotetimeoutwarningfreq;
00726       int sysstate_cur;
00727       struct sysstate s[MAX_SYSSTATES];
00728       char parrotmode;
00729       int parrottime;
00730       char *rptnode;
00731       char remote_mars;
00732       int voxtimeout_ms;
00733       int voxrecover_ms;
00734       int simplexpatchdelay;
00735       int simplexphonedelay;
00736       char *statpost_program;
00737       char *statpost_url;
00738    } p;
00739    struct rpt_link links;
00740    int unkeytocttimer;
00741    time_t lastkeyedtime;
00742    time_t lasttxkeyedtime;
00743    char keyed;
00744    char txkeyed;
00745    char exttx;
00746    char localtx;
00747    char remoterx;
00748    char remotetx;
00749    char remoteon;
00750    char remtxfreqok;
00751    char tounkeyed;
00752    char tonotify;
00753    char dtmfbuf[MAXDTMF];
00754    char macrobuf[MAXMACRO];
00755    char rem_dtmfbuf[MAXDTMF];
00756    char lastdtmfcommand[MAXDTMF];
00757    char cmdnode[50];
00758    char nowchan;                 // channel now
00759    char waschan;                 // channel selected initially or by command
00760    char bargechan;                  // barge in channel
00761    char macropatch;              // autopatch via tonemacro state
00762    char parrotstate;
00763    int  parrottimer;
00764    unsigned int parrotcnt;
00765    struct ast_channel *rxchannel,*txchannel, *monchannel, *parrotchannel;
00766    struct ast_channel *pchannel,*txpchannel, *dahdirxchannel, *dahditxchannel;
00767    struct ast_channel *voxchannel;
00768    struct ast_frame *lastf1,*lastf2;
00769    struct rpt_tele tele;
00770    struct timeval lasttv,curtv;
00771    pthread_t rpt_call_thread,rpt_thread;
00772    time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
00773    int calldigittimer;
00774    int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
00775    int mustid,tailid;
00776    int tailevent;
00777    int telemrefcount;
00778    int dtmfidx,rem_dtmfidx;
00779    int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
00780    int totalexecdcommands, dailyexecdcommands;
00781    long  retxtimer;
00782    long  rerxtimer;
00783    long long totaltxtime;
00784    char mydtmf;
00785    char exten[AST_MAX_EXTENSION];
00786    char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
00787    char offset;
00788    char powerlevel;
00789    char txplon;
00790    char rxplon;
00791    char remmode;
00792    char tunerequest;
00793    char hfscanmode;
00794    int hfscanstatus;
00795    char hfscanstop;
00796    char lastlinknode[MAXNODESTR];
00797    char savednodes[MAXNODESTR];
00798    int stopgen;
00799    char patchfarenddisconnect;
00800    char patchnoct;
00801    char patchquiet;
00802    char patchcontext[MAXPATCHCONTEXT];
00803    int patchdialtime;
00804    int macro_longest;
00805    int phone_longestfunc;
00806    int alt_longestfunc;
00807    int dphone_longestfunc;
00808    int link_longestfunc;
00809    int longestfunc;
00810    int longestnode;
00811    int threadrestarts;     
00812    int tailmessagen;
00813    time_t disgorgetime;
00814    time_t lastthreadrestarttime;
00815    long  macrotimer;
00816    char  lastnodewhichkeyedusup[MAXNODESTR];
00817    int   dtmf_local_timer;
00818    char  dtmf_local_str[100];
00819    struct ast_filestream *monstream,*parrotstream;
00820    char  loginuser[50];
00821    char  loginlevel[10];
00822    long  authtelltimer;
00823    long  authtimer;
00824    int iofd;
00825    time_t start_time,last_activity_time;
00826    char  lasttone[32];
00827    struct rpt_tele *active_telem;
00828    struct   rpt_topkey topkey[TOPKEYN];
00829    int topkeystate;
00830    time_t topkeytime;
00831    int topkeylong;
00832    struct vox vox;
00833    char wasvox;
00834    int voxtotimer;
00835    char voxtostate;
00836    int linkposttimer;         
00837    int keyposttimer;       
00838    char newkey;
00839    char inpadtest;
00840 #ifdef OLD_ASTERISK
00841    AST_LIST_HEAD(, ast_frame) txq;
00842 #else
00843    AST_LIST_HEAD_NOLOCK(, ast_frame) txq;
00844 #endif
00845    char txrealkeyed;
00846 #ifdef   __RPT_NOTCH
00847    struct rptfilter
00848    {
00849       char  desc[100];
00850       float x0;
00851       float x1;
00852       float x2;
00853       float y0;
00854       float y1;
00855       float y2;
00856       float gain;
00857       float const0;
00858       float const1;
00859       float const2;
00860    } filters[MAXFILTERS];
00861 #endif
00862 #ifdef   _MDC_DECODE_H_
00863    mdc_decoder_t *mdc;
00864    unsigned short lastunit;
00865 #endif
00866    struct rpt_cmd_struct cmdAction;
00867 } rpt_vars[MAXRPTS]; 
00868 
00869 struct nodelog {
00870 struct nodelog *next;
00871 struct nodelog *prev;
00872 time_t   timestamp;
00873 char archivedir[MAXNODESTR];
00874 char str[MAXNODESTR * 2];
00875 } nodelog;
00876 
00877 static int service_scan(struct rpt *myrpt);
00878 static int set_mode_ft897(struct rpt *myrpt, char newmode);
00879 static int set_mode_ic706(struct rpt *myrpt, char newmode);
00880 static int simple_command_ft897(struct rpt *myrpt, char command);
00881 static int setrem(struct rpt *myrpt);
00882 static int setrtx_check(struct rpt *myrpt);
00883 static int channel_revert(struct rpt *myrpt);
00884 static int channel_steer(struct rpt *myrpt, char *data);
00885 
00886 AST_MUTEX_DEFINE_STATIC(nodeloglock);
00887 
00888 AST_MUTEX_DEFINE_STATIC(nodelookuplock);
00889 
00890 #ifdef   APP_RPT_LOCK_DEBUG
00891 
00892 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
00893 
00894 #define  MAXLOCKTHREAD 100
00895 
00896 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
00897 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
00898 
00899 struct lockthread
00900 {
00901    pthread_t id;
00902    int lockcount;
00903    int lastlock;
00904    int lastunlock;
00905 } lockthreads[MAXLOCKTHREAD];
00906 
00907 
00908 struct by_lightning
00909 {
00910    int line;
00911    struct timeval tv;
00912    struct rpt *rpt;
00913    struct lockthread lockthread;
00914 } lock_ring[32];
00915 
00916 int lock_ring_index = 0;
00917 
00918 AST_MUTEX_DEFINE_STATIC(locklock);
00919 
00920 static struct lockthread *get_lockthread(pthread_t id)
00921 {
00922 int   i;
00923 
00924    for(i = 0; i < MAXLOCKTHREAD; i++)
00925    {
00926       if (lockthreads[i].id == id) return(&lockthreads[i]);
00927    }
00928    return(NULL);
00929 }
00930 
00931 static struct lockthread *put_lockthread(pthread_t id)
00932 {
00933 int   i;
00934 
00935    for(i = 0; i < MAXLOCKTHREAD; i++)
00936    {
00937       if (lockthreads[i].id == id)
00938          return(&lockthreads[i]);
00939    }
00940    for(i = 0; i < MAXLOCKTHREAD; i++)
00941    {
00942       if (!lockthreads[i].id)
00943       {
00944          lockthreads[i].lockcount = 0;
00945          lockthreads[i].lastlock = 0;
00946          lockthreads[i].lastunlock = 0;
00947          lockthreads[i].id = id;
00948          return(&lockthreads[i]);
00949       }
00950    }
00951    return(NULL);
00952 }
00953 
00954 
00955 static void rpt_mutex_spew(void)
00956 {
00957    struct by_lightning lock_ring_copy[32];
00958    int lock_ring_index_copy;
00959    int i,j;
00960    long long diff;
00961    char a[100];
00962    struct timeval lasttv;
00963 
00964    ast_mutex_lock(&locklock);
00965    memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
00966    lock_ring_index_copy = lock_ring_index;
00967    ast_mutex_unlock(&locklock);
00968 
00969    lasttv.tv_sec = lasttv.tv_usec = 0;
00970    for(i = 0 ; i < 32 ; i++)
00971    {
00972       j = (i + lock_ring_index_copy) % 32;
00973       strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
00974          localtime(&lock_ring_copy[j].tv.tv_sec));
00975       diff = 0;
00976       if(lasttv.tv_sec)
00977       {
00978          diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
00979             * 1000000;
00980          diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
00981       }
00982       lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
00983       lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
00984       if (!lock_ring_copy[j].tv.tv_sec) continue;
00985       if (lock_ring_copy[j].line < 0)
00986       {
00987          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00988             i - 31,-lock_ring_copy[j].line,lock_ring_copy[j].rpt->name,(int) lock_ring_copy[j].lockthread.id,diff,a,(int)lock_ring_copy[j].tv.tv_usec);
00989       }
00990       else
00991       {
00992          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00993             i - 31,lock_ring_copy[j].line,lock_ring_copy[j].rpt->name,(int) lock_ring_copy[j].lockthread.id,diff,a,(int)lock_ring_copy[j].tv.tv_usec);
00994       }
00995    }
00996 }
00997 
00998 
00999 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
01000 {
01001 struct lockthread *t;
01002 pthread_t id;
01003 
01004    id = pthread_self();
01005    ast_mutex_lock(&locklock);
01006    t = put_lockthread(id);
01007    if (!t)
01008    {
01009       ast_mutex_unlock(&locklock);
01010       return;
01011    }
01012    if (t->lockcount)
01013    {
01014       int lastline = t->lastlock;
01015       ast_mutex_unlock(&locklock);
01016       ast_log(LOG_NOTICE,"rpt_mutex_lock: Double lock request line %d node %s pid %x, last lock was line %d\n",line,myrpt->name,(int) t->id,lastline);
01017       rpt_mutex_spew();
01018       return;
01019    }
01020    t->lastlock = line;
01021    t->lockcount = 1;
01022    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
01023    lock_ring[lock_ring_index].rpt = myrpt;
01024    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
01025    lock_ring[lock_ring_index++].line = line;
01026    if(lock_ring_index == 32)
01027       lock_ring_index = 0;
01028    ast_mutex_unlock(&locklock);
01029    ast_mutex_lock(lockp);
01030 }
01031 
01032 
01033 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
01034 {
01035 struct lockthread *t;
01036 pthread_t id;
01037 
01038    id = pthread_self();
01039    ast_mutex_lock(&locklock);
01040    t = put_lockthread(id);
01041    if (!t)
01042    {
01043       ast_mutex_unlock(&locklock);
01044       return;
01045    }
01046    if (!t->lockcount)
01047    {
01048       int lastline = t->lastunlock;
01049       ast_mutex_unlock(&locklock);
01050       ast_log(LOG_NOTICE,"rpt_mutex_lock: Double un-lock request line %d node %s pid %x, last un-lock was line %d\n",line,myrpt->name,(int) t->id,lastline);
01051       rpt_mutex_spew();
01052       return;
01053    }
01054    t->lastunlock = line;
01055    t->lockcount = 0;
01056    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
01057    lock_ring[lock_ring_index].rpt = myrpt;
01058    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
01059    lock_ring[lock_ring_index++].line = -line;
01060    if(lock_ring_index == 32)
01061       lock_ring_index = 0;
01062    ast_mutex_unlock(&locklock);
01063    ast_mutex_unlock(lockp);
01064 }
01065 
01066 #else  /* APP_RPT_LOCK_DEBUG */
01067 
01068 #define rpt_mutex_lock(x) ast_mutex_lock(x)
01069 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
01070 
01071 #endif  /* APP_RPT_LOCK_DEBUG */
01072 
01073 /*
01074 * Return 1 if rig is multimode capable
01075 */
01076 
01077 static int multimode_capable(struct rpt *myrpt)
01078 {
01079    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
01080       return 1;
01081    if(!strcmp(myrpt->remoterig, remote_rig_ic706))
01082       return 1;
01083    return 0;
01084 }  
01085 
01086 static void voxinit_rpt(struct rpt *myrpt,char enable)
01087 {
01088 
01089    myrpt->vox.speech_energy = 0.0;
01090    myrpt->vox.noise_energy = 0.0;
01091    myrpt->vox.enacount = 0;
01092    myrpt->vox.voxena = 0;
01093    if (!enable) myrpt->vox.voxena = -1;
01094    myrpt->vox.lastvox = 0;
01095    myrpt->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
01096    myrpt->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
01097    myrpt->wasvox = 0;
01098    myrpt->voxtotimer = 0;
01099    myrpt->voxtostate = 0;
01100 }
01101 
01102 static void voxinit_link(struct rpt_link *mylink,char enable)
01103 {
01104 
01105    mylink->vox.speech_energy = 0.0;
01106    mylink->vox.noise_energy = 0.0;
01107    mylink->vox.enacount = 0;
01108    mylink->vox.voxena = 0;
01109    if (!enable) mylink->vox.voxena = -1;
01110    mylink->vox.lastvox = 0;
01111    mylink->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
01112    mylink->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
01113    mylink->wasvox = 0;
01114    mylink->voxtotimer = 0;
01115    mylink->voxtostate = 0;
01116 }
01117 
01118 static int dovox(struct vox *v,short *buf,int bs)
01119 {
01120 
01121    int i;
01122    float esquare = 0.0;
01123    float energy = 0.0;
01124    float threshold = 0.0;
01125    
01126    if (v->voxena < 0) return(v->lastvox);
01127    for(i = 0; i < bs; i++)
01128    {
01129       esquare += (float) buf[i] * (float) buf[i];
01130    }
01131    energy = sqrt(esquare);
01132 
01133    if (energy >= v->speech_energy)
01134       v->speech_energy += (energy - v->speech_energy) / 4;
01135    else
01136       v->speech_energy += (energy - v->speech_energy) / 64;
01137 
01138    if (energy >= v->noise_energy)
01139       v->noise_energy += (energy - v->noise_energy) / 64;
01140    else
01141       v->noise_energy += (energy - v->noise_energy) / 4;
01142    
01143    if (v->voxena) threshold = v->speech_energy / 8;
01144    else
01145    {
01146       threshold = mymax(v->speech_energy / 16,v->noise_energy * 2);
01147       threshold = mymin(threshold,VOX_MAX_THRESHOLD);
01148    }
01149    threshold = mymax(threshold,VOX_MIN_THRESHOLD);
01150    if (energy > threshold)
01151    {
01152       if (v->voxena) v->noise_energy *= 0.75;
01153       v->voxena = 1;
01154    } else   v->voxena = 0;
01155    if (v->lastvox != v->voxena)
01156    {
01157       if (v->enacount++ >= ((v->lastvox) ? v->offdebcnt : v->ondebcnt))
01158       {
01159          v->lastvox = v->voxena;
01160          v->enacount = 0;
01161       }
01162    } else v->enacount = 0;
01163    return(v->lastvox);
01164 }
01165 
01166 
01167 
01168 
01169 /*
01170 * CLI extensions
01171 */
01172 
01173 /* Debug mode */
01174 static int rpt_do_debug(int fd, int argc, const char * const *argv);
01175 static int rpt_do_dump(int fd, int argc, const char * const *argv);
01176 static int rpt_do_stats(int fd, int argc, const char * const *argv);
01177 static int rpt_do_lstats(int fd, int argc, const char * const *argv);
01178 static int rpt_do_nodes(int fd, int argc, const char * const *argv);
01179 static int rpt_do_local_nodes(int fd, int argc, const char * const *argv);
01180 static int rpt_do_reload(int fd, int argc, const char * const *argv);
01181 static int rpt_do_restart(int fd, int argc, const char * const *argv);
01182 static int rpt_do_fun(int fd, int argc, const char * const *argv);
01183 static int rpt_do_fun1(int fd, int argc, const char * const *argv);
01184 static int rpt_do_cmd(int fd, int argc, const char * const *argv);
01185 
01186 static char debug_usage[] =
01187 "Usage: rpt debug level {0-7}\n"
01188 "       Enables debug messages in app_rpt\n";
01189 
01190 static char dump_usage[] =
01191 "Usage: rpt dump <nodename>\n"
01192 "       Dumps struct debug info to log\n";
01193 
01194 static char dump_stats[] =
01195 "Usage: rpt stats <nodename>\n"
01196 "       Dumps node statistics to console\n";
01197 
01198 static char dump_lstats[] =
01199 "Usage: rpt lstats <nodename>\n"
01200 "       Dumps link statistics to console\n";
01201 
01202 static char dump_nodes[] =
01203 "Usage: rpt nodes <nodename>\n"
01204 "       Dumps a list of directly and indirectly connected nodes to the console\n";
01205 
01206 static char usage_local_nodes[] =
01207 "Usage: rpt localnodes\n"
01208 "       Dumps a list of the locally configured node numbers to the console.\n";
01209 
01210 static char reload_usage[] =
01211 "Usage: rpt reload\n"
01212 "       Reloads app_rpt running config parameters\n";
01213 
01214 static char restart_usage[] =
01215 "Usage: rpt restart\n"
01216 "       Restarts app_rpt\n";
01217 
01218 static char fun_usage[] =
01219 "Usage: rpt fun <nodename> <command>\n"
01220 "       Send a DTMF function to a node\n";
01221 
01222 static char cmd_usage[] =
01223 "Usage: rpt cmd <nodename> <cmd-name> <cmd-index> <cmd-args.\n"
01224 "       Send a command to a node.\n        i.e. rpt cmd 2000 ilink 3 2001\n";
01225 
01226 #ifndef  NEW_ASTERISK
01227 
01228 static struct ast_cli_entry  cli_debug =
01229         { { "rpt", "debug", "level" }, rpt_do_debug, 
01230       "Enable app_rpt debugging", debug_usage };
01231 
01232 static struct ast_cli_entry  cli_dump =
01233         { { "rpt", "dump" }, rpt_do_dump,
01234       "Dump app_rpt structs for debugging", dump_usage };
01235 
01236 static struct ast_cli_entry  cli_stats =
01237         { { "rpt", "stats" }, rpt_do_stats,
01238       "Dump node statistics", dump_stats };
01239 
01240 static struct ast_cli_entry  cli_nodes =
01241         { { "rpt", "nodes" }, rpt_do_nodes,
01242       "Dump node list", dump_nodes };
01243 
01244 static struct ast_cli_entry  cli_local_nodes =
01245         { { "rpt", "localnodes" }, rpt_do_local_nodes,
01246       "Dump list of local node numbers", usage_local_nodes };
01247 
01248 static struct ast_cli_entry  cli_lstats =
01249         { { "rpt", "lstats" }, rpt_do_lstats,
01250       "Dump link statistics", dump_lstats };
01251 
01252 static struct ast_cli_entry  cli_reload =
01253         { { "rpt", "reload" }, rpt_do_reload,
01254       "Reload app_rpt config", reload_usage };
01255 
01256 static struct ast_cli_entry  cli_restart =
01257         { { "rpt", "restart" }, rpt_do_restart,
01258       "Restart app_rpt", restart_usage };
01259 
01260 static struct ast_cli_entry  cli_fun =
01261         { { "rpt", "fun" }, rpt_do_fun,
01262       "Execute a DTMF function", fun_usage };
01263 
01264 static struct ast_cli_entry  cli_fun1 =
01265         { { "rpt", "fun1" }, rpt_do_fun1,
01266       "Execute a DTMF function", fun_usage };
01267 
01268 static struct ast_cli_entry  cli_cmd =
01269         { { "rpt", "cmd" }, rpt_do_cmd,
01270       "Execute a DTMF function", cmd_usage };
01271 
01272 #endif
01273 
01274 /*
01275 * Telemetry defaults
01276 */
01277 
01278 
01279 static struct telem_defaults tele_defs[] = {
01280    {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
01281    {"ct2","|t(660,880,150,3072)"},
01282    {"ct3","|t(440,0,150,3072)"},
01283    {"ct4","|t(550,0,150,3072)"},
01284    {"ct5","|t(660,0,150,3072)"},
01285    {"ct6","|t(880,0,150,3072)"},
01286    {"ct7","|t(660,440,150,3072)"},
01287    {"ct8","|t(700,1100,150,3072)"},
01288    {"remotemon","|t(1600,0,75,2048)"},
01289    {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
01290    {"cmdmode","|t(900,904,200,2048)"},
01291    {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
01292 } ;
01293 
01294 /*
01295 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
01296 */
01297 
01298 static int setrbi(struct rpt *myrpt);
01299 static int set_ft897(struct rpt *myrpt);
01300 static int set_ic706(struct rpt *myrpt);
01301 static int setkenwood(struct rpt *myrpt);
01302 static int set_tm271(struct rpt *myrpt);
01303 static int setrbi_check(struct rpt *myrpt);
01304 
01305 
01306 
01307 /*
01308 * Define function protos for function table here
01309 */
01310 
01311 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01312 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01313 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01314 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01315 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01316 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01317 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01318 static int function_playback(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01319 /*
01320 * Function table
01321 */
01322 
01323 static struct function_table_tag function_table[] = {
01324    {"cop", function_cop},
01325    {"autopatchup", function_autopatchup},
01326    {"autopatchdn", function_autopatchdn},
01327    {"ilink", function_ilink},
01328    {"status", function_status},
01329    {"remote", function_remote},
01330    {"macro", function_macro},
01331    {"playback", function_playback}
01332 } ;
01333 
01334 static long diskavail(struct rpt *myrpt)
01335 {
01336 struct   statfs statfsbuf;
01337 
01338    if (!myrpt->p.archivedir) return(0);
01339    if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
01340    {
01341       ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
01342          myrpt->p.archivedir,myrpt->name);
01343       return(-1);
01344    }
01345    return(statfsbuf.f_bavail);
01346 }
01347 
01348 static void flush_telem(struct rpt *myrpt)
01349 {
01350    struct rpt_tele *telem;
01351    if(debug > 2)
01352       ast_log(LOG_NOTICE, "flush_telem()!!");
01353    rpt_mutex_lock(&myrpt->lock);
01354    telem = myrpt->tele.next;
01355    while(telem != &myrpt->tele)
01356    {
01357       if (telem->mode != SETREMOTE) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
01358       telem = telem->next;
01359    }
01360    rpt_mutex_unlock(&myrpt->lock);
01361 }
01362 /*
01363    return via error priority
01364 */
01365 static int priority_jump(struct rpt *myrpt, struct ast_channel *chan)
01366 {
01367    int res=0;
01368 
01369    // if (ast_test_flag(&flags,OPT_JUMP) && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
01370    if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
01371       res = 0;
01372    } else {
01373       res = -1;
01374    }
01375    return res;
01376 }
01377 /*
01378 */
01379 static int linkcount(struct rpt *myrpt)
01380 {
01381    struct   rpt_link *l;
01382    char *reverse_patch_state;
01383    int numoflinks;
01384 
01385    reverse_patch_state = "DOWN";
01386    numoflinks = 0;
01387    l = myrpt->links.next;
01388    while(l && (l != &myrpt->links)){
01389       if(numoflinks >= MAX_STAT_LINKS){
01390          ast_log(LOG_WARNING,
01391          "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
01392          break;
01393       }
01394       //if (l->name[0] == '0'){ /* Skip '0' nodes */
01395       // reverse_patch_state = "UP";
01396       // l = l->next;
01397       // continue;
01398       //}
01399       numoflinks++;
01400     
01401       l = l->next;
01402    }
01403    ast_log(LOG_NOTICE, "numoflinks=%i\n",numoflinks);
01404    return numoflinks;
01405 }
01406 /*
01407  * Retrieve a memory channel
01408  * Return 0 if sucessful,
01409  * -1 if channel not found,
01410  *  1 if parse error
01411  */
01412 static int retreive_memory(struct rpt *myrpt, char *memory)
01413 {
01414    char tmp[30], *s, *s1, *val;
01415 
01416    if (debug)ast_log(LOG_NOTICE, "memory=%s block=%s\n",memory,myrpt->p.memory);
01417 
01418    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, memory);
01419    if (!val){
01420       return -1;
01421    }        
01422    strncpy(tmp,val,sizeof(tmp) - 1);
01423    tmp[sizeof(tmp)-1] = 0;
01424 
01425    s = strchr(tmp,',');
01426    if (!s)
01427       return 1; 
01428    *s++ = 0;
01429    s1 = strchr(s,',');
01430    if (!s1)
01431       return 1;
01432    *s1++ = 0;
01433    strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
01434    strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
01435    strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
01436    myrpt->remmode = REM_MODE_FM;
01437    myrpt->offset = REM_SIMPLEX;
01438    myrpt->powerlevel = REM_MEDPWR;
01439    myrpt->txplon = myrpt->rxplon = 0;
01440    while(*s1){
01441       switch(*s1++){
01442          case 'A':
01443          case 'a':
01444             strcpy(myrpt->rxpl, "100.0");
01445             strcpy(myrpt->txpl, "100.0");
01446             myrpt->remmode = REM_MODE_AM; 
01447             break;
01448          case 'B':
01449          case 'b':
01450             strcpy(myrpt->rxpl, "100.0");
01451             strcpy(myrpt->txpl, "100.0");
01452             myrpt->remmode = REM_MODE_LSB;
01453             break;
01454          case 'F':
01455             myrpt->remmode = REM_MODE_FM;
01456             break;
01457          case 'L':
01458          case 'l':
01459             myrpt->powerlevel = REM_LOWPWR;
01460             break;               
01461          case 'H':
01462          case 'h':
01463             myrpt->powerlevel = REM_HIPWR;
01464             break;
01465                
01466          case 'M':
01467          case 'm':
01468             myrpt->powerlevel = REM_MEDPWR;
01469             break;
01470                   
01471          case '-':
01472             myrpt->offset = REM_MINUS;
01473             break;
01474                   
01475          case '+':
01476             myrpt->offset = REM_PLUS;
01477             break;
01478                   
01479          case 'S':
01480          case 's':
01481             myrpt->offset = REM_SIMPLEX;
01482             break;
01483                   
01484          case 'T':
01485          case 't':
01486             myrpt->txplon = 1;
01487             break;
01488                   
01489          case 'R':
01490          case 'r':
01491             myrpt->rxplon = 1;
01492             break;
01493 
01494          case 'U':
01495          case 'u':
01496             strcpy(myrpt->rxpl, "100.0");
01497             strcpy(myrpt->txpl, "100.0");
01498             myrpt->remmode = REM_MODE_USB;
01499             break;
01500          default:
01501             return 1;
01502       }
01503    }
01504    return 0;
01505 }
01506 /*
01507 
01508 */
01509 static void birdbath(struct rpt *myrpt)
01510 {
01511    struct rpt_tele *telem;
01512    if(debug > 2)
01513       ast_log(LOG_NOTICE, "birdbath!!");
01514    rpt_mutex_lock(&myrpt->lock);
01515    telem = myrpt->tele.next;
01516    while(telem != &myrpt->tele)
01517    {
01518       if (telem->mode == PARROT) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
01519       telem = telem->next;
01520    }
01521    rpt_mutex_unlock(&myrpt->lock);
01522 }
01523 
01524 static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
01525 {
01526 struct        rpt_link *l;
01527 
01528        l = myrpt->links.next;
01529        /* go thru all the links */
01530        while(l != &myrpt->links)
01531        {
01532                if (!l->phonemode)
01533                {
01534                        l = l->next;
01535                        continue;
01536                }
01537                /* don't send to self */
01538                if (mylink && (l == mylink))
01539                {
01540                        l = l->next;
01541                        continue;
01542                }
01543 #ifdef   NEW_ASTERISK
01544                if (l->chan) ast_senddigit(l->chan,c,0);
01545 #else
01546                if (l->chan) ast_senddigit(l->chan,c);
01547 #endif
01548                l = l->next;
01549        }
01550        return;
01551 }
01552 
01553 /* node logging function */
01554 static void donodelog(struct rpt *myrpt,char *str)
01555 {
01556 struct nodelog *nodep;
01557 char  datestr[100];
01558 
01559    if (!myrpt->p.archivedir) return;
01560    nodep = (struct nodelog *)ast_malloc(sizeof(struct nodelog));
01561    if (nodep == NULL)
01562    {
01563       ast_log(LOG_ERROR,"Cannot get memory for node log");
01564       return;
01565    }
01566    time(&nodep->timestamp);
01567    strncpy(nodep->archivedir,myrpt->p.archivedir,
01568       sizeof(nodep->archivedir) - 1);
01569    strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
01570       localtime(&nodep->timestamp));
01571    snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
01572       myrpt->name,datestr,str);
01573    ast_mutex_lock(&nodeloglock);
01574    insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
01575    ast_mutex_unlock(&nodeloglock);
01576 }
01577 
01578 /* must be called locked */
01579 static void do_dtmf_local(struct rpt *myrpt, char c)
01580 {
01581 int   i;
01582 char  digit;
01583 static const char* dtmf_tones[] = {
01584    "!941+1336/200,!0/200", /* 0 */
01585    "!697+1209/200,!0/200", /* 1 */
01586    "!697+1336/200,!0/200", /* 2 */
01587    "!697+1477/200,!0/200", /* 3 */
01588    "!770+1209/200,!0/200", /* 4 */
01589    "!770+1336/200,!0/200", /* 5 */
01590    "!770+1477/200,!0/200", /* 6 */
01591    "!852+1209/200,!0/200", /* 7 */
01592    "!852+1336/200,!0/200", /* 8 */
01593    "!852+1477/200,!0/200", /* 9 */
01594    "!697+1633/200,!0/200", /* A */
01595    "!770+1633/200,!0/200", /* B */
01596    "!852+1633/200,!0/200", /* C */
01597    "!941+1633/200,!0/200", /* D */
01598    "!941+1209/200,!0/200", /* * */
01599    "!941+1477/200,!0/200" };  /* # */
01600 
01601 
01602    if (c)
01603    {
01604       snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
01605       if (!myrpt->dtmf_local_timer) 
01606           myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
01607    }
01608    /* if at timeout */
01609    if (myrpt->dtmf_local_timer == 1)
01610    {
01611       if(debug > 6)
01612          ast_log(LOG_NOTICE,"time out dtmf_local_timer=%i\n",myrpt->dtmf_local_timer);
01613 
01614       /* if anything in the string */
01615       if (myrpt->dtmf_local_str[0])
01616       {
01617          digit = myrpt->dtmf_local_str[0];
01618          myrpt->dtmf_local_str[0] = 0;
01619          for(i = 1; myrpt->dtmf_local_str[i]; i++)
01620          {
01621             myrpt->dtmf_local_str[i - 1] =
01622                myrpt->dtmf_local_str[i];
01623          }
01624          myrpt->dtmf_local_str[i - 1] = 0;
01625          myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
01626          rpt_mutex_unlock(&myrpt->lock);
01627          if (digit >= '0' && digit <='9')
01628             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
01629          else if (digit >= 'A' && digit <= 'D')
01630             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
01631          else if (digit == '*')
01632             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
01633          else if (digit == '#')
01634             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
01635          else {
01636             /* not handled */
01637             ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name);
01638          }
01639          rpt_mutex_lock(&myrpt->lock);
01640       }
01641       else
01642       {
01643          myrpt->dtmf_local_timer = 0;
01644       }
01645    }
01646 }
01647 
01648 static int setdtr(int fd, int enable)
01649 {
01650 struct termios mode;
01651 
01652    if (fd < 0) return -1;
01653    if (tcgetattr(fd, &mode)) {
01654       ast_log(LOG_WARNING, "Unable to get serial parameters for dtr: %s\n", strerror(errno));
01655       return -1;
01656    }
01657    if (enable)
01658    {
01659       cfsetspeed(&mode, B9600);
01660    }
01661    else
01662    {
01663       cfsetspeed(&mode, B0);
01664       usleep(100000);
01665    }
01666    if (tcsetattr(fd, TCSADRAIN, &mode)) {
01667       ast_log(LOG_WARNING, "Unable to set serial parameters for dtr: %s\n", strerror(errno));
01668       return -1;
01669    }
01670    if (enable) usleep(100000);
01671    return 0;
01672 }
01673 
01674 static int openserial(struct rpt *myrpt,char *fname)
01675 {
01676    struct termios mode;
01677    int fd;
01678 
01679    fd = open(fname,O_RDWR);
01680    if (fd == -1)
01681    {
01682       ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
01683       return -1;
01684    }
01685    memset(&mode, 0, sizeof(mode));
01686    if (tcgetattr(fd, &mode)) {
01687       ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
01688       return -1;
01689    }
01690 #ifndef  SOLARIS
01691    cfmakeraw(&mode);
01692 #else
01693         mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
01694                         |INLCR|IGNCR|ICRNL|IXON);
01695         mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
01696         mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
01697         mode.c_cflag |= CS8;
01698    mode.c_cc[VTIME] = 3;
01699    mode.c_cc[VMIN] = 1; 
01700 #endif
01701 
01702    cfsetispeed(&mode, B9600);
01703    cfsetospeed(&mode, B9600);
01704    if (tcsetattr(fd, TCSANOW, &mode)) 
01705       ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
01706    if(!strcmp(myrpt->remoterig, remote_rig_kenwood)) setdtr(fd,0); 
01707    usleep(100000);
01708    if (debug)ast_log(LOG_NOTICE,"Opened serial port %s\n",fname);
01709    return(fd); 
01710 }
01711 
01712 static void mdc1200_notify(struct rpt *myrpt,char *fromnode, unsigned int unit)
01713 {
01714    if (!fromnode)
01715    {
01716       ast_verbose("Got MDC-1200 ID %04X from local system (%s)\n",
01717          unit,myrpt->name);
01718    }
01719    else
01720    {
01721       ast_verbose("Got MDC-1200 ID %04X from node %s (%s)\n",
01722          unit,fromnode,myrpt->name);
01723    }
01724 }
01725 
01726 #ifdef   _MDC_DECODE_H_
01727 
01728 static void mdc1200_send(struct rpt *myrpt, unsigned int unit)
01729 {
01730 struct rpt_link *l;
01731 struct   ast_frame wf;
01732 char  str[200];
01733 
01734 
01735    sprintf(str,"I %s %04X",myrpt->name,unit);
01736 
01737    wf.frametype = AST_FRAME_TEXT;
01738    wf.subclass.integer = 0;
01739    wf.offset = 0;
01740    wf.mallocd = 0;
01741    wf.datalen = strlen(str) + 1;
01742    wf.samples = 0;
01743 
01744 
01745    l = myrpt->links.next;
01746    /* otherwise, send it to all of em */
01747    while(l != &myrpt->links)
01748    {
01749       if (l->name[0] == '0') 
01750       {
01751          l = l->next;
01752          continue;
01753       }
01754       wf.data = str;
01755       if (l->chan) ast_write(l->chan,&wf); 
01756       l = l->next;
01757    }
01758    return;
01759 }
01760 
01761 #endif
01762 
01763 static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
01764 {
01765 time_t   now;
01766 int   gotone;
01767 
01768    time(&now);
01769    gotone = 0;
01770    /* if too much time, reset the skate machine */
01771    if ((now - xlat->lastone) > MAXXLATTIME)
01772    {
01773       xlat->funcindex = xlat->endindex = 0;
01774    }
01775    if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
01776    {
01777       time(&xlat->lastone);
01778       gotone = 1;
01779       if (!xlat->funccharseq[xlat->funcindex])
01780       {
01781          xlat->funcindex = xlat->endindex = 0;
01782          return(myrpt->p.funcchar);
01783       }
01784    } else xlat->funcindex = 0;
01785    if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
01786    {
01787       time(&xlat->lastone);
01788       gotone = 1;
01789       if (!xlat->endcharseq[xlat->endindex])
01790       {
01791          xlat->funcindex = xlat->endindex = 0;
01792          return(myrpt->p.endchar);
01793       }
01794    } else xlat->endindex = 0;
01795    /* if in middle of decode seq, send nothing back */
01796    if (gotone) return(0);
01797    /* if no pass chars specified, return em all */
01798    if (!xlat->passchars[0]) return(c);
01799    /* if a "pass char", pass it */
01800    if (strchr(xlat->passchars,c)) return(c);
01801    return(0);
01802 }
01803 
01804 /*
01805  * Return a pointer to the first non-whitespace character
01806  */
01807 
01808 static char *eatwhite(char *s)
01809 {
01810    while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
01811       if(!*s)
01812          break;
01813       s++;
01814    }
01815    return s;
01816 }
01817 
01818 /*
01819 * Break up a delimited string into a table of substrings
01820 *
01821 * str - delimited string ( will be modified )
01822 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
01823 * limit- maximum number of substrings to process
01824 */
01825    
01826 
01827 
01828 static int finddelim(char *str, char *strp[], int limit)
01829 {
01830 int     i,l,inquo;
01831 
01832         inquo = 0;
01833         i = 0;
01834         strp[i++] = str;
01835         if (!*str)
01836            {
01837                 strp[0] = 0;
01838                 return(0);
01839            }
01840         for(l = 0; *str && (l < limit) ; str++)
01841            {
01842                 if (*str == QUOTECHR)
01843                    {
01844                         if (inquo)
01845                            {
01846                                 *str = 0;
01847                                 inquo = 0;
01848                            }
01849                         else
01850                            {
01851                                 strp[i - 1] = str + 1;
01852                                 inquo = 1;
01853                            }
01854       }
01855                 if ((*str == DELIMCHR) && (!inquo))
01856                 {
01857                         *str = 0;
01858          l++;
01859                         strp[i++] = str + 1;
01860                 }
01861            }
01862         strp[i] = 0;
01863         return(i);
01864 
01865 }
01866 /*
01867    send asterisk frame text message on the current tx channel
01868 */
01869 static int send_usb_txt(struct rpt *myrpt, char *txt) 
01870 {
01871    struct ast_frame wf;
01872  
01873    if (debug)ast_log(LOG_NOTICE, "send_usb_txt %s\n",txt);
01874    wf.frametype = AST_FRAME_TEXT;
01875    wf.subclass.integer = 0;
01876    wf.offset = 0;
01877    wf.mallocd = 0;
01878    wf.datalen = strlen(txt) + 1;
01879    wf.data.ptr = txt;
01880    wf.samples = 0;
01881    ast_write(myrpt->txchannel,&wf); 
01882    return 0;
01883 }
01884 /* must be called locked */
01885 static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
01886 {
01887 struct rpt_link *l;
01888 char mode;
01889 int   i,spos;
01890 
01891    buf[0] = 0; /* clear output buffer */
01892    if (myrpt->remote) return;
01893    /* go thru all links */
01894    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01895    {
01896       /* if is not a real link, ignore it */
01897       if (l->name[0] == '0') continue;
01898       /* don't count our stuff */
01899       if (l == mylink) continue;
01900       if (mylink && (!strcmp(l->name,mylink->name))) continue;
01901       /* figure out mode to report */
01902       mode = 'T'; /* use Tranceive by default */
01903       if (!l->mode) mode = 'R'; /* indicate RX for our mode */
01904       if (!l->thisconnected)  mode = 'C'; /* indicate connecting */
01905       spos = strlen(buf); /* current buf size (b4 we add our stuff) */
01906       if (spos)
01907       {
01908          strcat(buf,",");
01909          spos++;
01910       }
01911       /* add nodes into buffer */
01912       if (l->linklist[0])
01913       {
01914          snprintf(buf + spos,MAXLINKLIST - spos,
01915             "%c%s,%s",mode,l->name,l->linklist);
01916       }
01917       else /* if no nodes, add this node into buffer */
01918       {
01919          snprintf(buf + spos,MAXLINKLIST - spos,
01920             "%c%s",mode,l->name);
01921       }
01922       /* if we are in tranceive mode, let all modes stand */
01923       if (mode == 'T') continue;
01924       /* downgrade everyone on this node if appropriate */
01925       for(i = spos; buf[i]; i++)
01926       {
01927          if (buf[i] == 'T') buf[i] = mode;
01928          if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
01929       }
01930    }
01931    return;
01932 }
01933 
01934 /* must be called locked */
01935 static void __kickshort(struct rpt *myrpt)
01936 {
01937 struct rpt_link *l;
01938 
01939    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01940    {
01941       /* if is not a real link, ignore it */
01942       if (l->name[0] == '0') continue;
01943       l->linklisttimer = LINKLISTSHORTTIME;
01944    }
01945    myrpt->linkposttimer = LINKPOSTSHORTTIME;
01946    return;
01947 }
01948 
01949 static void statpost(struct rpt *myrpt,char *pairs)
01950 {
01951 char *str,*astr;
01952 char *astrs[100];
01953 int   n,pid;
01954 time_t   now;
01955 unsigned int seq;
01956 
01957    if (!myrpt->p.statpost_url) return;
01958    str = ast_malloc(strlen(pairs) + strlen(myrpt->p.statpost_url) + 200);
01959    astr = ast_strdup(myrpt->p.statpost_program);
01960    if ((!str) || (!astr)) {
01961       ast_free(str);
01962       ast_free(astr);
01963       return;
01964    }
01965    n = finddelim(astr,astrs,100);
01966    if (n < 1) return;
01967    ast_mutex_lock(&myrpt->statpost_lock);
01968    seq = ++myrpt->statpost_seqno;
01969    ast_mutex_unlock(&myrpt->statpost_lock);
01970    astrs[n++] = str;
01971    astrs[n] = NULL;
01972    time(&now);
01973    sprintf(str,"%s?node=%s&time=%u&seqno=%u",myrpt->p.statpost_url,
01974       myrpt->name,(unsigned int) now,seq);
01975    if (pairs) sprintf(str + strlen(str),"&%s",pairs);
01976    if (!(pid = ast_safe_fork(0)))
01977    {
01978       execv(astrs[0],astrs);
01979       ast_log(LOG_ERROR, "exec of %s failed.\n", astrs[0]);
01980       perror("asterisk");
01981       exit(0);
01982    }
01983    ast_free(astr);
01984    ast_free(str);
01985    return;
01986 }
01987 
01988 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
01989 {
01990 
01991 char *val;
01992 int longestnode,j;
01993 struct stat mystat;
01994 static time_t last = 0;
01995 static struct ast_config *ourcfg = NULL;
01996 struct ast_variable *vp;
01997 
01998    /* try to look it up locally first */
01999    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
02000    if (val) return(val);
02001    ast_mutex_lock(&nodelookuplock);
02002    /* if file does not exist */
02003    if (stat(myrpt->p.extnodefile,&mystat) == -1)
02004    {
02005       if (ourcfg) ast_config_destroy(ourcfg);
02006       ourcfg = NULL;
02007       ast_mutex_unlock(&nodelookuplock);
02008       return(NULL);
02009    }
02010    /* if we need to reload */
02011    if (mystat.st_mtime > last)
02012    {
02013       if (ourcfg) ast_config_destroy(ourcfg);
02014 #ifdef   NEW_ASTERISK
02015       ourcfg = ast_config_load(myrpt->p.extnodefile,config_flags);
02016 #else
02017       ourcfg = ast_config_load(myrpt->p.extnodefile);
02018 #endif
02019       /* if file not there, just bail */
02020       if (!ourcfg || ourcfg == CONFIG_STATUS_FILEINVALID)
02021       {
02022          ast_mutex_unlock(&nodelookuplock);
02023          return(NULL);
02024       }
02025       /* reset "last" time */
02026       last = mystat.st_mtime;
02027 
02028       /* determine longest node length again */    
02029       longestnode = 0;
02030       vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
02031       while(vp){
02032          j = strlen(vp->name);
02033          if (j > longestnode)
02034             longestnode = j;
02035          vp = vp->next;
02036       }
02037 
02038       vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
02039       while(vp){
02040          j = strlen(vp->name);
02041          if (j > longestnode)
02042             longestnode = j;
02043          vp = vp->next;
02044       }
02045 
02046       myrpt->longestnode = longestnode;
02047    }
02048    val = NULL;
02049    if (ourcfg)
02050       val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
02051    ast_mutex_unlock(&nodelookuplock);
02052    return(val);
02053 }
02054 
02055 /*
02056 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
02057 * If param is passed in non-null, then it will be set to the first character past the match
02058 */
02059 
02060 static int matchkeyword(char *string, char **param, char *keywords[])
02061 {
02062 int   i,ls;
02063    for( i = 0 ; keywords[i] ; i++){
02064       ls = strlen(keywords[i]);
02065       if(!ls){
02066          *param = NULL;
02067          return 0;
02068       }
02069       if(!strncmp(string, keywords[i], ls)){
02070          if(param)
02071             *param = string + ls;
02072          return i + 1; 
02073       }
02074    }
02075    *param = NULL;
02076    return 0;
02077 }
02078 
02079 /*
02080 * Skip characters in string which are in charlist, and return a pointer to the
02081 * first non-matching character
02082 */
02083 
02084 static char *skipchars(char *string, char *charlist)
02085 {
02086 int i;   
02087    while(*string){
02088       for(i = 0; charlist[i] ; i++){
02089          if(*string == charlist[i]){
02090             string++;
02091             break;
02092          }
02093       }
02094       if(!charlist[i])
02095          return string;
02096    }
02097    return string;
02098 }
02099 
02100 static int myatoi(const char *str)
02101 {
02102    int   ret;
02103 
02104    if (!str) {
02105       return -1;
02106    }
02107 
02108    /* leave this %i alone, non-base-10 input is useful here */
02109    if (sscanf(str, "%30i", &ret) != 1) {
02110       return -1;
02111    }
02112 
02113    return ret;
02114 }
02115 
02116 static int mycompar(const void *a, const void *b)
02117 {
02118 char  **x = (char **) a;
02119 char  **y = (char **) b;
02120 int   xoff,yoff;
02121 
02122    if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
02123    if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
02124    return(strcmp((*x) + xoff,(*y) + yoff));
02125 }
02126 
02127 static int topcompar(const void *a, const void *b)
02128 {
02129 struct rpt_topkey *x = (struct rpt_topkey *) a;
02130 struct rpt_topkey *y = (struct rpt_topkey *) b;
02131 
02132    return(x->timesince - y->timesince);
02133 }
02134 
02135 #ifdef   __RPT_NOTCH
02136 
02137 /* rpt filter routine */
02138 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
02139 {
02140 int   i,j;
02141 struct   rptfilter *f;
02142 
02143    for(i = 0; i < len; i++)
02144    {
02145       for(j = 0; j < MAXFILTERS; j++)
02146       {
02147          f = &myrpt->filters[j];
02148          if (!*f->desc) continue;
02149          f->x0 = f->x1; f->x1 = f->x2;
02150               f->x2 = ((float)buf[i]) / f->gain;
02151               f->y0 = f->y1; f->y1 = f->y2;
02152               f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
02153                            + (f->const1 * f->y0) + (f->const2 * f->y1);
02154          buf[i] = (short)f->y2;
02155       }
02156    }
02157 }
02158 
02159 #endif
02160 
02161 
02162 /*
02163  Get the time for the machine's time zone
02164  Note: Asterisk requires a copy of localtime
02165  in the /etc directory for this to work properly.
02166  If /etc/localtime is not present, you will get
02167  GMT time! This is especially important on systems
02168  running embedded linux distributions as they don't usually
02169  have support for locales. 
02170 
02171  If OLD_ASTERISK is defined, then the older localtime_r
02172  function will be used. The /etc/localtime file is not
02173  required in this case. This provides backward compatibility
02174  with Asterisk 1.2 systems.
02175 
02176 */
02177 
02178 #ifdef   NEW_ASTERISK
02179 static void rpt_localtime( time_t * t, struct ast_tm *lt)
02180 {
02181    struct timeval when;
02182 
02183    when.tv_sec = *t;
02184    when.tv_usec = 0;
02185    ast_localtime(&when, lt, NULL);
02186 }
02187 
02188 #else
02189 static void rpt_localtime( time_t * t, struct tm *lt)
02190 {
02191 #ifdef OLD_ASTERISK
02192    localtime_r(t, lt);
02193 #else
02194    ast_localtime(t, lt, NULL);
02195 #endif
02196 }
02197 #endif
02198 
02199 
02200 /* Retrieve an int from a config file */
02201                                                                                 
02202 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
02203 {
02204         char *var;
02205         int ret;
02206    char include_zero = 0;
02207 
02208    if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
02209       min = -min;
02210       include_zero = 1;
02211    }           
02212                                                                      
02213         var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
02214         if(var){
02215                 ret = myatoi(var);
02216       if(include_zero && !ret)
02217          return 0;
02218                 if(ret < min)
02219                         ret = min;
02220                 if(ret > max)
02221                         ret = max;
02222         }
02223         else
02224                 ret = defl;
02225         return ret;
02226 }
02227 
02228 
02229 static void load_rpt_vars(int n,int init)
02230 {
02231 char *this,*val;
02232 int   i,j,longestnode;
02233 struct ast_variable *vp;
02234 struct ast_config *cfg;
02235 char *strs[100];
02236 char s1[256];
02237 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
02238             "ufena","ufdis","atena","atdis",NULL};
02239 
02240    if (option_verbose > 2)
02241       ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
02242          (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
02243    ast_mutex_lock(&rpt_vars[n].lock);
02244    if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
02245 #ifdef   NEW_ASTERISK
02246    cfg = ast_config_load("rpt.conf",config_flags);
02247 #else
02248    cfg = ast_config_load("rpt.conf");
02249 #endif
02250    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
02251       ast_mutex_unlock(&rpt_vars[n].lock);
02252       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
02253       pthread_exit(NULL);
02254    }
02255    rpt_vars[n].cfg = cfg; 
02256    this = rpt_vars[n].name;
02257    memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
02258    if (init)
02259    {
02260       char *cp;
02261       int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
02262 
02263       cp = (char *) &rpt_vars[n].p;
02264       memset(cp + sizeof(rpt_vars[n].p),0,
02265          sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
02266       rpt_vars[n].tele.next = &rpt_vars[n].tele;
02267       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
02268       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
02269       rpt_vars[n].tailmessagen = 0;
02270    }
02271 #ifdef   __RPT_NOTCH
02272    /* zot out filters stuff */
02273    memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
02274 #endif
02275    val = (char *) ast_variable_retrieve(cfg,this,"context");
02276    if (val) rpt_vars[n].p.ourcontext = val;
02277    else rpt_vars[n].p.ourcontext = this;
02278    val = (char *) ast_variable_retrieve(cfg,this,"callerid");
02279    if (val) rpt_vars[n].p.ourcallerid = val;
02280    val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
02281    if (val) rpt_vars[n].p.acctcode = val;
02282    val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
02283    if (val) rpt_vars[n].p.ident = val;
02284    val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
02285    if (val) rpt_vars[n].p.hangtime = atoi(val);
02286       else rpt_vars[n].p.hangtime = HANGTIME;
02287    val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
02288    if (val) rpt_vars[n].p.althangtime = atoi(val);
02289       else rpt_vars[n].p.althangtime = HANGTIME;
02290    val = (char *) ast_variable_retrieve(cfg,this,"totime");
02291    if (val) rpt_vars[n].p.totime = atoi(val);
02292       else rpt_vars[n].p.totime = TOTIME;
02293    val = (char *) ast_variable_retrieve(cfg,this,"voxtimeout");
02294    if (val) rpt_vars[n].p.voxtimeout_ms = atoi(val);
02295       else rpt_vars[n].p.voxtimeout_ms = VOX_TIMEOUT_MS;
02296    val = (char *) ast_variable_retrieve(cfg,this,"voxrecover");
02297    if (val) rpt_vars[n].p.voxrecover_ms = atoi(val);
02298       else rpt_vars[n].p.voxrecover_ms = VOX_RECOVER_MS;
02299    val = (char *) ast_variable_retrieve(cfg,this,"simplexpatchdelay");
02300    if (val) rpt_vars[n].p.simplexpatchdelay = atoi(val);
02301       else rpt_vars[n].p.simplexpatchdelay = SIMPLEX_PATCH_DELAY;
02302    val = (char *) ast_variable_retrieve(cfg,this,"simplexphonedelay");
02303    if (val) rpt_vars[n].p.simplexphonedelay = atoi(val);
02304       else rpt_vars[n].p.simplexphonedelay = SIMPLEX_PHONE_DELAY;
02305    val = (char *) ast_variable_retrieve(cfg,this,"statpost_program");
02306    if (val) rpt_vars[n].p.statpost_program = val;
02307       else rpt_vars[n].p.statpost_program = STATPOST_PROGRAM;
02308    rpt_vars[n].p.statpost_url = 
02309       (char *) ast_variable_retrieve(cfg,this,"statpost_url");
02310    rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);    
02311    rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);     
02312    rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
02313    rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME);   /* Enforce a min max including zero */
02314    rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
02315    val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
02316    if (val) rpt_vars[n].p.tonezone = val;
02317    rpt_vars[n].p.tailmessages[0] = 0;
02318    rpt_vars[n].p.tailmessagemax = 0;
02319    val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
02320    if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
02321    val = (char *) ast_variable_retrieve(cfg,this,"memory");
02322    if (!val) val = MEMORY;
02323    rpt_vars[n].p.memory = val;
02324    val = (char *) ast_variable_retrieve(cfg,this,"macro");
02325    if (!val) val = MACRO;
02326    rpt_vars[n].p.macro = val;
02327    val = (char *) ast_variable_retrieve(cfg,this,"tonemacro");
02328    if (!val) val = TONEMACRO;
02329    rpt_vars[n].p.tonemacro = val;
02330    val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
02331    if (val) rpt_vars[n].p.startupmacro = val;
02332    val = (char *) ast_variable_retrieve(cfg,this,"iobase");
02333    /* do not use atoi() here, we need to be able to have
02334       the input specified in hex or decimal so we use
02335       sscanf with a %i */
02336    if ((!val) || (sscanf(val,"%30i",&rpt_vars[n].p.iobase) != 1))
02337       rpt_vars[n].p.iobase = DEFAULT_IOBASE;
02338    val = (char *) ast_variable_retrieve(cfg,this,"ioport");
02339    rpt_vars[n].p.ioport = val;
02340    val = (char *) ast_variable_retrieve(cfg,this,"functions");
02341    if (!val)
02342       {
02343          val = FUNCTIONS;
02344          rpt_vars[n].p.simple = 1;
02345       } 
02346    rpt_vars[n].p.functions = val;
02347    val =  (char *) ast_variable_retrieve(cfg,this,"link_functions");
02348    if (val) rpt_vars[n].p.link_functions = val;
02349    else 
02350       rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
02351    val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
02352    if (val) rpt_vars[n].p.phone_functions = val;
02353    val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
02354    if (val) rpt_vars[n].p.dphone_functions = val;
02355    val = (char *) ast_variable_retrieve(cfg,this,"alt_functions");
02356    if (val) rpt_vars[n].p.alt_functions = val;
02357    val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
02358    if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
02359       rpt_vars[n].p.funcchar = *val;      
02360    val = (char *) ast_variable_retrieve(cfg,this,"endchar");
02361    if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
02362       rpt_vars[n].p.endchar = *val;    
02363    val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
02364    if (val) rpt_vars[n].p.nobusyout = ast_true(val);
02365    val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
02366    if (val) rpt_vars[n].p.notelemtx = ast_true(val);
02367    val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
02368    if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
02369    val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
02370    if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
02371    val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
02372    if (val) rpt_vars[n].p.linktolink = ast_true(val);
02373    val = (char *) ast_variable_retrieve(cfg,this,"nodes");
02374    if (!val) val = NODES;
02375    rpt_vars[n].p.nodes = val;
02376    val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
02377    if (!val) val = EXTNODES;
02378    rpt_vars[n].p.extnodes = val;
02379    val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
02380    if (!val) val = EXTNODEFILE;
02381    rpt_vars[n].p.extnodefile = val;
02382    val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
02383    if (val) rpt_vars[n].p.archivedir = val;
02384    val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
02385    if (val) rpt_vars[n].p.authlevel = atoi(val); 
02386    else rpt_vars[n].p.authlevel = 0;
02387    val = (char *) ast_variable_retrieve(cfg,this,"parrot");
02388    if (val) rpt_vars[n].p.parrotmode = ast_true(val) * 2;
02389    else rpt_vars[n].p.parrotmode = 0;
02390    val = (char *) ast_variable_retrieve(cfg,this,"parrottime");
02391    if (val) rpt_vars[n].p.parrottime = atoi(val); 
02392    else rpt_vars[n].p.parrottime = PARROTTIME;
02393    val = (char *) ast_variable_retrieve(cfg,this,"rptnode");
02394    rpt_vars[n].p.rptnode = val;
02395    val = (char *) ast_variable_retrieve(cfg,this,"mars");
02396    if (val) rpt_vars[n].p.remote_mars = atoi(val); 
02397    else rpt_vars[n].p.remote_mars = 0;
02398    val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
02399    if (val) rpt_vars[n].p.monminblocks = atol(val); 
02400    else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
02401    val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
02402    if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); 
02403    else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
02404    val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
02405    if (val) rpt_vars[n].p.civaddr = atoi(val); 
02406    else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
02407    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
02408    if (val) rpt_vars[n].p.remotetimeout = atoi(val); 
02409    else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
02410    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
02411    if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); 
02412    else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
02413    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
02414    if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); 
02415    else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
02416 #ifdef   __RPT_NOTCH
02417    val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
02418    if (val) {
02419       i = finddelim(val,strs,MAXFILTERS * 2);
02420       i &= ~1; /* force an even number, rounded down */
02421       if (i >= 2) for(j = 0; j < i; j += 2)
02422       {
02423          rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
02424            &rpt_vars[n].filters[j >> 1].gain,
02425              &rpt_vars[n].filters[j >> 1].const0,
02426             &rpt_vars[n].filters[j >> 1].const1,
02427                 &rpt_vars[n].filters[j >> 1].const2);
02428          sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
02429             strs[j],strs[j + 1]);
02430       }
02431 
02432    }
02433 #endif
02434    val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
02435    if (val) {
02436       memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
02437       i = finddelim(val,strs,3);
02438       if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
02439       if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
02440       if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
02441    }
02442    val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
02443    if (val) {
02444       memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
02445       i = finddelim(val,strs,3);
02446       if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
02447       if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
02448       if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
02449    }
02450    /* retreive the stanza name for the control states if there is one */
02451    val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
02452    rpt_vars[n].p.csstanzaname = val;
02453       
02454    /* retreive the stanza name for the scheduler if there is one */
02455    val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
02456    rpt_vars[n].p.skedstanzaname = val;
02457 
02458    /* retreive the stanza name for the txlimits */
02459    val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
02460    rpt_vars[n].p.txlimitsstanzaname = val;
02461 
02462    longestnode = 0;
02463 
02464    vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
02465       
02466    while(vp){
02467       j = strlen(vp->name);
02468       if (j > longestnode)
02469          longestnode = j;
02470       vp = vp->next;
02471    }
02472 
02473    rpt_vars[n].longestnode = longestnode;
02474       
02475    /*
02476    * For this repeater, Determine the length of the longest function 
02477    */
02478    rpt_vars[n].longestfunc = 0;
02479    vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
02480    while(vp){
02481       j = strlen(vp->name);
02482       if (j > rpt_vars[n].longestfunc)
02483          rpt_vars[n].longestfunc = j;
02484       vp = vp->next;
02485    }
02486    /*
02487    * For this repeater, Determine the length of the longest function 
02488    */
02489    rpt_vars[n].link_longestfunc = 0;
02490    vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
02491    while(vp){
02492       j = strlen(vp->name);
02493       if (j > rpt_vars[n].link_longestfunc)
02494          rpt_vars[n].link_longestfunc = j;
02495       vp = vp->next;
02496    }
02497    rpt_vars[n].phone_longestfunc = 0;
02498    if (rpt_vars[n].p.phone_functions)
02499    {
02500       vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
02501       while(vp){
02502          j = strlen(vp->name);
02503          if (j > rpt_vars[n].phone_longestfunc)
02504             rpt_vars[n].phone_longestfunc = j;
02505          vp = vp->next;
02506       }
02507    }
02508    rpt_vars[n].dphone_longestfunc = 0;
02509    if (rpt_vars[n].p.dphone_functions)
02510    {
02511       vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
02512       while(vp){
02513          j = strlen(vp->name);
02514          if (j > rpt_vars[n].dphone_longestfunc)
02515             rpt_vars[n].dphone_longestfunc = j;
02516          vp = vp->next;
02517       }
02518    }
02519    rpt_vars[n].alt_longestfunc = 0;
02520    if (rpt_vars[n].p.alt_functions)
02521    {
02522       vp = ast_variable_browse(cfg, rpt_vars[n].p.alt_functions);
02523       while(vp){
02524          j = strlen(vp->name);
02525          if (j > rpt_vars[n].alt_longestfunc)
02526             rpt_vars[n].alt_longestfunc = j;
02527          vp = vp->next;
02528       }
02529    }
02530    rpt_vars[n].macro_longest = 1;
02531    vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
02532    while(vp){
02533       j = strlen(vp->name);
02534       if (j > rpt_vars[n].macro_longest)
02535          rpt_vars[n].macro_longest = j;
02536       vp = vp->next;
02537    }
02538    
02539    /* Browse for control states */
02540    if(rpt_vars[n].p.csstanzaname)
02541       vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
02542    else
02543       vp = NULL;
02544    for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
02545       int k,nukw,statenum;
02546       statenum=atoi(vp->name);
02547       strncpy(s1, vp->value, 255);
02548       s1[255] = 0;
02549       nukw  = finddelim(s1,strs,32);
02550       
02551       for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */  
02552          for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
02553             if(!strcmp(strs[k],cs_keywords[j])){
02554                switch(j){
02555                   case 0: /* rptena */
02556                      rpt_vars[n].p.s[statenum].txdisable = 0;
02557                      break;
02558                   case 1: /* rptdis */
02559                      rpt_vars[n].p.s[statenum].txdisable = 1;
02560                      break;
02561          
02562                   case 2: /* apena */
02563                      rpt_vars[n].p.s[statenum].autopatchdisable = 0;
02564                      break;
02565 
02566                   case 3: /* apdis */
02567                      rpt_vars[n].p.s[statenum].autopatchdisable = 1;
02568                      break;
02569 
02570                   case 4: /* lnkena */
02571                      rpt_vars[n].p.s[statenum].linkfundisable = 0;
02572                      break;
02573    
02574                   case 5: /* lnkdis */
02575                      rpt_vars[n].p.s[statenum].linkfundisable = 1;
02576                      break;
02577 
02578                   case 6: /* totena */
02579                      rpt_vars[n].p.s[statenum].totdisable = 0;
02580                      break;
02581                
02582                   case 7: /* totdis */
02583                      rpt_vars[n].p.s[statenum].totdisable = 1;
02584                      break;
02585 
02586                   case 8: /* skena */
02587                      rpt_vars[n].p.s[statenum].schedulerdisable = 0;
02588                      break;
02589 
02590                   case 9: /* skdis */
02591                      rpt_vars[n].p.s[statenum].schedulerdisable = 1;
02592                      break;
02593 
02594                   case 10: /* ufena */
02595                      rpt_vars[n].p.s[statenum].userfundisable = 0;
02596                      break;
02597 
02598                   case 11: /* ufdis */
02599                      rpt_vars[n].p.s[statenum].userfundisable = 1;
02600                      break;
02601 
02602                   case 12: /* atena */
02603                      rpt_vars[n].p.s[statenum].alternatetail = 1;
02604                      break;
02605 
02606                   case 13: /* atdis */
02607                      rpt_vars[n].p.s[statenum].alternatetail = 0;
02608                      break;
02609          
02610                   default:
02611                      ast_log(LOG_WARNING,
02612                         "Unhandled control state keyword %s", cs_keywords[i]);
02613                      break;
02614                }
02615             }
02616          }
02617       }
02618       vp = vp->next;
02619    }
02620    ast_mutex_unlock(&rpt_vars[n].lock);
02621 }
02622 
02623 /*
02624 * Enable or disable debug output at a given level at the console
02625 */
02626 static int rpt_do_debug(int fd, int argc, const char * const *argv)
02627 {
02628    int newlevel;
02629 
02630    if (argc != 4) {
02631       return RESULT_SHOWUSAGE;
02632    }
02633 
02634    newlevel = myatoi(argv[3]);
02635 
02636    if (newlevel < 0 || newlevel > 7) {
02637       return RESULT_SHOWUSAGE;
02638    }
02639 
02640    if (newlevel) {
02641       ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
02642    } else {
02643       ast_cli(fd, "app_rpt Debugging disabled\n");
02644    }
02645 
02646    debug = newlevel;
02647 
02648    return RESULT_SUCCESS;
02649 }
02650 
02651 /*
02652 * Dump rpt struct debugging onto console
02653 */
02654                                                                                                                                  
02655 static int rpt_do_dump(int fd, int argc, const char * const *argv)
02656 {
02657    int i;
02658 
02659         if (argc != 3)
02660                 return RESULT_SHOWUSAGE;
02661 
02662    for(i = 0; i < nrpts; i++)
02663    {
02664       if (!strcmp(argv[2],rpt_vars[i].name))
02665       {
02666          rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
02667               ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
02668               return RESULT_SUCCESS;
02669       }
02670    }
02671    return RESULT_FAILURE;
02672 }
02673 
02674 /*
02675 * Dump statistics onto console
02676 */
02677 
02678 static int rpt_do_stats(int fd, int argc, const char * const *argv)
02679 {
02680    int i,j,numoflinks;
02681    int dailytxtime, dailykerchunks;
02682    time_t now;
02683    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
02684    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
02685    int uptime;
02686    long long totaltxtime;
02687    struct   rpt_link *l;
02688    char *listoflinks[MAX_STAT_LINKS];  
02689    char *lastdtmfcommand,*parrot_ena;
02690    char *tot_state, *ider_state, *patch_state;
02691    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
02692    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
02693    struct rpt *myrpt;
02694 
02695    static char *not_applicable = "N/A";
02696 
02697    if(argc != 3)
02698       return RESULT_SHOWUSAGE;
02699 
02700    tot_state = ider_state = 
02701    patch_state = reverse_patch_state = 
02702    input_signal = not_applicable;
02703    called_number = lastdtmfcommand = NULL;
02704 
02705    time(&now);
02706    for(i = 0; i < nrpts; i++)
02707    {
02708       if (!strcmp(argv[2],rpt_vars[i].name)){
02709          /* Make a copy of all stat variables while locked */
02710          myrpt = &rpt_vars[i];
02711          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02712          uptime = (int)(now - starttime);
02713          dailytxtime = myrpt->dailytxtime;
02714          totaltxtime = myrpt->totaltxtime;
02715          dailykeyups = myrpt->dailykeyups;
02716          totalkeyups = myrpt->totalkeyups;
02717          dailykerchunks = myrpt->dailykerchunks;
02718          totalkerchunks = myrpt->totalkerchunks;
02719          dailyexecdcommands = myrpt->dailyexecdcommands;
02720          totalexecdcommands = myrpt->totalexecdcommands;
02721          timeouts = myrpt->timeouts;
02722 
02723          /* Traverse the list of connected nodes */
02724          reverse_patch_state = "DOWN";
02725          numoflinks = 0;
02726          l = myrpt->links.next;
02727          while(l && (l != &myrpt->links)){
02728             if(numoflinks >= MAX_STAT_LINKS){
02729                ast_log(LOG_NOTICE,
02730                "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
02731                break;
02732             }
02733             if (l->name[0] == '0'){ /* Skip '0' nodes */
02734                reverse_patch_state = "UP";
02735                l = l->next;
02736                continue;
02737             }
02738             listoflinks[numoflinks] = ast_strdup(l->name);
02739             if(listoflinks[numoflinks] == NULL){
02740                break;
02741             }
02742             else{
02743                numoflinks++;
02744             }
02745             l = l->next;
02746          }
02747 
02748          if(myrpt->keyed)
02749             input_signal = "YES";
02750          else
02751             input_signal = "NO";
02752 
02753          if(myrpt->p.parrotmode)
02754             parrot_ena = "ENABLED";
02755          else
02756             parrot_ena = "DISABLED";
02757 
02758          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
02759             sys_ena = "DISABLED";
02760          else
02761             sys_ena = "ENABLED";
02762 
02763          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
02764             tot_ena = "DISABLED";
02765          else
02766             tot_ena = "ENABLED";
02767 
02768          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
02769             link_ena = "DISABLED";
02770          else
02771             link_ena = "ENABLED";
02772 
02773          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
02774             patch_ena = "DISABLED";
02775          else
02776             patch_ena = "ENABLED";
02777 
02778          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
02779             sch_ena = "DISABLED";
02780          else
02781             sch_ena = "ENABLED";
02782 
02783          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
02784             user_funs = "DISABLED";
02785          else
02786             user_funs = "ENABLED";
02787 
02788          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
02789             tail_type = "ALTERNATE";
02790          else
02791             tail_type = "STANDARD";
02792 
02793          if(!myrpt->totimer)
02794             tot_state = "TIMED OUT!";
02795          else if(myrpt->totimer != myrpt->p.totime)
02796             tot_state = "ARMED";
02797          else
02798             tot_state = "RESET";
02799 
02800          if(myrpt->tailid)
02801             ider_state = "QUEUED IN TAIL";
02802          else if(myrpt->mustid)
02803             ider_state = "QUEUED FOR CLEANUP";
02804          else
02805             ider_state = "CLEAN";
02806 
02807          switch(myrpt->callmode){
02808             case 1:
02809                patch_state = "DIALING";
02810                break;
02811             case 2:
02812                patch_state = "CONNECTING";
02813                break;
02814             case 3:
02815                patch_state = "UP";
02816                break;
02817 
02818             case 4:
02819                patch_state = "CALL FAILED";
02820                break;
02821 
02822             default:
02823                patch_state = "DOWN";
02824          }
02825 
02826          if(strlen(myrpt->exten)){
02827             called_number = ast_strdup(myrpt->exten);
02828          }
02829 
02830          if(strlen(myrpt->lastdtmfcommand)){
02831             lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
02832          }
02833          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02834 
02835          ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
02836          ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
02837          ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
02838          ast_cli(fd, "System...........................................: %s\n", sys_ena);
02839          ast_cli(fd, "Parrot Mode......................................: %s\n", parrot_ena);
02840          ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
02841          ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
02842          ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
02843          ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
02844          ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
02845          ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
02846          ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
02847          ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
02848          ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
02849          ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
02850          ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
02851          ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
02852          ast_cli(fd, "Last DTMF command executed.......................: %s\n", 
02853          (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
02854          hours = dailytxtime/3600000;
02855          dailytxtime %= 3600000;
02856          minutes = dailytxtime/60000;
02857          dailytxtime %= 60000;
02858          seconds = dailytxtime/1000;
02859          dailytxtime %= 1000;
02860 
02861          ast_cli(fd, "TX time today....................................: %02d:%02d:%02d.%d\n",
02862             hours, minutes, seconds, dailytxtime);
02863 
02864          hours = (int) totaltxtime/3600000;
02865          totaltxtime %= 3600000;
02866          minutes = (int) totaltxtime/60000;
02867          totaltxtime %= 60000;
02868          seconds = (int)  totaltxtime/1000;
02869          totaltxtime %= 1000;
02870 
02871          ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
02872              hours, minutes, seconds, (int) totaltxtime);
02873 
02874                         hours = uptime/3600;
02875                         uptime %= 3600;
02876                         minutes = uptime/60;
02877                         uptime %= 60;
02878 
02879                         ast_cli(fd, "Uptime...........................................: %02d:%02d:%02d\n",
02880                                 hours, minutes, uptime);
02881 
02882          ast_cli(fd, "Nodes currently connected to us..................: ");
02883                         if(!numoflinks){
02884                          ast_cli(fd,"<NONE>");
02885                         }
02886          else{
02887             for(j = 0 ;j < numoflinks; j++){
02888                ast_cli(fd, "%s", listoflinks[j]);
02889                if(j % 4 == 3){
02890                   ast_cli(fd, "\n");
02891                   ast_cli(fd, "                                                 : ");
02892                }  
02893                else{
02894                   if((numoflinks - 1) - j  > 0)
02895                      ast_cli(fd, ", ");
02896                }
02897             }
02898          }
02899          ast_cli(fd,"\n");
02900 
02901          ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
02902          ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
02903          ast_cli(fd, "Autopatch called number..........................: %s\n",
02904          (called_number && strlen(called_number)) ? called_number : not_applicable);
02905          ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
02906          ast_cli(fd, "User linking commands............................: %s\n", link_ena);
02907          ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
02908 
02909          for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
02910             ast_free(listoflinks[j]);
02911          }
02912          ast_free(called_number);
02913          ast_free(lastdtmfcommand);
02914               return RESULT_SUCCESS;
02915       }
02916    }
02917    return RESULT_FAILURE;
02918 }
02919 
02920 /*
02921 * Link stats function
02922 */
02923 
02924 static int rpt_do_lstats(int fd, int argc, const char * const *argv)
02925 {
02926    int i,j;
02927    char *connstate;
02928    struct rpt *myrpt;
02929    struct rpt_link *l;
02930    struct rpt_lstat *s,*t;
02931    struct rpt_lstat s_head;
02932    if(argc != 3)
02933       return RESULT_SHOWUSAGE;
02934 
02935    s = NULL;
02936    s_head.next = &s_head;
02937    s_head.prev = &s_head;
02938 
02939    for(i = 0; i < nrpts; i++)
02940    {
02941       if (!strcmp(argv[2],rpt_vars[i].name)){
02942          /* Make a copy of all stat variables while locked */
02943          myrpt = &rpt_vars[i];
02944          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02945          /* Traverse the list of connected nodes */
02946          j = 0;
02947          l = myrpt->links.next;
02948          while(l && (l != &myrpt->links)){
02949             if (l->name[0] == '0'){ /* Skip '0' nodes */
02950                l = l->next;
02951                continue;
02952             }
02953             if((s = (struct rpt_lstat *) ast_malloc(sizeof(struct rpt_lstat))) == NULL){
02954                ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
02955                rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02956                return RESULT_FAILURE;
02957             }
02958             memset(s, 0, sizeof(struct rpt_lstat));
02959             strncpy(s->name, l->name, MAXREMSTR - 1);
02960             if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
02961             else strcpy(s->peer,"(none)");
02962             s->mode = l->mode;
02963             s->outbound = l->outbound;
02964             s->reconnects = l->reconnects;
02965             s->connecttime = l->connecttime;
02966             s->thisconnected = l->thisconnected;
02967             memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
02968             insque((struct qelem *) s, (struct qelem *) s_head.next);
02969             memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
02970             l = l->next;
02971          }
02972          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02973          ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME        CONNECT STATE\n");
02974          ast_cli(fd, "----      ----                ----------  ---------  ------------        -------------\n");
02975 
02976          for(s = s_head.next; s != &s_head; s = s->next){
02977             int hours, minutes, seconds;
02978             long long connecttime = s->connecttime;
02979             char conntime[21];
02980             hours = (int) connecttime/3600000;
02981             connecttime %= 3600000;
02982             minutes = (int) connecttime/60000;
02983             connecttime %= 60000;
02984             seconds = (int)  connecttime/1000;
02985             connecttime %= 1000;
02986             snprintf(conntime, 20, "%02d:%02d:%02d.%d",
02987                hours, minutes, seconds, (int) connecttime);
02988             conntime[20] = 0;
02989             if(s->thisconnected)
02990                connstate  = "ESTABLISHED";
02991             else
02992                connstate = "CONNECTING";
02993             ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
02994                s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
02995          }  
02996          /* destroy our local link queue */
02997          s = s_head.next;
02998          while(s != &s_head){
02999             t = s;
03000             s = s->next;
03001             remque((struct qelem *)t);
03002             ast_free(t);
03003          }        
03004          return RESULT_SUCCESS;
03005       }
03006    }
03007    return RESULT_FAILURE;
03008 }
03009 
03010 /*
03011 * List all nodes connected, directly or indirectly
03012 */
03013 
03014 static int rpt_do_nodes(int fd, int argc, const char * const *argv)
03015 {
03016    int i,j;
03017    char ns;
03018    char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
03019    struct rpt *myrpt;
03020    if(argc != 3)
03021       return RESULT_SHOWUSAGE;
03022 
03023    for(i = 0; i < nrpts; i++)
03024    {
03025       if (!strcmp(argv[2],rpt_vars[i].name)){
03026          /* Make a copy of all stat variables while locked */
03027          myrpt = &rpt_vars[i];
03028          rpt_mutex_lock(&myrpt->lock); /* LOCK */
03029          __mklinklist(myrpt,NULL,lbuf);
03030          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
03031          /* parse em */
03032          ns = finddelim(lbuf,strs,MAXLINKLIST);
03033          /* sort em */
03034          if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
03035          ast_cli(fd,"\n");
03036          ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
03037          for(j = 0 ;; j++){
03038             if(!strs[j]){
03039                if(!j){
03040                   ast_cli(fd,"<NONE>");
03041                }
03042                break;
03043             }
03044             ast_cli(fd, "%s", strs[j]);
03045             if(j % 8 == 7){
03046                ast_cli(fd, "\n");
03047             }
03048             else{
03049                if(strs[j + 1])
03050                   ast_cli(fd, ", ");
03051             }
03052          }
03053          ast_cli(fd,"\n\n");
03054          return RESULT_SUCCESS;
03055       }
03056    }
03057    return RESULT_FAILURE;
03058 }
03059 
03060 /*
03061 * List all locally configured nodes
03062 */
03063 
03064 static int rpt_do_local_nodes(int fd, int argc, const char * const *argv)
03065 {
03066 
03067     int i;
03068     ast_cli(fd, "\nNode\n----\n");
03069     for (i=0; i< nrpts; i++)
03070     {
03071         ast_cli(fd, "%s\n", rpt_vars[i].name);        
03072     } /* for i */
03073     ast_cli(fd,"\n");
03074     return RESULT_SUCCESS;
03075 } 
03076 
03077 
03078 /*
03079 * reload vars 
03080 */
03081 
03082 static int rpt_do_reload(int fd, int argc, const char * const *argv)
03083 {
03084 int   n;
03085 
03086         if (argc > 2) return RESULT_SHOWUSAGE;
03087 
03088    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
03089 
03090    return RESULT_FAILURE;
03091 }
03092 
03093 /*
03094 * restart app_rpt
03095 */
03096                                                                                                                                  
03097 static int rpt_do_restart(int fd, int argc, const char * const *argv)
03098 {
03099 int   i;
03100 
03101         if (argc > 2) return RESULT_SHOWUSAGE;
03102    for(i = 0; i < nrpts; i++)
03103    {
03104       if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
03105    }
03106    return RESULT_FAILURE;
03107 }
03108 
03109 
03110 /*
03111 * send an app_rpt DTMF function from the CLI
03112 */
03113                                                                                                                                  
03114 static int rpt_do_fun(int fd, int argc, const char * const *argv)
03115 {
03116    int   i,busy=0;
03117 
03118         if (argc != 4) return RESULT_SHOWUSAGE;
03119 
03120    for(i = 0; i < nrpts; i++){
03121       if(!strcmp(argv[2], rpt_vars[i].name)){
03122          struct rpt *myrpt = &rpt_vars[i];
03123          rpt_mutex_lock(&myrpt->lock);
03124          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
03125             rpt_mutex_unlock(&myrpt->lock);
03126             busy=1;
03127          }
03128          if(!busy){
03129             myrpt->macrotimer = MACROTIME;
03130             strncat(myrpt->macrobuf,argv[3],MAXMACRO - 1);
03131          }
03132          rpt_mutex_unlock(&myrpt->lock);
03133       }
03134    }
03135    if(busy){
03136       ast_cli(fd, "Function decoder busy");
03137    }
03138    return RESULT_FAILURE;
03139 }
03140 /*
03141    the convention is that macros in the data from the rpt() application
03142    are all at the end of the data, separated by the | and start with a *
03143    when put into the macro buffer, the characters have their high bit
03144    set so the macro processor knows they came from the application data
03145    and to use the alt-functions table.
03146    sph:
03147 */
03148 static int rpt_push_alt_macro(struct rpt *myrpt, char *sptr)
03149 {
03150    int   busy=0;
03151 
03152    rpt_mutex_lock(&myrpt->lock);
03153    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(sptr)){
03154       rpt_mutex_unlock(&myrpt->lock);
03155       busy=1;
03156    }
03157    if(!busy){
03158       int x;
03159       if (debug)ast_log(LOG_NOTICE, "rpt_push_alt_macro %s\n",sptr);
03160       myrpt->macrotimer = MACROTIME;
03161       for(x = 0; *(sptr + x); x++)
03162           myrpt->macrobuf[x] = *(sptr + x) | 0x80;
03163       *(sptr + x) = 0;
03164    }
03165    rpt_mutex_unlock(&myrpt->lock);
03166 
03167    if(busy)ast_log(LOG_WARNING, "Function decoder busy on app_rpt command macro.\n");
03168 
03169    return busy;
03170 }
03171 /*
03172    allows us to test rpt() application data commands
03173 */
03174 static int rpt_do_fun1(int fd, int argc, const char * const *argv)
03175 {
03176    int   i;
03177 
03178     if (argc != 4) return RESULT_SHOWUSAGE;
03179 
03180    for(i = 0; i < nrpts; i++){
03181       if(!strcmp(argv[2], rpt_vars[i].name)){
03182          struct rpt *myrpt = &rpt_vars[i];
03183          rpt_push_alt_macro(myrpt, (char *) argv[3]);
03184       }
03185    }
03186    return RESULT_FAILURE;
03187 }
03188 /*
03189 * send an app_rpt **command** from the CLI
03190 */
03191 
03192 static int rpt_do_cmd(int fd, int argc, const char * const *argv)
03193 {
03194    int i, l;
03195    int busy=0;
03196    int maxActions = sizeof(function_table)/sizeof(struct function_table_tag);
03197 
03198    int thisRpt = -1;
03199    int thisAction = -1;
03200    struct rpt *myrpt = NULL;
03201    if (argc != 6) return RESULT_SHOWUSAGE;
03202    
03203    for(i = 0; i < nrpts; i++)
03204    {
03205       if(!strcmp(argv[2], rpt_vars[i].name))
03206       {
03207          thisRpt = i;
03208          myrpt = &rpt_vars[i];
03209          break;
03210       } /* if !strcmp... */
03211    } /* for i */
03212 
03213    if (thisRpt < 0)
03214    {
03215       ast_cli(fd, "Unknown node number %s.\n", argv[2]);
03216       return RESULT_FAILURE;
03217    } /* if thisRpt < 0 */
03218    
03219    /* Look up the action */
03220    l = strlen(argv[3]);
03221    for(i = 0 ; i < maxActions; i++)
03222    {
03223       if(!strncasecmp(argv[3], function_table[i].action, l))
03224       {
03225          thisAction = i;
03226          break;
03227       } /* if !strncasecmp... */
03228    } /* for i */
03229    
03230    if (thisAction < 0)
03231    {
03232       ast_cli(fd, "Unknown action name %s.\n", argv[3]);
03233       return RESULT_FAILURE;
03234    } /* if thisAction < 0 */
03235 
03236    /* at this point, it looks like all the arguments make sense... */
03237 
03238    rpt_mutex_lock(&myrpt->lock);
03239 
03240    if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE)
03241    {
03242       rpt_vars[thisRpt].cmdAction.state = CMD_STATE_BUSY;
03243       rpt_vars[thisRpt].cmdAction.functionNumber = thisAction;
03244       strncpy(rpt_vars[thisRpt].cmdAction.param, argv[4], MAXDTMF);
03245       strncpy(rpt_vars[thisRpt].cmdAction.digits, argv[5], MAXDTMF);
03246       rpt_vars[thisRpt].cmdAction.command_source = SOURCE_RPT;
03247       rpt_vars[thisRpt].cmdAction.state = CMD_STATE_READY;
03248    } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
03249    else
03250    {
03251       busy = 1;
03252    } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
03253    rpt_mutex_unlock(&myrpt->lock);
03254 
03255    return (busy ? RESULT_FAILURE : RESULT_SUCCESS);
03256 } /* rpt_do_cmd() */
03257 
03258 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
03259 {
03260    int res;
03261 
03262         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
03263                 return res;
03264                                                                                                                                             
03265         while(chan->generatordata) {
03266       if (ast_safe_sleep(chan,1)) return -1;
03267    }
03268 
03269         return 0;
03270 }
03271 
03272 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
03273 {
03274    return play_tone_pair(chan, freq, 0, duration, amplitude);
03275 }
03276 
03277 static int play_silence(struct ast_channel *chan, int duration)
03278 {
03279    return play_tone_pair(chan, 0, 0, duration, 0);
03280 }
03281 
03282 #ifdef   NEW_ASTERISK
03283 
03284 static char *res2cli(int r)
03285 
03286 {
03287    switch (r)
03288    {
03289        case RESULT_SUCCESS:
03290       return(CLI_SUCCESS);
03291        case RESULT_SHOWUSAGE:
03292       return(CLI_SHOWUSAGE);
03293        default:
03294       return(CLI_FAILURE);
03295    }
03296 }
03297 
03298 static char *handle_cli_debug(struct ast_cli_entry *e,
03299    int cmd, struct ast_cli_args *a)
03300 {
03301         switch (cmd) {
03302         case CLI_INIT:
03303                 e->command = "rpt debug level";
03304                 e->usage = debug_usage;
03305                 return NULL;
03306         case CLI_GENERATE:
03307                 return NULL;
03308    }
03309    return res2cli(rpt_do_debug(a->fd, a->argc, a->argv));
03310 }
03311 
03312 static char *handle_cli_dump(struct ast_cli_entry *e,
03313    int cmd, struct ast_cli_args *a)
03314 {
03315         switch (cmd) {
03316         case CLI_INIT:
03317                 e->command = "rpt dump level";
03318                 e->usage = dump_usage;
03319                 return NULL;
03320         case CLI_GENERATE:
03321                 return NULL;
03322    }
03323    return res2cli(rpt_do_dump(a->fd,a->argc,a->argv));
03324 }
03325 
03326 
03327 static char *handle_cli_stats(struct ast_cli_entry *e,
03328    int cmd, struct ast_cli_args *a)
03329 {
03330         switch (cmd) {
03331         case CLI_INIT:
03332                 e->command = "rpt stats";
03333                 e->usage = dump_stats;
03334                 return NULL;
03335         case CLI_GENERATE:
03336                 return NULL;
03337    }
03338    return res2cli(rpt_do_stats(a->fd,a->argc,a->argv));
03339 }
03340 
03341 static char *handle_cli_nodes(struct ast_cli_entry *e,
03342    int cmd, struct ast_cli_args *a)
03343 {
03344         switch (cmd) {
03345         case CLI_INIT:
03346                 e->command = "rpt nodes";
03347                 e->usage = dump_nodes;
03348                 return NULL;
03349         case CLI_GENERATE:
03350                 return NULL;
03351    }
03352    return res2cli(rpt_do_nodes(a->fd,a->argc,a->argv));
03353 }
03354 
03355 static char *handle_cli_local_nodes(struct ast_cli_entry *e,
03356    int cmd, struct ast_cli_args *a)
03357 {
03358         switch (cmd) {
03359         case CLI_INIT:
03360                 e->command = "rpt localnodes";
03361                 e->usage = usage_local_nodes;
03362                 return NULL;
03363         case CLI_GENERATE:
03364                 return NULL;
03365    }
03366    return res2cli(rpt_do_local_nodes(a->fd,a->argc,a->argv));
03367 }
03368 
03369 static char *handle_cli_lstats(struct ast_cli_entry *e,
03370    int cmd, struct ast_cli_args *a)
03371 {
03372         switch (cmd) {
03373         case CLI_INIT:
03374                 e->command = "rpt lstats";
03375                 e->usage = dump_lstats;
03376                 return NULL;
03377         case CLI_GENERATE:
03378                 return NULL;
03379    }
03380    return res2cli(rpt_do_lstats(a->fd,a->argc,a->argv));
03381 }
03382 
03383 static char *handle_cli_reload(struct ast_cli_entry *e,
03384    int cmd, struct ast_cli_args *a)
03385 {
03386         switch (cmd) {
03387         case CLI_INIT:
03388                 e->command = "rpt reload";
03389                 e->usage = reload_usage;
03390                 return NULL;
03391         case CLI_GENERATE:
03392                 return NULL;
03393    }
03394    return res2cli(rpt_do_reload(a->fd,a->argc,a->argv));
03395 }
03396 
03397 static char *handle_cli_restart(struct ast_cli_entry *e,
03398    int cmd, struct ast_cli_args *a)
03399 {
03400         switch (cmd) {
03401         case CLI_INIT:
03402                 e->command = "rpt restart";
03403                 e->usage = restart_usage;
03404                 return NULL;
03405         case CLI_GENERATE:
03406                 return NULL;
03407    }
03408    return res2cli(rpt_do_restart(a->fd,a->argc,a->argv));
03409 }
03410 
03411 static char *handle_cli_fun(struct ast_cli_entry *e,
03412    int cmd, struct ast_cli_args *a)
03413 {
03414         switch (cmd) {
03415         case CLI_INIT:
03416                 e->command = "rpt fun";
03417                 e->usage = fun_usage;
03418                 return NULL;
03419         case CLI_GENERATE:
03420                 return NULL;
03421    }
03422    return res2cli(rpt_do_fun(a->fd,a->argc,a->argv));
03423 }
03424 
03425 static char *handle_cli_fun1(struct ast_cli_entry *e,
03426    int cmd, struct ast_cli_args *a)
03427 {
03428         switch (cmd) {
03429         case CLI_INIT:
03430                 e->command = "rpt fun1";
03431                 e->usage = fun_usage;
03432                 return NULL;
03433         case CLI_GENERATE:
03434                 return NULL;
03435    }
03436    return res2cli(rpt_do_fun1(a->fd,a->argc,a->argv));
03437 }
03438 
03439 static char *handle_cli_cmd(struct ast_cli_entry *e,
03440    int cmd, struct ast_cli_args *a)
03441 {
03442         switch (cmd) {
03443         case CLI_INIT:
03444                 e->command = "rpt cmd";
03445                 e->usage = cmd_usage;
03446                 return NULL;
03447         case CLI_GENERATE:
03448                 return NULL;
03449    }
03450    return res2cli(rpt_do_cmd(a->fd,a->argc,a->argv));
03451 }
03452 
03453 static struct ast_cli_entry rpt_cli[] = {
03454    AST_CLI_DEFINE(handle_cli_debug,"Enable app_rpt debugging"),
03455    AST_CLI_DEFINE(handle_cli_dump,"Dump app_rpt structs for debugging"),
03456    AST_CLI_DEFINE(handle_cli_stats,"Dump node statistics"),
03457    AST_CLI_DEFINE(handle_cli_nodes,"Dump node list"),
03458    AST_CLI_DEFINE(handle_cli_local_nodes, "Dump list of local node numbers"),
03459    AST_CLI_DEFINE(handle_cli_lstats,"Dump link statistics"),
03460    AST_CLI_DEFINE(handle_cli_reload,"Reload app_rpt config"),
03461    AST_CLI_DEFINE(handle_cli_restart,"Restart app_rpt"),
03462    AST_CLI_DEFINE(handle_cli_fun,"Execute a DTMF function"),
03463    AST_CLI_DEFINE(handle_cli_fun1,"Execute a DTMF function"),
03464    AST_CLI_DEFINE(handle_cli_cmd,"Execute a DTMF function")
03465 };
03466 
03467 #endif
03468 
03469 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
03470 {
03471 
03472 static struct morse_bits mbits[] = {
03473       {0, 0}, /* SPACE */
03474       {0, 0}, 
03475       {6, 18},/* " */
03476       {0, 0},
03477       {7, 72},/* $ */
03478       {0, 0},
03479       {0, 0},
03480       {6, 30},/* ' */
03481       {5, 13},/* ( */
03482       {6, 29},/* ) */
03483       {0, 0},
03484       {5, 10},/* + */
03485       {6, 51},/* , */
03486       {6, 33},/* - */
03487       {6, 42},/* . */
03488       {5, 9}, /* / */
03489       {5, 31},/* 0 */
03490       {5, 30},/* 1 */
03491       {5, 28},/* 2 */
03492       {5, 24},/* 3 */
03493       {5, 16},/* 4 */
03494       {5, 0}, /* 5 */
03495       {5, 1}, /* 6 */
03496       {5, 3}, /* 7 */
03497       {5, 7}, /* 8 */
03498       {5, 15},/* 9 */
03499       {6, 7}, /* : */
03500       {6, 21},/* ; */
03501       {0, 0},
03502       {5, 33},/* = */
03503       {0, 0},
03504       {6, 12},/* ? */
03505       {0, 0},
03506          {2, 2}, /* A */
03507       {4, 1}, /* B */
03508       {4, 5}, /* C */
03509       {3, 1}, /* D */
03510       {1, 0}, /* E */
03511       {4, 4}, /* F */
03512       {3, 3}, /* G */
03513       {4, 0}, /* H */
03514       {2, 0}, /* I */
03515       {4, 14},/* J */
03516       {3, 5}, /* K */
03517       {4, 2}, /* L */
03518       {2, 3}, /* M */
03519       {2, 1}, /* N */
03520       {3, 7}, /* O */
03521       {4, 6}, /* P */
03522       {4, 11},/* Q */
03523       {3, 2}, /* R */
03524       {3, 0}, /* S */
03525       {1, 1}, /* T */
03526       {3, 4}, /* U */
03527       {4, 8}, /* V */
03528       {3, 6}, /* W */
03529       {4, 9}, /* X */
03530       {4, 13},/* Y */
03531       {4, 3}  /* Z */
03532    };
03533 
03534 
03535    int dottime;
03536    int dashtime;
03537    int intralettertime;
03538    int interlettertime;
03539    int interwordtime;
03540    int len, ddcomb;
03541    int res;
03542    int c;
03543    int i;
03544    int flags;
03545          
03546    res = 0;
03547    
03548    /* Approximate the dot time from the speed arg. */
03549    
03550    dottime = 900/speed;
03551    
03552    /* Establish timing releationships */
03553    
03554    dashtime = 3 * dottime;
03555    intralettertime = dottime;
03556    interlettertime = dottime * 4 ;
03557    interwordtime = dottime * 7;
03558    
03559    for(;(*string) && (!res); string++){
03560    
03561       c = *string;
03562       
03563       /* Convert lower case to upper case */
03564       
03565       if((c >= 'a') && (c <= 'z'))
03566          c -= 0x20;
03567       
03568       /* Can't deal with any char code greater than Z, skip it */
03569       
03570       if(c  > 'Z')
03571          continue;
03572       
03573       /* If space char, wait the inter word time */
03574                
03575       if(c == ' '){
03576          if(!res)
03577             res = play_silence(chan, interwordtime);
03578          continue;
03579       }
03580       
03581       /* Subtract out control char offset to match our table */
03582       
03583       c -= 0x20;
03584       
03585       /* Get the character data */
03586       
03587       len = mbits[c].len;
03588       ddcomb = mbits[c].ddcomb;
03589       
03590       /* Send the character */
03591       
03592       for(; len ; len--){
03593          if(!res)
03594             res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
03595          if(!res)
03596             res = play_silence(chan, intralettertime);
03597          ddcomb >>= 1;
03598       }
03599       
03600       /* Wait the interletter time */
03601       
03602       if(!res)
03603          res = play_silence(chan, interlettertime - intralettertime);
03604    }
03605    
03606    /* Wait for all the frames to be sent */
03607    
03608    if (!res) 
03609       res = ast_waitstream(chan, "");
03610    ast_stopstream(chan);
03611    
03612    /*
03613    * Wait for the DAHDI driver to physically write the tone blocks to the hardware
03614    */
03615 
03616    for(i = 0; i < 20 ; i++){
03617       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
03618       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
03619       if(flags & DAHDI_IOMUX_WRITEEMPTY)
03620          break;
03621       if( ast_safe_sleep(chan, 50)){
03622          res = -1;
03623          break;
03624       }
03625    }
03626 
03627    
03628    return res;
03629 }
03630 
03631 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
03632 {
03633    char *p,*stringp;
03634    char *tonesubset;
03635    int f1,f2;
03636    int duration;
03637    int amplitude;
03638    int res;
03639    int i;
03640    int flags;
03641    
03642    res = 0;
03643 
03644    if(!tonestring)
03645       return res;
03646    
03647    p = stringp = ast_strdup(tonestring);
03648 
03649    for(;tonestring;){
03650       tonesubset = strsep(&stringp,")");
03651       if(!tonesubset)
03652          break;
03653       if(sscanf(tonesubset,"(%30d,%30d,%30d,%30d", &f1, &f2, &duration, &amplitude) != 4)
03654          break;
03655       res = play_tone_pair(chan, f1, f2, duration, amplitude);
03656       if(res)
03657          break;
03658    }
03659    ast_free(p);
03660    if(!res)
03661       res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
03662    
03663    if (!res) 
03664       res = ast_waitstream(chan, "");
03665 
03666    ast_stopstream(chan);
03667 
03668    /*
03669    * Wait for the DAHDI driver to physically write the tone blocks to the hardware
03670    */
03671 
03672    for(i = 0; i < 20 ; i++){
03673       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
03674       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
03675       if(flags & DAHDI_IOMUX_WRITEEMPTY)
03676          break;
03677       if( ast_safe_sleep(chan, 50)){
03678          res = -1;
03679          break;
03680       }
03681    }
03682       
03683    return res;
03684       
03685 }
03686 
03687 static int sayfile(struct ast_channel *mychannel,char *fname)
03688 {
03689 int   res;
03690 
03691    res = ast_streamfile(mychannel, fname, mychannel->language);
03692    if (!res) 
03693       res = ast_waitstream(mychannel, "");
03694    else
03695        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03696    ast_stopstream(mychannel);
03697    return res;
03698 }
03699 
03700 static int saycharstr(struct ast_channel *mychannel,char *str)
03701 {
03702 int   res;
03703 
03704    res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
03705    if (!res) 
03706       res = ast_waitstream(mychannel, "");
03707    else
03708        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03709    ast_stopstream(mychannel);
03710    return res;
03711 }
03712 
03713 static int saynum(struct ast_channel *mychannel, int num)
03714 {
03715    int res;
03716    res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
03717    if(!res)
03718       res = ast_waitstream(mychannel, "");
03719    else
03720       ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03721    ast_stopstream(mychannel);
03722    return res;
03723 }
03724 
03725 /* say a node and nodename. Try to look in dir referred to by nodenames in
03726 config, and see if there's a custom node file to play, and if so, play it */
03727 
03728 static int saynode(struct rpt *myrpt, struct ast_channel *mychannel, char *name)
03729 {
03730 int   res;
03731 char  *val,fname[300];
03732 
03733    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "nodenames");
03734    if (!val) val = NODENAMES;
03735    snprintf(fname,sizeof(fname) - 1,"%s/%s",val,name);
03736    if (ast_fileexists(fname,NULL,mychannel->language) > 0)
03737       return(sayfile(mychannel,fname));
03738    res = sayfile(mychannel,"rpt/node");
03739    if (!res) 
03740       res = ast_say_character_str(mychannel,name,NULL,mychannel->language);
03741    return res;
03742 }
03743 
03744 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
03745 {
03746    int res;
03747    char c;
03748    
03749    static int morsespeed;
03750    static int morsefreq;
03751    static int morseampl;
03752    static int morseidfreq = 0;
03753    static int morseidampl;
03754    static char mcat[] = MORSE;
03755    
03756    res = 0;
03757    
03758    if(!morseidfreq){ /* Get the morse parameters if not already loaded */
03759       morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
03760          morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
03761          morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
03762       morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
03763       morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330); 
03764    }
03765    
03766    /* Is it a file, or a tone sequence? */
03767          
03768    if(entry[0] == '|'){
03769       c = entry[1];
03770       if((c >= 'a')&&(c <= 'z'))
03771          c -= 0x20;
03772    
03773       switch(c){
03774          case 'I': /* Morse ID */
03775             res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
03776             break;
03777          
03778          case 'M': /* Morse Message */
03779             res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
03780             break;
03781          
03782          case 'T': /* Tone sequence */
03783             res = send_tone_telemetry(chan, entry + 2);
03784             break;
03785          default:
03786             res = -1;
03787       }
03788    }
03789    else
03790       res = sayfile(chan, entry); /* File */
03791    return res;
03792 }
03793 
03794 /*
03795 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
03796 *
03797 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
03798 */
03799 
03800 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
03801 {
03802    
03803    int res;
03804    int i;
03805    char *entry;
03806    char *telemetry;
03807    char *telemetry_save;
03808 
03809    res = 0;
03810    telemetry_save = NULL;
03811    entry = NULL;
03812    
03813    /* Retrieve the section name for telemetry from the node section */
03814    telemetry = (char *) ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
03815    if(telemetry ){
03816       telemetry_save = ast_strdup(telemetry);
03817       if(!telemetry_save){
03818          ast_log(LOG_WARNING,"ast_strdup() failed in telem_lookup()\n");
03819          return res;
03820       }
03821       entry = (char *) ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
03822    }
03823    
03824    /* Try to look up the telemetry name */   
03825 
03826    if(!entry){
03827       /* Telemetry name wasn't found in the config file, use the default */
03828       for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
03829          if(!strcasecmp(tele_defs[i].name, name))
03830             entry = tele_defs[i].value;
03831       }
03832    }
03833    if(entry){  
03834       if(strlen(entry))
03835          if (chan) telem_any(myrpt,chan, entry);
03836    }
03837    else{
03838       res = -1;
03839    }
03840    ast_free(telemetry_save);
03841    return res;
03842 }
03843 
03844 /*
03845 * Retrieve a wait interval
03846 */
03847 
03848 static int get_wait_interval(struct rpt *myrpt, int type)
03849 {
03850         int interval;
03851         char *wait_times;
03852         char *wait_times_save;
03853                                                                                                                   
03854         wait_times_save = NULL;
03855         wait_times = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
03856                                                                                                                   
03857         if(wait_times){
03858                 wait_times_save = ast_strdup(wait_times);
03859                 if(!wait_times_save)
03860          return 0;
03861                 
03862         }
03863                                                                                                                   
03864         switch(type){
03865                 case DLY_TELEM:
03866                         if(wait_times)
03867                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
03868                         else
03869                                 interval = 1000;
03870                         break;
03871                                                                                                                   
03872                 case DLY_ID:
03873                         if(wait_times)
03874                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
03875                         else
03876                                 interval = 500;
03877                         break;
03878                                                                                                                   
03879                 case DLY_UNKEY:
03880                         if(wait_times)
03881                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",50,5000,1000);
03882                         else
03883                                 interval = 1000;
03884                         break;
03885                                                                                                                   
03886                 case DLY_LINKUNKEY:
03887                         if(wait_times)
03888                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "linkunkeywait",500,5000,1000);
03889                         else
03890                                 interval = 1000;
03891                         break;
03892                                                                                                                   
03893                 case DLY_CALLTERM:
03894                         if(wait_times)
03895                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
03896                         else
03897                                 interval = 1500;
03898                         break;
03899                                                                                                                   
03900                 case DLY_COMP:
03901                         if(wait_times)
03902                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "compwait",500,5000,200);
03903                         else
03904                                 interval = 200;
03905                         break;
03906                                                                                                                   
03907                 case DLY_PARROT:
03908                         if(wait_times)
03909                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "parrotwait",500,5000,200);
03910                         else
03911                                 interval = 200;
03912                         break;
03913                                                                                                                   
03914                 default:
03915          interval = 0;
03916          break;
03917         }
03918    ast_free(wait_times_save);
03919    return interval;
03920 }                                                                                                                  
03921 
03922 
03923 /*
03924 * Wait a configurable interval of time 
03925 */
03926 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
03927 {
03928    int interval;
03929    interval = get_wait_interval(myrpt, type);
03930    if(debug)
03931       ast_log(LOG_NOTICE,"Delay interval = %d\n", interval);
03932    if(interval)
03933       ast_safe_sleep(chan,interval);
03934    if(debug)
03935       ast_log(LOG_NOTICE,"Delay complete\n");
03936    return;
03937 }
03938 
03939 static int split_freq(char *mhz, char *decimals, char *freq);
03940 
03941 static void *rpt_tele_thread(void *this)
03942 {
03943 struct dahdi_confinfo ci;  /* conference info */
03944 int   res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
03945 struct   rpt_tele *mytele = (struct rpt_tele *)this;
03946 struct  rpt_tele *tlist;
03947 struct   rpt *myrpt;
03948 struct   rpt_link *l,*l1,linkbase;
03949 struct   ast_channel *mychannel;
03950 int vmajor, vminor, m;
03951 char *p,*ct,*ct_copy,*ident, *nodename,*cp;
03952 time_t t;
03953 #ifdef   NEW_ASTERISK
03954 struct ast_tm localtm;
03955 #else
03956 struct tm localtm;
03957 #endif
03958 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
03959 int   i,ns,rbimode;
03960 char mhz[MAXREMSTR];
03961 char decimals[MAXREMSTR];
03962 char  mystr[200];
03963 struct dahdi_params par;
03964 
03965 
03966    /* get a pointer to myrpt */
03967    myrpt = mytele->rpt;
03968 
03969    /* Snag copies of a few key myrpt variables */
03970    rpt_mutex_lock(&myrpt->lock);
03971    nodename = ast_strdup(myrpt->name);
03972    if(!nodename)
03973    {
03974        fprintf(stderr,"rpt:Sorry unable strdup nodename\n");
03975        rpt_mutex_lock(&myrpt->lock);
03976        remque((struct qelem *)mytele);
03977        ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03978        rpt_mutex_unlock(&myrpt->lock);
03979        ast_free(mytele);
03980        pthread_exit(NULL);
03981    }
03982 
03983    if (myrpt->p.ident){
03984       ident = ast_strdup(myrpt->p.ident);
03985          if(!ident)
03986       {
03987                  fprintf(stderr,"rpt:Sorry unable strdup ident\n");
03988          rpt_mutex_lock(&myrpt->lock);
03989                   remque((struct qelem *)mytele);
03990                   ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",
03991          __LINE__, mytele->mode); /*@@@@@@@@@@@*/
03992                   rpt_mutex_unlock(&myrpt->lock);
03993          ast_free(nodename);
03994                   ast_free(mytele);
03995                   pthread_exit(NULL);
03996          }
03997    }
03998    else
03999    {
04000       ident = "";
04001    }
04002    rpt_mutex_unlock(&myrpt->lock);
04003       
04004 
04005 
04006    /* allocate a pseudo-channel thru asterisk */
04007    mychannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
04008    if (!mychannel)
04009    {
04010       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
04011       rpt_mutex_lock(&myrpt->lock);
04012       remque((struct qelem *)mytele);
04013       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04014       rpt_mutex_unlock(&myrpt->lock);
04015       ast_free(nodename);
04016       ast_free(ident);
04017       ast_free(mytele);    
04018       pthread_exit(NULL);
04019    }
04020 #ifdef   AST_CDR_FLAG_POST_DISABLED
04021    if (mychannel->cdr) 
04022       ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
04023 #endif
04024    rpt_mutex_lock(&myrpt->lock);
04025    mytele->chan = mychannel;
04026    rpt_mutex_unlock(&myrpt->lock);
04027 
04028    while((mytele->mode != SETREMOTE) && (mytele->mode != UNKEY) &&
04029       (mytele->mode != LINKUNKEY))
04030    {  
04031                 rpt_mutex_lock(&myrpt->lock);
04032       if (!myrpt->active_telem)
04033       {
04034          myrpt->active_telem = mytele;
04035                    rpt_mutex_unlock(&myrpt->lock);
04036          break;
04037       }
04038                 rpt_mutex_unlock(&myrpt->lock);
04039       usleep(100000);
04040    }
04041 
04042    /* make a conference for the tx */
04043    ci.chan = 0;
04044    /* If the telemetry is only intended for a local audience, */
04045    /* only connect the ID audio to the local tx conference so */
04046    /* linked systems can't hear it */
04047    ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
04048       (mytele->mode == TAILMSG) || (mytele->mode == LINKUNKEY) || (mytele->mode == TIMEOUT) || 
04049       (mytele->mode == PARROT) || (mytele->mode == STATS_TIME_LOCAL)) ? 
04050          myrpt->txconf : myrpt->conf);
04051    ci.confmode = DAHDI_CONF_CONFANN;
04052    /* first put the channel on the conference in announce mode */
04053    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04054    {
04055       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04056       rpt_mutex_lock(&myrpt->lock);
04057       myrpt->active_telem = NULL;
04058       remque((struct qelem *)mytele);
04059       rpt_mutex_unlock(&myrpt->lock);
04060       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04061       ast_free(nodename);
04062       ast_free(ident);
04063       ast_free(mytele);    
04064       ast_hangup(mychannel);
04065       pthread_exit(NULL);
04066    }
04067    ast_stopstream(mychannel);
04068    switch(mytele->mode)
04069    {
04070        case ID:
04071        case ID1:
04072       /* wait a bit */
04073       wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
04074       res = telem_any(myrpt,mychannel, ident); 
04075       imdone=1;   
04076       break;
04077       
04078        case TAILMSG:
04079       res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language); 
04080       break;
04081       
04082        case IDTALKOVER:
04083          p = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
04084          if(p)
04085          res = telem_any(myrpt,mychannel, p); 
04086       imdone=1;   
04087          break;
04088             
04089        case PROC:
04090       /* wait a little bit longer */
04091       wait_interval(myrpt, DLY_TELEM, mychannel);
04092       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
04093       if(res < 0){ /* Then default message */
04094          res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
04095       }
04096       break;
04097        case TERM:
04098       /* wait a little bit longer */
04099       wait_interval(myrpt, DLY_CALLTERM, mychannel);
04100       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
04101       if(res < 0){ /* Then default message */
04102          res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
04103       }
04104       break;
04105        case COMPLETE:
04106       /* wait a little bit */
04107       wait_interval(myrpt, DLY_TELEM, mychannel);
04108       res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04109       break;
04110        case MACRO_NOTFOUND:
04111       /* wait a little bit */
04112       wait_interval(myrpt, DLY_TELEM, mychannel);
04113       res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
04114       break;
04115        case MACRO_BUSY:
04116       /* wait a little bit */
04117       wait_interval(myrpt, DLY_TELEM, mychannel);
04118       res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
04119       break;
04120        case UNKEY:
04121       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
04122          imdone = 1;
04123          break;
04124       }
04125          
04126       /*
04127       * Reset the Unkey to CT timer
04128       */
04129 
04130       x = get_wait_interval(myrpt, DLY_UNKEY);
04131       rpt_mutex_lock(&myrpt->lock);
04132       myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
04133       rpt_mutex_unlock(&myrpt->lock);
04134 
04135       /*
04136       * If there's one already queued, don't do another
04137       */
04138 
04139       tlist = myrpt->tele.next;
04140       unkeys_queued = 0;
04141                 if (tlist != &myrpt->tele)
04142                 {
04143                         rpt_mutex_lock(&myrpt->lock);
04144                         while(tlist != &myrpt->tele){
04145                                 if (tlist->mode == UNKEY) unkeys_queued++;
04146                                 tlist = tlist->next;
04147                         }
04148                         rpt_mutex_unlock(&myrpt->lock);
04149       }
04150       if( unkeys_queued > 1){
04151          imdone = 1;
04152          break;
04153       }
04154 
04155       /* Wait for the telemetry timer to expire */
04156       /* Periodically check the timer since it can be re-initialized above */
04157       while(myrpt->unkeytocttimer)
04158       {
04159          int ctint;
04160          if(myrpt->unkeytocttimer > 100)
04161             ctint = 100;
04162          else
04163             ctint = myrpt->unkeytocttimer;
04164          ast_safe_sleep(mychannel, ctint);
04165          rpt_mutex_lock(&myrpt->lock);
04166          if(myrpt->unkeytocttimer < ctint)
04167             myrpt->unkeytocttimer = 0;
04168          else
04169             myrpt->unkeytocttimer -= ctint;
04170          rpt_mutex_unlock(&myrpt->lock);
04171       }
04172    
04173       /*
04174       * Now, the carrier on the rptr rx should be gone. 
04175       * If it re-appeared, then forget about sending the CT
04176       */
04177       if(myrpt->keyed){
04178          imdone = 1;
04179          break;
04180       }
04181       
04182       rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
04183       myrpt->dailykerchunks++;
04184       myrpt->totalkerchunks++;
04185       rpt_mutex_unlock(&myrpt->lock);
04186    
04187       haslink = 0;
04188       hastx = 0;
04189       hasremote = 0;    
04190       l = myrpt->links.next;
04191       if (l != &myrpt->links)
04192       {
04193          rpt_mutex_lock(&myrpt->lock);
04194          while(l != &myrpt->links)
04195          {
04196             if (l->name[0] == '0')
04197             {
04198                l = l->next;
04199                continue;
04200             }
04201             haslink = 1;
04202             if (l->mode) {
04203                hastx++;
04204                if (l->isremote) hasremote++;
04205             }
04206             l = l->next;
04207          }
04208          rpt_mutex_unlock(&myrpt->lock);
04209       }
04210       if (haslink)
04211       {
04212 
04213          res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
04214          if(res)
04215             ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
04216          
04217       
04218          /* if in remote cmd mode, indicate it */
04219          if (myrpt->cmdnode[0])
04220          {
04221             ast_safe_sleep(mychannel,200);
04222             res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
04223             if(res)
04224                ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
04225             ast_stopstream(mychannel);
04226          }
04227       }
04228       else if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
04229          ct_copy = ast_strdup(ct);
04230          if(ct_copy)
04231          {
04232             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04233             ast_free(ct_copy);
04234          }
04235          else
04236             res = -1;
04237          if(res)
04238             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
04239       }  
04240       if (hasremote && (!myrpt->cmdnode[0]))
04241       {
04242          /* set for all to hear */
04243          ci.chan = 0;
04244          ci.confno = myrpt->conf;
04245          ci.confmode = DAHDI_CONF_CONFANN;
04246          /* first put the channel on the conference in announce mode */
04247          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04248          {
04249             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04250             rpt_mutex_lock(&myrpt->lock);
04251             myrpt->active_telem = NULL;
04252             remque((struct qelem *)mytele);
04253             rpt_mutex_unlock(&myrpt->lock);
04254             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04255             ast_free(nodename);
04256             ast_free(ident);
04257             ast_free(mytele);    
04258             ast_hangup(mychannel);
04259             pthread_exit(NULL);
04260          }
04261          if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
04262             ast_safe_sleep(mychannel,200);
04263             ct_copy = ast_strdup(ct);
04264             if(ct_copy)
04265             {
04266                res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04267                ast_free(ct_copy);
04268             }
04269             else
04270                res = -1;
04271       
04272             if(res)
04273                ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
04274          }  
04275       }
04276 #if   defined(_MDC_DECODE_H_) && defined(MDC_SAY_WHEN_DOING_CT)
04277       if (myrpt->lastunit)
04278       {
04279          char mystr[10];
04280 
04281          ast_safe_sleep(mychannel,200);
04282          /* set for all to hear */
04283          ci.chan = 0;
04284          ci.confno = myrpt->txconf;
04285          ci.confmode = DAHDI_CONF_CONFANN;
04286          /* first put the channel on the conference in announce mode */
04287          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04288          {
04289             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04290             rpt_mutex_lock(&myrpt->lock);
04291             myrpt->active_telem = NULL;
04292             remque((struct qelem *)mytele);
04293             rpt_mutex_unlock(&myrpt->lock);
04294             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04295             ast_free(nodename);
04296             ast_free(ident);
04297             ast_free(mytele);    
04298             ast_hangup(mychannel);
04299             pthread_exit(NULL);
04300          }
04301          sprintf(mystr,"%04x",myrpt->lastunit);
04302          myrpt->lastunit = 0;
04303          ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
04304          break;
04305       }
04306 #endif
04307       imdone = 1;
04308       break;
04309        case LINKUNKEY:
04310       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
04311          imdone = 1;
04312          break;
04313       }
04314          
04315       /*
04316       * Reset the Unkey to CT timer
04317       */
04318 
04319       x = get_wait_interval(myrpt, DLY_LINKUNKEY);
04320       mytele->mylink.linkunkeytocttimer = x; /* Must be protected as it is changed below */
04321 
04322       /*
04323       * If there's one already queued, don't do another
04324       */
04325 
04326       tlist = myrpt->tele.next;
04327       unkeys_queued = 0;
04328                 if (tlist != &myrpt->tele)
04329                 {
04330                         rpt_mutex_lock(&myrpt->lock);
04331                         while(tlist != &myrpt->tele){
04332                                 if (tlist->mode == LINKUNKEY) unkeys_queued++;
04333                                 tlist = tlist->next;
04334                         }
04335                         rpt_mutex_unlock(&myrpt->lock);
04336       }
04337       if( unkeys_queued > 1){
04338          imdone = 1;
04339          break;
04340       }
04341 
04342       /* Wait for the telemetry timer to expire */
04343       /* Periodically check the timer since it can be re-initialized above */
04344       while(mytele->mylink.linkunkeytocttimer)
04345       {
04346          int ctint;
04347          if(mytele->mylink.linkunkeytocttimer > 100)
04348             ctint = 100;
04349          else
04350             ctint = mytele->mylink.linkunkeytocttimer;
04351          ast_safe_sleep(mychannel, ctint);
04352          rpt_mutex_lock(&myrpt->lock);
04353          if(mytele->mylink.linkunkeytocttimer < ctint)
04354             mytele->mylink.linkunkeytocttimer = 0;
04355          else
04356             mytele->mylink.linkunkeytocttimer -= ctint;
04357          rpt_mutex_unlock(&myrpt->lock);
04358       }
04359    
04360       if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "linkunkeyct"))){ /* Unlinked Courtesy Tone */
04361          ct_copy = ast_strdup(ct);
04362          if(ct_copy){
04363             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04364             ast_free(ct_copy);
04365          }
04366          else
04367             res = -1;
04368          if(res)
04369             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
04370       }  
04371       imdone = 1;
04372       break;
04373        case REMDISC:
04374       /* wait a little bit */
04375       wait_interval(myrpt, DLY_TELEM, mychannel);
04376       l = myrpt->links.next;
04377       haslink = 0;
04378       /* don't report if a link for this one still on system */
04379       if (l != &myrpt->links)
04380       {
04381          rpt_mutex_lock(&myrpt->lock);
04382          while(l != &myrpt->links)
04383          {
04384             if (l->name[0] == '0')
04385             {
04386                l = l->next;
04387                continue;
04388             }
04389             if (!strcmp(l->name,mytele->mylink.name))
04390             {
04391                haslink = 1;
04392                break;
04393             }
04394             l = l->next;
04395          }
04396          rpt_mutex_unlock(&myrpt->lock);
04397       }
04398       if (haslink)
04399       {
04400          imdone = 1;
04401          break;
04402       }
04403       res = saynode(myrpt,mychannel,mytele->mylink.name);
04404       if (!res) 
04405           res = ast_streamfile(mychannel, ((mytele->mylink.hasconnected) ? 
04406          "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
04407       break;
04408        case REMALREADY:
04409       /* wait a little bit */
04410       wait_interval(myrpt, DLY_TELEM, mychannel);
04411       res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
04412       break;
04413        case REMNOTFOUND:
04414       /* wait a little bit */
04415       wait_interval(myrpt, DLY_TELEM, mychannel);
04416       res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
04417       break;
04418        case REMGO:
04419       /* wait a little bit */
04420       wait_interval(myrpt, DLY_TELEM, mychannel);
04421       res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
04422       break;
04423        case CONNECTED:
04424       /* wait a little bit */
04425       wait_interval(myrpt, DLY_TELEM,  mychannel);
04426       res = saynode(myrpt,mychannel,mytele->mylink.name);
04427       if (!res)
04428           res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
04429       if (!res) 
04430          res = ast_waitstream(mychannel, "");
04431       else
04432           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04433       ast_stopstream(mychannel);
04434       res = ast_streamfile(mychannel, "digits/2", mychannel->language);
04435       if (!res) 
04436          res = ast_waitstream(mychannel, "");
04437       else
04438           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04439       ast_stopstream(mychannel);
04440       res = saynode(myrpt,mychannel,myrpt->name);
04441       imdone = 1;
04442       break;
04443        case CONNFAIL:
04444       res = saynode(myrpt,mychannel,mytele->mylink.name);
04445       if (!res) 
04446           res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
04447       break;
04448        case MEMNOTFOUND:
04449       /* wait a little bit */
04450       wait_interval(myrpt, DLY_TELEM, mychannel);
04451       res = ast_streamfile(mychannel, "rpt/memory_notfound", mychannel->language);
04452       break;
04453        case PLAYBACK:
04454       /* wait a little bit */
04455       wait_interval(myrpt, DLY_TELEM, mychannel);
04456       res = ast_streamfile(mychannel, mytele->param, mychannel->language);
04457       break;
04458        case TOPKEY:
04459       /* wait a little bit */
04460       wait_interval(myrpt, DLY_TELEM, mychannel);
04461       for(i = 0; i < TOPKEYN; i++)
04462       {
04463          if (!myrpt->topkey[i].node[0]) continue;
04464          if ((!myrpt->topkeylong) && (myrpt->topkey[i].keyed)) continue;
04465          res = saynode(myrpt, mychannel,  myrpt->topkey[i].node);
04466          if (!res) res = sayfile(mychannel,(myrpt->topkey[i].keyed) ?
04467             "rpt/keyedfor" : "rpt/unkeyedfor");
04468          if (!res) res = saynum(mychannel,
04469             myrpt->topkey[i].timesince);
04470          if (!res) res = sayfile(mychannel,"rpt/seconds");
04471          if (!myrpt->topkeylong) break;
04472       }
04473       imdone = 1;
04474       break;
04475        case SETREMOTE:
04476       ast_mutex_lock(&myrpt->remlock);
04477       res = 0;
04478       if(!strcmp(myrpt->remoterig, remote_rig_ft897))
04479       {
04480          res = set_ft897(myrpt);
04481       }
04482       else if(!strcmp(myrpt->remoterig, remote_rig_tm271))
04483       {
04484          res = set_tm271(myrpt);
04485       }
04486       else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
04487       {
04488          res = set_ic706(myrpt);
04489       }
04490 #ifdef HAVE_IOPERM
04491       else if(!strcmp(myrpt->remoterig, remote_rig_rbi)||!strcmp(myrpt->remoterig, remote_rig_ppp16))
04492       {
04493          if (ioperm(myrpt->p.iobase,1,1) == -1)
04494          {
04495             rpt_mutex_unlock(&myrpt->lock);
04496             ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
04497             res = -1;
04498          }
04499          else res = setrbi(myrpt);
04500       }
04501 #endif
04502       else if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
04503       {
04504          if (myrpt->iofd >= 0) setdtr(myrpt->iofd,1);
04505          res = setkenwood(myrpt);
04506          if (myrpt->iofd >= 0) setdtr(myrpt->iofd,0);
04507          if (ast_safe_sleep(mychannel,200) == -1)
04508          {
04509             ast_mutex_unlock(&myrpt->remlock);
04510             res = -1;
04511             break;
04512          }
04513          if (myrpt->iofd < 0)
04514          {
04515             i = DAHDI_FLUSH_EVENT;
04516             if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_FLUSH,&i) == -1)
04517             {
04518                ast_mutex_unlock(&myrpt->remlock);
04519                ast_log(LOG_ERROR,"Cant flush events");
04520                res = -1;
04521                break;
04522             }
04523             if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_GET_PARAMS,&par) == -1)
04524             {
04525                ast_mutex_unlock(&myrpt->remlock);
04526                ast_log(LOG_ERROR,"Cant get params");
04527                res = -1;
04528                break;
04529             }
04530             myrpt->remoterx = 
04531                (par.rxisoffhook || (myrpt->tele.next != &myrpt->tele));
04532          }
04533       }
04534 
04535       ast_mutex_unlock(&myrpt->remlock);
04536       if (!res)
04537       {
04538          imdone = 1;
04539          break;
04540       }
04541       /* fall thru to invalid freq */
04542        case INVFREQ:
04543       /* wait a little bit */
04544       wait_interval(myrpt, DLY_TELEM, mychannel);
04545       res = ast_streamfile(mychannel, "rpt/invalid-freq", mychannel->language);
04546       break;
04547        case REMMODE:
04548       cp = 0;
04549       wait_interval(myrpt, DLY_TELEM, mychannel);
04550       switch(myrpt->remmode)
04551       {
04552           case REM_MODE_FM:
04553          saycharstr(mychannel,"FM");
04554          break;
04555           case REM_MODE_USB:
04556          saycharstr(mychannel,"USB");
04557          break;
04558           case REM_MODE_LSB:
04559          saycharstr(mychannel,"LSB");
04560          break;
04561           case REM_MODE_AM:
04562          saycharstr(mychannel,"AM");
04563          break;
04564       }
04565       wait_interval(myrpt, DLY_COMP, mychannel);
04566       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04567       break;
04568        case LOGINREQ:
04569       wait_interval(myrpt, DLY_TELEM, mychannel);
04570       sayfile(mychannel,"rpt/login");
04571       saycharstr(mychannel,myrpt->name);
04572       break;
04573        case REMLOGIN:
04574       wait_interval(myrpt, DLY_TELEM, mychannel);
04575       saycharstr(mychannel,myrpt->loginuser);
04576       saynode(myrpt,mychannel,myrpt->name);
04577       wait_interval(myrpt, DLY_COMP, mychannel);
04578       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04579       break;
04580        case REMXXX:
04581       wait_interval(myrpt, DLY_TELEM, mychannel);
04582       res = 0;
04583       switch(mytele->submode)
04584       {
04585           case 100: /* RX PL Off */
04586          sayfile(mychannel, "rpt/rxpl");
04587          sayfile(mychannel, "rpt/off");
04588          break;
04589           case 101: /* RX PL On */
04590          sayfile(mychannel, "rpt/rxpl");
04591          sayfile(mychannel, "rpt/on");
04592          break;
04593           case 102: /* TX PL Off */
04594          sayfile(mychannel, "rpt/txpl");
04595          sayfile(mychannel, "rpt/off");
04596          break;
04597           case 103: /* TX PL On */
04598          sayfile(mychannel, "rpt/txpl");
04599          sayfile(mychannel, "rpt/on");
04600          break;
04601           case 104: /* Low Power */
04602          sayfile(mychannel, "rpt/lopwr");
04603          break;
04604           case 105: /* Medium Power */
04605          sayfile(mychannel, "rpt/medpwr");
04606          break;
04607           case 106: /* Hi Power */
04608          sayfile(mychannel, "rpt/hipwr");
04609          break;
04610           case 113: /* Scan down slow */
04611          sayfile(mychannel,"rpt/down");
04612          sayfile(mychannel, "rpt/slow");
04613          break;
04614           case 114: /* Scan down quick */
04615          sayfile(mychannel,"rpt/down");
04616          sayfile(mychannel, "rpt/quick");
04617          break;
04618           case 115: /* Scan down fast */
04619          sayfile(mychannel,"rpt/down");
04620          sayfile(mychannel, "rpt/fast");
04621          break;
04622           case 116: /* Scan up slow */
04623          sayfile(mychannel,"rpt/up");
04624          sayfile(mychannel, "rpt/slow");
04625          break;
04626           case 117: /* Scan up quick */
04627          sayfile(mychannel,"rpt/up");
04628          sayfile(mychannel, "rpt/quick");
04629          break;
04630           case 118: /* Scan up fast */
04631          sayfile(mychannel,"rpt/up");
04632          sayfile(mychannel, "rpt/fast");
04633          break;
04634           default:
04635          res = -1;
04636       }
04637       wait_interval(myrpt, DLY_COMP, mychannel);
04638       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04639       break;
04640        case SCAN:
04641       ast_mutex_lock(&myrpt->remlock);
04642       if (myrpt->hfscanstop)
04643       {
04644          myrpt->hfscanstatus = 0;
04645          myrpt->hfscanmode = 0;
04646          myrpt->hfscanstop = 0;
04647          mytele->mode = SCANSTAT;
04648          ast_mutex_unlock(&myrpt->remlock);
04649          if (ast_safe_sleep(mychannel,1000) == -1) break;
04650          sayfile(mychannel, "rpt/stop"); 
04651          imdone = 1;
04652          break;
04653       }
04654       if (myrpt->hfscanstatus > -2) service_scan(myrpt);
04655       i = myrpt->hfscanstatus;
04656       myrpt->hfscanstatus = 0;
04657       if (i) mytele->mode = SCANSTAT;
04658       ast_mutex_unlock(&myrpt->remlock);
04659       if (i < 0) sayfile(mychannel, "rpt/stop"); 
04660       else if (i > 0) saynum(mychannel,i);
04661       imdone = 1;
04662       break;
04663        case TUNE:
04664       ast_mutex_lock(&myrpt->remlock);
04665       if (!strcmp(myrpt->remoterig,remote_rig_ic706))
04666       {
04667          set_mode_ic706(myrpt, REM_MODE_AM);
04668          if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
04669          ast_safe_sleep(mychannel,500);
04670          set_mode_ic706(myrpt, myrpt->remmode);
04671          myrpt->tunerequest = 0;
04672          ast_mutex_unlock(&myrpt->remlock);
04673          imdone = 1;
04674          break;
04675       }
04676       set_mode_ft897(myrpt, REM_MODE_AM);
04677       simple_command_ft897(myrpt, 8);
04678       if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
04679       simple_command_ft897(myrpt, 0x88);
04680       ast_safe_sleep(mychannel,500);
04681       set_mode_ft897(myrpt, myrpt->remmode);
04682       myrpt->tunerequest = 0;
04683       ast_mutex_unlock(&myrpt->remlock);
04684       imdone = 1;
04685       break;
04686        case REMSHORTSTATUS:
04687        case REMLONGSTATUS: 
04688       wait_interval(myrpt, DLY_TELEM, mychannel);
04689       res = saynode(myrpt,mychannel,myrpt->name);
04690       if(!res)
04691          res = sayfile(mychannel,"rpt/frequency");
04692       if(!res)
04693          res = split_freq(mhz, decimals, myrpt->freq);
04694       if (!multimode_capable(myrpt)) decimals[3] = 0;
04695       if(!res){
04696          m = atoi(mhz);
04697          if(m < 100)
04698             res = saynum(mychannel, m);
04699          else
04700             res = saycharstr(mychannel, mhz);
04701       }
04702       if(!res)
04703          res = sayfile(mychannel, "letters/dot");
04704       if(!res)
04705          res = saycharstr(mychannel, decimals);
04706    
04707       if(res)  break;
04708       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
04709          switch(myrpt->offset){
04710    
04711             case REM_MINUS:
04712                res = sayfile(mychannel,"rpt/minus");
04713                break;
04714             
04715             case REM_SIMPLEX:
04716                res = sayfile(mychannel,"rpt/simplex");
04717                break;
04718                
04719             case REM_PLUS:
04720                res = sayfile(mychannel,"rpt/plus");
04721                break;
04722                
04723             default:
04724                break;
04725          }
04726       }
04727       else{ /* Must be USB, LSB, or AM */
04728          switch(myrpt->remmode){
04729 
04730             case REM_MODE_USB:
04731                res = saycharstr(mychannel, "USB");
04732                break;
04733 
04734             case REM_MODE_LSB:
04735                res = saycharstr(mychannel, "LSB");
04736                break;
04737 
04738             case REM_MODE_AM:
04739                res = saycharstr(mychannel, "AM");
04740                break;
04741 
04742 
04743             default:
04744                break;
04745          }
04746       }
04747 
04748       if (res == -1) break;
04749 
04750       if(mytele->mode == REMSHORTSTATUS){ /* Short status? */
04751          wait_interval(myrpt, DLY_COMP, mychannel);
04752          if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04753          break;
04754       }
04755 
04756       if (strcmp(myrpt->remoterig,remote_rig_ic706))
04757       {
04758          switch(myrpt->powerlevel){
04759 
04760             case REM_LOWPWR:
04761                res = sayfile(mychannel,"rpt/lopwr") ;
04762                break;
04763             case REM_MEDPWR:
04764                res = sayfile(mychannel,"rpt/medpwr");
04765                break;
04766             case REM_HIPWR:
04767                res = sayfile(mychannel,"rpt/hipwr"); 
04768                break;
04769             }
04770       }
04771 
04772       rbimode = ((!strncmp(myrpt->remoterig,remote_rig_rbi,3))
04773         || (!strncmp(myrpt->remoterig,remote_rig_ic706,3)));
04774       if (res || (sayfile(mychannel,"rpt/rxpl") == -1)) break;
04775       if (rbimode && (sayfile(mychannel,"rpt/txpl") == -1)) break;
04776       if ((sayfile(mychannel,"rpt/frequency") == -1) ||
04777          (saycharstr(mychannel,myrpt->rxpl) == -1)) break;
04778       if ((!rbimode) && ((sayfile(mychannel,"rpt/txpl") == -1) ||
04779          (sayfile(mychannel,"rpt/frequency") == -1) ||
04780          (saycharstr(mychannel,myrpt->txpl) == -1))) break;
04781       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
04782          if ((sayfile(mychannel,"rpt/rxpl") == -1) ||
04783             (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1) ||
04784             (sayfile(mychannel,"rpt/txpl") == -1) ||
04785             (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1))
04786             {
04787                break;
04788             }
04789       }
04790       wait_interval(myrpt, DLY_COMP, mychannel);
04791       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04792       break;
04793        case STATUS:
04794       /* wait a little bit */
04795       wait_interval(myrpt, DLY_TELEM, mychannel);
04796       hastx = 0;
04797       linkbase.next = &linkbase;
04798       linkbase.prev = &linkbase;
04799       rpt_mutex_lock(&myrpt->lock);
04800       /* make our own list of links */
04801       l = myrpt->links.next;
04802       while(l != &myrpt->links)
04803       {
04804          if (l->name[0] == '0')
04805          {
04806             l = l->next;
04807             continue;
04808          }
04809          l1 = ast_malloc(sizeof(struct rpt_link));
04810          if (!l1)
04811          {
04812             ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
04813             remque((struct qelem *)mytele);
04814             myrpt->active_telem = NULL;
04815             rpt_mutex_unlock(&myrpt->lock);
04816             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04817             ast_free(nodename);
04818             ast_free(ident);
04819             ast_free(mytele);    
04820             ast_hangup(mychannel);
04821             pthread_exit(NULL);
04822          }
04823          memcpy(l1,l,sizeof(struct rpt_link));
04824          l1->next = l1->prev = NULL;
04825          insque((struct qelem *)l1,(struct qelem *)linkbase.next);
04826          l = l->next;
04827       }
04828       rpt_mutex_unlock(&myrpt->lock);
04829       res = saynode(myrpt,mychannel,myrpt->name);
04830       if (myrpt->callmode)
04831       {
04832          hastx = 1;
04833          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
04834          if (!res) 
04835             res = ast_waitstream(mychannel, "");
04836          else
04837              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04838          ast_stopstream(mychannel);
04839       }
04840       l = linkbase.next;
04841       while(l != &linkbase)
04842       {
04843          char *s;
04844 
04845          hastx = 1;
04846          res = saynode(myrpt,mychannel,l->name);
04847          s = "rpt/tranceive";
04848          if (!l->mode) s = "rpt/monitor";
04849          if (!l->thisconnected) s = "rpt/connecting";
04850          res = ast_streamfile(mychannel, s, mychannel->language);
04851          if (!res) 
04852             res = ast_waitstream(mychannel, "");
04853          else
04854             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04855          ast_stopstream(mychannel);
04856          l = l->next;
04857       }        
04858       if (!hastx)
04859       {
04860          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
04861          if (!res) 
04862             res = ast_waitstream(mychannel, "");
04863          else
04864              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04865          ast_stopstream(mychannel);
04866       }
04867       /* destroy our local link queue */
04868       l = linkbase.next;
04869       while(l != &linkbase)
04870       {
04871          l1 = l;
04872          l = l->next;
04873          remque((struct qelem *)l1);
04874          ast_free(l1);
04875       }        
04876       imdone = 1;
04877       break;
04878        case FULLSTATUS:
04879       rpt_mutex_lock(&myrpt->lock);
04880       /* get all the nodes */
04881       __mklinklist(myrpt,NULL,lbuf);
04882       rpt_mutex_unlock(&myrpt->lock);
04883       /* parse em */
04884       ns = finddelim(lbuf,strs,MAXLINKLIST);
04885       /* sort em */
04886       if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
04887       /* wait a little bit */
04888       wait_interval(myrpt, DLY_TELEM, mychannel);
04889       hastx = 0;
04890       res = saynode(myrpt,mychannel,myrpt->name);
04891       if (myrpt->callmode)
04892       {
04893          hastx = 1;
04894          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
04895          if (!res) 
04896             res = ast_waitstream(mychannel, "");
04897          else
04898              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04899          ast_stopstream(mychannel);
04900       }
04901       /* go thru all the nodes in list */
04902       for(i = 0; i < ns; i++)
04903       {
04904          char *s,mode = 'T';
04905 
04906          /* if a mode spec at first, handle it */
04907          if ((*strs[i] < '0') || (*strs[i] > '9'))
04908          {
04909             mode = *strs[i];
04910             strs[i]++;
04911          }
04912 
04913          hastx = 1;
04914          res = saynode(myrpt,mychannel,strs[i]);
04915          s = "rpt/tranceive";
04916          if (mode == 'R') s = "rpt/monitor";
04917          if (mode == 'C') s = "rpt/connecting";
04918          res = ast_streamfile(mychannel, s, mychannel->language);
04919          if (!res) 
04920             res = ast_waitstream(mychannel, "");
04921          else
04922             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04923          ast_stopstream(mychannel);
04924       }        
04925       if (!hastx)
04926       {
04927          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
04928          if (!res) 
04929             res = ast_waitstream(mychannel, "");
04930          else
04931              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04932          ast_stopstream(mychannel);
04933       }
04934       imdone = 1;
04935       break;
04936 
04937        case LASTNODEKEY: /* Identify last node which keyed us up */
04938       rpt_mutex_lock(&myrpt->lock);
04939       if(myrpt->lastnodewhichkeyedusup){
04940          p = ast_strdup(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
04941          if(!p){
04942             ast_log(LOG_WARNING, "ast_strdup failed in telemetery LASTNODEKEY");
04943             imdone = 1;
04944             break;
04945          }
04946       }
04947       else
04948          p = NULL;
04949       rpt_mutex_unlock(&myrpt->lock);
04950       if(!p){
04951          imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
04952          break;
04953       }
04954       wait_interval(myrpt, DLY_TELEM, mychannel);
04955       res = saynode(myrpt,mychannel,p);
04956       ast_free(p);
04957       imdone = 1;
04958       break;      
04959 
04960        case UNAUTHTX: /* Say unauthorized transmit frequency */
04961       wait_interval(myrpt, DLY_TELEM, mychannel);
04962       res = ast_streamfile(mychannel, "rpt/unauthtx", mychannel->language);
04963       if (!res) 
04964          res = ast_waitstream(mychannel, "");
04965       else
04966           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04967       ast_stopstream(mychannel);
04968       imdone = 1;
04969       break;
04970 
04971        case PARROT: /* Repeat stuff */
04972 
04973       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04974       if (ast_fileexists(mystr,NULL,mychannel->language) <= 0)
04975       {
04976          imdone = 1;
04977          myrpt->parrotstate = 0;
04978          break;
04979       }
04980       wait_interval(myrpt, DLY_PARROT, mychannel);
04981       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04982       res = ast_streamfile(mychannel, mystr, mychannel->language);
04983       if (!res) 
04984          res = ast_waitstream(mychannel, "");
04985       else
04986           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04987       ast_stopstream(mychannel);
04988       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04989       strcat(mystr,".wav");
04990       unlink(mystr);       
04991       imdone = 1;
04992       myrpt->parrotstate = 0;
04993       break;
04994 
04995        case TIMEOUT:
04996       res = saynode(myrpt,mychannel,myrpt->name);
04997       if (!res)
04998          res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
04999       break;
05000       
05001        case TIMEOUT_WARNING:
05002       time(&t);
05003       res = saynode(myrpt,mychannel,myrpt->name);
05004       if (!res)
05005          res = ast_streamfile(mychannel, "rpt/timeout-warning", mychannel->language);
05006       if (!res) 
05007          res = ast_waitstream(mychannel, "");
05008       else
05009           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05010       ast_stopstream(mychannel);
05011       if(!res) /* Say number of seconds */
05012          ast_say_number(mychannel, myrpt->p.remotetimeout - 
05013              (t - myrpt->last_activity_time), 
05014             "", mychannel->language, (char *) NULL);
05015       if (!res) 
05016          res = ast_waitstream(mychannel, "");
05017       ast_stopstream(mychannel); 
05018       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
05019       break;
05020 
05021        case ACT_TIMEOUT_WARNING:
05022       time(&t);
05023       res = saynode(myrpt,mychannel,myrpt->name);
05024       if (!res)
05025           res = ast_streamfile(mychannel, "rpt/act-timeout-warning", mychannel->language);
05026       if (!res) 
05027          res = ast_waitstream(mychannel, "");
05028       else
05029           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05030       ast_stopstream(mychannel);
05031       if(!res) /* Say number of seconds */
05032          ast_say_number(mychannel, myrpt->p.remoteinacttimeout - 
05033              (t - myrpt->last_activity_time), 
05034             "", mychannel->language, (char *) NULL);
05035       if (!res) 
05036          res = ast_waitstream(mychannel, "");
05037       ast_stopstream(mychannel); 
05038       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
05039       break;
05040       
05041        case STATS_TIME:
05042             case STATS_TIME_LOCAL:
05043          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05044       t = time(NULL);
05045       rpt_localtime(&t, &localtm);
05046       /* Say the phase of the day is before the time */
05047       if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
05048          p = "rpt/goodmorning";
05049       else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
05050          p = "rpt/goodafternoon";
05051       else
05052          p = "rpt/goodevening";
05053       if (sayfile(mychannel,p) == -1)
05054       {
05055          imdone = 1;
05056          break;
05057       }
05058       /* Say the time is ... */     
05059       if (sayfile(mychannel,"rpt/thetimeis") == -1)
05060       {
05061          imdone = 1;
05062          break;
05063       }
05064       /* Say the time */            
05065          res = ast_say_time(mychannel, t, "", mychannel->language);
05066       if (!res) 
05067          res = ast_waitstream(mychannel, "");
05068       ast_stopstream(mychannel);    
05069       imdone = 1;
05070          break;
05071        case STATS_VERSION:
05072       p = strstr(tdesc, "version"); 
05073       if(!p)
05074          break;   
05075       if(sscanf(p, "version %30d.%30d", &vmajor, &vminor) != 2)
05076          break;
05077          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05078       /* Say "version" */
05079       if (sayfile(mychannel,"rpt/version") == -1)
05080       {
05081          imdone = 1;
05082          break;
05083       }
05084       if(!res) /* Say "X" */
05085          ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
05086       if (!res) 
05087          res = ast_waitstream(mychannel, "");
05088       ast_stopstream(mychannel); 
05089       if (saycharstr(mychannel,".") == -1)
05090       {
05091          imdone = 1;
05092          break;
05093       }
05094       if(!res) /* Say "Y" */
05095          ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
05096       if (!res){
05097          res = ast_waitstream(mychannel, "");
05098          ast_stopstream(mychannel);
05099       }  
05100       else
05101           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05102       imdone = 1;
05103          break;
05104        case ARB_ALPHA:
05105          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05106          if(mytele->param)
05107             saycharstr(mychannel, mytele->param);
05108          imdone = 1;
05109       break;
05110        case REV_PATCH:
05111          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05112          if(mytele->param) {
05113 
05114          /* Parts of this section taken from app_parkandannounce */
05115          char *tpl_working, *tpl_current;
05116          char *tmp[100], *myparm;
05117          int looptemp=0,idx=0, dres = 0;
05118    
05119 
05120          tpl_working = ast_strdup(mytele->param);
05121          myparm = strsep(&tpl_working,",");
05122          tpl_current=strsep(&tpl_working, ":");
05123 
05124          while(tpl_current && looptemp < sizeof(tmp)) {
05125             tmp[looptemp]=tpl_current;
05126             looptemp++;
05127             tpl_current=strsep(&tpl_working,":");
05128          }
05129 
05130          for(idx=0; idx<looptemp; idx++) {
05131             if(!strcmp(tmp[idx], "PARKED")) {
05132                ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
05133             } else if(!strcmp(tmp[idx], "NODE")) {
05134                ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
05135             } else {
05136                dres = ast_streamfile(mychannel, tmp[idx], mychannel->language);
05137                if(!dres) {
05138                   dres = ast_waitstream(mychannel, "");
05139                } else {
05140                   ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[idx], mychannel->name);
05141                   dres = 0;
05142                }
05143             }
05144          }
05145          ast_free(tpl_working);
05146       }
05147          imdone = 1;
05148       break;
05149        case TEST_TONE:
05150       imdone = 1;
05151       if (myrpt->stopgen) break;
05152       myrpt->stopgen = -1;
05153            if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
05154       {
05155          myrpt->stopgen = 0;
05156          break;
05157       }
05158            while(mychannel->generatordata && (myrpt->stopgen <= 0)) {
05159          if (ast_safe_sleep(mychannel,1)) break;
05160             imdone = 1;
05161          }
05162       myrpt->stopgen = 0;
05163       break;
05164        default:
05165          break;
05166    }
05167    if (!imdone)
05168    {
05169       if (!res) 
05170          res = ast_waitstream(mychannel, "");
05171       else {
05172          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05173          res = 0;
05174       }
05175    }
05176    ast_stopstream(mychannel);
05177    rpt_mutex_lock(&myrpt->lock);
05178    if (mytele->mode == TAILMSG)
05179    {
05180       if (!res)
05181       {
05182          myrpt->tailmessagen++;
05183          if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
05184       }
05185       else
05186       {
05187          myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
05188       }
05189    }
05190    remque((struct qelem *)mytele);
05191    myrpt->active_telem = NULL;
05192    rpt_mutex_unlock(&myrpt->lock);
05193    ast_free(nodename);
05194    ast_free(ident);
05195    ast_free(mytele);    
05196    ast_hangup(mychannel);
05197 #ifdef  APP_RPT_LOCK_DEBUG
05198    {
05199       struct lockthread *t;
05200 
05201       sleep(5);
05202       ast_mutex_lock(&locklock);
05203       t = get_lockthread(pthread_self());
05204       if (t) memset(t,0,sizeof(struct lockthread));
05205       ast_mutex_unlock(&locklock);
05206    }        
05207 #endif
05208    pthread_exit(NULL);
05209 }
05210 
05211 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
05212 {
05213 struct rpt_tele *tele;
05214 struct rpt_link *mylink = NULL;
05215 int res;
05216 pthread_attr_t attr;
05217 char *v1, *v2;
05218 
05219    if(debug > 6)
05220       ast_log(LOG_NOTICE,"mode=%i  data=%s\n",mode, (char *)data);
05221 
05222    switch(mode)
05223    {
05224        case UNKEY:
05225       /* if any of the following are defined, go ahead and do it,
05226          otherwise, don't bother */
05227       v1 = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, 
05228          "unlinkedct");
05229       v2 = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, 
05230          "remotect");
05231       if (telem_lookup(myrpt,NULL, myrpt->name, "remotemon") &&
05232         telem_lookup(myrpt,NULL, myrpt->name, "remotetx") &&
05233         telem_lookup(myrpt,NULL, myrpt->name, "cmdmode") &&
05234         (!(v1 && telem_lookup(myrpt,NULL, myrpt->name, v1))) && 
05235         (!(v2 && telem_lookup(myrpt,NULL, myrpt->name, v2)))) return;
05236       break;
05237        case LINKUNKEY:
05238       if (!ast_variable_retrieve(myrpt->cfg, myrpt->name, "linkunkeyct"))
05239          return;
05240       break;
05241        default:
05242       break;
05243    }
05244    tele = ast_malloc(sizeof(struct rpt_tele));
05245    if (!tele)
05246    {
05247       ast_log(LOG_WARNING, "Unable to allocate memory\n");
05248       pthread_exit(NULL);
05249       return;
05250    }
05251    /* zero it out */
05252    memset((char *)tele,0,sizeof(struct rpt_tele));
05253    tele->rpt = myrpt;
05254    tele->mode = mode;
05255    if (mode == PARROT) tele->parrot = (uintptr_t) data;
05256    else mylink = (struct rpt_link *) data;
05257    rpt_mutex_lock(&myrpt->lock);
05258    if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED) ||
05259        (mode == LINKUNKEY)){
05260       memset(&tele->mylink,0,sizeof(struct rpt_link));
05261       if (mylink){
05262          memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
05263       }
05264    }
05265    else if ((mode == ARB_ALPHA) || (mode == REV_PATCH) || (mode == PLAYBACK)) {
05266       strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
05267       tele->param[TELEPARAMSIZE - 1] = 0;
05268    }
05269    if (mode == REMXXX) tele->submode = (intptr_t) data;
05270    insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
05271    rpt_mutex_unlock(&myrpt->lock);
05272         pthread_attr_init(&attr);
05273         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05274    res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
05275    if(res < 0){
05276       rpt_mutex_lock(&myrpt->lock);
05277       remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
05278       rpt_mutex_unlock(&myrpt->lock);  
05279       ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
05280    }
05281    return;
05282 }
05283 
05284 static void *rpt_call(void *this)
05285 {
05286 struct dahdi_confinfo ci;  /* conference info */
05287 struct   rpt *myrpt = (struct rpt *)this;
05288 int   res;
05289 int stopped,congstarted,dialtimer,lastcidx,aborted;
05290 struct ast_channel *mychannel,*genchannel;
05291 
05292    myrpt->mydtmf = 0;
05293    /* allocate a pseudo-channel thru asterisk */
05294    mychannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
05295    if (!mychannel)
05296    {
05297       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
05298       pthread_exit(NULL);
05299    }
05300 #ifdef   AST_CDR_FLAG_POST_DISABLED
05301    if (mychannel->cdr)
05302       ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
05303 #endif
05304    ci.chan = 0;
05305    ci.confno = myrpt->conf; /* use the pseudo conference */
05306 #if   0
05307    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
05308       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
05309 #endif
05310    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
05311    /* first put the channel on the conference */
05312    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05313    {
05314       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05315       ast_hangup(mychannel);
05316       myrpt->callmode = 0;
05317       pthread_exit(NULL);
05318    }
05319    /* allocate a pseudo-channel thru asterisk */
05320    genchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
05321    if (!genchannel)
05322    {
05323       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
05324       ast_hangup(mychannel);
05325       pthread_exit(NULL);
05326    }
05327 #ifdef   AST_CDR_FLAG_POST_DISABLED
05328    if (genchannel->cdr)
05329       ast_set_flag(genchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
05330 #endif
05331    ci.chan = 0;
05332    ci.confno = myrpt->conf;
05333    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
05334       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
05335    /* first put the channel on the conference */
05336    if (ioctl(genchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05337    {
05338       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05339       ast_hangup(mychannel);
05340       ast_hangup(genchannel);
05341       myrpt->callmode = 0;
05342       pthread_exit(NULL);
05343    }
05344    if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
05345    {
05346       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
05347       ast_hangup(mychannel);
05348       ast_hangup(genchannel);
05349       myrpt->callmode = 0;
05350       pthread_exit(NULL);
05351    }
05352    if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
05353    {
05354       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
05355       ast_hangup(mychannel);
05356       ast_hangup(genchannel);
05357       myrpt->callmode = 0;
05358       pthread_exit(NULL);
05359    }
05360    /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
05361    if ((!myrpt->patchquiet) && (tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_DIALTONE) < 0))
05362    {
05363       ast_log(LOG_WARNING, "Cannot start dialtone\n");
05364       ast_hangup(mychannel);
05365       ast_hangup(genchannel);
05366       myrpt->callmode = 0;
05367       pthread_exit(NULL);
05368    }
05369    stopped = 0;
05370    congstarted = 0;
05371    dialtimer = 0;
05372    lastcidx = 0;
05373    myrpt->calldigittimer = 0;
05374    aborted = 0;
05375 
05376    while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
05377    {
05378       if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
05379          dialtimer = 0;
05380          lastcidx = myrpt->cidx;
05381       }     
05382 
05383       if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){ 
05384           if(debug)
05385             ast_log(LOG_NOTICE, "dialtimer %i > patchdialtime %i\n", dialtimer,myrpt->patchdialtime);
05386          rpt_mutex_lock(&myrpt->lock);
05387          aborted = 1;
05388          myrpt->callmode = 0;
05389          rpt_mutex_unlock(&myrpt->lock);
05390          break;
05391       }
05392    
05393       if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
05394       {
05395          stopped = 1;
05396          /* stop dial tone */
05397          tone_zone_play_tone(genchannel->fds[0],-1);
05398       }
05399       if (myrpt->callmode == 1)
05400       {
05401          if(myrpt->calldigittimer > PATCH_DIALPLAN_TIMEOUT)
05402          {
05403             myrpt->callmode = 2;
05404             break;
05405          }
05406          /* bump timer if active */
05407          if (myrpt->calldigittimer) 
05408             myrpt->calldigittimer += MSWAIT;
05409       }
05410       if (myrpt->callmode == 4)
05411       {
05412          if(!congstarted){
05413             congstarted = 1;
05414             /* start congestion tone */
05415             tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
05416          }
05417       }
05418       res = ast_safe_sleep(mychannel, MSWAIT);
05419       if (res < 0)
05420       {
05421           if(debug)
05422             ast_log(LOG_NOTICE, "ast_safe_sleep=%i\n", res);
05423          ast_hangup(mychannel);
05424          ast_hangup(genchannel);
05425          rpt_mutex_lock(&myrpt->lock);
05426          myrpt->callmode = 0;
05427          rpt_mutex_unlock(&myrpt->lock);
05428          pthread_exit(NULL);
05429       }
05430       dialtimer += MSWAIT;
05431    }
05432    /* stop any tone generation */
05433    tone_zone_play_tone(genchannel->fds[0],-1);
05434    /* end if done */
05435    if (!myrpt->callmode)
05436    {
05437       if(debug)
05438          ast_log(LOG_NOTICE, "callmode==0\n");
05439       ast_hangup(mychannel);
05440       ast_hangup(genchannel);
05441       rpt_mutex_lock(&myrpt->lock);
05442       myrpt->callmode = 0;
05443       myrpt->macropatch=0;
05444       channel_revert(myrpt);
05445       rpt_mutex_unlock(&myrpt->lock);
05446       if((!myrpt->patchquiet) && aborted)
05447          rpt_telemetry(myrpt, TERM, NULL);
05448       pthread_exit(NULL);        
05449    }
05450 
05451    if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
05452       char *name, *loc, *instr;
05453       instr = ast_strdup(myrpt->p.ourcallerid);
05454       if(instr){
05455          ast_callerid_parse(instr, &name, &loc);
05456          if(loc){
05457             mychannel->caller.id.number.valid = 1;
05458             ast_free(mychannel->caller.id.number.str);
05459             mychannel->caller.id.number.str = ast_strdup(loc);
05460          }
05461          if(name){
05462             mychannel->caller.id.name.valid = 1;
05463             ast_free(mychannel->caller.id.name.str);
05464             mychannel->caller.id.name.str = ast_strdup(name);
05465          }
05466          ast_free(instr);
05467       }
05468    }
05469 
05470    ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
05471    ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
05472    
05473    if (myrpt->p.acctcode)
05474       ast_cdr_setaccount(mychannel,myrpt->p.acctcode);
05475    mychannel->priority = 1;
05476    ast_channel_undefer_dtmf(mychannel);
05477    if (ast_pbx_start(mychannel) < 0)
05478    {
05479       ast_log(LOG_WARNING, "Unable to start PBX!!\n");
05480       ast_hangup(mychannel);
05481       ast_hangup(genchannel);
05482       rpt_mutex_lock(&myrpt->lock);
05483       myrpt->callmode = 0;
05484       rpt_mutex_unlock(&myrpt->lock);
05485       pthread_exit(NULL);
05486    }
05487    usleep(10000);
05488    rpt_mutex_lock(&myrpt->lock);
05489    myrpt->callmode = 3;
05490    /* set appropriate conference for the pseudo */
05491    ci.chan = 0;
05492    ci.confno = myrpt->conf;
05493    ci.confmode = (myrpt->p.duplex == 2) ? DAHDI_CONF_CONFANNMON :
05494       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
05495    /* first put the channel on the conference in announce mode */
05496    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05497    {
05498       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05499       ast_hangup(mychannel);
05500       ast_hangup(genchannel);
05501       myrpt->callmode = 0;
05502       pthread_exit(NULL);
05503    }
05504    /* get its channel number */
05505    if (ioctl(mychannel->fds[0],DAHDI_CHANNO,&res) == -1)
05506    {
05507       ast_log(LOG_WARNING, "Unable to get autopatch channel number\n");
05508       ast_hangup(mychannel);
05509       myrpt->callmode = 0;
05510       pthread_exit(NULL);
05511    }
05512    ci.chan = 0;
05513    ci.confno = res;
05514    ci.confmode = DAHDI_CONF_MONITOR;
05515    /* put vox channel monitoring on the channel  */
05516    if (ioctl(myrpt->voxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05517    {
05518       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05519       ast_hangup(mychannel);
05520       myrpt->callmode = 0;
05521       pthread_exit(NULL);
05522    }
05523    while(myrpt->callmode)
05524    {
05525       if ((!mychannel->pbx) && (myrpt->callmode != 4))
05526       {
05527           /* If patch is setup for far end disconnect */
05528          if(myrpt->patchfarenddisconnect || (myrpt->p.duplex < 2)){ 
05529             if(debug)ast_log(LOG_NOTICE,"callmode=%i, patchfarenddisconnect=%i, duplex=%i\n",\
05530                   myrpt->callmode,myrpt->patchfarenddisconnect,myrpt->p.duplex);
05531             myrpt->callmode = 0;
05532             myrpt->macropatch=0;
05533             if(!myrpt->patchquiet){
05534                rpt_mutex_unlock(&myrpt->lock);
05535                rpt_telemetry(myrpt, TERM, NULL);
05536                rpt_mutex_lock(&myrpt->lock);
05537             }
05538          }
05539          else{ /* Send congestion until patch is downed by command */
05540             myrpt->callmode = 4;
05541             rpt_mutex_unlock(&myrpt->lock);
05542             /* start congestion tone */
05543             tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
05544             rpt_mutex_lock(&myrpt->lock);
05545          }
05546       }
05547       if (myrpt->mydtmf)
05548       {
05549          struct ast_frame wf = {AST_FRAME_DTMF, } ;
05550          wf.subclass.integer = myrpt->mydtmf;
05551          rpt_mutex_unlock(&myrpt->lock);
05552          ast_queue_frame(mychannel,&wf);
05553 #ifdef   NEW_ASTERISK
05554          ast_senddigit(genchannel,myrpt->mydtmf,0);
05555 #else
05556          ast_senddigit(genchannel,myrpt->mydtmf);
05557 #endif
05558          rpt_mutex_lock(&myrpt->lock);
05559          myrpt->mydtmf = 0;
05560       }
05561       rpt_mutex_unlock(&myrpt->lock);
05562       usleep(MSWAIT * 1000);
05563       rpt_mutex_lock(&myrpt->lock);
05564    }
05565    if(debug)
05566       ast_log(LOG_NOTICE, "exit channel loop\n");
05567    rpt_mutex_unlock(&myrpt->lock);
05568    tone_zone_play_tone(genchannel->fds[0],-1);
05569    if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
05570    ast_hangup(genchannel);
05571    rpt_mutex_lock(&myrpt->lock);
05572    myrpt->callmode = 0;
05573    myrpt->macropatch=0;
05574    channel_revert(myrpt);
05575    rpt_mutex_unlock(&myrpt->lock);
05576    /* set appropriate conference for the pseudo */
05577    ci.chan = 0;
05578    ci.confno = myrpt->conf;
05579    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
05580       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
05581    /* first put the channel on the conference in announce mode */
05582    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05583    {
05584       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05585    }
05586    pthread_exit(NULL);
05587 }
05588 
05589 static void send_link_dtmf(struct rpt *myrpt,char c)
05590 {
05591 char  str[300];
05592 struct   ast_frame wf;
05593 struct   rpt_link *l;
05594 
05595    snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
05596    wf.frametype = AST_FRAME_TEXT;
05597    wf.subclass.integer = 0;
05598    wf.offset = 0;
05599    wf.mallocd = 0;
05600    wf.datalen = strlen(str) + 1;
05601    wf.samples = 0;
05602    l = myrpt->links.next;
05603    /* first, see if our dude is there */
05604    while(l != &myrpt->links)
05605    {
05606       if (l->name[0] == '0') 
05607       {
05608          l = l->next;
05609          continue;
05610       }
05611       /* if we found it, write it and were done */
05612       if (!strcmp(l->name,myrpt->cmdnode))
05613       {
05614          wf.data.ptr = str;
05615          if (l->chan) ast_write(l->chan,&wf);
05616          return;
05617       }
05618       l = l->next;
05619    }
05620    l = myrpt->links.next;
05621    /* if not, give it to everyone */
05622    while(l != &myrpt->links)
05623    {
05624       wf.data.ptr = str;
05625       if (l->chan) ast_write(l->chan,&wf);
05626       l = l->next;
05627    }
05628    return;
05629 }
05630 
05631 static void send_link_keyquery(struct rpt *myrpt)
05632 {
05633 char  str[300];
05634 struct   ast_frame wf;
05635 struct   rpt_link *l;
05636 
05637    rpt_mutex_lock(&myrpt->lock);
05638    memset(myrpt->topkey,0,sizeof(myrpt->topkey));
05639    myrpt->topkeystate = 1;
05640    time(&myrpt->topkeytime);
05641    rpt_mutex_unlock(&myrpt->lock);
05642    snprintf(str, sizeof(str), "K? * %s 0 0", myrpt->name);
05643    wf.frametype = AST_FRAME_TEXT;
05644    wf.subclass.integer = 0;
05645    wf.offset = 0;
05646    wf.mallocd = 0;
05647    wf.datalen = strlen(str) + 1;
05648    wf.samples = 0;
05649    l = myrpt->links.next;
05650    /* give it to everyone */
05651    while(l != &myrpt->links)
05652    {
05653       wf.data.ptr = str;
05654       if (l->chan) ast_write(l->chan,&wf);
05655       l = l->next;
05656    }
05657    return;
05658 }
05659 
05660 /* send newkey request */
05661 
05662 static void send_newkey(struct ast_channel *chan)
05663 {
05664 
05665    /* ast_safe_sleep(chan,10); */
05666    ast_sendtext(chan,newkeystr);
05667    return;
05668 }
05669 
05670 
05671 /* 
05672  * Connect a link 
05673  *
05674  * Return values:
05675  * -2: Attempt to connect to self 
05676  * -1: No such node
05677  *  0: Success
05678  *  1: No match yet
05679  *  2: Already connected to this node
05680  */
05681 
05682 static int connect_link(struct rpt *myrpt, char* node, int mode, int perma)
05683 {
05684    char *val, *s, *s1, *s2, *tele;
05685    char lstr[MAXLINKLIST],*strs[MAXLINKLIST];
05686    char tmp[300], deststr[300] = "",modechange = 0;
05687    char sx[320],*sy;
05688    struct rpt_link *l;
05689    int reconnects = 0;
05690    int i,n;
05691    struct dahdi_confinfo ci;  /* conference info */
05692 
05693    val = node_lookup(myrpt,node);
05694    if (!val){
05695       if(strlen(node) >= myrpt->longestnode)
05696          return -1; /* No such node */
05697       return 1; /* No match yet */
05698    }
05699 
05700    if(!strcmp(myrpt->name,node)) /* Do not allow connections to self */
05701       return -2;
05702       
05703    if(debug > 3){
05704       ast_log(LOG_NOTICE,"Connect attempt to node %s\n", node);
05705       ast_log(LOG_NOTICE,"Mode: %s\n",(mode)?"Transceive":"Monitor");
05706       ast_log(LOG_NOTICE,"Connection type: %s\n",(perma)?"Permalink":"Normal");
05707    }
05708 
05709    strncpy(tmp,val,sizeof(tmp) - 1);
05710    s = tmp;
05711    s1 = strsep(&s,",");
05712    if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
05713    {
05714       sy = strchr(s1,'/');    
05715       *sy = 0;
05716       sprintf(sx,"%s:4569/%s",s1,sy + 1);
05717       s1 = sx;
05718    }
05719    s2 = strsep(&s,",");
05720    rpt_mutex_lock(&myrpt->lock);
05721    l = myrpt->links.next;
05722    /* try to find this one in queue */
05723    while(l != &myrpt->links){
05724       if (l->name[0] == '0') 
05725       {
05726          l = l->next;
05727          continue;
05728       }
05729    /* if found matching string */
05730       if (!strcmp(l->name, node))
05731          break;
05732       l = l->next;
05733    }
05734    /* if found */
05735    if (l != &myrpt->links){ 
05736    /* if already in this mode, just ignore */
05737       if ((l->mode) || (!l->chan)) {
05738          rpt_mutex_unlock(&myrpt->lock);
05739          return 2; /* Already linked */
05740       }
05741       reconnects = l->reconnects;
05742       rpt_mutex_unlock(&myrpt->lock);
05743       if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
05744       l->retries = l->max_retries + 1;
05745       l->disced = 2;
05746       modechange = 1;
05747    } else
05748    {
05749       __mklinklist(myrpt,NULL,lstr);
05750       rpt_mutex_unlock(&myrpt->lock);
05751       n = finddelim(lstr,strs,MAXLINKLIST);
05752       for(i = 0; i < n; i++)
05753       {
05754          if ((*strs[i] < '0') || 
05755              (*strs[i] > '9')) strs[i]++;
05756          if (!strcmp(strs[i],node))
05757          {
05758             return 2; /* Already linked */
05759          }
05760       }
05761    }
05762    strncpy(myrpt->lastlinknode,node,MAXNODESTR - 1);
05763    /* establish call */
05764    l = ast_malloc(sizeof(struct rpt_link));
05765    if (!l)
05766    {
05767       ast_log(LOG_WARNING, "Unable to malloc\n");
05768       return -1;
05769    }
05770    /* zero the silly thing */
05771    memset((char *)l,0,sizeof(struct rpt_link));
05772    l->mode = mode;
05773    l->outbound = 1;
05774    l->thisconnected = 0;
05775    voxinit_link(l,1);
05776    strncpy(l->name, node, MAXNODESTR - 1);
05777    l->isremote = (s && ast_true(s));
05778    if (modechange) l->connected = 1;
05779    l->hasconnected = l->perma = perma;
05780 #ifdef ALLOW_LOCAL_CHANNELS
05781    if ((strncasecmp(s1,"iax2/", 5) == 0) || (strncasecmp(s1, "local/", 6) == 0))
05782          strncpy(deststr, s1, sizeof(deststr));
05783    else
05784            snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
05785 #else
05786    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
05787 #endif
05788    tele = strchr(deststr, '/');
05789    if (!tele){
05790       ast_log(LOG_WARNING,"link3:Dial number (%s) must be in format tech/number\n",deststr);
05791       ast_free(l);
05792       return -1;
05793    }
05794    *tele++ = 0;
05795    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, NULL, tele, NULL);
05796    if (l->chan){
05797       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
05798       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
05799 #ifdef   AST_CDR_FLAG_POST_DISABLED
05800       if (l->chan->cdr)
05801          ast_set_flag(l->chan->cdr,AST_CDR_FLAG_POST_DISABLED);
05802 #endif
05803 #ifndef  NEW_ASTERISK
05804       l->chan->whentohangup = 0;
05805 #endif
05806       l->chan->appl = "Apprpt";
05807       l->chan->data = "(Remote Rx)";
05808       if (debug > 3)
05809          ast_log(LOG_NOTICE, "rpt (remote) initiating call to %s/%s on %s\n",
05810       deststr, tele, l->chan->name);
05811       l->chan->caller.id.number.valid = 1;
05812       ast_free(l->chan->caller.id.number.str);
05813       l->chan->caller.id.number.str = ast_strdup(myrpt->name);
05814       ast_call(l->chan,tele,999);
05815    }
05816    else {
05817       if(debug > 3) 
05818          ast_log(LOG_NOTICE, "Unable to place call to %s/%s on %s\n",
05819       deststr,tele,l->chan->name);
05820       if (myrpt->p.archivedir)
05821       {
05822          char str[100];
05823          sprintf(str,"LINKFAIL,%s",l->name);
05824          donodelog(myrpt,str);
05825       }
05826       ast_free(l);
05827       return -1;
05828    }
05829    /* allocate a pseudo-channel thru asterisk */
05830    l->pchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
05831    if (!l->pchan){
05832       ast_log(LOG_WARNING,"rpt connect: Sorry unable to obtain pseudo channel\n");
05833       ast_hangup(l->chan);
05834       ast_free(l);
05835       return -1;
05836    }
05837    ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
05838    ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
05839 #ifdef   AST_CDR_FLAG_POST_DISABLED
05840    if (l->pchan->cdr)
05841       ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
05842 #endif
05843    /* make a conference for the tx */
05844    ci.chan = 0;
05845    ci.confno = myrpt->conf;
05846    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
05847    /* first put the channel on the conference in proper mode */
05848    if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1)
05849    {
05850       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05851       ast_hangup(l->chan);
05852       ast_hangup(l->pchan);
05853       ast_free(l);
05854       return -1;
05855    }
05856    rpt_mutex_lock(&myrpt->lock);
05857    l->reconnects = reconnects;
05858    /* insert at end of queue */
05859    l->max_retries = MAX_RETRIES;
05860    if (perma)
05861       l->max_retries = MAX_RETRIES_PERM;
05862    if (l->isremote) l->retries = l->max_retries + 1;
05863    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
05864    __kickshort(myrpt);
05865    rpt_mutex_unlock(&myrpt->lock);
05866    if (!l->phonemode) send_newkey(l->chan);
05867    return 0;
05868 }
05869 
05870 
05871 
05872 /*
05873 * Internet linking function 
05874 */
05875 
05876 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
05877 {
05878 
05879    char *val, *s, *s1, *s2;
05880    char tmp[300];
05881    char digitbuf[MAXNODESTR],*strs[MAXLINKLIST];
05882    char mode,perma;
05883    char sx[320],*sy;
05884    struct rpt_link *l;
05885    int i,r;
05886 
05887    if(!param)
05888       return DC_ERROR;
05889       
05890          
05891    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable )
05892       return DC_ERROR;
05893 
05894    strncpy(digitbuf,digits,MAXNODESTR - 1);
05895 
05896    if(debug > 6)
05897       printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
05898       
05899    switch(myatoi(param)){
05900       case 11: /* Perm Link off */
05901       case 1: /* Link off */
05902          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
05903             strcpy(digitbuf,myrpt->lastlinknode);
05904          val = node_lookup(myrpt,digitbuf);
05905          if (!val){
05906             if(strlen(digitbuf) >= myrpt->longestnode)
05907                return DC_ERROR;
05908             break;
05909          }
05910          strncpy(tmp,val,sizeof(tmp) - 1);
05911          s = tmp;
05912          s1 = strsep(&s,",");
05913          if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
05914          {
05915             sy = strchr(s1,'/');    
05916             *sy = 0;
05917             sprintf(sx,"%s:4569/%s",s1,sy + 1);
05918             s1 = sx;
05919          }
05920          s2 = strsep(&s,",");
05921          rpt_mutex_lock(&myrpt->lock);
05922          l = myrpt->links.next;
05923          /* try to find this one in queue */
05924          while(l != &myrpt->links){
05925             if (l->name[0] == '0') 
05926             {
05927                l = l->next;
05928                continue;
05929             }
05930             /* if found matching string */
05931             if (!strcmp(l->name, digitbuf))
05932                break;
05933             l = l->next;
05934          }
05935          if (l != &myrpt->links){ /* if found */
05936             struct   ast_frame wf;
05937 
05938             /* must use perm command on perm link */
05939             if ((myatoi(param) < 10) && 
05940                 (l->max_retries > MAX_RETRIES))
05941             {
05942                rpt_mutex_unlock(&myrpt->lock);
05943                return DC_COMPLETE;
05944             }
05945             strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
05946             l->retries = l->max_retries + 1;
05947             l->disced = 1;
05948             rpt_mutex_unlock(&myrpt->lock);
05949             wf.frametype = AST_FRAME_TEXT;
05950             wf.subclass.integer = 0;
05951             wf.offset = 0;
05952             wf.mallocd = 0;
05953             wf.datalen = strlen(discstr) + 1;
05954             wf.samples = 0;
05955             wf.data.ptr = discstr;
05956             if (l->chan)
05957             {
05958                ast_write(l->chan,&wf);
05959                if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
05960                ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
05961             }
05962             rpt_telemetry(myrpt, COMPLETE, NULL);
05963             return DC_COMPLETE;
05964          }
05965          rpt_mutex_unlock(&myrpt->lock);  
05966          return DC_COMPLETE;
05967       case 2: /* Link Monitor */
05968       case 3: /* Link transceive */
05969       case 12: /* Link Monitor permanent */
05970       case 13: /* Link transceive permanent */
05971          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
05972             strcpy(digitbuf,myrpt->lastlinknode);
05973          /* Attempt connection  */
05974          perma = (atoi(param) > 10) ? 1 : 0;
05975          mode = (atoi(param) & 1) ? 1 : 0;
05976          r = connect_link(myrpt, digitbuf, mode, perma);
05977          switch(r){
05978             case -2: /* Attempt to connect to self */
05979                return DC_COMPLETE; /* Silent error */
05980 
05981             case 0:
05982                rpt_telemetry(myrpt, COMPLETE, NULL);
05983                return DC_COMPLETE;
05984 
05985             case 1:
05986                break;
05987             
05988             case 2:
05989                rpt_telemetry(myrpt, REMALREADY, NULL);
05990                return DC_COMPLETE;
05991             
05992             default:
05993                rpt_telemetry(myrpt, CONNFAIL, NULL);
05994                return DC_COMPLETE;
05995          }
05996          break;
05997 
05998       case 4: /* Enter Command Mode */
05999       
06000          /* if doesnt allow link cmd, or no links active, return */
06001          if (((command_source != SOURCE_RPT) && 
06002             (command_source != SOURCE_PHONE) &&
06003             (command_source != SOURCE_ALT) &&
06004             (command_source != SOURCE_DPHONE)) ||
06005              (myrpt->links.next == &myrpt->links))
06006             return DC_COMPLETE;
06007          
06008          /* if already in cmd mode, or selected self, fughetabahtit */
06009          if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
06010          
06011             rpt_telemetry(myrpt, REMALREADY, NULL);
06012             return DC_COMPLETE;
06013          }
06014          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
06015             strcpy(digitbuf,myrpt->lastlinknode);
06016          /* node must at least exist in list */
06017          val = node_lookup(myrpt,digitbuf);
06018          if (!val){
06019             if(strlen(digitbuf) >= myrpt->longestnode)
06020                return DC_ERROR;
06021             break;
06022          
06023          }
06024          rpt_mutex_lock(&myrpt->lock);
06025          strcpy(myrpt->lastlinknode,digitbuf);
06026          strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
06027          rpt_mutex_unlock(&myrpt->lock);
06028          rpt_telemetry(myrpt, REMGO, NULL);  
06029          return DC_COMPLETE;
06030          
06031       case 5: /* Status */
06032          rpt_telemetry(myrpt, STATUS, NULL);
06033          return DC_COMPLETE;
06034 
06035       case 15: /* Full Status */
06036          rpt_telemetry(myrpt, FULLSTATUS, NULL);
06037          return DC_COMPLETE;
06038          
06039          
06040       case 6: /* All Links Off, including permalinks */
06041                        rpt_mutex_lock(&myrpt->lock);
06042          myrpt->savednodes[0] = 0;
06043                         l = myrpt->links.next;
06044                         /* loop through all links */
06045                         while(l != &myrpt->links){
06046             struct   ast_frame wf;
06047                                 if (l->name[0] == '0') /* Skip any IAXRPT monitoring */
06048                                 {
06049                                         l = l->next;
06050                                         continue;
06051                                 }
06052             /* Make a string of disconnected nodes for possible restoration */
06053             sprintf(tmp,"%c%c%s",(l->mode) ? 'X' : 'M',(l->perma) ? 'P':'T',l->name);
06054             if(strlen(tmp) + strlen(myrpt->savednodes) + 1 < MAXNODESTR){ 
06055                if(myrpt->savednodes[0])
06056                   strcat(myrpt->savednodes, ",");
06057                strcat(myrpt->savednodes, tmp);
06058             }
06059                               l->retries = l->max_retries + 1;
06060                                 l->disced = 2; /* Silently disconnect */
06061                                 rpt_mutex_unlock(&myrpt->lock);
06062             /* ast_log(LOG_NOTICE,"dumping link %s\n",l->name); */
06063                                 
06064                                 wf.frametype = AST_FRAME_TEXT;
06065                                 wf.subclass.integer = 0;
06066                                 wf.offset = 0;
06067                                 wf.mallocd = 0;
06068                                 wf.datalen = strlen(discstr) + 1;
06069                                 wf.samples = 0;
06070                                 wf.data.ptr = discstr;
06071                                 if (l->chan)
06072                                 {
06073                                         ast_write(l->chan,&wf);
06074                                         ast_safe_sleep(l->chan,250); /* It's dead already, why check the return value? */
06075                                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
06076                                 }
06077             rpt_mutex_lock(&myrpt->lock);
06078                                 l = l->next;
06079                         }
06080          rpt_mutex_unlock(&myrpt->lock);
06081          if(debug > 3)
06082             ast_log(LOG_NOTICE,"Nodes disconnected: %s\n",myrpt->savednodes);
06083                         rpt_telemetry(myrpt, COMPLETE, NULL);
06084          return DC_COMPLETE;
06085 
06086       case 7: /* Identify last node which keyed us up */
06087          rpt_telemetry(myrpt, LASTNODEKEY, NULL);
06088          break;
06089 
06090 
06091 #ifdef   _MDC_DECODE_H_
06092       case 8:
06093          myrpt->lastunit = 0xd00d; 
06094          mdc1200_notify(myrpt,NULL,myrpt->lastunit);
06095          mdc1200_send(myrpt,myrpt->lastunit);
06096          break;
06097 #endif
06098 
06099       case 16: /* Restore links disconnected with "disconnect all links" command */
06100          strcpy(tmp, myrpt->savednodes); /* Make a copy */
06101          finddelim(tmp, strs, MAXLINKLIST); /* convert into substrings */
06102          for(i = 0; tmp[0] && strs[i] != NULL && i < MAXLINKLIST; i++){
06103             s1 = strs[i];
06104             mode = (s1[0] == 'X') ? 1 : 0;
06105             perma = (s1[1] == 'P') ? 1 : 0;
06106             connect_link(myrpt, s1 + 2, mode, perma); /* Try to reconnect */
06107          }
06108                         rpt_telemetry(myrpt, COMPLETE, NULL);
06109          break;
06110    
06111       case 200:
06112       case 201:
06113       case 202:
06114       case 203:
06115       case 204:
06116       case 205:
06117       case 206:
06118       case 207:
06119       case 208:
06120       case 209:
06121       case 210:
06122       case 211:
06123       case 212:
06124       case 213:
06125       case 214:
06126       case 215:
06127          if (((myrpt->p.propagate_dtmf) && 
06128               (command_source == SOURCE_LNK)) ||
06129              ((myrpt->p.propagate_phonedtmf) &&
06130             ((command_source == SOURCE_PHONE) ||
06131               (command_source == SOURCE_ALT) ||
06132                 (command_source == SOURCE_DPHONE))))
06133                do_dtmf_local(myrpt,
06134                   remdtmfstr[myatoi(param) - 200]);
06135       default:
06136          return DC_ERROR;
06137          
06138    }
06139    
06140    return DC_INDETERMINATE;
06141 }  
06142 
06143 /*
06144 * Autopatch up
06145 */
06146 
06147 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06148 {
06149    pthread_attr_t attr;
06150    int i, idx, paramlength;
06151    char *lparam;
06152    char *value = NULL;
06153    char *paramlist[20];
06154 
06155    static char *keywords[] = {
06156    "context",
06157    "dialtime",
06158    "farenddisconnect",
06159    "noct",
06160    "quiet",
06161    NULL
06162    };
06163       
06164    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
06165       return DC_ERROR;
06166       
06167    if(debug)
06168       printf("@@@@ Autopatch up\n");
06169 
06170    if(!myrpt->callmode){
06171       /* Set defaults */
06172       myrpt->patchnoct = 0;
06173       myrpt->patchdialtime = 0;
06174       myrpt->patchfarenddisconnect = 0;
06175       myrpt->patchquiet = 0;
06176       strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
06177 
06178       if(param){
06179          /* Process parameter list */
06180          lparam = ast_strdup(param);
06181          if(!lparam){
06182             ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
06183             return DC_ERROR;  
06184          }
06185          paramlength = finddelim(lparam, paramlist, 20);          
06186          for(i = 0; i < paramlength; i++){
06187             idx = matchkeyword(paramlist[i], &value, keywords);
06188             if(value)
06189                value = skipchars(value, "= ");
06190             switch(idx){
06191 
06192                case 1: /* context */
06193                   strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ;
06194                   break;
06195                   
06196                case 2: /* dialtime */
06197                   myrpt->patchdialtime = atoi(value);
06198                   break;
06199 
06200                case 3: /* farenddisconnect */
06201                   myrpt->patchfarenddisconnect = atoi(value);
06202                   break;
06203 
06204                case 4:  /* noct */
06205                   myrpt->patchnoct = atoi(value);
06206                   break;
06207 
06208                case 5: /* quiet */
06209                   myrpt->patchquiet = atoi(value);
06210                   break;
06211                            
06212                default:
06213                   break;
06214             }
06215          }
06216       ast_free(lparam);
06217       }
06218    }
06219                
06220    rpt_mutex_lock(&myrpt->lock);
06221 
06222    /* if on call, force * into current audio stream */
06223    
06224    if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
06225       myrpt->mydtmf = myrpt->p.endchar;
06226    }
06227    if (myrpt->callmode){
06228       rpt_mutex_unlock(&myrpt->lock);
06229       return DC_COMPLETE;
06230    }
06231    myrpt->callmode = 1;
06232    myrpt->cidx = 0;
06233    myrpt->exten[myrpt->cidx] = 0;
06234    rpt_mutex_unlock(&myrpt->lock);
06235    pthread_attr_init(&attr);
06236    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
06237    ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
06238    return DC_COMPLETE;
06239 }
06240 
06241 /*
06242 * Autopatch down
06243 */
06244 
06245 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06246 {
06247    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
06248       return DC_ERROR;
06249    
06250    if(debug)
06251       printf("@@@@ Autopatch down\n");
06252       
06253    rpt_mutex_lock(&myrpt->lock);
06254    
06255    myrpt->macropatch=0;
06256 
06257    if (!myrpt->callmode){
06258       rpt_mutex_unlock(&myrpt->lock);
06259       return DC_COMPLETE;
06260    }
06261    
06262    myrpt->callmode = 0;
06263    channel_revert(myrpt);
06264    rpt_mutex_unlock(&myrpt->lock);
06265    rpt_telemetry(myrpt, TERM, NULL);
06266    return DC_COMPLETE;
06267 }
06268 
06269 /*
06270 * Status
06271 */
06272 
06273 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06274 {
06275 
06276    if (!param)
06277       return DC_ERROR;
06278 
06279    if ((myrpt->p.s[myrpt->p.sysstate_cur].txdisable) || (myrpt->p.s[myrpt->p.sysstate_cur].userfundisable))
06280       return DC_ERROR;
06281 
06282    if(debug)
06283       printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06284    
06285    switch(myatoi(param)){
06286       case 1: /* System ID */
06287          rpt_telemetry(myrpt, ID1, NULL);
06288          return DC_COMPLETE;
06289       case 2: /* System Time */
06290          rpt_telemetry(myrpt, STATS_TIME, NULL);
06291          return DC_COMPLETE;
06292       case 3: /* app_rpt.c version */
06293          rpt_telemetry(myrpt, STATS_VERSION, NULL);
06294          return DC_COMPLETE;
06295       case 11: /* System ID (local only)*/
06296           rpt_telemetry(myrpt, ID , NULL);
06297             return DC_COMPLETE;
06298         case 12: /* System Time (local only)*/
06299             rpt_telemetry(myrpt, STATS_TIME_LOCAL, NULL);
06300             return DC_COMPLETE;
06301       default:
06302          return DC_ERROR;
06303    }
06304    return DC_INDETERMINATE;
06305 }
06306 /*
06307 *  Macro-oni (without Salami)
06308 */
06309 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06310 {
06311 char  *val;
06312 int   i;
06313    if (myrpt->remote)
06314       return DC_ERROR;
06315 
06316    if(debug) 
06317       printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06318    
06319    if(strlen(digitbuf) < 1) /* needs 1 digit */
06320       return DC_INDETERMINATE;
06321          
06322    for(i = 0 ; i < digitbuf[i] ; i++) {
06323       if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06324          return DC_ERROR;
06325    }
06326    
06327    if (*digitbuf == '0') val = myrpt->p.startupmacro;
06328    else val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
06329    /* param was 1 for local buf */
06330    if (!val){
06331                 if (strlen(digitbuf) < myrpt->macro_longest)
06332                         return DC_INDETERMINATE;
06333       rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
06334       return DC_COMPLETE;
06335    }        
06336    rpt_mutex_lock(&myrpt->lock);
06337    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
06338    {
06339       rpt_mutex_unlock(&myrpt->lock);
06340       rpt_telemetry(myrpt, MACRO_BUSY, NULL);
06341       return DC_ERROR;
06342    }
06343    myrpt->macrotimer = MACROTIME;
06344    strncat(myrpt->macrobuf,val,MAXMACRO - 1);
06345    rpt_mutex_unlock(&myrpt->lock);
06346    return DC_COMPLETE;  
06347 }
06348 
06349 /*
06350 *  Playback a recording
06351 */
06352 
06353 static int function_playback(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06354 {
06355 
06356    if (myrpt->remote)
06357       return DC_ERROR;
06358 
06359    if(debug) 
06360       printf("@@@@ playback param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06361    
06362    if (ast_fileexists(param,NULL,myrpt->rxchannel->language) <= 0)
06363       return DC_ERROR;
06364 
06365    rpt_telemetry(myrpt,PLAYBACK,param);
06366    return DC_COMPLETE;
06367 }
06368 
06369 /*
06370 * COP - Control operator
06371 */
06372 
06373 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06374 {
06375    char string[16];
06376    int res;
06377 
06378    int i, r;
06379 
06380    if(!param)
06381       return DC_ERROR;
06382    
06383    switch(myatoi(param)){
06384       case 1: /* System reset */
06385          res = system("killall -9 asterisk");
06386          return DC_COMPLETE;
06387 
06388       case 2:
06389          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 0;
06390          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
06391          return DC_COMPLETE;
06392          
06393       case 3:
06394          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 1;
06395          return DC_COMPLETE;
06396          
06397       case 4: /* test tone on */
06398          if (myrpt->stopgen < 0) 
06399          {
06400             myrpt->stopgen = 1;
06401          }
06402          else 
06403          {
06404             myrpt->stopgen = 0;
06405             rpt_telemetry(myrpt, TEST_TONE, NULL);
06406          }
06407          return DC_COMPLETE;
06408 
06409       case 5: /* Disgorge variables to log for debug purposes */
06410          myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
06411          return DC_COMPLETE;
06412 
06413       case 6: /* Simulate COR being activated (phone only) */
06414          if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
06415          return DC_DOKEY;  
06416 
06417 
06418       case 7: /* Time out timer enable */
06419          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 0;
06420          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTENA");
06421          return DC_COMPLETE;
06422          
06423       case 8: /* Time out timer disable */
06424          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 1;
06425          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTDIS");
06426          return DC_COMPLETE;
06427 
06428                 case 9: /* Autopatch enable */
06429                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 0;
06430                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APENA");
06431                         return DC_COMPLETE;
06432 
06433                 case 10: /* Autopatch disable */
06434                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 1;
06435                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APDIS");
06436                         return DC_COMPLETE;
06437 
06438                 case 11: /* Link Enable */
06439                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 0;
06440                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKENA");
06441                         return DC_COMPLETE;
06442 
06443                 case 12: /* Link Disable */
06444                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 1;
06445                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKDIS");
06446                         return DC_COMPLETE;
06447 
06448       case 13: /* Query System State */
06449          string[0] = string[1] = 'S';
06450          string[2] = myrpt->p.sysstate_cur + '0';
06451          string[3] = '\0';
06452          rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
06453          return DC_COMPLETE;
06454 
06455       case 14: /* Change System State */
06456          if(strlen(digitbuf) == 0)
06457             break;
06458          if((digitbuf[0] < '0') || (digitbuf[0] > '9'))
06459             return DC_ERROR;
06460          myrpt->p.sysstate_cur = digitbuf[0] - '0';
06461                         string[0] = string[1] = 'S';
06462                         string[2] = myrpt->p.sysstate_cur + '0';
06463                         string[3] = '\0';
06464                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
06465                         return DC_COMPLETE;
06466 
06467                 case 15: /* Scheduler Enable */
06468                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 0;
06469                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKENA");
06470                         return DC_COMPLETE;
06471 
06472                 case 16: /* Scheduler Disable */
06473                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 1;
06474                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKDIS");
06475                         return DC_COMPLETE;
06476 
06477                 case 17: /* User functions Enable */
06478                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 0;
06479                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFENA");
06480                         return DC_COMPLETE;
06481 
06482                 case 18: /* User Functions Disable */
06483                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 1;
06484                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFDIS");
06485                         return DC_COMPLETE;
06486 
06487                 case 19: /* Alternate Tail Enable */
06488                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 1;
06489                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATENA");
06490                         return DC_COMPLETE;
06491 
06492                 case 20: /* Alternate Tail Disable */
06493                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 0;
06494                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATDIS");
06495                         return DC_COMPLETE;
06496 
06497                 case 21: /* Parrot Mode Disable */
06498          birdbath(myrpt);
06499          if (myrpt->p.parrotmode < 2)
06500          {
06501             myrpt->p.parrotmode = 0;
06502             rpt_telemetry(myrpt,COMPLETE,NULL);
06503             return DC_COMPLETE;
06504          }
06505          break;
06506 
06507                 case 22: /* Parrot Mode Enable */
06508          birdbath(myrpt);
06509          if (myrpt->p.parrotmode < 2)
06510          {
06511             myrpt->p.parrotmode = 1;
06512             rpt_telemetry(myrpt,COMPLETE,NULL);
06513             return DC_COMPLETE;
06514          }
06515          break;
06516       case 23: /* flush parrot in progress */
06517          birdbath(myrpt);
06518          rpt_telemetry(myrpt,COMPLETE,NULL);
06519          return DC_COMPLETE;
06520       case 24: /* flush all telemetry */
06521          flush_telem(myrpt);
06522          rpt_telemetry(myrpt,COMPLETE,NULL);
06523          return DC_COMPLETE;
06524       case 25: /* request keying info (brief) */
06525          send_link_keyquery(myrpt);
06526          myrpt->topkeylong = 0;
06527          rpt_telemetry(myrpt,COMPLETE,NULL);
06528          return DC_COMPLETE;
06529       case 26: /* request keying info (full) */
06530          send_link_keyquery(myrpt);
06531          myrpt->topkeylong = 1;
06532          rpt_telemetry(myrpt,COMPLETE,NULL);
06533          return DC_COMPLETE;
06534 
06535       case 30: /* recall memory location on programmable radio */
06536 
06537          if(strlen(digitbuf) < 2) /* needs 2 digits */
06538             break;
06539          
06540          for(i = 0 ; i < 2 ; i++){
06541             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06542                return DC_ERROR;
06543          }
06544        
06545          r = retreive_memory(myrpt, digitbuf);
06546          if (r < 0){
06547             rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
06548             return DC_COMPLETE;
06549          }
06550          if (r > 0){
06551             return DC_ERROR;
06552          }
06553          if (setrem(myrpt) == -1) return DC_ERROR;
06554          return DC_COMPLETE;  
06555 
06556       case 31: 
06557           /* set channel. note that it's going to change channel 
06558              then confirm on the new channel! */
06559          if(strlen(digitbuf) < 2) /* needs 2 digits */
06560             break;
06561          
06562          for(i = 0 ; i < 2 ; i++){
06563             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06564                return DC_ERROR;
06565          }
06566          channel_steer(myrpt,digitbuf);
06567          return DC_COMPLETE;  
06568 
06569       case 32: /* Touch Tone Pad Test */
06570          i = strlen(digitbuf);
06571          if(!i){
06572             if(debug > 3)
06573             ast_log(LOG_NOTICE,"Padtest entered");
06574             myrpt->inpadtest = 1;
06575          }
06576          else{
06577             if(debug > 3)
06578                ast_log(LOG_NOTICE,"Padtest len= %d digits=%s",i,digitbuf);
06579             if(digitbuf[i-1] != myrpt->p.endchar)
06580                break;
06581             rpt_telemetry(myrpt, ARB_ALPHA, digitbuf);
06582             myrpt->inpadtest = 0;
06583             if(debug > 3)
06584                ast_log(LOG_NOTICE,"Padtest exited");
06585             return DC_COMPLETE;
06586          }
06587    }  
06588    return DC_INDETERMINATE;
06589 }
06590 /*
06591 * Collect digits one by one until something matches
06592 */
06593 static int collect_function_digits(struct rpt *myrpt, char *digits, 
06594    int command_source, struct rpt_link *mylink)
06595 {
06596    int i,rv;
06597    char *stringp,*action,*param,*functiondigits;
06598    char function_table_name[30] = "";
06599    char workstring[200];
06600    
06601    struct ast_variable *vp;
06602    
06603    if (debug > 6) ast_log(LOG_NOTICE,"digits=%s  source=%d\n",digits, command_source);
06604 
06605    //if(debug) 
06606    // printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
06607    
06608    if (command_source == SOURCE_DPHONE) {
06609       if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
06610       strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1);
06611       }
06612    else if (command_source == SOURCE_ALT) {
06613       if (!myrpt->p.alt_functions) return DC_INDETERMINATE;
06614       strncpy(function_table_name, myrpt->p.alt_functions, sizeof(function_table_name) - 1);
06615       }
06616    else if (command_source == SOURCE_PHONE) {
06617       if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
06618       strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1);
06619       }
06620    else if (command_source == SOURCE_LNK)
06621       strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1);
06622    else
06623       strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1);
06624     /* find context for function table in rpt.conf file */
06625    vp = ast_variable_browse(myrpt->cfg, function_table_name);
06626    while(vp) {
06627       if(!strncasecmp(vp->name, digits, strlen(vp->name)))
06628          break;
06629       vp = vp->next;
06630    }  
06631    /* if function context not found */
06632    if(!vp) {
06633       int n;
06634 
06635       n = myrpt->longestfunc;
06636       if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
06637       else 
06638       if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
06639       else 
06640       if (command_source == SOURCE_ALT) n = myrpt->alt_longestfunc;
06641       else 
06642       if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
06643       
06644       if(strlen(digits) >= n)
06645          return DC_ERROR;
06646       else
06647          return DC_INDETERMINATE;
06648    }  
06649    /* Found a match, retrieve value part and parse */
06650    strncpy(workstring, vp->value, sizeof(workstring) - 1 );
06651    stringp = workstring;
06652    action = strsep(&stringp, ",");
06653    param = stringp;
06654    if(debug)
06655       printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
06656    /* Look up the action */
06657    for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
06658       if(!strncasecmp(action, function_table[i].action, strlen(action)))
06659          break;
06660    }
06661    if(debug)
06662       printf("@@@@ table index i = %d\n",i);
06663    if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
06664       /* Error, action not in table */
06665       return DC_ERROR;
06666    }
06667    if(function_table[i].function == NULL){
06668       /* Error, function undefined */
06669       if(debug)
06670          printf("@@@@ NULL for action: %s\n",action);
06671       return DC_ERROR;
06672    }
06673    functiondigits = digits + strlen(vp->name);
06674    rv=(*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
06675    if (debug > 6) ast_log(LOG_NOTICE,"rv=%i\n",rv);
06676    return(rv);
06677 }
06678 
06679 
06680 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
06681    char *str)
06682 {
06683 /* XXX ATTENTION: if you change the size of these arrays you MUST
06684  * change the limits in corresponding sscanf() calls below. */
06685 char  tmp[512],tmp1[512],cmd[300] = "",dest[300],src[300],c;
06686 int   i,seq, res, ts;
06687 struct rpt_link *l;
06688 struct   ast_frame wf;
06689 
06690    wf.frametype = AST_FRAME_TEXT;
06691    wf.subclass.integer = 0;
06692    wf.offset = 0;
06693    wf.mallocd = 0;
06694    wf.datalen = strlen(str) + 1;
06695    wf.samples = 0;
06696    /* put string in our buffer */
06697    strncpy(tmp,str,sizeof(tmp) - 1);
06698 
06699         if (!strcmp(tmp,discstr))
06700         {
06701                 mylink->disced = 1;
06702       mylink->retries = mylink->max_retries + 1;
06703                 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
06704                 return;
06705         }
06706         if (!strcmp(tmp,newkeystr))
06707         {
06708       mylink->newkey = 1;
06709                 return;
06710         }
06711    if (tmp[0] == 'L')
06712    {
06713       rpt_mutex_lock(&myrpt->lock);
06714       strcpy(mylink->linklist,tmp + 2);
06715       time(&mylink->linklistreceived);
06716       rpt_mutex_unlock(&myrpt->lock);
06717       if (debug > 6) ast_log(LOG_NOTICE,"@@@@ node %s received node list %s from node %s\n",
06718          myrpt->name,tmp,mylink->name);
06719       return;
06720    }
06721    if (tmp[0] == 'K')
06722    {
06723       if (sscanf(tmp, "%299s %299s %299s %30d %30d", cmd, dest, src, &seq, &ts) != 5)
06724       {
06725          ast_log(LOG_WARNING, "Unable to parse keying string %s\n",str);
06726          return;
06727       }
06728       if (dest[0] == '0')
06729       {
06730          strcpy(dest,myrpt->name);
06731       }     
06732       /* if not for me, redistribute to all links */
06733       if (strcmp(dest,myrpt->name))
06734       {
06735          l = myrpt->links.next;
06736          /* see if this is one in list */
06737          while(l != &myrpt->links)
06738          {
06739             if (l->name[0] == '0') 
06740             {
06741                l = l->next;
06742                continue;
06743             }
06744             /* don't send back from where it came */
06745             if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06746             {
06747                l = l->next;
06748                continue;
06749             }
06750             /* if it is, send it and we're done */
06751             if (!strcmp(l->name,dest))
06752             {
06753                /* send, but not to src */
06754                if (strcmp(l->name,src)) {
06755                   wf.data.ptr = str;
06756                   if (l->chan) ast_write(l->chan,&wf);
06757                }
06758                return;
06759             }
06760             l = l->next;
06761          }
06762       }
06763       /* if not for me, or is broadcast, redistribute to all links */
06764       if ((strcmp(dest,myrpt->name)) || (dest[0] == '*'))
06765       {
06766          l = myrpt->links.next;
06767          /* otherwise, send it to all of em */
06768          while(l != &myrpt->links)
06769          {
06770             if (l->name[0] == '0') 
06771             {
06772                l = l->next;
06773                continue;
06774             }
06775             /* don't send back from where it came */
06776             if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06777             {
06778                l = l->next;
06779                continue;
06780             }
06781             /* send, but not to src */
06782             if (strcmp(l->name,src)) {
06783                wf.data.ptr = str;
06784                if (l->chan) ast_write(l->chan,&wf); 
06785             }
06786             l = l->next;
06787          }
06788       }
06789       /* if not for me, end here */
06790       if (strcmp(dest,myrpt->name) && (dest[0] != '*')) return;
06791       if (cmd[1] == '?')
06792       {
06793          time_t now;
06794          int n = 0;
06795 
06796          time(&now);
06797          if (myrpt->lastkeyedtime)
06798          {
06799             n = (int)(now - myrpt->lastkeyedtime);
06800          }
06801          sprintf(tmp1,"K %s %s %d %d",src,myrpt->name,myrpt->keyed,n);
06802          wf.data.ptr = tmp1;
06803          wf.datalen = strlen(tmp1) + 1;
06804          if (mylink->chan) ast_write(mylink->chan,&wf); 
06805          return;
06806       }
06807       if (myrpt->topkeystate != 1) return;
06808       rpt_mutex_lock(&myrpt->lock);
06809       for(i = 0; i < TOPKEYN; i++)
06810       {
06811          if (!strcmp(myrpt->topkey[i].node,src)) break;
06812       }
06813       if (i >= TOPKEYN)
06814       {
06815          for(i = 0; i < TOPKEYN; i++)
06816          {
06817             if (!myrpt->topkey[i].node[0]) break;
06818          }
06819       }
06820       if (i < TOPKEYN)
06821       {
06822          strncpy(myrpt->topkey[i].node,src,TOPKEYMAXSTR - 1);
06823          myrpt->topkey[i].timesince = ts;
06824          myrpt->topkey[i].keyed = seq;
06825       }
06826       rpt_mutex_unlock(&myrpt->lock);
06827       return;
06828    }
06829    if (tmp[0] == 'I')
06830    {
06831       /* XXX WARNING: be very careful with the limits on the folowing
06832        * sscanf() call, make sure they match the values defined above */
06833       if (sscanf(tmp,"%299s %299s %30x",cmd,src,&seq) != 3)
06834       {
06835          ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
06836          return;
06837       }
06838       mdc1200_notify(myrpt,src,seq);
06839       strcpy(dest,"*");
06840    }
06841    else
06842    {
06843       /* XXX WARNING: be very careful with the limits on the folowing
06844        * sscanf() call, make sure they match the values defined above */
06845       if (sscanf(tmp,"%299s %299s %299s %30d %1c",cmd,dest,src,&seq,&c) != 5)
06846       {
06847          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
06848          return;
06849       }
06850       if (strcmp(cmd,"D"))
06851       {
06852          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
06853          return;
06854       }
06855    }
06856    if (dest[0] == '0')
06857    {
06858       strcpy(dest,myrpt->name);
06859    }     
06860 
06861    /* if not for me, redistribute to all links */
06862    if (strcmp(dest,myrpt->name))
06863    {
06864       l = myrpt->links.next;
06865       /* see if this is one in list */
06866       while(l != &myrpt->links)
06867       {
06868          if (l->name[0] == '0') 
06869          {
06870             l = l->next;
06871             continue;
06872          }
06873          /* don't send back from where it came */
06874          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06875          {
06876             l = l->next;
06877             continue;
06878          }
06879          /* if it is, send it and we're done */
06880          if (!strcmp(l->name,dest))
06881          {
06882             /* send, but not to src */
06883             if (strcmp(l->name,src)) {
06884                wf.data.ptr = str;
06885                if (l->chan) ast_write(l->chan,&wf);
06886             }
06887             return;
06888          }
06889          l = l->next;
06890       }
06891       l = myrpt->links.next;
06892       /* otherwise, send it to all of em */
06893       while(l != &myrpt->links)
06894       {
06895          if (l->name[0] == '0') 
06896          {
06897             l = l->next;
06898             continue;
06899          }
06900          /* don't send back from where it came */
06901          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06902          {
06903             l = l->next;
06904             continue;
06905          }
06906          /* send, but not to src */
06907          if (strcmp(l->name,src)) {
06908             wf.data.ptr = str;
06909             if (l->chan) ast_write(l->chan,&wf); 
06910          }
06911          l = l->next;
06912       }
06913       return;
06914    }
06915    if (myrpt->p.archivedir)
06916    {
06917       char dtmfstr[100];
06918 
06919       sprintf(dtmfstr,"DTMF,%s,%c",mylink->name,c);
06920       donodelog(myrpt,dtmfstr);
06921    }
06922    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
06923    if (!c) return;
06924    rpt_mutex_lock(&myrpt->lock);
06925    if (c == myrpt->p.endchar) myrpt->stopgen = 1;
06926    if (myrpt->callmode == 1)
06927    {
06928       myrpt->exten[myrpt->cidx++] = c;
06929       myrpt->exten[myrpt->cidx] = 0;
06930       /* if this exists */
06931       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
06932       {
06933          /* if this really it, end now */
06934          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
06935             myrpt->exten,1,NULL)) 
06936          {
06937             myrpt->callmode = 2;
06938             if(!myrpt->patchquiet)
06939             {
06940                rpt_mutex_unlock(&myrpt->lock);
06941                rpt_telemetry(myrpt,PROC,NULL); 
06942                rpt_mutex_lock(&myrpt->lock);
06943             }
06944          }
06945          else /* othewise, reset timer */
06946          {
06947             myrpt->calldigittimer = 1;
06948          }
06949       }
06950       /* if can continue, do so */
06951       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
06952       {
06953          /* call has failed, inform user */
06954          myrpt->callmode = 4;
06955       }
06956    }
06957    if ((!myrpt->inpadtest) &&(c == myrpt->p.funcchar))
06958    {
06959       myrpt->rem_dtmfidx = 0;
06960       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
06961       time(&myrpt->rem_dtmf_time);
06962       rpt_mutex_unlock(&myrpt->lock);
06963       return;
06964    } 
06965    else if (myrpt->rem_dtmfidx < 0)
06966    {
06967       if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
06968       {
06969          myrpt->mydtmf = c;
06970       }
06971       if (myrpt->p.propagate_dtmf) do_dtmf_local(myrpt,c);
06972       if (myrpt->p.propagate_phonedtmf) do_dtmf_phone(myrpt,mylink,c);
06973       rpt_mutex_unlock(&myrpt->lock);
06974       return;
06975    }
06976    else if (((myrpt->inpadtest) || (c != myrpt->p.endchar)) && (myrpt->rem_dtmfidx >= 0))
06977    {
06978       time(&myrpt->rem_dtmf_time);
06979       if (myrpt->rem_dtmfidx < MAXDTMF)
06980       {
06981          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
06982          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
06983          
06984          rpt_mutex_unlock(&myrpt->lock);
06985          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
06986          res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
06987          rpt_mutex_lock(&myrpt->lock);
06988          
06989          switch(res){
06990 
06991             case DC_INDETERMINATE:
06992                break;
06993             
06994             case DC_REQ_FLUSH:
06995                myrpt->rem_dtmfidx = 0;
06996                myrpt->rem_dtmfbuf[0] = 0;
06997                break;
06998             
06999             
07000             case DC_COMPLETE:
07001             case DC_COMPLETEQUIET:
07002                myrpt->totalexecdcommands++;
07003                myrpt->dailyexecdcommands++;
07004                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
07005                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
07006                myrpt->rem_dtmfbuf[0] = 0;
07007                myrpt->rem_dtmfidx = -1;
07008                myrpt->rem_dtmf_time = 0;
07009                break;
07010             
07011             case DC_ERROR:
07012             default:
07013                myrpt->rem_dtmfbuf[0] = 0;
07014                myrpt->rem_dtmfidx = -1;
07015                myrpt->rem_dtmf_time = 0;
07016                break;
07017          }
07018       }
07019 
07020    }
07021    rpt_mutex_unlock(&myrpt->lock);
07022    return;
07023 }
07024 
07025 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
07026    char c)
07027 {
07028 
07029 char  cmd[300];
07030 int   res;
07031 
07032    if (myrpt->p.archivedir)
07033    {
07034       char str[100];
07035 
07036       sprintf(str,"DTMF(P),%s,%c",mylink->name,c);
07037       donodelog(myrpt,str);
07038    }
07039    rpt_mutex_lock(&myrpt->lock);
07040 
07041    if (mylink->phonemode == 3) /*If in simplex dumb phone mode */
07042    {
07043       if(c == myrpt->p.endchar) /* If end char */
07044       {
07045          mylink->lastrealrx = 0; /* Keying state = off */
07046          rpt_mutex_unlock(&myrpt->lock);
07047          return;
07048       }
07049 
07050       if(c == myrpt->p.funcchar) /* If lead-in char */
07051       {
07052          mylink->lastrealrx = !mylink->lastrealrx; /* Toggle keying state */
07053          rpt_mutex_unlock(&myrpt->lock);
07054          return;
07055       }
07056    }
07057    else
07058    {
07059       if (c == myrpt->p.endchar)
07060       {
07061          if (mylink->lastrx)
07062          {
07063             mylink->lastrealrx = 0;
07064             rpt_mutex_unlock(&myrpt->lock);
07065             return;
07066          }
07067          myrpt->stopgen = 1;
07068          if (myrpt->cmdnode[0])
07069          {
07070             myrpt->cmdnode[0] = 0;
07071             myrpt->dtmfidx = -1;
07072             myrpt->dtmfbuf[0] = 0;
07073             rpt_mutex_unlock(&myrpt->lock);
07074             rpt_telemetry(myrpt,COMPLETE,NULL);
07075             return;
07076          }
07077       }
07078    }
07079    if (myrpt->cmdnode[0])
07080    {
07081       rpt_mutex_unlock(&myrpt->lock);
07082       send_link_dtmf(myrpt,c);
07083       return;
07084    }
07085    if (myrpt->callmode == 1)
07086    {
07087       myrpt->exten[myrpt->cidx++] = c;
07088       myrpt->exten[myrpt->cidx] = 0;
07089       /* if this exists */
07090       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
07091       {
07092          /* if this really it, end now */
07093          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
07094             myrpt->exten,1,NULL)) 
07095          {
07096             myrpt->callmode = 2;
07097             if(!myrpt->patchquiet)
07098             {
07099                rpt_mutex_unlock(&myrpt->lock);
07100                rpt_telemetry(myrpt,PROC,NULL); 
07101                rpt_mutex_lock(&myrpt->lock);
07102             }
07103          }
07104          else /* othewise, reset timer */
07105          {
07106             myrpt->calldigittimer = 1;
07107          }
07108       }
07109       /* if can continue, do so */
07110       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
07111       {
07112          /* call has failed, inform user */
07113          myrpt->callmode = 4;
07114       }
07115    }
07116    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
07117    {
07118       myrpt->mydtmf = c;
07119    }
07120    if ((!myrpt->inpadtest) && (c == myrpt->p.funcchar))
07121    {
07122       myrpt->rem_dtmfidx = 0;
07123       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
07124       time(&myrpt->rem_dtmf_time);
07125       rpt_mutex_unlock(&myrpt->lock);
07126       return;
07127    } 
07128    else if (((myrpt->inpadtest) || (c != myrpt->p.endchar)) && (myrpt->rem_dtmfidx >= 0))
07129    {
07130       time(&myrpt->rem_dtmf_time);
07131       if (myrpt->rem_dtmfidx < MAXDTMF)
07132       {
07133          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
07134          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
07135          
07136          rpt_mutex_unlock(&myrpt->lock);
07137          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
07138          switch(mylink->phonemode)
07139          {
07140              case 1:
07141             res = collect_function_digits(myrpt, cmd, 
07142                SOURCE_PHONE, mylink);
07143             break;
07144              case 2:
07145             res = collect_function_digits(myrpt, cmd, 
07146                SOURCE_DPHONE,mylink);
07147             break;
07148              case 4:
07149             res = collect_function_digits(myrpt, cmd, 
07150                SOURCE_ALT,mylink);
07151             break;
07152              default:
07153             res = collect_function_digits(myrpt, cmd, 
07154                SOURCE_LNK, mylink);
07155             break;
07156          }
07157 
07158          rpt_mutex_lock(&myrpt->lock);
07159          
07160          switch(res){
07161 
07162             case DC_INDETERMINATE:
07163                break;
07164             
07165             case DC_DOKEY:
07166                mylink->lastrealrx = 1;
07167                break;
07168             
07169             case DC_REQ_FLUSH:
07170                myrpt->rem_dtmfidx = 0;
07171                myrpt->rem_dtmfbuf[0] = 0;
07172                break;
07173             
07174             
07175             case DC_COMPLETE:
07176             case DC_COMPLETEQUIET:
07177                myrpt->totalexecdcommands++;
07178                myrpt->dailyexecdcommands++;
07179                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
07180                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
07181                myrpt->rem_dtmfbuf[0] = 0;
07182                myrpt->rem_dtmfidx = -1;
07183                myrpt->rem_dtmf_time = 0;
07184                break;
07185             
07186             case DC_ERROR:
07187             default:
07188                myrpt->rem_dtmfbuf[0] = 0;
07189                myrpt->rem_dtmfidx = -1;
07190                myrpt->rem_dtmf_time = 0;
07191                break;
07192          }
07193       }
07194 
07195    }
07196    rpt_mutex_unlock(&myrpt->lock);
07197    return;
07198 }
07199 
07200 /* Doug Hall RBI-1 serial data definitions:
07201  *
07202  * Byte 0: Expansion external outputs 
07203  * Byte 1: 
07204  * Bits 0-3 are BAND as follows:
07205  * Bits 4-5 are POWER bits as follows:
07206  *    00 - Low Power
07207  *    01 - Hi Power
07208  *    02 - Med Power
07209  * Bits 6-7 are always set
07210  * Byte 2:
07211  * Bits 0-3 MHZ in BCD format
07212  * Bits 4-5 are offset as follows:
07213  *    00 - minus
07214  *    01 - plus
07215  *    02 - simplex
07216  *    03 - minus minus (whatever that is)
07217  * Bit 6 is the 0/5 KHZ bit
07218  * Bit 7 is always set
07219  * Byte 3:
07220  * Bits 0-3 are 10 KHZ in BCD format
07221  * Bits 4-7 are 100 KHZ in BCD format
07222  * Byte 4: PL Tone code and encode/decode enable bits
07223  * Bits 0-5 are PL tone code (comspec binary codes)
07224  * Bit 6 is encode enable/disable
07225  * Bit 7 is decode enable/disable
07226  */
07227 
07228 /* take the frequency from the 10 mhz digits (and up) and convert it
07229    to a band number */
07230 
07231 static int rbi_mhztoband(char *str)
07232 {
07233 int   i;
07234 
07235    i = atoi(str) / 10; /* get the 10's of mhz */
07236    switch(i)
07237    {
07238        case 2:
07239       return 10;
07240        case 5:
07241       return 11;
07242        case 14:
07243       return 2;
07244        case 22:
07245       return 3;
07246        case 44:
07247       return 4;
07248        case 124:
07249       return 0;
07250        case 125:
07251       return 1;
07252        case 126:
07253       return 8;
07254        case 127:
07255       return 5;
07256        case 128:
07257       return 6;
07258        case 129:
07259       return 7;
07260        default:
07261       break;
07262    }
07263    return -1;
07264 }
07265 
07266 /* take a PL frequency and turn it into a code */
07267 static int rbi_pltocode(char *str)
07268 {
07269 int i;
07270 char *s;
07271 
07272    s = strchr(str,'.');
07273    i = 0;
07274    if (s) i = atoi(s + 1);
07275    i += atoi(str) * 10;
07276    switch(i)
07277    {
07278        case 670:
07279       return 0;
07280        case 719:
07281       return 1;
07282        case 744:
07283       return 2;
07284        case 770:
07285       return 3;
07286        case 797:
07287       return 4;
07288        case 825:
07289       return 5;
07290        case 854:
07291       return 6;
07292        case 885:
07293       return 7;
07294        case 915:
07295       return 8;
07296        case 948:
07297       return 9;
07298        case 974:
07299       return 10;
07300        case 1000:
07301       return 11;
07302        case 1035:
07303       return 12;
07304        case 1072:
07305       return 13;
07306        case 1109:
07307       return 14;
07308        case 1148:
07309       return 15;
07310        case 1188:
07311       return 16;
07312        case 1230:
07313       return 17;
07314        case 1273:
07315       return 18;
07316        case 1318:
07317       return 19;
07318        case 1365:
07319       return 20;
07320        case 1413:
07321       return 21;
07322        case 1462:
07323       return 22;
07324        case 1514:
07325       return 23;
07326        case 1567:
07327       return 24;
07328        case 1622:
07329       return 25;
07330        case 1679:
07331       return 26;
07332        case 1738:
07333       return 27;
07334        case 1799:
07335       return 28;
07336        case 1862:
07337       return 29;
07338        case 1928:
07339       return 30;
07340        case 2035:
07341       return 31;
07342        case 2107:
07343       return 32;
07344        case 2181:
07345       return 33;
07346        case 2257:
07347       return 34;
07348        case 2336:
07349       return 35;
07350        case 2418:
07351       return 36;
07352        case 2503:
07353       return 37;
07354    }
07355    return -1;
07356 }
07357 
07358 /*
07359 * Shift out a formatted serial bit stream
07360 */
07361 
07362 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
07363     {
07364 #ifdef __i386__
07365     int i,j;
07366     unsigned char od,d;
07367     static volatile long long delayvar;
07368 
07369     for(i = 0 ; i < 5 ; i++){
07370         od = *data++; 
07371         for(j = 0 ; j < 8 ; j++){
07372             d = od & 1;
07373             outb(d,myrpt->p.iobase);
07374        /* >= 15 us */
07375        for(delayvar = 1; delayvar < 15000; delayvar++); 
07376             od >>= 1;
07377             outb(d | 2,myrpt->p.iobase);
07378        /* >= 30 us */
07379        for(delayvar = 1; delayvar < 30000; delayvar++); 
07380             outb(d,myrpt->p.iobase);
07381        /* >= 10 us */
07382        for(delayvar = 1; delayvar < 10000; delayvar++); 
07383             }
07384         }
07385    /* >= 50 us */
07386         for(delayvar = 1; delayvar < 50000; delayvar++); 
07387 #endif
07388     }
07389 
07390 static void rbi_out(struct rpt *myrpt,unsigned char *data)
07391 {
07392 struct dahdi_radio_param r;
07393 
07394    memset(&r,0,sizeof(struct dahdi_radio_param));
07395    r.radpar = DAHDI_RADPAR_REMMODE;
07396    r.data = DAHDI_RADPAR_REM_RBI1;
07397    /* if setparam ioctl fails, its probably not a pciradio card */
07398    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
07399    {
07400       rbi_out_parallel(myrpt,data);
07401       return;
07402    }
07403    r.radpar = DAHDI_RADPAR_REMCOMMAND;
07404    memcpy(&r.data,data,5);
07405    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
07406    {
07407       ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->dahdirxchannel->name);
07408       return;
07409    }
07410 }
07411 
07412 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, 
07413    unsigned char *rxbuf, int rxmaxbytes, int asciiflag)
07414 {
07415    int i,j,idx,oldmode,olddata;
07416    struct dahdi_radio_param prm;
07417    char c;
07418 
07419     if(debug) {
07420        ast_log(LOG_NOTICE, "ioport=%s  iofd=0x%x\n",myrpt->p.ioport,myrpt->iofd);
07421       printf("String output was:\n");
07422       for(i = 0; i < txbytes; i++)
07423          printf("%02X ", (unsigned char ) txbuf[i]);
07424       printf("\n");
07425    }
07426 
07427    if (myrpt->iofd >= 0)  /* if to do out a serial port */
07428    {
07429       if (write(myrpt->iofd,txbuf,txbytes) != txbytes)
07430       {
07431          return -1;
07432       }
07433       if ((!rxmaxbytes) || (rxbuf == NULL)) 
07434       {
07435          return(0);
07436       }
07437       memset(rxbuf,0,rxmaxbytes);
07438       for(i = 0; i < rxmaxbytes; i++)
07439       {
07440          j = read(myrpt->iofd,&c,1);
07441          if (j < 1) 
07442          {
07443             return(i);
07444          }
07445          rxbuf[i] = c;
07446          if (asciiflag & 1)
07447          {
07448             rxbuf[i + 1] = 0;
07449             if (c == '\r') break;
07450          }
07451       }              
07452       if(debug) {
07453          printf("String returned was:\n");
07454          for(j = 0; j < i; j++)
07455             printf("%02X ", (unsigned char ) rxbuf[j]);
07456          printf("\n");
07457       }
07458       return(i);
07459    }
07460 
07461    /* if not a DAHDI channel, cant use pciradio stuff */
07462    if (myrpt->rxchannel != myrpt->dahdirxchannel) return -1;   
07463 
07464    prm.radpar = DAHDI_RADPAR_UIOMODE;
07465    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
07466    oldmode = prm.data;
07467    prm.radpar = DAHDI_RADPAR_UIODATA;
07468    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
07469    olddata = prm.data;
07470         prm.radpar = DAHDI_RADPAR_REMMODE;
07471         if (asciiflag & 1)  prm.data = DAHDI_RADPAR_REM_SERIAL_ASCII;
07472         else prm.data = DAHDI_RADPAR_REM_SERIAL;
07473    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07474    if (asciiflag & 2)
07475    {
07476       i = DAHDI_ONHOOK;
07477       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
07478       usleep(100000);
07479    }
07480         prm.radpar = DAHDI_RADPAR_REMCOMMAND;
07481         prm.data = rxmaxbytes;
07482         memcpy(prm.buf,txbuf,txbytes);
07483         prm.index = txbytes;
07484    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07485         if (rxbuf)
07486         {
07487                 *rxbuf = 0;
07488                 memcpy(rxbuf,prm.buf,prm.index);
07489         }
07490    idx = prm.index;
07491         prm.radpar = DAHDI_RADPAR_REMMODE;
07492         prm.data = DAHDI_RADPAR_REM_NONE;
07493    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07494    if (asciiflag & 2)
07495    {
07496       i = DAHDI_OFFHOOK;
07497       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
07498    }
07499    prm.radpar = DAHDI_RADPAR_UIOMODE;
07500    prm.data = oldmode;
07501    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07502    prm.radpar = DAHDI_RADPAR_UIODATA;
07503    prm.data = olddata;
07504    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07505         return(idx);
07506 }
07507 
07508 static int civ_cmd(struct rpt *myrpt,unsigned char *cmd, int cmdlen)
07509 {
07510 unsigned char rxbuf[100];
07511 int   i,rv ;
07512 
07513    rv = serial_remote_io(myrpt,cmd,cmdlen,rxbuf,cmdlen + 6,0);
07514    if (rv == -1) return(-1);
07515    if (rv != (cmdlen + 6)) return(1);
07516    for(i = 0; i < 6; i++)
07517       if (rxbuf[i] != cmd[i]) return(1);
07518    if (rxbuf[cmdlen] != 0xfe) return(1);
07519    if (rxbuf[cmdlen + 1] != 0xfe) return(1);
07520    if (rxbuf[cmdlen + 4] != 0xfb) return(1);
07521    if (rxbuf[cmdlen + 5] != 0xfd) return(1);
07522    return(0);
07523 }
07524 
07525 static int sendkenwood(struct rpt *myrpt,char *txstr, char *rxstr)
07526 {
07527 int   i;
07528 
07529 ast_log(LOG_NOTICE,"Sent to kenwood: %s\n",txstr);
07530    if (debug) printf("Send to kenwood: %s\n",txstr);
07531    i = serial_remote_io(myrpt, (unsigned char *)txstr, strlen(txstr), 
07532       (unsigned char *)rxstr,RAD_SERIAL_BUFLEN - 1,3);
07533    if (i < 0) return -1;
07534    if ((i > 0) && (rxstr[i - 1] == '\r'))
07535       rxstr[i-- - 1] = 0;
07536    if (debug) printf("Got from kenwood: %s\n",rxstr);
07537 ast_log(LOG_NOTICE,"Got from kenwood: %s\n",rxstr);
07538    return(i);
07539 }
07540 
07541 /* take a PL frequency and turn it into a code */
07542 static int kenwood_pltocode(char *str)
07543 {
07544 int i;
07545 char *s;
07546 
07547    s = strchr(str,'.');
07548    i = 0;
07549    if (s) i = atoi(s + 1);
07550    i += atoi(str) * 10;
07551    switch(i)
07552    {
07553        case 670:
07554       return 1;
07555        case 719:
07556       return 3;
07557        case 744:
07558       return 4;
07559        case 770:
07560       return 5;
07561        case 797:
07562       return 6;
07563        case 825:
07564       return 7;
07565        case 854:
07566       return 8;
07567        case 885:
07568       return 9;
07569        case 915:
07570       return 10;
07571        case 948:
07572       return 11;
07573        case 974:
07574       return 12;
07575        case 1000:
07576       return 13;
07577        case 1035:
07578       return 14;
07579        case 1072:
07580       return 15;
07581        case 1109:
07582       return 16;
07583        case 1148:
07584       return 17;
07585        case 1188:
07586       return 18;
07587        case 1230:
07588       return 19;
07589        case 1273:
07590       return 20;
07591        case 1318:
07592       return 21;
07593        case 1365:
07594       return 22;
07595        case 1413:
07596       return 23;
07597        case 1462:
07598       return 24;
07599        case 1514:
07600       return 25;
07601        case 1567:
07602       return 26;
07603        case 1622:
07604       return 27;
07605        case 1679:
07606       return 28;
07607        case 1738:
07608       return 29;
07609        case 1799:
07610       return 30;
07611        case 1862:
07612       return 31;
07613        case 1928:
07614       return 32;
07615        case 2035:
07616       return 33;
07617        case 2107:
07618       return 34;
07619        case 2181:
07620       return 35;
07621        case 2257:
07622       return 36;
07623        case 2336:
07624       return 37;
07625        case 2418:
07626       return 38;
07627        case 2503:
07628       return 39;
07629    }
07630    return -1;
07631 }
07632 
07633 static int sendrxkenwood(struct rpt *myrpt, char *txstr, char *rxstr, 
07634    char *cmpstr)
07635 {
07636 int   i,j;
07637 
07638    for(i = 0;i < KENWOOD_RETRIES;i++)
07639    {
07640       j = sendkenwood(myrpt,txstr,rxstr);
07641       if (j < 0) return(j);
07642       if (j == 0) continue;
07643       if (!strncmp(rxstr,cmpstr,strlen(cmpstr))) return(0);
07644    }
07645    return(-1);
07646 }     
07647 
07648 static int setkenwood(struct rpt *myrpt)
07649 {
07650 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
07651 char mhz[MAXREMSTR],offset[20],band,decimals[MAXREMSTR],band1,band2;
07652 int myrxpl;
07653    
07654 int offsets[] = {0,2,1};
07655 int powers[] = {2,1,0};
07656 
07657    if (sendrxkenwood(myrpt,"VMC 0,0\r",rxstr,"VMC") < 0) return -1;
07658    split_freq(mhz, decimals, myrpt->freq);
07659    if (atoi(mhz) > 400)
07660    {
07661       band = '6';
07662       band1 = '1';
07663       band2 = '5';
07664       strcpy(offset,"005000000");
07665    }
07666    else
07667    {
07668       band = '2';
07669       band1 = '0';
07670       band2 = '2';
07671       strcpy(offset,"000600000");
07672    }
07673    strcpy(freq,"000000");
07674    strncpy(freq,decimals,strlen(decimals));
07675    myrxpl = myrpt->rxplon;
07676    if (IS_XPMR(myrpt)) myrxpl = 0;
07677    sprintf(txstr,"VW %c,%05d%s,0,%d,0,%d,%d,,%02d,,%02d,%s\r",
07678       band,atoi(mhz),freq,offsets[(int)myrpt->offset],
07679       (myrpt->txplon != 0),myrxpl,
07680       kenwood_pltocode(myrpt->txpl),kenwood_pltocode(myrpt->rxpl),
07681       offset);
07682    if (sendrxkenwood(myrpt,txstr,rxstr,"VW") < 0) return -1;
07683    sprintf(txstr,"RBN %c\r",band2);
07684    if (sendrxkenwood(myrpt,txstr,rxstr,"RBN") < 0) return -1;
07685    sprintf(txstr,"PC %c,%d\r",band1,powers[(int)myrpt->powerlevel]);
07686    if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
07687    return 0;
07688 }
07689 
07690 static int set_tm271(struct rpt *myrpt)
07691 {
07692 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
07693 char mhz[MAXREMSTR],decimals[MAXREMSTR];
07694    
07695 int offsets[] = {0,2,1};
07696 int powers[] = {2,1,0};
07697 
07698    split_freq(mhz, decimals, myrpt->freq);
07699    strcpy(freq,"000000");
07700    strncpy(freq,decimals,strlen(decimals));
07701 
07702    sprintf(txstr,"VF %04d%s,4,%d,0,%d,0,0,%d,%d,000,00600000,0,0\r",
07703       atoi(mhz),freq,offsets[(int)myrpt->offset],
07704       (myrpt->txplon != 0),kenwood_pltocode(myrpt->txpl),
07705       kenwood_pltocode(myrpt->rxpl));
07706 
07707    if (sendrxkenwood(myrpt,txstr,rxstr,"VF") < 0) return -1;
07708    if (sendrxkenwood(myrpt,"VM 0\r",rxstr,"VM") < 0) return -1;
07709    sprintf(txstr,"PC %d\r",powers[(int)myrpt->powerlevel]);
07710    if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
07711    return 0;
07712 }
07713 
07714 static int setrbi(struct rpt *myrpt)
07715 {
07716 char tmp[MAXREMSTR] = "",*s;
07717 unsigned char rbicmd[5];
07718 int   band,txoffset = 0,txpower = 0,rxpl;
07719 
07720    /* must be a remote system */
07721    if (!myrpt->remoterig) return(0);
07722    if (!myrpt->remoterig[0]) return(0);
07723    /* must have rbi hardware */
07724    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
07725    if (setrbi_check(myrpt) == -1) return(-1);
07726    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07727    s = strchr(tmp,'.');
07728    /* if no decimal, is invalid */
07729    
07730    if (s == NULL){
07731       if(debug)
07732          printf("@@@@ Frequency needs a decimal\n");
07733       return -1;
07734    }
07735    
07736    *s++ = 0;
07737    if (strlen(tmp) < 2){
07738       if(debug)
07739          printf("@@@@ Bad MHz digits: %s\n", tmp);
07740       return -1;
07741    }
07742     
07743    if (strlen(s) < 3){
07744       if(debug)
07745          printf("@@@@ Bad KHz digits: %s\n", s);
07746       return -1;
07747    }
07748 
07749    if ((s[2] != '0') && (s[2] != '5')){
07750       if(debug)
07751          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
07752       return -1;
07753    }
07754     
07755    band = rbi_mhztoband(tmp);
07756    if (band == -1){
07757       if(debug)
07758          printf("@@@@ Bad Band: %s\n", tmp);
07759       return -1;
07760    }
07761    
07762    rxpl = rbi_pltocode(myrpt->rxpl);
07763    
07764    if (rxpl == -1){
07765       if(debug)
07766          printf("@@@@ Bad TX PL: %s\n", myrpt->rxpl);
07767       return -1;
07768    }
07769 
07770    
07771    switch(myrpt->offset)
07772    {
07773        case REM_MINUS:
07774       txoffset = 0;
07775       break;
07776        case REM_PLUS:
07777       txoffset = 0x10;
07778       break;
07779        case REM_SIMPLEX:
07780       txoffset = 0x20;
07781       break;
07782    }
07783    switch(myrpt->powerlevel)
07784    {
07785        case REM_LOWPWR:
07786       txpower = 0;
07787       break;
07788        case REM_MEDPWR:
07789       txpower = 0x20;
07790       break;
07791        case REM_HIPWR:
07792       txpower = 0x10;
07793       break;
07794    }
07795    rbicmd[0] = 0;
07796    rbicmd[1] = band | txpower | 0xc0;
07797    rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
07798    if (s[2] == '5') rbicmd[2] |= 0x40;
07799    rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
07800    rbicmd[4] = rxpl;
07801    if (myrpt->txplon) rbicmd[4] |= 0x40;
07802    if (myrpt->rxplon) rbicmd[4] |= 0x80;
07803    rbi_out(myrpt,rbicmd);
07804    return 0;
07805 }
07806 
07807 static int setrtx(struct rpt *myrpt)
07808 {
07809 char tmp[MAXREMSTR] = "",*s,rigstr[200],pwr,res = 0;
07810 int   band,txoffset = 0,txpower = 0,rxpl,txpl;
07811 float ofac;
07812 double txfreq;
07813 
07814    /* must be a remote system */
07815    if (!myrpt->remoterig) return(0);
07816    if (!myrpt->remoterig[0]) return(0);
07817    /* must have rtx hardware */
07818    if (!ISRIG_RTX(myrpt->remoterig)) return(0);
07819    /* must be a usbradio interface type */
07820    if (!IS_XPMR(myrpt)) return(0);
07821    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07822    s = strchr(tmp,'.');
07823    /* if no decimal, is invalid */
07824    
07825    if(debug)printf("setrtx() %s %s\n",myrpt->name,myrpt->remoterig);
07826 
07827    if (s == NULL){
07828       if(debug)
07829          printf("@@@@ Frequency needs a decimal\n");
07830       return -1;
07831    }
07832    *s++ = 0;
07833    if (strlen(tmp) < 2){
07834       if(debug)
07835          printf("@@@@ Bad MHz digits: %s\n", tmp);
07836       return -1;
07837    }
07838     
07839    if (strlen(s) < 3){
07840       if(debug)
07841          printf("@@@@ Bad KHz digits: %s\n", s);
07842       return -1;
07843    }
07844 
07845    if ((s[2] != '0') && (s[2] != '5')){
07846       if(debug)
07847          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
07848       return -1;
07849    }
07850     
07851    band = rbi_mhztoband(tmp);
07852    if (band == -1){
07853       if(debug)
07854          printf("@@@@ Bad Band: %s\n", tmp);
07855       return -1;
07856    }
07857    
07858    rxpl = rbi_pltocode(myrpt->rxpl);
07859    
07860    if (rxpl == -1){
07861       if(debug)
07862          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
07863       return -1;
07864    }
07865 
07866    txpl = rbi_pltocode(myrpt->txpl);
07867    
07868    if (txpl == -1){
07869       if(debug)
07870          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
07871       return -1;
07872    }
07873    
07874    switch(myrpt->offset)
07875    {
07876        case REM_MINUS:
07877       txoffset = 0;
07878       break;
07879        case REM_PLUS:
07880       txoffset = 0x10;
07881       break;
07882        case REM_SIMPLEX:
07883       txoffset = 0x20;
07884       break;
07885    }
07886    switch(myrpt->powerlevel)
07887    {
07888        case REM_LOWPWR:
07889       txpower = 0;
07890       break;
07891        case REM_MEDPWR:
07892       txpower = 0x20;
07893       break;
07894        case REM_HIPWR:
07895       txpower = 0x10;
07896       break;
07897    }
07898 
07899    res = setrtx_check(myrpt);
07900    if (res < 0) return res;
07901    ofac = 0.0;
07902    if (myrpt->offset == REM_MINUS) ofac = -1.0;
07903    if (myrpt->offset == REM_PLUS) ofac = 1.0;
07904 
07905    if (!strcmp(myrpt->remoterig,remote_rig_rtx450))
07906       txfreq = atof(myrpt->freq) +  (ofac * 5.0);
07907    else
07908       txfreq = atof(myrpt->freq) +  (ofac * 0.6);
07909 
07910    pwr = 'L';
07911    if (myrpt->powerlevel == REM_HIPWR) pwr = 'H';
07912    if (!res)
07913    {
07914       sprintf(rigstr,"SETFREQ %s %f %s %s %c",myrpt->freq,txfreq,
07915          (myrpt->rxplon) ? myrpt->rxpl : "0.0",
07916          (myrpt->txplon) ? myrpt->txpl : "0.0",pwr);
07917       send_usb_txt(myrpt,rigstr);
07918       rpt_telemetry(myrpt,COMPLETE,NULL);
07919       res = 0;
07920    }
07921    return 0;
07922 }
07923 #if 0
07924 /*
07925    sets current signaling code for xpmr routines
07926    under development for new radios.
07927 */
07928 static int setxpmr(struct rpt *myrpt)
07929 {
07930    char rigstr[200];
07931    int rxpl,txpl;
07932 
07933    /* must be a remote system */
07934    if (!myrpt->remoterig) return(0);
07935    if (!myrpt->remoterig[0]) return(0);
07936    /* must not have rtx hardware */
07937    if (ISRIG_RTX(myrpt->remoterig)) return(0);
07938    /* must be a usbradio interface type */
07939    if (!IS_XPMR(myrpt)) return(0);
07940    
07941    if(debug)printf("setxpmr() %s %s\n",myrpt->name,myrpt->remoterig );
07942 
07943    rxpl = rbi_pltocode(myrpt->rxpl);
07944    
07945    if (rxpl == -1){
07946       if(debug)
07947          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
07948       return -1;
07949    }
07950 
07951    txpl = rbi_pltocode(myrpt->txpl);
07952    if (txpl == -1){
07953       if(debug)
07954          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
07955       return -1;
07956    }
07957    sprintf(rigstr,"SETFREQ 0.0 0.0 %s %s L",
07958       (myrpt->rxplon) ? myrpt->rxpl : "0.0",
07959       (myrpt->txplon) ? myrpt->txpl : "0.0");
07960    send_usb_txt(myrpt,rigstr);
07961    return 0;
07962 }
07963 #endif
07964 
07965 static int setrbi_check(struct rpt *myrpt)
07966 {
07967 char tmp[MAXREMSTR] = "",*s;
07968 int   band,txpl;
07969 
07970    /* must be a remote system */
07971    if (!myrpt->remote) return(0);
07972    /* must have rbi hardware */
07973    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
07974    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07975    s = strchr(tmp,'.');
07976    /* if no decimal, is invalid */
07977    
07978    if (s == NULL){
07979       if(debug)
07980          printf("@@@@ Frequency needs a decimal\n");
07981       return -1;
07982    }
07983    
07984    *s++ = 0;
07985    if (strlen(tmp) < 2){
07986       if(debug)
07987          printf("@@@@ Bad MHz digits: %s\n", tmp);
07988       return -1;
07989    }
07990     
07991    if (strlen(s) < 3){
07992       if(debug)
07993          printf("@@@@ Bad KHz digits: %s\n", s);
07994       return -1;
07995    }
07996 
07997    if ((s[2] != '0') && (s[2] != '5')){
07998       if(debug)
07999          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
08000       return -1;
08001    }
08002     
08003    band = rbi_mhztoband(tmp);
08004    if (band == -1){
08005       if(debug)
08006          printf("@@@@ Bad Band: %s\n", tmp);
08007       return -1;
08008    }
08009    
08010    txpl = rbi_pltocode(myrpt->txpl);
08011    
08012    if (txpl == -1){
08013       if(debug)
08014          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
08015       return -1;
08016    }
08017    return 0;
08018 }
08019 
08020 static int setrtx_check(struct rpt *myrpt)
08021 {
08022 char tmp[MAXREMSTR] = "",*s;
08023 int   band,txpl,rxpl;
08024 
08025    /* must be a remote system */
08026    if (!myrpt->remote) return(0);
08027    /* must have rbi hardware */
08028    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
08029    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
08030    s = strchr(tmp,'.');
08031    /* if no decimal, is invalid */
08032    
08033    if (s == NULL){
08034       if(debug)
08035          printf("@@@@ Frequency needs a decimal\n");
08036       return -1;
08037    }
08038    
08039    *s++ = 0;
08040    if (strlen(tmp) < 2){
08041       if(debug)
08042          printf("@@@@ Bad MHz digits: %s\n", tmp);
08043       return -1;
08044    }
08045     
08046    if (strlen(s) < 3){
08047       if(debug)
08048          printf("@@@@ Bad KHz digits: %s\n", s);
08049       return -1;
08050    }
08051 
08052    if ((s[2] != '0') && (s[2] != '5')){
08053       if(debug)
08054          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
08055       return -1;
08056    }
08057     
08058    band = rbi_mhztoband(tmp);
08059    if (band == -1){
08060       if(debug)
08061          printf("@@@@ Bad Band: %s\n", tmp);
08062       return -1;
08063    }
08064    
08065    txpl = rbi_pltocode(myrpt->txpl);
08066    
08067    if (txpl == -1){
08068       if(debug)
08069          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
08070       return -1;
08071    }
08072 
08073    rxpl = rbi_pltocode(myrpt->rxpl);
08074    
08075    if (rxpl == -1){
08076       if(debug)
08077          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
08078       return -1;
08079    }
08080    return 0;
08081 }
08082 
08083 static int check_freq_kenwood(int m, int d, int *defmode)
08084 {
08085    int dflmd = REM_MODE_FM;
08086 
08087    if (m == 144){ /* 2 meters */
08088       if(d < 10100)
08089          return -1;
08090    }
08091    else if((m >= 145) && (m < 148)){
08092       ;
08093    }
08094    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08095       ;
08096    }
08097    else
08098       return -1;
08099    
08100    if(defmode)
08101       *defmode = dflmd; 
08102 
08103 
08104    return 0;
08105 }
08106 
08107 
08108 static int check_freq_tm271(int m, int d, int *defmode)
08109 {
08110    int dflmd = REM_MODE_FM;
08111 
08112    if (m == 144){ /* 2 meters */
08113       if(d < 10100)
08114          return -1;
08115    }
08116    else if((m >= 145) && (m < 148)){
08117       ;
08118    }
08119       return -1;
08120    
08121    if(defmode)
08122       *defmode = dflmd; 
08123 
08124 
08125    return 0;
08126 }
08127 
08128 
08129 /* Check for valid rbi frequency */
08130 /* Hard coded limits now, configurable later, maybe? */
08131 
08132 static int check_freq_rbi(int m, int d, int *defmode)
08133 {
08134    int dflmd = REM_MODE_FM;
08135 
08136    if(m == 50){ /* 6 meters */
08137       if(d < 10100)
08138          return -1;
08139    }
08140    else if((m >= 51) && ( m < 54)){
08141                 ;
08142    }
08143    else if(m == 144){ /* 2 meters */
08144       if(d < 10100)
08145          return -1;
08146    }
08147    else if((m >= 145) && (m < 148)){
08148       ;
08149    }
08150    else if((m >= 222) && (m < 225)){ /* 1.25 meters */
08151       ;
08152    }
08153    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08154       ;
08155    }
08156    else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
08157       ;
08158    }
08159    else
08160       return -1;
08161    
08162    if(defmode)
08163       *defmode = dflmd; 
08164 
08165 
08166    return 0;
08167 }
08168 
08169 /* Check for valid rtx frequency */
08170 /* Hard coded limits now, configurable later, maybe? */
08171 
08172 static int check_freq_rtx(int m, int d, int *defmode, struct rpt *myrpt)
08173 {
08174    int dflmd = REM_MODE_FM;
08175 
08176    if (!strcmp(myrpt->remoterig,remote_rig_rtx150))
08177    {
08178 
08179       if(m == 144){ /* 2 meters */
08180          if(d < 10100)
08181             return -1;
08182       }
08183       else if((m >= 145) && (m < 148)){
08184          ;
08185       }
08186       else
08187          return -1;
08188    }
08189    else 
08190    {
08191       if((m >= 430) && (m < 450)){ /* 70 centimeters */
08192          ;
08193       }
08194       else
08195          return -1;
08196    }
08197    if(defmode)
08198       *defmode = dflmd; 
08199 
08200 
08201    return 0;
08202 }
08203 
08204 /*
08205  * Convert decimals of frequency to int
08206  */
08207 
08208 static int decimals2int(char *fraction)
08209 {
08210    int i;
08211    char len = strlen(fraction);
08212    int multiplier = 100000;
08213    int res = 0;
08214 
08215    if(!len)
08216       return 0;
08217    for( i = 0 ; i < len ; i++, multiplier /= 10)
08218       res += (fraction[i] - '0') * multiplier;
08219    return res;
08220 }
08221 
08222 
08223 /*
08224 * Split frequency into mhz and decimals
08225 */
08226  
08227 static int split_freq(char *mhz, char *decimals, char *freq)
08228 {
08229    char freq_copy[MAXREMSTR];
08230    char *decp;
08231 
08232    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
08233    if(decp){
08234       *decp++ = 0;
08235       strncpy(mhz, freq_copy, MAXREMSTR);
08236       strcpy(decimals, "00000");
08237       strncpy(decimals, decp, strlen(decp));
08238       decimals[5] = 0;
08239       return 0;
08240    }
08241    else
08242       return -1;
08243 
08244 }
08245    
08246 /*
08247 * Split ctcss frequency into hertz and decimal
08248 */
08249  
08250 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
08251 {
08252    char freq_copy[MAXREMSTR];
08253    char *decp;
08254 
08255    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
08256    if(decp){
08257       *decp++ = 0;
08258       strncpy(hertz, freq_copy, MAXREMSTR);
08259       strncpy(decimal, decp, strlen(decp));
08260       decimal[strlen(decp)] = '\0';
08261       return 0;
08262    }
08263    else
08264       return -1;
08265 }
08266 
08267 
08268 
08269 /*
08270 * FT-897 I/O handlers
08271 */
08272 
08273 /* Check to see that the frequency is valid */
08274 /* Hard coded limits now, configurable later, maybe? */
08275 
08276 
08277 static int check_freq_ft897(int m, int d, int *defmode)
08278 {
08279    int dflmd = REM_MODE_FM;
08280 
08281    if(m == 1){ /* 160 meters */
08282       dflmd =  REM_MODE_LSB; 
08283       if(d < 80000)
08284          return -1;
08285    }
08286    else if(m == 3){ /* 80 meters */
08287       dflmd = REM_MODE_LSB;
08288       if(d < 50000)
08289          return -1;
08290    }
08291    else if(m == 7){ /* 40 meters */
08292       dflmd = REM_MODE_LSB;
08293       if(d > 30000)
08294          return -1;
08295    }
08296    else if(m == 14){ /* 20 meters */
08297       dflmd = REM_MODE_USB;
08298       if(d > 35000)
08299          return -1;
08300    }
08301    else if(m == 18){ /* 17 meters */
08302       dflmd = REM_MODE_USB;
08303       if((d < 6800) || (d > 16800))
08304          return -1;
08305    }
08306    else if(m == 21){ /* 15 meters */
08307       dflmd = REM_MODE_USB;
08308       if((d < 20000) || (d > 45000))
08309          return -1;
08310    }
08311    else if(m == 24){ /* 12 meters */
08312       dflmd = REM_MODE_USB;
08313       if((d < 89000) || (d > 99000))
08314          return -1;
08315    }
08316    else if(m == 28){ /* 10 meters */
08317       dflmd = REM_MODE_USB;
08318    }
08319    else if(m == 29){ 
08320       if(d >= 51000)
08321          dflmd = REM_MODE_FM;
08322       else
08323          dflmd = REM_MODE_USB;
08324       if(d > 70000)
08325          return -1;
08326    }
08327    else if(m == 50){ /* 6 meters */
08328       if(d >= 30000)
08329          dflmd = REM_MODE_FM;
08330       else
08331          dflmd = REM_MODE_USB;
08332 
08333    }
08334    else if((m >= 51) && ( m < 54)){
08335       dflmd = REM_MODE_FM;
08336    }
08337    else if(m == 144){ /* 2 meters */
08338       if(d >= 30000)
08339          dflmd = REM_MODE_FM;
08340       else
08341          dflmd = REM_MODE_USB;
08342    }
08343    else if((m >= 145) && (m < 148)){
08344       dflmd = REM_MODE_FM;
08345    }
08346    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08347       if(m  < 438)
08348          dflmd = REM_MODE_USB;
08349       else
08350          dflmd = REM_MODE_FM;
08351       ;
08352    }
08353    else
08354       return -1;
08355 
08356    if(defmode)
08357       *defmode = dflmd;
08358 
08359    return 0;
08360 }
08361 
08362 /*
08363 * Set a new frequency for the FT897
08364 */
08365 
08366 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
08367 {
08368    unsigned char cmdstr[5];
08369    int fd,m,d;
08370    char mhz[MAXREMSTR];
08371    char decimals[MAXREMSTR];
08372 
08373    fd = 0;
08374    if(debug) 
08375       printf("New frequency: %s\n",newfreq);
08376 
08377    if(split_freq(mhz, decimals, newfreq))
08378       return -1; 
08379 
08380    m = atoi(mhz);
08381    d = atoi(decimals);
08382 
08383    /* The FT-897 likes packed BCD frequencies */
08384 
08385    cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10);        /* 100MHz 10Mhz */
08386    cmdstr[1] = ((m % 10) << 4) + (d / 10000);         /* 1MHz 100KHz */
08387    cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100);  /* 10KHz 1KHz */
08388    cmdstr[3] = (((d % 100)/10) << 4) + (d % 10);         /* 100Hz 10Hz */
08389    cmdstr[4] = 0x01;                /* command */
08390 
08391    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08392 
08393 }
08394 
08395 /* ft-897 simple commands */
08396 
08397 static int simple_command_ft897(struct rpt *myrpt, char command)
08398 {
08399    unsigned char cmdstr[5];
08400    
08401    memset(cmdstr, 0, 5);
08402 
08403    cmdstr[4] = command; 
08404 
08405    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08406 
08407 }
08408 
08409 /* ft-897 offset */
08410 
08411 static int set_offset_ft897(struct rpt *myrpt, char offset)
08412 {
08413    unsigned char cmdstr[5];
08414    
08415    memset(cmdstr, 0, 5);
08416 
08417    switch(offset){
08418       case  REM_SIMPLEX:
08419          cmdstr[0] = 0x89;
08420          break;
08421 
08422       case  REM_MINUS:
08423          cmdstr[0] = 0x09;
08424          break;
08425       
08426       case  REM_PLUS:
08427          cmdstr[0] = 0x49;
08428          break;   
08429 
08430       default:
08431          return -1;
08432    }
08433 
08434    cmdstr[4] = 0x09; 
08435 
08436    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08437 }
08438 
08439 /* ft-897 mode */
08440 
08441 static int set_mode_ft897(struct rpt *myrpt, char newmode)
08442 {
08443    unsigned char cmdstr[5];
08444    
08445    memset(cmdstr, 0, 5);
08446    
08447    switch(newmode){
08448       case  REM_MODE_FM:
08449          cmdstr[0] = 0x08;
08450          break;
08451 
08452       case  REM_MODE_USB:
08453          cmdstr[0] = 0x01;
08454          break;
08455 
08456       case  REM_MODE_LSB:
08457          cmdstr[0] = 0x00;
08458          break;
08459 
08460       case  REM_MODE_AM:
08461          cmdstr[0] = 0x04;
08462          break;
08463       
08464       default:
08465          return -1;
08466    }
08467    cmdstr[4] = 0x07; 
08468 
08469    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08470 }
08471 
08472 /* Set tone encode and decode modes */
08473 
08474 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
08475 {
08476    unsigned char cmdstr[5];
08477    
08478    memset(cmdstr, 0, 5);
08479    
08480    if(rxplon && txplon)
08481       cmdstr[0] = 0x2A; /* Encode and Decode */
08482    else if (!rxplon && txplon)
08483       cmdstr[0] = 0x4A; /* Encode only */
08484    else if (rxplon && !txplon)
08485       cmdstr[0] = 0x3A; /* Encode only */
08486    else
08487       cmdstr[0] = 0x8A; /* OFF */
08488 
08489    cmdstr[4] = 0x0A; 
08490 
08491    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08492 }
08493 
08494 
08495 /* Set transmit and receive ctcss tone frequencies */
08496 
08497 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
08498 {
08499    unsigned char cmdstr[5];
08500    char hertz[MAXREMSTR],decimal[MAXREMSTR];
08501    int h,d; 
08502 
08503    memset(cmdstr, 0, 5);
08504 
08505    if(split_ctcss_freq(hertz, decimal, txtone))
08506       return -1; 
08507 
08508    h = atoi(hertz);
08509    d = atoi(decimal);
08510    
08511    cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
08512    cmdstr[1] = ((h % 10) << 4) + (d % 10);
08513    
08514    if(rxtone){
08515    
08516       if(split_ctcss_freq(hertz, decimal, rxtone))
08517          return -1; 
08518 
08519       h = atoi(hertz);
08520       d = atoi(decimal);
08521    
08522       cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
08523       cmdstr[3] = ((h % 10) << 4) + (d % 10);
08524    }
08525    cmdstr[4] = 0x0B; 
08526 
08527    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08528 }  
08529 
08530 
08531 
08532 static int set_ft897(struct rpt *myrpt)
08533 {
08534    int res;
08535    
08536    if(debug)
08537       printf("@@@@ lock on\n");
08538 
08539    res = simple_command_ft897(myrpt, 0x00);  /* LOCK on */  
08540 
08541    if(debug)
08542       printf("@@@@ ptt off\n");
08543 
08544    if(!res)
08545       res = simple_command_ft897(myrpt, 0x88);     /* PTT off */
08546 
08547    if(debug)
08548       printf("Modulation mode\n");
08549 
08550    if(!res)
08551       res = set_mode_ft897(myrpt, myrpt->remmode);    /* Modulation mode */
08552 
08553    if(debug)
08554       printf("Split off\n");
08555 
08556    if(!res)
08557       simple_command_ft897(myrpt, 0x82);        /* Split off */
08558 
08559    if(debug)
08560       printf("Frequency\n");
08561 
08562    if(!res)
08563       res = set_freq_ft897(myrpt, myrpt->freq);    /* Frequency */
08564    if((myrpt->remmode == REM_MODE_FM)){
08565       if(debug)
08566          printf("Offset\n");
08567       if(!res)
08568          res = set_offset_ft897(myrpt, myrpt->offset);   /* Offset if FM */
08569       if((!res)&&(myrpt->rxplon || myrpt->txplon)){
08570          if(debug)
08571             printf("CTCSS tone freqs.\n");
08572          res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
08573       }
08574       if(!res){
08575          if(debug)
08576             printf("CTCSS mode\n");
08577          res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
08578       }
08579    }
08580    if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
08581       if(debug)
08582          printf("Clarifier off\n");
08583       simple_command_ft897(myrpt, 0x85);        /* Clarifier off if LSB or USB */
08584    }
08585    return res;
08586 }
08587 
08588 static int closerem_ft897(struct rpt *myrpt)
08589 {
08590    simple_command_ft897(myrpt, 0x88); /* PTT off */
08591    return 0;
08592 }  
08593 
08594 /*
08595 * Bump frequency up or down by a small amount 
08596 * Return 0 if the new frequnecy is valid, or -1 if invalid
08597 * Interval is in Hz, resolution is 10Hz 
08598 */
08599 
08600 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
08601 {
08602    int m,d;
08603    char mhz[MAXREMSTR], decimals[MAXREMSTR];
08604 
08605    if(debug)
08606       printf("Before bump: %s\n", myrpt->freq);
08607 
08608    if(split_freq(mhz, decimals, myrpt->freq))
08609       return -1;
08610    
08611    m = atoi(mhz);
08612    d = atoi(decimals);
08613 
08614    d += (interval / 10); /* 10Hz resolution */
08615    if(d < 0){
08616       m--;
08617       d += 100000;
08618    }
08619    else if(d >= 100000){
08620       m++;
08621       d -= 100000;
08622    }
08623 
08624    if(check_freq_ft897(m, d, NULL)){
08625       if(debug)
08626          printf("Bump freq invalid\n");
08627       return -1;
08628    }
08629 
08630    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
08631 
08632    if(debug)
08633       printf("After bump: %s\n", myrpt->freq);
08634 
08635    return set_freq_ft897(myrpt, myrpt->freq);   
08636 }
08637 
08638 
08639 
08640 /*
08641 * IC-706 I/O handlers
08642 */
08643 
08644 /* Check to see that the frequency is valid */
08645 /* returns 0 if frequency is valid          */
08646 
08647 static int check_freq_ic706(int m, int d, int *defmode, char mars)
08648 {
08649    int dflmd = REM_MODE_FM;
08650    int rv=0;
08651 
08652    if(debug > 6)
08653       ast_log(LOG_NOTICE,"(%i,%i,%i,%i)\n",m,d,*defmode,mars);
08654 
08655    /* first test for standard amateur radio bands */
08656 
08657    if(m == 1){                /* 160 meters */
08658       dflmd =  REM_MODE_LSB; 
08659       if(d < 80000)rv=-1;
08660    }
08661    else if(m == 3){           /* 80 meters */
08662       dflmd = REM_MODE_LSB;
08663       if(d < 50000)rv=-1;
08664    }
08665    else if(m == 7){           /* 40 meters */
08666       dflmd = REM_MODE_LSB;
08667       if(d > 30000)rv=-1;
08668    }
08669    else if(m == 14){             /* 20 meters */
08670       dflmd = REM_MODE_USB;
08671       if(d > 35000)rv=-1;
08672    }
08673    else if(m == 18){                      /* 17 meters */
08674       dflmd = REM_MODE_USB;
08675       if((d < 6800) || (d > 16800))rv=-1;
08676    }
08677    else if(m == 21){ /* 15 meters */
08678       dflmd = REM_MODE_USB;
08679       if((d < 20000) || (d > 45000))rv=-1;
08680    }
08681    else if(m == 24){ /* 12 meters */
08682       dflmd = REM_MODE_USB;
08683       if((d < 89000) || (d > 99000))rv=-1;
08684    }
08685    else if(m == 28){                      /* 10 meters */
08686       dflmd = REM_MODE_USB;
08687    }
08688    else if(m == 29){ 
08689       if(d >= 51000)
08690          dflmd = REM_MODE_FM;
08691       else
08692          dflmd = REM_MODE_USB;
08693       if(d > 70000)rv=-1;
08694    }
08695    else if(m == 50){                      /* 6 meters */
08696       if(d >= 30000)
08697          dflmd = REM_MODE_FM;
08698       else
08699          dflmd = REM_MODE_USB;
08700    }
08701    else if((m >= 51) && ( m < 54)){
08702       dflmd = REM_MODE_FM;
08703    }
08704    else if(m == 144){ /* 2 meters */
08705       if(d >= 30000)
08706          dflmd = REM_MODE_FM;
08707       else
08708          dflmd = REM_MODE_USB;
08709    }
08710    else if((m >= 145) && (m < 148)){
08711       dflmd = REM_MODE_FM;
08712    }
08713    else if((m >= 430) && (m < 450)){         /* 70 centimeters */
08714       if(m  < 438)
08715          dflmd = REM_MODE_USB;
08716       else
08717          dflmd = REM_MODE_FM;
08718    }
08719 
08720    /* check expanded coverage */
08721    if(mars && rv<0){
08722       if((m >= 450) && (m < 470)){        /* LMR */
08723          dflmd = REM_MODE_FM;
08724          rv=0;
08725       }
08726       else if((m >= 148) && (m < 174)){      /* LMR */
08727          dflmd = REM_MODE_FM;
08728          rv=0;
08729       }
08730       else if((m >= 138) && (m < 144)){      /* VHF-AM AIRCRAFT */
08731          dflmd = REM_MODE_AM;
08732          rv=0;
08733       }
08734       else if((m >= 108) && (m < 138)){      /* VHF-AM AIRCRAFT */
08735          dflmd = REM_MODE_AM;
08736          rv=0;
08737       }
08738       else if( (m==0 && d>=55000) || (m==1 && d<=75000) ){  /* AM BCB*/
08739          dflmd = REM_MODE_AM;
08740          rv=0;
08741       }
08742       else if( (m == 1 && d>75000) || (m>1 && m<30) ){      /* HF SWL*/
08743          dflmd = REM_MODE_AM;
08744          rv=0;
08745       }
08746    }
08747 
08748    if(defmode)
08749       *defmode = dflmd;
08750 
08751    if(debug > 1)
08752       ast_log(LOG_NOTICE,"(%i,%i,%i,%i) returning %i\n",m,d,*defmode,mars,rv);
08753 
08754    return rv;
08755 }
08756 
08757 /* take a PL frequency and turn it into a code */
08758 static int ic706_pltocode(char *str)
08759 {
08760    int i;
08761    char *s;
08762    int rv=-1;
08763 
08764    s = strchr(str,'.');
08765    i = 0;
08766    if (s) i = atoi(s + 1);
08767    i += atoi(str) * 10;
08768    switch(i)
08769    {
08770        case 670:
08771          rv=0;
08772        case 693:
08773          rv=1;
08774        case 719:
08775          rv=2;
08776        case 744:
08777          rv=3;
08778        case 770:
08779          rv=4;
08780        case 797:
08781          rv=5;
08782        case 825:
08783          rv=6;
08784        case 854:
08785          rv=7;
08786        case 885:
08787          rv=8;
08788        case 915:
08789          rv=9;
08790        case 948:
08791          rv=10;
08792        case 974:
08793          rv=11;
08794        case 1000:
08795          rv=12;
08796        case 1035:
08797          rv=13;
08798        case 1072:
08799          rv=14;
08800        case 1109:
08801          rv=15;
08802        case 1148:
08803          rv=16;
08804        case 1188:
08805          rv=17;
08806        case 1230:
08807          rv=18;
08808        case 1273:
08809          rv=19;
08810        case 1318:
08811          rv=20;
08812        case 1365:
08813          rv=21;
08814        case 1413:
08815          rv=22;
08816        case 1462:
08817          rv=23;
08818        case 1514:
08819          rv=24;
08820        case 1567:
08821          rv=25;
08822        case 1598:
08823          rv=26;
08824        case 1622:
08825          rv=27;
08826        case 1655:
08827          rv=28;      
08828        case 1679:
08829          rv=29;
08830        case 1713:
08831          rv=30;
08832        case 1738:
08833          rv=31;
08834        case 1773:
08835          rv=32;
08836        case 1799:
08837          rv=33;
08838         case 1835:
08839          rv=34;
08840        case 1862:
08841          rv=35;
08842        case 1899:
08843          rv=36;
08844        case 1928:
08845          rv=37;
08846        case 1966:
08847          rv=38;
08848        case 1995:
08849          rv=39;
08850        case 2035:
08851          rv=40;
08852        case 2065:
08853          rv=41;
08854        case 2107:
08855          rv=42;
08856        case 2181:
08857          rv=43;
08858        case 2257:
08859          rv=44;
08860        case 2291:
08861          rv=45;
08862        case 2336:
08863          rv=46;
08864        case 2418:
08865          rv=47;
08866        case 2503:
08867          rv=48;
08868        case 2541:
08869          rv=49;
08870    }
08871    if(debug > 1)
08872       ast_log(LOG_NOTICE,"%i  rv=%i\n",i, rv);
08873 
08874    return rv;
08875 }
08876 
08877 /* ic-706 simple commands */
08878 
08879 static int simple_command_ic706(struct rpt *myrpt, char command, char subcommand)
08880 {
08881    unsigned char cmdstr[10];
08882    
08883    cmdstr[0] = cmdstr[1] = 0xfe;
08884    cmdstr[2] = myrpt->p.civaddr;
08885    cmdstr[3] = 0xe0;
08886    cmdstr[4] = command;
08887    cmdstr[5] = subcommand;
08888    cmdstr[6] = 0xfd;
08889 
08890    return(civ_cmd(myrpt,cmdstr,7));
08891 }
08892 
08893 /*
08894 * Set a new frequency for the ic706
08895 */
08896 
08897 static int set_freq_ic706(struct rpt *myrpt, char *newfreq)
08898 {
08899    unsigned char cmdstr[20];
08900    char mhz[MAXREMSTR], decimals[MAXREMSTR];
08901    int fd,m,d;
08902 
08903    fd = 0;
08904    if(debug) 
08905       ast_log(LOG_NOTICE,"newfreq:%s\n",newfreq);        
08906 
08907    if(split_freq(mhz, decimals, newfreq))
08908       return -1; 
08909 
08910    m = atoi(mhz);
08911    d = atoi(decimals);
08912 
08913    /* The ic-706 likes packed BCD frequencies */
08914 
08915    cmdstr[0] = cmdstr[1] = 0xfe;
08916    cmdstr[2] = myrpt->p.civaddr;
08917    cmdstr[3] = 0xe0;
08918    cmdstr[4] = 5;
08919    cmdstr[5] = ((d % 10) << 4);
08920    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
08921    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
08922    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
08923    cmdstr[9] = (m / 100);
08924    cmdstr[10] = 0xfd;
08925 
08926    return(civ_cmd(myrpt,cmdstr,11));
08927 }
08928 
08929 /* ic-706 offset */
08930 
08931 static int set_offset_ic706(struct rpt *myrpt, char offset)
08932 {
08933    unsigned char c;
08934 
08935    if(debug > 6)
08936       ast_log(LOG_NOTICE,"offset=%i\n",offset);
08937 
08938    switch(offset){
08939       case  REM_SIMPLEX:
08940          c = 0x10;
08941          break;
08942 
08943       case  REM_MINUS:
08944          c = 0x11;
08945          break;
08946       
08947       case  REM_PLUS:
08948          c = 0x12;
08949          break;   
08950 
08951       default:
08952          return -1;
08953    }
08954 
08955    return simple_command_ic706(myrpt,0x0f,c);
08956 
08957 }
08958 
08959 /* ic-706 mode */
08960 
08961 static int set_mode_ic706(struct rpt *myrpt, char newmode)
08962 {
08963    unsigned char c;
08964    
08965    if(debug > 6)
08966       ast_log(LOG_NOTICE,"newmode=%i\n",newmode);
08967 
08968    switch(newmode){
08969       case  REM_MODE_FM:
08970          c = 5;
08971          break;
08972 
08973       case  REM_MODE_USB:
08974          c = 1;
08975          break;
08976 
08977       case  REM_MODE_LSB:
08978          c = 0;
08979          break;
08980 
08981       case  REM_MODE_AM:
08982          c = 2;
08983          break;
08984       
08985       default:
08986          return -1;
08987    }
08988    return simple_command_ic706(myrpt,6,c);
08989 }
08990 
08991 /* Set tone encode and decode modes */
08992 
08993 static int set_ctcss_mode_ic706(struct rpt *myrpt, char txplon, char rxplon)
08994 {
08995    unsigned char cmdstr[10];
08996    int rv;
08997 
08998    if(debug > 6)
08999       ast_log(LOG_NOTICE,"txplon=%i  rxplon=%i \n",txplon,rxplon);
09000 
09001    cmdstr[0] = cmdstr[1] = 0xfe;
09002    cmdstr[2] = myrpt->p.civaddr;
09003    cmdstr[3] = 0xe0;
09004    cmdstr[4] = 0x16;
09005    cmdstr[5] = 0x42;
09006    cmdstr[6] = (txplon != 0);
09007    cmdstr[7] = 0xfd;
09008 
09009    rv = civ_cmd(myrpt,cmdstr,8);
09010    if (rv) return(-1);
09011 
09012    cmdstr[0] = cmdstr[1] = 0xfe;
09013    cmdstr[2] = myrpt->p.civaddr;
09014    cmdstr[3] = 0xe0;
09015    cmdstr[4] = 0x16;
09016    cmdstr[5] = 0x43;
09017    cmdstr[6] = (rxplon != 0);
09018    cmdstr[7] = 0xfd;
09019 
09020    return(civ_cmd(myrpt,cmdstr,8));
09021 }
09022 
09023 #if 0
09024 /* Set transmit and receive ctcss tone frequencies */
09025 
09026 static int set_ctcss_freq_ic706(struct rpt *myrpt, char *txtone, char *rxtone)
09027 {
09028    unsigned char cmdstr[10];
09029    char hertz[MAXREMSTR],decimal[MAXREMSTR];
09030    int h,d,rv;
09031 
09032    memset(cmdstr, 0, 5);
09033 
09034    if(debug > 6)
09035       ast_log(LOG_NOTICE,"txtone=%s  rxtone=%s \n",txtone,rxtone);
09036 
09037    if(split_ctcss_freq(hertz, decimal, txtone))
09038       return -1; 
09039 
09040    h = atoi(hertz);
09041    d = atoi(decimal);
09042    
09043    cmdstr[0] = cmdstr[1] = 0xfe;
09044    cmdstr[2] = myrpt->p.civaddr;
09045    cmdstr[3] = 0xe0;
09046    cmdstr[4] = 0x1b;
09047    cmdstr[5] = 0;
09048    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
09049    cmdstr[7] = ((h % 10) << 4) + (d % 10);
09050    cmdstr[8] = 0xfd;
09051 
09052    rv = civ_cmd(myrpt,cmdstr,9);
09053    if (rv) return(-1);
09054 
09055    if (!rxtone) return(0);
09056 
09057    if(split_ctcss_freq(hertz, decimal, rxtone))
09058       return -1; 
09059 
09060    h = atoi(hertz);
09061    d = atoi(decimal);
09062 
09063    cmdstr[0] = cmdstr[1] = 0xfe;
09064    cmdstr[2] = myrpt->p.civaddr;
09065    cmdstr[3] = 0xe0;
09066    cmdstr[4] = 0x1b;
09067    cmdstr[5] = 1;
09068    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
09069    cmdstr[7] = ((h % 10) << 4) + (d % 10);
09070    cmdstr[8] = 0xfd;
09071    return(civ_cmd(myrpt,cmdstr,9));
09072 }  
09073 #endif
09074 
09075 static int vfo_ic706(struct rpt *myrpt)
09076 {
09077    unsigned char cmdstr[10];
09078    
09079    cmdstr[0] = cmdstr[1] = 0xfe;
09080    cmdstr[2] = myrpt->p.civaddr;
09081    cmdstr[3] = 0xe0;
09082    cmdstr[4] = 7;
09083    cmdstr[5] = 0xfd;
09084 
09085    return(civ_cmd(myrpt,cmdstr,6));
09086 }
09087 
09088 static int mem2vfo_ic706(struct rpt *myrpt)
09089 {
09090    unsigned char cmdstr[10];
09091    
09092    cmdstr[0] = cmdstr[1] = 0xfe;
09093    cmdstr[2] = myrpt->p.civaddr;
09094    cmdstr[3] = 0xe0;
09095    cmdstr[4] = 0x0a;
09096    cmdstr[5] = 0xfd;
09097 
09098    return(civ_cmd(myrpt,cmdstr,6));
09099 }
09100 
09101 static int select_mem_ic706(struct rpt *myrpt, int slot)
09102 {
09103    unsigned char cmdstr[10];
09104    
09105    cmdstr[0] = cmdstr[1] = 0xfe;
09106    cmdstr[2] = myrpt->p.civaddr;
09107    cmdstr[3] = 0xe0;
09108    cmdstr[4] = 8;
09109    cmdstr[5] = 0;
09110    cmdstr[6] = ((slot / 10) << 4) + (slot % 10);
09111    cmdstr[7] = 0xfd;
09112 
09113    return(civ_cmd(myrpt,cmdstr,8));
09114 }
09115 
09116 static int set_ic706(struct rpt *myrpt)
09117 {
09118    int res = 0,i;
09119    
09120    if(debug)ast_log(LOG_NOTICE, "Set to VFO A iobase=%i\n",myrpt->p.iobase);
09121 
09122    if (!res)
09123       res = simple_command_ic706(myrpt,7,0);
09124 
09125    if((myrpt->remmode == REM_MODE_FM))
09126    {
09127       i = ic706_pltocode(myrpt->rxpl);
09128       if (i == -1) return -1;
09129       if(debug)
09130          printf("Select memory number\n");
09131       if (!res)
09132          res = select_mem_ic706(myrpt,i + IC706_PL_MEMORY_OFFSET);
09133       if(debug)
09134          printf("Transfer memory to VFO\n");
09135       if (!res)
09136          res = mem2vfo_ic706(myrpt);
09137    }
09138       
09139    if(debug)
09140       printf("Set to VFO\n");
09141 
09142    if (!res)
09143       res = vfo_ic706(myrpt);
09144 
09145    if(debug)
09146       printf("Modulation mode\n");
09147 
09148    if (!res)
09149       res = set_mode_ic706(myrpt, myrpt->remmode);    /* Modulation mode */
09150 
09151    if(debug)
09152       printf("Split off\n");
09153 
09154    if(!res)
09155       simple_command_ic706(myrpt, 0x82,0);         /* Split off */
09156 
09157    if(debug)
09158       printf("Frequency\n");
09159 
09160    if(!res)
09161       res = set_freq_ic706(myrpt, myrpt->freq);    /* Frequency */
09162    if((myrpt->remmode == REM_MODE_FM)){
09163       if(debug)
09164          printf("Offset\n");
09165       if(!res)
09166          res = set_offset_ic706(myrpt, myrpt->offset);   /* Offset if FM */
09167       if(!res){
09168          if(debug)
09169             printf("CTCSS mode\n");
09170          res = set_ctcss_mode_ic706(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
09171       }
09172    }
09173    return res;
09174 }
09175 
09176 /*
09177 * Bump frequency up or down by a small amount 
09178 * Return 0 if the new frequnecy is valid, or -1 if invalid
09179 * Interval is in Hz, resolution is 10Hz 
09180 */
09181 
09182 static int multimode_bump_freq_ic706(struct rpt *myrpt, int interval)
09183 {
09184    int m,d;
09185    char mhz[MAXREMSTR], decimals[MAXREMSTR];
09186    unsigned char cmdstr[20];
09187 
09188    if(debug)
09189       printf("Before bump: %s\n", myrpt->freq);
09190 
09191    if(split_freq(mhz, decimals, myrpt->freq))
09192       return -1;
09193    
09194    m = atoi(mhz);
09195    d = atoi(decimals);
09196 
09197    d += (interval / 10); /* 10Hz resolution */
09198    if(d < 0){
09199       m--;
09200       d += 100000;
09201    }
09202    else if(d >= 100000){
09203       m++;
09204       d -= 100000;
09205    }
09206 
09207    if(check_freq_ic706(m, d, NULL,myrpt->p.remote_mars)){
09208       if(debug)
09209          printf("Bump freq invalid\n");
09210       return -1;
09211    }
09212 
09213    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
09214 
09215    if(debug)
09216       printf("After bump: %s\n", myrpt->freq);
09217 
09218    /* The ic-706 likes packed BCD frequencies */
09219 
09220    cmdstr[0] = cmdstr[1] = 0xfe;
09221    cmdstr[2] = myrpt->p.civaddr;
09222    cmdstr[3] = 0xe0;
09223    cmdstr[4] = 0;
09224    cmdstr[5] = ((d % 10) << 4);
09225    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
09226    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
09227    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
09228    cmdstr[9] = (m / 100);
09229    cmdstr[10] = 0xfd;
09230 
09231    return(serial_remote_io(myrpt,cmdstr,11,NULL,0,0));
09232 }
09233 
09234 
09235 
09236 /*
09237 * Dispatch to correct I/O handler 
09238 */
09239 static int setrem(struct rpt *myrpt)
09240 {
09241 char  str[300];
09242 char  *offsets[] = {"SIMPLEX","MINUS","PLUS"};
09243 char  *powerlevels[] = {"LOW","MEDIUM","HIGH"};
09244 char  *modes[] = {"FM","USB","LSB","AM"};
09245 int   res = -1;
09246 
09247 #if   0
09248 printf("FREQ,%s,%s,%s,%s,%s,%s,%d,%d\n",myrpt->freq,
09249    modes[(int)myrpt->remmode],
09250    myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
09251    powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
09252    myrpt->rxplon);
09253 #endif
09254    if (myrpt->p.archivedir)
09255    {
09256       sprintf(str,"FREQ,%s,%s,%s,%s,%s,%s,%d,%d",myrpt->freq,
09257          modes[(int)myrpt->remmode],
09258          myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
09259          powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
09260          myrpt->rxplon);
09261       donodelog(myrpt,str);
09262    }
09263    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09264    {
09265       rpt_telemetry(myrpt,SETREMOTE,NULL);
09266       res = 0;
09267    }
09268    if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09269    {
09270       rpt_telemetry(myrpt,SETREMOTE,NULL);
09271       res = 0;
09272    }
09273    if(!strcmp(myrpt->remoterig, remote_rig_tm271))
09274    {
09275       rpt_telemetry(myrpt,SETREMOTE,NULL);
09276       res = 0;
09277    }
09278    else if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09279    {
09280       res = setrbi_check(myrpt);
09281       if (!res)
09282       {
09283          rpt_telemetry(myrpt,SETREMOTE,NULL);
09284          res = 0;
09285       }
09286    }
09287    else if(ISRIG_RTX(myrpt->remoterig))
09288    {
09289       setrtx(myrpt);
09290       res = 0;
09291    }
09292    else if(!strcmp(myrpt->remoterig, remote_rig_kenwood)) {
09293       rpt_telemetry(myrpt,SETREMOTE,NULL);
09294       res = 0;
09295    }
09296    else
09297       res = 0;
09298 
09299    if (res < 0) ast_log(LOG_ERROR,"Unable to send remote command on node %s\n",myrpt->name);
09300 
09301    return res;
09302 }
09303 
09304 static int closerem(struct rpt *myrpt)
09305 {
09306    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09307       return closerem_ft897(myrpt);
09308    else
09309       return 0;
09310 }
09311 
09312 /*
09313 * Dispatch to correct RX frequency checker
09314 */
09315 
09316 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
09317 {
09318    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09319       return check_freq_ft897(m, d, defmode);
09320    else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09321       return check_freq_ic706(m, d, defmode,myrpt->p.remote_mars);
09322    else if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09323       return check_freq_rbi(m, d, defmode);
09324    else if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
09325       return check_freq_kenwood(m, d, defmode);
09326    else if(!strcmp(myrpt->remoterig, remote_rig_tm271))
09327       return check_freq_tm271(m, d, defmode);
09328    else if(ISRIG_RTX(myrpt->remoterig))
09329       return check_freq_rtx(m, d, defmode, myrpt);
09330    else
09331       return -1;
09332 }
09333 
09334 /*
09335  * Check TX frequency before transmitting
09336    rv=1 if tx frequency in ok.
09337 */
09338 
09339 static char check_tx_freq(struct rpt *myrpt)
09340 {
09341    int i,rv=0;
09342    int radio_mhz, radio_decimals, ulimit_mhz, ulimit_decimals, llimit_mhz, llimit_decimals;
09343    char radio_mhz_char[MAXREMSTR];
09344    char radio_decimals_char[MAXREMSTR];
09345    char limit_mhz_char[MAXREMSTR];
09346    char limit_decimals_char[MAXREMSTR];
09347    char limits[256];
09348    char *limit_ranges[40];
09349    struct ast_variable *limitlist;
09350    
09351    if(debug > 3){
09352       ast_log(LOG_NOTICE, "myrpt->freq = %s\n", myrpt->freq);
09353    }
09354 
09355    /* Must have user logged in and tx_limits defined */
09356 
09357    if(!myrpt->p.txlimitsstanzaname || !myrpt->loginuser[0] || !myrpt->loginlevel[0]){
09358       if(debug > 3){
09359          ast_log(LOG_NOTICE, "No tx band table defined, or no user logged in. rv=1\n");
09360       }
09361       rv=1;
09362       return 1; /* Assume it's ok otherwise */
09363    }
09364 
09365    /* Retrieve the band table for the loginlevel */
09366    limitlist = ast_variable_browse(myrpt->cfg, myrpt->p.txlimitsstanzaname);
09367 
09368    if(!limitlist){
09369       ast_log(LOG_WARNING, "No entries in %s band table stanza. rv=0\n", myrpt->p.txlimitsstanzaname);
09370       rv=0;
09371       return 0;
09372    }
09373 
09374    split_freq(radio_mhz_char, radio_decimals_char, myrpt->freq);
09375    radio_mhz = atoi(radio_mhz_char);
09376    radio_decimals = decimals2int(radio_decimals_char);
09377 
09378    if(debug > 3){
09379       ast_log(LOG_NOTICE, "Login User = %s, login level = %s\n", myrpt->loginuser, myrpt->loginlevel);
09380    }
09381 
09382    /* Find our entry */
09383 
09384    for(;limitlist; limitlist=limitlist->next){
09385       if(!strcmp(limitlist->name, myrpt->loginlevel))
09386          break;
09387    }
09388 
09389    if(!limitlist){
09390       ast_log(LOG_WARNING, "Can't find %s entry in band table stanza %s. rv=0\n", myrpt->loginlevel, myrpt->p.txlimitsstanzaname);
09391       rv=0;
09392        return 0;
09393    }
09394    
09395    if(debug > 3){
09396       ast_log(LOG_NOTICE, "Auth: %s = %s\n", limitlist->name, limitlist->value);
09397    }
09398 
09399    /* Parse the limits */
09400 
09401    strncpy(limits, limitlist->value, 256);
09402    limits[255] = 0;
09403    finddelim(limits, limit_ranges, 40);
09404    for(i = 0; i < 40 && limit_ranges[i] ; i++){
09405       char range[40];
09406       char *r,*s;
09407       strncpy(range, limit_ranges[i], 40);
09408       range[39] = 0;
09409         if(debug > 3) 
09410          ast_log(LOG_NOTICE, "Check %s within %s\n", myrpt->freq, range);
09411    
09412       r = strchr(range, '-');
09413       if(!r){
09414          ast_log(LOG_WARNING, "Malformed range in %s tx band table entry. rv=0\n", limitlist->name);
09415          rv=0;
09416          break;
09417       }
09418       *r++ = 0;
09419       s = eatwhite(range);
09420       r = eatwhite(r);
09421       split_freq(limit_mhz_char, limit_decimals_char, s);
09422       llimit_mhz = atoi(limit_mhz_char);
09423       llimit_decimals = decimals2int(limit_decimals_char);
09424       split_freq(limit_mhz_char, limit_decimals_char, r);
09425       ulimit_mhz = atoi(limit_mhz_char);
09426       ulimit_decimals = decimals2int(limit_decimals_char);
09427          
09428       if((radio_mhz >= llimit_mhz) && (radio_mhz <= ulimit_mhz)){
09429          if(radio_mhz == llimit_mhz){ /* CASE 1: TX freq is in llimit mhz portion of band */
09430             if(radio_decimals >= llimit_decimals){ /* Cannot be below llimit decimals */
09431                if(llimit_mhz == ulimit_mhz){ /* If bandwidth < 1Mhz, check ulimit decimals */
09432                   if(radio_decimals <= ulimit_decimals){
09433                      rv=1;
09434                      break;
09435                   }
09436                   else{
09437                      if(debug > 3)
09438                         ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 1\n");
09439                      rv=0;
09440                      break;
09441                   }
09442                }
09443                else{
09444                   rv=1;
09445                   break;
09446                }
09447             }
09448             else{ /* Is below llimit decimals */
09449                if(debug > 3)
09450                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 2\n");
09451                rv=0;
09452                break;
09453             }
09454          }
09455          else if(radio_mhz == ulimit_mhz){ /* CASE 2: TX freq not in llimit mhz portion of band */
09456             if(radio_decimals <= ulimit_decimals){
09457                if(debug > 3)
09458                   ast_log(LOG_NOTICE, "radio_decimals <= ulimit_decimals\n");
09459                rv=1;
09460                break;
09461             }
09462             else{ /* Is above ulimit decimals */
09463                if(debug > 3)
09464                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 3\n");
09465                rv=0;
09466                break;
09467             }
09468          }
09469          else /* CASE 3: TX freq within a multi-Mhz band and ok */
09470             if(debug > 3)
09471                   ast_log(LOG_NOTICE, "Valid TX freq within a multi-Mhz band and ok.\n");
09472             rv=1;
09473             break;
09474       }
09475    }
09476    if(debug > 3)  
09477       ast_log(LOG_NOTICE, "rv=%i\n",rv);
09478 
09479    return rv;
09480 }
09481 
09482 
09483 /*
09484 * Dispatch to correct frequency bumping function
09485 */
09486 
09487 static int multimode_bump_freq(struct rpt *myrpt, int interval)
09488 {
09489    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09490       return multimode_bump_freq_ft897(myrpt, interval);
09491    else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09492       return multimode_bump_freq_ic706(myrpt, interval);
09493    else
09494       return -1;
09495 }
09496 
09497 
09498 /*
09499 * Queue announcment that scan has been stopped 
09500 */
09501 
09502 static void stop_scan(struct rpt *myrpt)
09503 {
09504    myrpt->hfscanstop = 1;
09505    rpt_telemetry(myrpt,SCAN,0);
09506 }
09507 
09508 /*
09509 * This is called periodically when in scan mode
09510 */
09511 
09512 
09513 static int service_scan(struct rpt *myrpt)
09514 {
09515    int res, interval;
09516    char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
09517 
09518    switch(myrpt->hfscanmode){
09519 
09520       case HF_SCAN_DOWN_SLOW:
09521          interval = -10; /* 100Hz /sec */
09522          break;
09523 
09524       case HF_SCAN_DOWN_QUICK:
09525          interval = -50; /* 500Hz /sec */
09526          break;
09527 
09528       case HF_SCAN_DOWN_FAST:
09529          interval = -200; /* 2KHz /sec */
09530          break;
09531 
09532       case HF_SCAN_UP_SLOW:
09533          interval = 10; /* 100Hz /sec */
09534          break;
09535 
09536       case HF_SCAN_UP_QUICK:
09537          interval = 50; /* 500 Hz/sec */
09538          break;
09539 
09540       case HF_SCAN_UP_FAST:
09541          interval = 200; /* 2KHz /sec */
09542          break;
09543 
09544       default:
09545          myrpt->hfscanmode = 0; /* Huh? */
09546          return -1;
09547    }
09548 
09549    res = split_freq(mhz, decimals, myrpt->freq);
09550       
09551    if(!res){
09552       k100 =decimals[0];
09553       k10 = decimals[1];
09554       res = multimode_bump_freq(myrpt, interval);
09555    }
09556 
09557    if(!res)
09558       res = split_freq(mhz, decimals, myrpt->freq);
09559 
09560 
09561    if(res){
09562       myrpt->hfscanmode = 0;
09563       myrpt->hfscanstatus = -2;
09564       return -1;
09565    }
09566 
09567    /* Announce 10KHz boundaries */
09568    if(k10 != decimals[1]){
09569       int myhund = (interval < 0) ? k100 : decimals[0];
09570       int myten = (interval < 0) ? k10 : decimals[1];
09571       myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
09572    } else myrpt->hfscanstatus = 0;
09573    return res;
09574 
09575 }
09576 /*
09577    retrieve memory setting and set radio
09578 */
09579 static int get_mem_set(struct rpt *myrpt, char *digitbuf)
09580 {
09581    int res=0;
09582    if(debug)ast_log(LOG_NOTICE," digitbuf=%s\n", digitbuf);
09583    res = retreive_memory(myrpt, digitbuf);
09584    if(!res)res=setrem(myrpt); 
09585    if(debug)ast_log(LOG_NOTICE," freq=%s  res=%i\n", myrpt->freq, res);
09586    return res;
09587 }
09588 /*
09589    steer the radio selected channel to either one programmed into the radio
09590    or if the radio is VFO agile, to an rpt.conf memory location.
09591 */
09592 static int channel_steer(struct rpt *myrpt, char *data)
09593 {
09594    int res=0;
09595 
09596    if(debug)ast_log(LOG_NOTICE,"remoterig=%s, data=%s\n",myrpt->remoterig,data);
09597    if (!myrpt->remoterig) return(0);
09598    if(data<=0)
09599    {
09600       res=-1;
09601    }
09602    else
09603    {
09604       myrpt->nowchan=strtod(data,NULL);
09605       if(!strcmp(myrpt->remoterig, remote_rig_ppp16))
09606       {
09607          char string[16];
09608          sprintf(string,"SETCHAN %d ",myrpt->nowchan);
09609          send_usb_txt(myrpt,string);   
09610       }
09611       else
09612       {
09613          if(get_mem_set(myrpt, data))res=-1;
09614       }
09615    }
09616    if(debug)ast_log(LOG_NOTICE,"nowchan=%i  res=%i\n",myrpt->nowchan, res);
09617    return res;
09618 }
09619 /*
09620 */
09621 static int channel_revert(struct rpt *myrpt)
09622 {
09623    int res=0;
09624    if(debug)ast_log(LOG_NOTICE,"remoterig=%s, nowchan=%02d, waschan=%02d\n",myrpt->remoterig,myrpt->nowchan,myrpt->waschan);
09625    if (!myrpt->remoterig) return(0);
09626    if(myrpt->nowchan!=myrpt->waschan)
09627    {
09628       char data[8];
09629         if(debug)ast_log(LOG_NOTICE,"reverting.\n");
09630       sprintf(data,"%02d",myrpt->waschan);
09631       myrpt->nowchan=myrpt->waschan;
09632       channel_steer(myrpt,data);
09633       res=1;
09634    }
09635    return(res);
09636 }
09637 /*
09638 * Remote base function
09639 */
09640 
09641 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
09642 {
09643    char *s,*s1,*s2;
09644    int i,j,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode=0;
09645    intptr_t p;
09646    char multimode = 0;
09647    char oc,*cp,*cp1,*cp2;
09648    char tmp[20], freq[20] = "", savestr[20] = "";
09649    char mhz[MAXREMSTR], decimals[MAXREMSTR];
09650 
09651     if(debug > 6) {
09652       ast_log(LOG_NOTICE,"%s param=%s digitbuf=%s source=%i\n",myrpt->name,param,digitbuf,command_source);
09653    }
09654 
09655    if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
09656       return DC_ERROR;
09657       
09658    p = myatoi(param);
09659 
09660    if ((p != 99) && (p != 5) && (p != 140) && myrpt->p.authlevel && 
09661       (!myrpt->loginlevel[0])) return DC_ERROR;
09662    multimode = multimode_capable(myrpt);
09663 
09664    switch(p){
09665 
09666       case 1:  /* retrieve memory */
09667          if(strlen(digitbuf) < 2) /* needs 2 digits */
09668             break;
09669          
09670          for(i = 0 ; i < 2 ; i++){
09671             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09672                return DC_ERROR;
09673          }
09674          r=get_mem_set(myrpt, digitbuf);
09675          if (r < 0){
09676             rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
09677             return DC_COMPLETE;
09678          }
09679          else if (r > 0){
09680             return DC_ERROR;
09681          }
09682          return DC_COMPLETE;  
09683          
09684       case 2:  /* set freq and offset */
09685       
09686          
09687             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
09688             if(digitbuf[i] == '*'){
09689                j++;
09690                continue;
09691             }
09692             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09693                goto invalid_freq;
09694             else{
09695                if(j == 0)
09696                   l++; /* # of digits before first * */
09697                if(j == 1)
09698                   k++; /* # of digits after first * */
09699             }
09700          }
09701       
09702          i = strlen(digitbuf) - 1;
09703          if(multimode){
09704             if((j > 2) || (l > 3) || (k > 6))
09705                goto invalid_freq; /* &^@#! */
09706          }
09707          else{
09708             if((j > 2) || (l > 4) || (k > 3))
09709                goto invalid_freq; /* &^@#! */
09710          }
09711 
09712          /* Wait for M+*K+* */
09713 
09714          if(j < 2)
09715             break; /* Not yet */
09716 
09717          /* We have a frequency */
09718 
09719          strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
09720          
09721          s = tmp;
09722          s1 = strsep(&s, "*"); /* Pick off MHz */
09723          s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
09724          ls2 = strlen(s2); 
09725          
09726          switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
09727             case 1:
09728                ht = 0;
09729                k = 100 * atoi(s2);
09730                break;
09731             
09732             case 2:
09733                ht = 0;
09734                k = 10 * atoi(s2);
09735                break;
09736                
09737             case 3:
09738                if(!multimode){
09739                   if((s2[2] != '0')&&(s2[2] != '5'))
09740                      goto invalid_freq;
09741                }
09742                ht = 0;
09743                k = atoi(s2);
09744                   break;
09745             case 4:
09746                k = atoi(s2)/10;
09747                ht = 10 * (atoi(s2+(ls2-1)));
09748                break;
09749 
09750             case 5:
09751                k = atoi(s2)/100;
09752                ht = (atoi(s2+(ls2-2)));
09753                break;
09754                
09755             default:
09756                goto invalid_freq;
09757          }
09758 
09759          /* Check frequency for validity and establish a default mode */
09760          
09761          snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
09762 
09763          if(debug)
09764             ast_log(LOG_NOTICE, "New frequency: %s\n", freq);
09765    
09766          split_freq(mhz, decimals, freq);
09767          m = atoi(mhz);
09768          d = atoi(decimals);
09769 
09770          if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
09771                  goto invalid_freq;
09772 
09773 
09774          if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
09775             break; /* Not yet */
09776 
09777 
09778          offset = REM_SIMPLEX; /* Assume simplex */
09779 
09780          if(defmode == REM_MODE_FM){
09781             oc = *s; /* Pick off offset */
09782          
09783             if (oc){
09784                switch(oc){
09785                   case '1':
09786                      offset = REM_MINUS;
09787                      break;
09788                   
09789                   case '2':
09790                      offset = REM_SIMPLEX;
09791                   break;
09792                   
09793                   case '3':
09794                      offset = REM_PLUS;
09795                      break;
09796                   
09797                   default:
09798                      goto invalid_freq;
09799                } 
09800             } 
09801          }  
09802          offsave = myrpt->offset;
09803          modesave = myrpt->remmode;
09804          strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
09805          strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
09806          myrpt->offset = offset;
09807          myrpt->remmode = defmode;
09808 
09809          if (setrem(myrpt) == -1){
09810             myrpt->offset = offsave;
09811             myrpt->remmode = modesave;
09812             strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
09813             goto invalid_freq;
09814          }
09815 
09816          return DC_COMPLETE;
09817 
09818 invalid_freq:
09819          rpt_telemetry(myrpt,INVFREQ,NULL);
09820          return DC_ERROR; 
09821       
09822       case 3: /* set rx PL tone */
09823             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
09824             if(digitbuf[i] == '*'){
09825                j++;
09826                continue;
09827             }
09828             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09829                return DC_ERROR;
09830             else{
09831                if(j)
09832                   l++;
09833                else
09834                   k++;
09835             }
09836          }
09837          if((j > 1) || (k > 3) || (l > 1))
09838             return DC_ERROR; /* &$@^! */
09839          i = strlen(digitbuf) - 1;
09840          if((j != 1) || (k < 2)|| (l != 1))
09841             break; /* Not yet */
09842          if(debug)
09843             printf("PL digits entered %s\n", digitbuf);
09844             
09845          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
09846          /* see if we have at least 1 */
09847          s = strchr(tmp,'*');
09848          if(s)
09849             *s = '.';
09850          strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
09851          strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
09852          if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09853          {
09854             strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
09855          }
09856          if (setrem(myrpt) == -1){
09857             strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
09858             return DC_ERROR;
09859          }
09860          return DC_COMPLETE;
09861       
09862       case 4: /* set tx PL tone */
09863          /* cant set tx tone on RBI (rx tone does both) */
09864          if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09865             return DC_ERROR;
09866          /*  eventually for the ic706 instead of just throwing the exception
09867             we can check if we are in encode only mode and allow the tx
09868             ctcss code to be changed. but at least the warning message is
09869             issued for now.
09870          */
09871          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09872          {
09873             if(debug)
09874                ast_log(LOG_WARNING,"Setting IC706 Tx CTCSS Code Not Supported. Set Rx Code for both.\n");
09875             return DC_ERROR;
09876          }
09877          for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
09878             if(digitbuf[i] == '*'){
09879                j++;
09880                continue;
09881             }
09882             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09883                return DC_ERROR;
09884             else{
09885                if(j)
09886                   l++;
09887                else
09888                   k++;
09889             }
09890          }
09891          if((j > 1) || (k > 3) || (l > 1))
09892             return DC_ERROR; /* &$@^! */
09893          i = strlen(digitbuf) - 1;
09894          if((j != 1) || (k < 2)|| (l != 1))
09895             break; /* Not yet */
09896          if(debug)
09897             printf("PL digits entered %s\n", digitbuf);
09898             
09899          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
09900          /* see if we have at least 1 */
09901          s = strchr(tmp,'*');
09902          if(s)
09903             *s = '.';
09904          strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1);
09905          strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
09906          
09907          if (setrem(myrpt) == -1){
09908             strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
09909             return DC_ERROR;
09910          }
09911          return DC_COMPLETE;
09912       
09913 
09914       case 6: /* MODE (FM,USB,LSB,AM) */
09915          if(strlen(digitbuf) < 1)
09916             break;
09917 
09918          if(!multimode)
09919             return DC_ERROR; /* Multimode radios only */
09920 
09921          switch(*digitbuf){
09922             case '1':
09923                split_freq(mhz, decimals, myrpt->freq); 
09924                m=atoi(mhz);
09925                if(m < 29) /* No FM allowed below 29MHz! */
09926                   return DC_ERROR;
09927                myrpt->remmode = REM_MODE_FM;
09928                
09929                rpt_telemetry(myrpt,REMMODE,NULL);
09930                break;
09931 
09932             case '2':
09933                myrpt->remmode = REM_MODE_USB;
09934                rpt_telemetry(myrpt,REMMODE,NULL);
09935                break;   
09936 
09937             case '3':
09938                myrpt->remmode = REM_MODE_LSB;
09939                rpt_telemetry(myrpt,REMMODE,NULL);
09940                break;
09941             
09942             case '4':
09943                myrpt->remmode = REM_MODE_AM;
09944                rpt_telemetry(myrpt,REMMODE,NULL);
09945                break;
09946       
09947             default:
09948                return DC_ERROR;
09949          }
09950 
09951          if(setrem(myrpt))
09952             return DC_ERROR;
09953          return DC_COMPLETEQUIET;
09954       case 99:
09955          /* cant log in when logged in */
09956          if (myrpt->loginlevel[0]) 
09957             return DC_ERROR;
09958          *myrpt->loginuser = 0;
09959          myrpt->loginlevel[0] = 0;
09960          cp = ast_strdup(param);
09961          cp1 = strchr(cp,',');
09962          ast_mutex_lock(&myrpt->lock);
09963          if (cp1) 
09964          {
09965             *cp1 = 0;
09966             cp2 = strchr(cp1 + 1,',');
09967             if (cp2) 
09968             {
09969                *cp2 = 0;
09970                strncpy(myrpt->loginlevel,cp2 + 1,
09971                   sizeof(myrpt->loginlevel) - 1);
09972             }
09973             strncpy(myrpt->loginuser,cp1 + 1,sizeof(myrpt->loginuser));
09974             ast_mutex_unlock(&myrpt->lock);
09975             if (myrpt->p.archivedir)
09976             {
09977                char str[100];
09978 
09979                sprintf(str,"LOGIN,%s,%s",
09980                    myrpt->loginuser,myrpt->loginlevel);
09981                donodelog(myrpt,str);
09982             }
09983             if (debug) 
09984                printf("loginuser %s level %s\n",myrpt->loginuser,myrpt->loginlevel);
09985             rpt_telemetry(myrpt,REMLOGIN,NULL);
09986          }
09987          ast_free(cp);
09988          return DC_COMPLETEQUIET;
09989       case 100: /* RX PL Off */
09990          myrpt->rxplon = 0;
09991          setrem(myrpt);
09992          rpt_telemetry(myrpt,REMXXX,(void *)p);
09993          return DC_COMPLETEQUIET;
09994       case 101: /* RX PL On */
09995          myrpt->rxplon = 1;
09996          setrem(myrpt);
09997          rpt_telemetry(myrpt,REMXXX,(void *)p);
09998          return DC_COMPLETEQUIET;
09999       case 102: /* TX PL Off */
10000          myrpt->txplon = 0;
10001          setrem(myrpt);
10002          rpt_telemetry(myrpt,REMXXX,(void *)p);
10003          return DC_COMPLETEQUIET;
10004       case 103: /* TX PL On */
10005          myrpt->txplon = 1;
10006          setrem(myrpt);
10007          rpt_telemetry(myrpt,REMXXX,(void *)p);
10008          return DC_COMPLETEQUIET;
10009       case 104: /* Low Power */
10010          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10011             return DC_ERROR;
10012          myrpt->powerlevel = REM_LOWPWR;
10013          setrem(myrpt);
10014          rpt_telemetry(myrpt,REMXXX,(void *)p);
10015          return DC_COMPLETEQUIET;
10016       case 105: /* Medium Power */
10017          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10018             return DC_ERROR;
10019          if (ISRIG_RTX(myrpt->remoterig)) return DC_ERROR;
10020          myrpt->powerlevel = REM_MEDPWR;
10021          setrem(myrpt);
10022          rpt_telemetry(myrpt,REMXXX,(void *)p);
10023          return DC_COMPLETEQUIET;
10024       case 106: /* Hi Power */
10025          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10026             return DC_ERROR;
10027          myrpt->powerlevel = REM_HIPWR;
10028          setrem(myrpt);
10029          rpt_telemetry(myrpt,REMXXX,(void *)p);
10030          return DC_COMPLETEQUIET;
10031       case 107: /* Bump down 20Hz */
10032          multimode_bump_freq(myrpt, -20);
10033          return DC_COMPLETE;
10034       case 108: /* Bump down 100Hz */
10035          multimode_bump_freq(myrpt, -100);
10036          return DC_COMPLETE;
10037       case 109: /* Bump down 500Hz */
10038          multimode_bump_freq(myrpt, -500);
10039          return DC_COMPLETE;
10040       case 110: /* Bump up 20Hz */
10041          multimode_bump_freq(myrpt, 20);
10042          return DC_COMPLETE;
10043       case 111: /* Bump up 100Hz */
10044          multimode_bump_freq(myrpt, 100);
10045          return DC_COMPLETE;
10046       case 112: /* Bump up 500Hz */
10047          multimode_bump_freq(myrpt, 500);
10048          return DC_COMPLETE;
10049       case 113: /* Scan down slow */
10050          myrpt->scantimer = REM_SCANTIME;
10051          myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
10052          rpt_telemetry(myrpt,REMXXX,(void *)p);
10053          return DC_COMPLETEQUIET;
10054       case 114: /* Scan down quick */
10055          myrpt->scantimer = REM_SCANTIME;
10056          myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
10057          rpt_telemetry(myrpt,REMXXX,(void *)p);
10058          return DC_COMPLETEQUIET;
10059       case 115: /* Scan down fast */
10060          myrpt->scantimer = REM_SCANTIME;
10061          myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
10062          rpt_telemetry(myrpt,REMXXX,(void *)p);
10063          return DC_COMPLETEQUIET;
10064       case 116: /* Scan up slow */
10065          myrpt->scantimer = REM_SCANTIME;
10066          myrpt->hfscanmode = HF_SCAN_UP_SLOW;
10067          rpt_telemetry(myrpt,REMXXX,(void *)p);
10068          return DC_COMPLETEQUIET;
10069       case 117: /* Scan up quick */
10070          myrpt->scantimer = REM_SCANTIME;
10071          myrpt->hfscanmode = HF_SCAN_UP_QUICK;
10072          rpt_telemetry(myrpt,REMXXX,(void *)p);
10073          return DC_COMPLETEQUIET;
10074       case 118: /* Scan up fast */
10075          myrpt->scantimer = REM_SCANTIME;
10076          myrpt->hfscanmode = HF_SCAN_UP_FAST;
10077          rpt_telemetry(myrpt,REMXXX,(void *)p);
10078          return DC_COMPLETEQUIET;
10079       case 119: /* Tune Request */
10080          if(debug > 3)
10081             ast_log(LOG_NOTICE,"TUNE REQUEST\n");
10082          /* if not currently going, and valid to do */
10083          if((!myrpt->tunerequest) && 
10084              ((!strcmp(myrpt->remoterig, remote_rig_ft897) || 
10085             !strcmp(myrpt->remoterig, remote_rig_ic706)) )) { 
10086             myrpt->remotetx = 0;
10087             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
10088             myrpt->tunerequest = 1;
10089             rpt_telemetry(myrpt,TUNE,NULL);
10090             return DC_COMPLETEQUIET;
10091          }
10092          return DC_ERROR;        
10093       case 5: /* Long Status */
10094          rpt_telemetry(myrpt,REMLONGSTATUS,NULL);
10095          return DC_COMPLETEQUIET;
10096       case 140: /* Short Status */
10097          rpt_telemetry(myrpt,REMSHORTSTATUS,NULL);
10098          return DC_COMPLETEQUIET;
10099       case 200:
10100       case 201:
10101       case 202:
10102       case 203:
10103       case 204:
10104       case 205:
10105       case 206:
10106       case 207:
10107       case 208:
10108       case 209:
10109       case 210:
10110       case 211:
10111       case 212:
10112       case 213:
10113       case 214:
10114       case 215:
10115          do_dtmf_local(myrpt,remdtmfstr[p - 200]);
10116          return DC_COMPLETEQUIET;
10117       default:
10118          break;
10119    }
10120    return DC_INDETERMINATE;
10121 }
10122 
10123 
10124 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode)
10125 {
10126 time_t   now;
10127 int   ret,res = 0,src;
10128 
10129    if(debug > 6)
10130       ast_log(LOG_NOTICE,"c=%c  phonemode=%i  dtmfidx=%i\n",c,phonemode,myrpt->dtmfidx);
10131 
10132    time(&myrpt->last_activity_time);
10133    /* Stop scan mode if in scan mode */
10134    if(myrpt->hfscanmode){
10135       stop_scan(myrpt);
10136       return 0;
10137    }
10138 
10139    time(&now);
10140    /* if timed-out */
10141    if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
10142    {
10143       myrpt->dtmfidx = -1;
10144       myrpt->dtmfbuf[0] = 0;
10145       myrpt->dtmf_time_rem = 0;
10146    }
10147    /* if decode not active */
10148    if (myrpt->dtmfidx == -1)
10149    {
10150       /* if not lead-in digit, don't worry */
10151       if (c != myrpt->p.funcchar)
10152       {
10153          if (!myrpt->p.propagate_dtmf)
10154          {
10155             rpt_mutex_lock(&myrpt->lock);
10156             do_dtmf_local(myrpt,c);
10157             rpt_mutex_unlock(&myrpt->lock);
10158          }
10159          return 0;
10160       }
10161       myrpt->dtmfidx = 0;
10162       myrpt->dtmfbuf[0] = 0;
10163       myrpt->dtmf_time_rem = now;
10164       return 0;
10165    }
10166    /* if too many in buffer, start over */
10167    if (myrpt->dtmfidx >= MAXDTMF)
10168    {
10169       myrpt->dtmfidx = 0;
10170       myrpt->dtmfbuf[0] = 0;
10171       myrpt->dtmf_time_rem = now;
10172    }
10173    if (c == myrpt->p.funcchar)
10174    {
10175       /* if star at beginning, or 2 together, erase buffer */
10176       if ((myrpt->dtmfidx < 1) || 
10177          (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
10178       {
10179          myrpt->dtmfidx = 0;
10180          myrpt->dtmfbuf[0] = 0;
10181          myrpt->dtmf_time_rem = now;
10182          return 0;
10183       }
10184    }
10185    myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
10186    myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10187    myrpt->dtmf_time_rem = now;
10188    
10189    
10190    src = SOURCE_RMT;
10191    if (phonemode == 2) src = SOURCE_DPHONE;
10192    else if (phonemode) src = SOURCE_PHONE;
10193    else if (phonemode == 4) src = SOURCE_ALT;
10194    ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
10195    
10196    switch(ret){
10197    
10198       case DC_INDETERMINATE:
10199          res = 0;
10200          break;
10201             
10202       case DC_DOKEY:
10203          if (keyed) *keyed = 1;
10204          res = 0;
10205          break;
10206             
10207       case DC_REQ_FLUSH:
10208          myrpt->dtmfidx = 0;
10209          myrpt->dtmfbuf[0] = 0;
10210          res = 0;
10211          break;
10212             
10213             
10214       case DC_COMPLETE:
10215          res = 1;
10216       case DC_COMPLETEQUIET:
10217          myrpt->totalexecdcommands++;
10218          myrpt->dailyexecdcommands++;
10219          strncpy(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF-1);
10220          myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
10221          myrpt->dtmfbuf[0] = 0;
10222          myrpt->dtmfidx = -1;
10223          myrpt->dtmf_time_rem = 0;
10224          break;
10225             
10226       case DC_ERROR:
10227       default:
10228          myrpt->dtmfbuf[0] = 0;
10229          myrpt->dtmfidx = -1;
10230          myrpt->dtmf_time_rem = 0;
10231          res = 0;
10232          break;
10233    }
10234 
10235    return res;
10236 }
10237 
10238 static int handle_remote_data(struct rpt *myrpt, char *str)
10239 {
10240 /* XXX ATTENTION: if you change the size of these arrays you MUST
10241  * change the limits in corresponding sscanf() calls below. */
10242 char  tmp[300],cmd[300],dest[300],src[300],c;
10243 int   seq,res;
10244 
10245    /* put string in our buffer */
10246    strncpy(tmp,str,sizeof(tmp) - 1);
10247    if (!strcmp(tmp,discstr)) return 0;
10248         if (!strcmp(tmp,newkeystr))
10249         {
10250       myrpt->newkey = 1;
10251                 return 0;
10252         }
10253 
10254 #ifndef  DO_NOT_NOTIFY_MDC1200_ON_REMOTE_BASES
10255    if (tmp[0] == 'I')
10256    {
10257       /* XXX WARNING: be very careful with the limits on the folowing
10258        * sscanf() call, make sure they match the values defined above */
10259       if (sscanf(tmp,"%299s %299s %30x",cmd,src,&seq) != 3)
10260       {
10261          ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
10262          return 0;
10263       }
10264       mdc1200_notify(myrpt,src,seq);
10265       return 0;
10266    }
10267 #endif
10268    /* XXX WARNING: be very careful with the limits on the folowing
10269     * sscanf() call, make sure they match the values defined above */
10270    if (sscanf(tmp,"%299s %299s %299s %30d %1c",cmd,dest,src,&seq,&c) != 5)
10271    {
10272       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
10273       return 0;
10274    }
10275    if (strcmp(cmd,"D"))
10276    {
10277       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
10278       return 0;
10279    }
10280    /* if not for me, ignore */
10281    if (strcmp(dest,myrpt->name)) return 0;
10282    if (myrpt->p.archivedir)
10283    {
10284       char dtmfstr[100];
10285 
10286       sprintf(dtmfstr,"DTMF,%c",c);
10287       donodelog(myrpt,dtmfstr);
10288    }
10289    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
10290    if (!c) return(0);
10291    res = handle_remote_dtmf_digit(myrpt,c, NULL, 0);
10292    if (res != 1)
10293       return res;
10294    rpt_telemetry(myrpt,COMPLETE,NULL);
10295    return 0;
10296 }
10297 
10298 static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode)
10299 {
10300 int   res;
10301 
10302 
10303    if(phonemode == 3) /* simplex phonemode, funcchar key/unkey toggle */
10304    {
10305       if (keyed && *keyed && ((c == myrpt->p.funcchar) || (c == myrpt->p.endchar)))
10306       {
10307          *keyed = 0; /* UNKEY */
10308          return 0;
10309       }
10310       else if (keyed && !*keyed && (c = myrpt->p.funcchar))
10311       {
10312          *keyed = 1; /* KEY */
10313          return 0;
10314       }
10315    }
10316    else /* endchar unkey */
10317    {
10318 
10319       if (keyed && *keyed && (c == myrpt->p.endchar))
10320       {
10321          *keyed = 0;
10322          return DC_INDETERMINATE;
10323       }
10324    }
10325    if (myrpt->p.archivedir)
10326    {
10327       char str[100];
10328 
10329       sprintf(str,"DTMF(P),%c",c);
10330       donodelog(myrpt,str);
10331    }
10332    res = handle_remote_dtmf_digit(myrpt,c,keyed, phonemode);
10333    if (res != 1)
10334       return res;
10335    rpt_telemetry(myrpt,COMPLETE,NULL);
10336    return 0;
10337 }
10338 
10339 static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
10340 {
10341    char *val, *s, *s1, *s2, *tele;
10342    char tmp[300], deststr[300] = "";
10343    char sx[320],*sy;
10344 
10345 
10346    val = node_lookup(myrpt,l->name);
10347    if (!val)
10348    {
10349       fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
10350       return -1;
10351    }
10352 
10353    rpt_mutex_lock(&myrpt->lock);
10354    /* remove from queue */
10355    remque((struct qelem *) l);
10356    rpt_mutex_unlock(&myrpt->lock);
10357    strncpy(tmp,val,sizeof(tmp) - 1);
10358    s = tmp;
10359    s1 = strsep(&s,",");
10360    if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
10361    {
10362       sy = strchr(s1,'/');    
10363       *sy = 0;
10364       sprintf(sx,"%s:4569/%s",s1,sy + 1);
10365       s1 = sx;
10366    }
10367    s2 = strsep(&s,",");
10368    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
10369    tele = strchr(deststr, '/');
10370    if (!tele) {
10371       fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
10372       return -1;
10373    }
10374    *tele++ = 0;
10375    l->elaptime = 0;
10376    l->connecttime = 0;
10377    l->thisconnected = 0;
10378    l->newkey = 0;
10379    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, NULL, tele, NULL);
10380    if (l->chan){
10381       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
10382       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
10383 #ifndef  NEW_ASTERISK
10384       l->chan->whentohangup = 0;
10385 #endif
10386       l->chan->appl = "Apprpt";
10387       l->chan->data = "(Remote Rx)";
10388       if (option_verbose > 2)
10389          ast_verbose(VERBOSE_PREFIX_3 "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
10390             deststr, tele, l->chan->name);
10391       l->chan->caller.id.number.valid = 1;
10392       ast_free(l->chan->caller.id.number.str);
10393       l->chan->caller.id.number.str = ast_strdup(myrpt->name);
10394                 ast_call(l->chan,tele,999); 
10395 
10396    }
10397    else 
10398    {
10399       if (option_verbose > 2)
10400          ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
10401             deststr,tele,l->chan->name);
10402       return -1;
10403    }
10404    rpt_mutex_lock(&myrpt->lock);
10405    /* put back in queue */
10406    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
10407    rpt_mutex_unlock(&myrpt->lock);
10408    ast_log(LOG_WARNING,"Reconnect Attempt to %s in process\n",l->name);
10409    if (!l->phonemode) send_newkey(l->chan);
10410    return 0;
10411 }
10412 
10413 /* 0 return=continue, 1 return = break, -1 return = error */
10414 static void local_dtmf_helper(struct rpt *myrpt,char c_in)
10415 {
10416 int   res;
10417 pthread_attr_t attr;
10418 char  cmd[MAXDTMF+1] = "",c;
10419 
10420 
10421    c = c_in & 0x7f;
10422    if (myrpt->p.archivedir)
10423    {
10424       char str[100];
10425 
10426       sprintf(str,"DTMF,MAIN,%c",c);
10427       donodelog(myrpt,str);
10428    }
10429    if (c == myrpt->p.endchar)
10430    {
10431    /* if in simple mode, kill autopatch */
10432       if (myrpt->p.simple && myrpt->callmode)
10433       {   
10434          if(debug)
10435             ast_log(LOG_WARNING, "simple mode autopatch kill\n");
10436          rpt_mutex_lock(&myrpt->lock);
10437          myrpt->callmode = 0;
10438          myrpt->macropatch=0;
10439          channel_revert(myrpt);
10440          rpt_mutex_unlock(&myrpt->lock);
10441          rpt_telemetry(myrpt,TERM,NULL);
10442          return;
10443       }
10444       rpt_mutex_lock(&myrpt->lock);
10445       myrpt->stopgen = 1;
10446       if (myrpt->cmdnode[0])
10447       {
10448          myrpt->cmdnode[0] = 0;
10449          myrpt->dtmfidx = -1;
10450          myrpt->dtmfbuf[0] = 0;
10451          rpt_mutex_unlock(&myrpt->lock);
10452          rpt_telemetry(myrpt,COMPLETE,NULL);
10453          return;
10454       } 
10455       else if(!myrpt->inpadtest)
10456                 {
10457                         rpt_mutex_unlock(&myrpt->lock);
10458                         if (myrpt->p.propagate_phonedtmf)
10459                                do_dtmf_phone(myrpt,NULL,c);
10460          return;
10461                 }
10462       else
10463          rpt_mutex_unlock(&myrpt->lock);
10464    }
10465    rpt_mutex_lock(&myrpt->lock);
10466    if (myrpt->cmdnode[0])
10467    {
10468       rpt_mutex_unlock(&myrpt->lock);
10469       send_link_dtmf(myrpt,c);
10470       return;
10471    }
10472    if (!myrpt->p.simple)
10473    {
10474       if ((!myrpt->inpadtest)&&(c == myrpt->p.funcchar))
10475       {
10476          myrpt->dtmfidx = 0;
10477          myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10478          rpt_mutex_unlock(&myrpt->lock);
10479          time(&myrpt->dtmf_time);
10480          return;
10481       } 
10482       else if (((myrpt->inpadtest)||(c != myrpt->p.endchar)) && (myrpt->dtmfidx >= 0))
10483       {
10484          time(&myrpt->dtmf_time);
10485          
10486          if (myrpt->dtmfidx < MAXDTMF)
10487          {
10488             int src;
10489 
10490             myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
10491             myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10492             
10493             strncpy(cmd, myrpt->dtmfbuf, sizeof(cmd) - 1);
10494             
10495             rpt_mutex_unlock(&myrpt->lock);
10496             src = SOURCE_RPT;
10497             if (c_in & 0x80) src = SOURCE_ALT;
10498             res = collect_function_digits(myrpt, cmd, src, NULL);
10499             rpt_mutex_lock(&myrpt->lock);
10500             switch(res){
10501                 case DC_INDETERMINATE:
10502                break;
10503                 case DC_REQ_FLUSH:
10504                myrpt->dtmfidx = 0;
10505                myrpt->dtmfbuf[0] = 0;
10506                break;
10507                 case DC_COMPLETE:
10508                 case DC_COMPLETEQUIET:
10509                myrpt->totalexecdcommands++;
10510                myrpt->dailyexecdcommands++;
10511                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
10512                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
10513                myrpt->dtmfbuf[0] = 0;
10514                myrpt->dtmfidx = -1;
10515                myrpt->dtmf_time = 0;
10516                break;
10517 
10518                 case DC_ERROR:
10519                 default:
10520                myrpt->dtmfbuf[0] = 0;
10521                myrpt->dtmfidx = -1;
10522                myrpt->dtmf_time = 0;
10523                break;
10524             }
10525             if(res != DC_INDETERMINATE) {
10526                rpt_mutex_unlock(&myrpt->lock);
10527                return;
10528             }
10529          } 
10530       }
10531    }
10532    else /* if simple */
10533    {
10534       if ((!myrpt->callmode) && (c == myrpt->p.funcchar))
10535       {
10536          myrpt->callmode = 1;
10537          myrpt->patchnoct = 0;
10538          myrpt->patchquiet = 0;
10539          myrpt->patchfarenddisconnect = 0;
10540          myrpt->patchdialtime = 0;
10541          strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
10542          myrpt->cidx = 0;
10543          myrpt->exten[myrpt->cidx] = 0;
10544          rpt_mutex_unlock(&myrpt->lock);
10545               pthread_attr_init(&attr);
10546               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10547          ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
10548          return;
10549       }
10550    }
10551    if (myrpt->callmode == 1)
10552    {
10553       myrpt->exten[myrpt->cidx++] = c;
10554       myrpt->exten[myrpt->cidx] = 0;
10555       /* if this exists */
10556       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
10557       {
10558          /* if this really it, end now */
10559          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
10560             myrpt->exten,1,NULL)) 
10561          {
10562             myrpt->callmode = 2;
10563             rpt_mutex_unlock(&myrpt->lock);
10564             if(!myrpt->patchquiet)
10565                rpt_telemetry(myrpt,PROC,NULL); 
10566             return;
10567          }
10568          else /* othewise, reset timer */
10569          {
10570             myrpt->calldigittimer = 1;
10571          }
10572       }
10573       /* if can continue, do so */
10574       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
10575       {
10576          /* call has failed, inform user */
10577          myrpt->callmode = 4;
10578       }
10579       rpt_mutex_unlock(&myrpt->lock);
10580       return;
10581    }
10582    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
10583    {
10584       myrpt->mydtmf = c;
10585    }
10586    rpt_mutex_unlock(&myrpt->lock);
10587    if ((myrpt->dtmfidx < 0) && myrpt->p.propagate_phonedtmf)
10588       do_dtmf_phone(myrpt,NULL,c);
10589    return;
10590 }
10591 
10592 
10593 /* place an ID event in the telemetry queue */
10594 
10595 static void queue_id(struct rpt *myrpt)
10596 {
10597    if(myrpt->p.idtime){ /* ID time must be non-zero */
10598       myrpt->mustid = myrpt->tailid = 0;
10599       myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
10600       rpt_mutex_unlock(&myrpt->lock);
10601       rpt_telemetry(myrpt,ID,NULL);
10602       rpt_mutex_lock(&myrpt->lock);
10603    }
10604 }
10605 
10606 /* Scheduler */
10607 /* must be called locked */
10608 
10609 static void do_scheduler(struct rpt *myrpt)
10610 {
10611    int i,res;
10612 
10613 #ifdef   NEW_ASTERISK
10614    struct ast_tm tmnow;
10615 #else
10616    struct tm tmnow;
10617 #endif
10618    struct ast_variable *skedlist;
10619    char *strs[5],*vp,*val,value[100];
10620 
10621    memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
10622    
10623    if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
10624       ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
10625 
10626    /* Try to get close to a 1 second resolution */
10627    
10628    if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
10629       return;
10630 
10631    rpt_localtime(&myrpt->curtv.tv_sec, &tmnow);
10632 
10633    /* If midnight, then reset all daily statistics */
10634    
10635    if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
10636       myrpt->dailykeyups = 0;
10637       myrpt->dailytxtime = 0;
10638       myrpt->dailykerchunks = 0;
10639       myrpt->dailyexecdcommands = 0;
10640    }
10641 
10642    if(tmnow.tm_sec != 0)
10643       return;
10644 
10645    /* Code below only executes once per minute */
10646 
10647 
10648    /* Don't schedule if remote */
10649 
10650         if (myrpt->remote)
10651                 return;
10652 
10653    /* Don't schedule if disabled */
10654 
10655         if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable){
10656       if(debug > 6)
10657          ast_log(LOG_NOTICE, "Scheduler disabled\n");
10658       return;
10659    }
10660 
10661    if(!myrpt->p.skedstanzaname){ /* No stanza means we do nothing */
10662       if(debug > 6)
10663          ast_log(LOG_NOTICE,"No stanza for scheduler in rpt.conf\n");
10664       return;
10665    }
10666 
10667     /* get pointer to linked list of scheduler entries */
10668     skedlist = ast_variable_browse(myrpt->cfg, myrpt->p.skedstanzaname);
10669 
10670    if(debug > 6){
10671       ast_log(LOG_NOTICE, "Time now: %02d:%02d %02d %02d %02d\n",
10672          tmnow.tm_hour,tmnow.tm_min,tmnow.tm_mday,tmnow.tm_mon + 1, tmnow.tm_wday); 
10673    }
10674    /* walk the list */
10675    for(; skedlist; skedlist = skedlist->next){
10676       if(debug > 6)
10677          ast_log(LOG_NOTICE, "Scheduler entry %s = %s being considered\n",skedlist->name, skedlist->value);
10678       strncpy(value,skedlist->value,99);
10679       value[99] = 0;
10680       /* point to the substrings for minute, hour, dom, month, and dow */
10681       for( i = 0, vp = value ; i < 5; i++){
10682          if(!*vp)
10683             break;
10684          while((*vp == ' ') || (*vp == 0x09)) /* get rid of any leading white space */
10685             vp++;
10686          strs[i] = vp; /* save pointer to beginning of substring */
10687          while((*vp != ' ') && (*vp != 0x09) && (*vp != 0)) /* skip over substring */
10688             vp++;
10689          if(*vp)
10690             *vp++ = 0; /* mark end of substring */
10691       }
10692       if(debug > 6)
10693          ast_log(LOG_NOTICE, "i = %d, min = %s, hour = %s, mday=%s, mon=%s, wday=%s\n",i,
10694             strs[0], strs[1], strs[2], strs[3], strs[4]); 
10695       if(i == 5){
10696          if((*strs[0] != '*')&&(atoi(strs[0]) != tmnow.tm_min))
10697             continue;
10698          if((*strs[1] != '*')&&(atoi(strs[1]) != tmnow.tm_hour))
10699             continue;
10700          if((*strs[2] != '*')&&(atoi(strs[2]) != tmnow.tm_mday))
10701             continue;
10702          if((*strs[3] != '*')&&(atoi(strs[3]) != tmnow.tm_mon + 1))
10703             continue;
10704          if(atoi(strs[4]) == 7)
10705             strs[4] = "0";
10706          if((*strs[4] != '*')&&(atoi(strs[4]) != tmnow.tm_wday))
10707             continue;
10708          if(debug)
10709             ast_log(LOG_NOTICE, "Executing scheduler entry %s = %s\n", skedlist->name, skedlist->value);
10710          if(atoi(skedlist->name) == 0)
10711             return; /* Zero is reserved for the startup macro */
10712          val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, skedlist->name);
10713          if (!val){
10714             ast_log(LOG_WARNING,"Scheduler could not find macro %s\n",skedlist->name);
10715             return; /* Macro not found */
10716          }
10717          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)){
10718             ast_log(LOG_WARNING, "Scheduler could not execute macro %s: Macro buffer full\n",
10719                skedlist->name);
10720             return; /* Macro buffer full */
10721          }
10722          myrpt->macrotimer = MACROTIME;
10723          strncat(myrpt->macrobuf,val,MAXMACRO - 1);
10724       }
10725       else{
10726          ast_log(LOG_WARNING,"Malformed scheduler entry in rpt.conf: %s = %s\n",
10727             skedlist->name, skedlist->value);
10728       }
10729    }
10730 
10731 }
10732 
10733 /* single thread with one file (request) to dial */
10734 static void *rpt(void *this)
10735 {
10736 struct   rpt *myrpt = (struct rpt *)this;
10737 char *tele,*idtalkover,c,myfirst,*p;
10738 int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued;
10739 int tailmessagequeued,ctqueued,dtmfed,lastmyrx,localmsgqueued;
10740 struct ast_channel *who;
10741 struct dahdi_confinfo ci;  /* conference info */
10742 time_t   t;
10743 struct rpt_link *l,*m;
10744 struct rpt_tele *telem;
10745 char tmpstr[300],lstr[MAXLINKLIST];
10746 
10747 
10748    if (myrpt->p.archivedir) mkdir(myrpt->p.archivedir,0600);
10749    sprintf(tmpstr,"%s/%s",myrpt->p.archivedir,myrpt->name);
10750    mkdir(tmpstr,0600);
10751    rpt_mutex_lock(&myrpt->lock);
10752 
10753    telem = myrpt->tele.next;
10754    while(telem != &myrpt->tele)
10755    {
10756       ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
10757       telem = telem->next;
10758    }
10759    rpt_mutex_unlock(&myrpt->lock);
10760    /* find our index, and load the vars initially */
10761    for(i = 0; i < nrpts; i++)
10762    {
10763       if (&rpt_vars[i] == myrpt)
10764       {
10765          load_rpt_vars(i,0);
10766          break;
10767       }
10768    }
10769 
10770    rpt_mutex_lock(&myrpt->lock);
10771    while(myrpt->xlink)
10772    {
10773       myrpt->xlink = 3;
10774       rpt_mutex_unlock(&myrpt->lock);
10775       usleep(100000);
10776       rpt_mutex_lock(&myrpt->lock);
10777    }
10778 #ifdef HAVE_IOPERM
10779    if ((!strcmp(myrpt->remoterig, remote_rig_rbi)) &&
10780      (ioperm(myrpt->p.iobase,1,1) == -1))
10781    {
10782       rpt_mutex_unlock(&myrpt->lock);
10783       ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
10784       myrpt->rpt_thread = AST_PTHREADT_STOP;
10785       pthread_exit(NULL);
10786    }
10787 #endif
10788    strncpy(tmpstr,myrpt->rxchanname,sizeof(tmpstr) - 1);
10789    tele = strchr(tmpstr,'/');
10790    if (!tele)
10791    {
10792       fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
10793       rpt_mutex_unlock(&myrpt->lock);
10794       myrpt->rpt_thread = AST_PTHREADT_STOP;
10795       pthread_exit(NULL);
10796    }
10797    *tele++ = 0;
10798    myrpt->rxchannel = ast_request(tmpstr, AST_FORMAT_SLINEAR, NULL, tele, NULL);
10799    myrpt->dahdirxchannel = NULL;
10800    if (!strcasecmp(tmpstr,"DAHDI"))
10801       myrpt->dahdirxchannel = myrpt->rxchannel;
10802    if (myrpt->rxchannel)
10803    {
10804       if (myrpt->rxchannel->_state == AST_STATE_BUSY)
10805       {
10806          fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
10807          rpt_mutex_unlock(&myrpt->lock);
10808          ast_hangup(myrpt->rxchannel);
10809          myrpt->rpt_thread = AST_PTHREADT_STOP;
10810          pthread_exit(NULL);
10811       }
10812       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10813       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10814 #ifdef   AST_CDR_FLAG_POST_DISABLED
10815       if (myrpt->rxchannel->cdr)
10816          ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10817 #endif
10818 #ifndef  NEW_ASTERISK
10819       myrpt->rxchannel->whentohangup = 0;
10820 #endif
10821       myrpt->rxchannel->appl = "Apprpt";
10822       myrpt->rxchannel->data = "(Repeater Rx)";
10823       if (option_verbose > 2)
10824          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
10825             tmpstr,tele,myrpt->rxchannel->name);
10826       ast_call(myrpt->rxchannel,tele,999);
10827       if (myrpt->rxchannel->_state != AST_STATE_UP)
10828       {
10829          rpt_mutex_unlock(&myrpt->lock);
10830          ast_hangup(myrpt->rxchannel);
10831          myrpt->rpt_thread = AST_PTHREADT_STOP;
10832          pthread_exit(NULL);
10833       }
10834    }
10835    else
10836    {
10837       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
10838       rpt_mutex_unlock(&myrpt->lock);
10839       myrpt->rpt_thread = AST_PTHREADT_STOP;
10840       pthread_exit(NULL);
10841    }
10842    myrpt->dahditxchannel = NULL;
10843    if (myrpt->txchanname)
10844    {
10845       strncpy(tmpstr,myrpt->txchanname,sizeof(tmpstr) - 1);
10846       tele = strchr(tmpstr,'/');
10847       if (!tele)
10848       {
10849          fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
10850          rpt_mutex_unlock(&myrpt->lock);
10851          ast_hangup(myrpt->rxchannel);
10852          myrpt->rpt_thread = AST_PTHREADT_STOP;
10853          pthread_exit(NULL);
10854       }
10855       *tele++ = 0;
10856       myrpt->txchannel = ast_request(tmpstr, AST_FORMAT_SLINEAR, NULL, tele, NULL);
10857       if (!strcasecmp(tmpstr,"DAHDI"))
10858          myrpt->dahditxchannel = myrpt->txchannel;
10859       if (myrpt->txchannel)
10860       {
10861          if (myrpt->txchannel->_state == AST_STATE_BUSY)
10862          {
10863             fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
10864             rpt_mutex_unlock(&myrpt->lock);
10865             ast_hangup(myrpt->txchannel);
10866             ast_hangup(myrpt->rxchannel);
10867             myrpt->rpt_thread = AST_PTHREADT_STOP;
10868             pthread_exit(NULL);
10869          }        
10870          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
10871          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
10872 #ifdef   AST_CDR_FLAG_POST_DISABLED
10873          if (myrpt->txchannel->cdr)
10874             ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10875 #endif
10876 #ifndef  NEW_ASTERISK
10877          myrpt->txchannel->whentohangup = 0;
10878 #endif
10879          myrpt->txchannel->appl = "Apprpt";
10880          myrpt->txchannel->data = "(Repeater Tx)";
10881          if (option_verbose > 2)
10882             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
10883                tmpstr,tele,myrpt->txchannel->name);
10884          ast_call(myrpt->txchannel,tele,999);
10885          if (myrpt->rxchannel->_state != AST_STATE_UP)
10886          {
10887             rpt_mutex_unlock(&myrpt->lock);
10888             ast_hangup(myrpt->rxchannel);
10889             ast_hangup(myrpt->txchannel);
10890             myrpt->rpt_thread = AST_PTHREADT_STOP;
10891             pthread_exit(NULL);
10892          }
10893       }
10894       else
10895       {
10896          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
10897          rpt_mutex_unlock(&myrpt->lock);
10898          ast_hangup(myrpt->rxchannel);
10899          myrpt->rpt_thread = AST_PTHREADT_STOP;
10900          pthread_exit(NULL);
10901       }
10902    }
10903    else
10904    {
10905       myrpt->txchannel = myrpt->rxchannel;
10906       if (!strncasecmp(myrpt->rxchanname,"DAHDI",3))
10907          myrpt->dahditxchannel = myrpt->txchannel;
10908    }
10909    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
10910    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
10911    /* allocate a pseudo-channel thru asterisk */
10912    myrpt->pchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
10913    if (!myrpt->pchannel)
10914    {
10915       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10916       rpt_mutex_unlock(&myrpt->lock);
10917       if (myrpt->txchannel != myrpt->rxchannel) 
10918          ast_hangup(myrpt->txchannel);
10919       ast_hangup(myrpt->rxchannel);
10920       myrpt->rpt_thread = AST_PTHREADT_STOP;
10921       pthread_exit(NULL);
10922    }
10923 #ifdef   AST_CDR_FLAG_POST_DISABLED
10924    if (myrpt->pchannel->cdr)
10925       ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10926 #endif
10927    if (!myrpt->dahdirxchannel) myrpt->dahdirxchannel = myrpt->pchannel;
10928    if (!myrpt->dahditxchannel)
10929    {
10930       /* allocate a pseudo-channel thru asterisk */
10931       myrpt->dahditxchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
10932       if (!myrpt->dahditxchannel)
10933       {
10934          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10935          rpt_mutex_unlock(&myrpt->lock);
10936          if (myrpt->txchannel != myrpt->rxchannel) 
10937             ast_hangup(myrpt->txchannel);
10938          ast_hangup(myrpt->rxchannel);
10939          myrpt->rpt_thread = AST_PTHREADT_STOP;
10940          pthread_exit(NULL);
10941       }
10942       ast_set_read_format(myrpt->dahditxchannel,AST_FORMAT_SLINEAR);
10943       ast_set_write_format(myrpt->dahditxchannel,AST_FORMAT_SLINEAR);
10944 #ifdef   AST_CDR_FLAG_POST_DISABLED
10945       if (myrpt->dahditxchannel->cdr)
10946          ast_set_flag(myrpt->dahditxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10947 #endif
10948    }
10949    /* allocate a pseudo-channel thru asterisk */
10950    myrpt->monchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
10951    if (!myrpt->monchannel)
10952    {
10953       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10954       rpt_mutex_unlock(&myrpt->lock);
10955       if (myrpt->txchannel != myrpt->rxchannel) 
10956          ast_hangup(myrpt->txchannel);
10957       ast_hangup(myrpt->rxchannel);
10958       myrpt->rpt_thread = AST_PTHREADT_STOP;
10959       pthread_exit(NULL);
10960    }
10961    ast_set_read_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
10962    ast_set_write_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
10963 #ifdef   AST_CDR_FLAG_POST_DISABLED
10964    if (myrpt->monchannel->cdr)
10965       ast_set_flag(myrpt->monchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10966 #endif
10967    /* make a conference for the tx */
10968    ci.chan = 0;
10969    ci.confno = -1; /* make a new conf */
10970    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER;
10971    /* first put the channel on the conference in proper mode */
10972    if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
10973    {
10974       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10975       rpt_mutex_unlock(&myrpt->lock);
10976       ast_hangup(myrpt->pchannel);
10977       ast_hangup(myrpt->monchannel);
10978       if (myrpt->txchannel != myrpt->rxchannel) 
10979          ast_hangup(myrpt->txchannel);
10980       ast_hangup(myrpt->rxchannel);
10981       myrpt->rpt_thread = AST_PTHREADT_STOP;
10982       pthread_exit(NULL);
10983    }
10984    /* save tx conference number */
10985    myrpt->txconf = ci.confno;
10986    /* make a conference for the pseudo */
10987    ci.chan = 0;
10988    ci.confno = -1; /* make a new conf */
10989    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
10990       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
10991    /* first put the channel on the conference in announce mode */
10992    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
10993    {
10994       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10995       rpt_mutex_unlock(&myrpt->lock);
10996       ast_hangup(myrpt->pchannel);
10997       ast_hangup(myrpt->monchannel);
10998       if (myrpt->txchannel != myrpt->rxchannel) 
10999          ast_hangup(myrpt->txchannel);
11000       ast_hangup(myrpt->rxchannel);
11001       myrpt->rpt_thread = AST_PTHREADT_STOP;
11002       pthread_exit(NULL);
11003    }
11004    /* save pseudo channel conference number */
11005    myrpt->conf = ci.confno;
11006    /* make a conference for the pseudo */
11007    ci.chan = 0;
11008    if ((strstr(myrpt->txchannel->name,"pseudo") == NULL) &&
11009       (myrpt->dahditxchannel == myrpt->txchannel))
11010    {
11011       /* get tx channel's port number */
11012       if (ioctl(myrpt->txchannel->fds[0],DAHDI_CHANNO,&ci.confno) == -1)
11013       {
11014          ast_log(LOG_WARNING, "Unable to set tx channel's chan number\n");
11015          rpt_mutex_unlock(&myrpt->lock);
11016          ast_hangup(myrpt->pchannel);
11017          ast_hangup(myrpt->monchannel);
11018          if (myrpt->txchannel != myrpt->rxchannel) 
11019             ast_hangup(myrpt->txchannel);
11020          ast_hangup(myrpt->rxchannel);
11021          myrpt->rpt_thread = AST_PTHREADT_STOP;
11022          pthread_exit(NULL);
11023       }
11024       ci.confmode = DAHDI_CONF_MONITORTX;
11025    }
11026    else
11027    {
11028       ci.confno = myrpt->txconf;
11029       ci.confmode = DAHDI_CONF_CONFANNMON;
11030    }
11031    /* first put the channel on the conference in announce mode */
11032    if (ioctl(myrpt->monchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11033    {
11034       ast_log(LOG_WARNING, "Unable to set conference mode for monitor\n");
11035       rpt_mutex_unlock(&myrpt->lock);
11036       ast_hangup(myrpt->pchannel);
11037       ast_hangup(myrpt->monchannel);
11038       if (myrpt->txchannel != myrpt->rxchannel) 
11039          ast_hangup(myrpt->txchannel);
11040       ast_hangup(myrpt->rxchannel);
11041       myrpt->rpt_thread = AST_PTHREADT_STOP;
11042       pthread_exit(NULL);
11043    }
11044    /* allocate a pseudo-channel thru asterisk */
11045    myrpt->parrotchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
11046    if (!myrpt->parrotchannel)
11047    {
11048       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11049       rpt_mutex_unlock(&myrpt->lock);
11050       if (myrpt->txchannel != myrpt->rxchannel) 
11051          ast_hangup(myrpt->txchannel);
11052       ast_hangup(myrpt->rxchannel);
11053       myrpt->rpt_thread = AST_PTHREADT_STOP;
11054       pthread_exit(NULL);
11055    }
11056    ast_set_read_format(myrpt->parrotchannel,AST_FORMAT_SLINEAR);
11057    ast_set_write_format(myrpt->parrotchannel,AST_FORMAT_SLINEAR);
11058 #ifdef   AST_CDR_FLAG_POST_DISABLED
11059    if (myrpt->parrotchannel->cdr)
11060       ast_set_flag(myrpt->parrotchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11061 #endif
11062    /* allocate a pseudo-channel thru asterisk */
11063    myrpt->voxchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
11064    if (!myrpt->voxchannel)
11065    {
11066       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11067       rpt_mutex_unlock(&myrpt->lock);
11068       if (myrpt->txchannel != myrpt->rxchannel) 
11069          ast_hangup(myrpt->txchannel);
11070       ast_hangup(myrpt->rxchannel);
11071       myrpt->rpt_thread = AST_PTHREADT_STOP;
11072       pthread_exit(NULL);
11073    }
11074    ast_set_read_format(myrpt->voxchannel,AST_FORMAT_SLINEAR);
11075    ast_set_write_format(myrpt->voxchannel,AST_FORMAT_SLINEAR);
11076 #ifdef   AST_CDR_FLAG_POST_DISABLED
11077    if (myrpt->voxchannel->cdr)
11078       ast_set_flag(myrpt->voxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11079 #endif
11080    /* allocate a pseudo-channel thru asterisk */
11081    myrpt->txpchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
11082    if (!myrpt->txpchannel)
11083    {
11084       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11085       rpt_mutex_unlock(&myrpt->lock);
11086       ast_hangup(myrpt->pchannel);
11087       ast_hangup(myrpt->monchannel);
11088       if (myrpt->txchannel != myrpt->rxchannel) 
11089          ast_hangup(myrpt->txchannel);
11090       ast_hangup(myrpt->rxchannel);
11091       myrpt->rpt_thread = AST_PTHREADT_STOP;
11092       pthread_exit(NULL);
11093    }
11094 #ifdef   AST_CDR_FLAG_POST_DISABLED
11095    if (myrpt->txpchannel->cdr)
11096       ast_set_flag(myrpt->txpchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11097 #endif
11098    /* make a conference for the tx */
11099    ci.chan = 0;
11100    ci.confno = myrpt->txconf;
11101    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER ;
11102    /* first put the channel on the conference in proper mode */
11103    if (ioctl(myrpt->txpchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11104    {
11105       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
11106       rpt_mutex_unlock(&myrpt->lock);
11107       ast_hangup(myrpt->txpchannel);
11108       ast_hangup(myrpt->monchannel);
11109       if (myrpt->txchannel != myrpt->rxchannel) 
11110          ast_hangup(myrpt->txchannel);
11111       ast_hangup(myrpt->rxchannel);
11112       myrpt->rpt_thread = AST_PTHREADT_STOP;
11113       pthread_exit(NULL);
11114    }
11115    /* if serial io port, open it */
11116    myrpt->iofd = -1;
11117    if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt,myrpt->p.ioport)) == -1))
11118    {
11119       ast_log(LOG_ERROR, "Unable to open %s\n",myrpt->p.ioport);
11120       rpt_mutex_unlock(&myrpt->lock);
11121       ast_hangup(myrpt->pchannel);
11122       if (myrpt->txchannel != myrpt->rxchannel) 
11123          ast_hangup(myrpt->txchannel);
11124       ast_hangup(myrpt->rxchannel);
11125       pthread_exit(NULL);
11126    }
11127    /* Now, the idea here is to copy from the physical rx channel buffer
11128       into the pseudo tx buffer, and from the pseudo rx buffer into the 
11129       tx channel buffer */
11130    myrpt->links.next = &myrpt->links;
11131    myrpt->links.prev = &myrpt->links;
11132    myrpt->tailtimer = 0;
11133    myrpt->totimer = 0;
11134    myrpt->tmsgtimer = myrpt->p.tailmessagetime;
11135    myrpt->idtimer = myrpt->p.politeid;
11136    myrpt->mustid = myrpt->tailid = 0;
11137    myrpt->callmode = 0;
11138    myrpt->tounkeyed = 0;
11139    myrpt->tonotify = 0;
11140    myrpt->retxtimer = 0;
11141    myrpt->rerxtimer = 0;
11142    myrpt->skedtimer = 0;
11143    myrpt->tailevent = 0;
11144    lasttx = 0;
11145    myrpt->keyed = 0;
11146    myrpt->txkeyed = 0;
11147    time(&myrpt->lastkeyedtime);
11148    myrpt->lastkeyedtime -= RPT_LOCKOUT_SECS;
11149    time(&myrpt->lasttxkeyedtime);
11150    myrpt->lasttxkeyedtime -= RPT_LOCKOUT_SECS;
11151    idtalkover = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
11152    myrpt->dtmfidx = -1;
11153    myrpt->dtmfbuf[0] = 0;
11154    myrpt->rem_dtmfidx = -1;
11155    myrpt->rem_dtmfbuf[0] = 0;
11156    myrpt->dtmf_time = 0;
11157    myrpt->rem_dtmf_time = 0;
11158    myrpt->inpadtest = 0;
11159    myrpt->disgorgetime = 0;
11160    myrpt->lastnodewhichkeyedusup[0] = '\0';
11161    myrpt->dailytxtime = 0;
11162    myrpt->totaltxtime = 0;
11163    myrpt->dailykeyups = 0;
11164    myrpt->totalkeyups = 0;
11165    myrpt->dailykerchunks = 0;
11166    myrpt->totalkerchunks = 0;
11167    myrpt->dailyexecdcommands = 0;
11168    myrpt->totalexecdcommands = 0;
11169    myrpt->timeouts = 0;
11170    myrpt->exten[0] = '\0';
11171    myrpt->lastdtmfcommand[0] = '\0';
11172    voxinit_rpt(myrpt,1);
11173    myrpt->wasvox = 0;
11174    if (myrpt->p.startupmacro)
11175    {
11176       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
11177    }
11178    rpt_mutex_unlock(&myrpt->lock);
11179    val = 1;
11180    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
11181    val = 1;
11182    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
11183    if (myrpt->p.archivedir) donodelog(myrpt,"STARTUP");
11184    dtmfed = 0;
11185    if (myrpt->remoterig && !ISRIG_RTX(myrpt->remoterig)) setrem(myrpt);
11186    lastmyrx = 0;
11187    myfirst = 0;
11188    while (ms >= 0)
11189    {
11190       struct ast_frame *f,*f1,*f2;
11191       struct ast_channel *cs[300],*cs1[300];
11192       int totx=0,elap=0,n,x,toexit=0;
11193 
11194       /* DEBUG Dump */
11195       if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){
11196          struct rpt_link *dl;
11197          struct rpt_tele *dt;
11198 
11199          myrpt->disgorgetime = 0;
11200          ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n");
11201          ast_log(LOG_NOTICE,"totx = %d\n",totx);
11202          ast_log(LOG_NOTICE,"remrx = %d\n",remrx);
11203          ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx);
11204          ast_log(LOG_NOTICE,"elap = %d\n",elap);
11205          ast_log(LOG_NOTICE,"toexit = %d\n",toexit);
11206 
11207          ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed);
11208          ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx);
11209          ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode);
11210          ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
11211          ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed);
11212          ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify);
11213          ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
11214          ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
11215          ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
11216          ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
11217 
11218          dl = myrpt->links.next;
11219                   while(dl != &myrpt->links){
11220             ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",dl->name);
11221             ast_log(LOG_NOTICE,"        link->lasttx %d\n",dl->lasttx);
11222             ast_log(LOG_NOTICE,"        link->lastrx %d\n",dl->lastrx);
11223             ast_log(LOG_NOTICE,"        link->connected %d\n",dl->connected);
11224             ast_log(LOG_NOTICE,"        link->hasconnected %d\n",dl->hasconnected);
11225             ast_log(LOG_NOTICE,"        link->outbound %d\n",dl->outbound);
11226             ast_log(LOG_NOTICE,"        link->disced %d\n",dl->disced);
11227             ast_log(LOG_NOTICE,"        link->killme %d\n",dl->killme);
11228             ast_log(LOG_NOTICE,"        link->disctime %ld\n",dl->disctime);
11229             ast_log(LOG_NOTICE,"        link->retrytimer %ld\n",dl->retrytimer);
11230             ast_log(LOG_NOTICE,"        link->retries = %d\n",dl->retries);
11231             ast_log(LOG_NOTICE,"        link->reconnects = %d\n",dl->reconnects);
11232             ast_log(LOG_NOTICE,"        link->newkey = %d\n",dl->newkey);
11233                            dl = dl->next;
11234                   }
11235                                                                                                                                
11236          dt = myrpt->tele.next;
11237          if(dt != &myrpt->tele)
11238             ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n");
11239                   while(dt != &myrpt->tele){
11240             ast_log(LOG_NOTICE,"        Telemetry mode: %d\n",dt->mode);
11241                            dt = dt->next;
11242                   }
11243          ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n");
11244 
11245       }  
11246 
11247 
11248       if (myrpt->reload)
11249       {
11250          struct rpt_tele *inner_telem;
11251 
11252          rpt_mutex_lock(&myrpt->lock);
11253          inner_telem = myrpt->tele.next;
11254          while(inner_telem != &myrpt->tele)
11255          {
11256             ast_softhangup(inner_telem->chan,AST_SOFTHANGUP_DEV);
11257             inner_telem = inner_telem->next;
11258          }
11259          myrpt->reload = 0;
11260          rpt_mutex_unlock(&myrpt->lock);
11261          usleep(10000);
11262          /* find our index, and load the vars */
11263          for(i = 0; i < nrpts; i++)
11264          {
11265             if (&rpt_vars[i] == myrpt)
11266             {
11267                load_rpt_vars(i,0);
11268                break;
11269             }
11270          }
11271       }
11272 
11273       rpt_mutex_lock(&myrpt->lock);
11274       if (ast_check_hangup(myrpt->rxchannel)) break;
11275       if (ast_check_hangup(myrpt->txchannel)) break;
11276       if (ast_check_hangup(myrpt->pchannel)) break;
11277       if (ast_check_hangup(myrpt->monchannel)) break;
11278       if (myrpt->parrotchannel && 
11279          ast_check_hangup(myrpt->parrotchannel)) break;
11280       if (myrpt->voxchannel && 
11281          ast_check_hangup(myrpt->voxchannel)) break;
11282       if (ast_check_hangup(myrpt->txpchannel)) break;
11283       if (myrpt->dahditxchannel && ast_check_hangup(myrpt->dahditxchannel)) break;
11284 
11285       /* Set local tx with keyed */
11286       myrpt->localtx = myrpt->keyed;
11287       /* If someone's connected, and they're transmitting from their end to us, set remrx true */
11288       l = myrpt->links.next;
11289       remrx = 0;
11290       while(l != &myrpt->links)
11291       {
11292          if (l->lastrx){
11293             remrx = 1;
11294             if(l->name[0] != '0') /* Ignore '0' nodes */
11295                strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
11296          }
11297          l = l->next;
11298       }
11299       /* Create a "must_id" flag for the cleanup ID */      
11300       if(myrpt->p.idtime) /* ID time must be non-zero */
11301          myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
11302       /* Build a fresh totx from myrpt->keyed and autopatch activated */
11303       /* If full duplex, add local tx to totx */
11304       if (myrpt->p.duplex > 1) 
11305       {
11306          totx = myrpt->callmode;
11307          totx = totx || myrpt->localtx;
11308       }
11309       else
11310       {
11311          int myrx = myrpt->localtx || remrx || (!myrpt->callmode);
11312 
11313          if (lastmyrx != myrx)
11314          {
11315             voxinit_rpt(myrpt,!myrx);
11316             lastmyrx = myrx;
11317          }
11318          totx = 0;
11319          if (myrpt->callmode && (myrpt->voxtotimer <= 0))
11320          {
11321             if (myrpt->voxtostate)
11322             {
11323                myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
11324                myrpt->voxtostate = 0;
11325             }           
11326             else
11327             {
11328                myrpt->voxtotimer = myrpt->p.voxrecover_ms;
11329                myrpt->voxtostate = 1;
11330             }
11331          }
11332          if (!myrpt->voxtostate)
11333             totx = myrpt->callmode && myrpt->wasvox;
11334       }
11335       /* Traverse the telemetry list to see what's queued */
11336       identqueued = 0;
11337       localmsgqueued = 0;
11338       othertelemqueued = 0;
11339       tailmessagequeued = 0;
11340       ctqueued = 0;
11341       telem = myrpt->tele.next;
11342       while(telem != &myrpt->tele)
11343       {
11344          if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
11345             identqueued = 1; /* Identification telemetry */
11346          }
11347          else if(telem->mode == TAILMSG)
11348          {
11349             tailmessagequeued = 1; /* Tail message telemetry */
11350          }
11351          else if(telem->mode == STATS_TIME_LOCAL) 
11352          {
11353             localmsgqueued = 1; /* Local message */
11354          }
11355          else
11356          {
11357             if ((telem->mode != UNKEY) && (telem->mode != LINKUNKEY))
11358                othertelemqueued = 1;  /* Other telemetry */
11359             else
11360                ctqueued = 1; /* Courtesy tone telemetry */
11361          }
11362          telem = telem->next;
11363       }
11364    
11365       /* Add in any "other" telemetry, unless specified otherwise */
11366       if (!myrpt->p.notelemtx) totx = totx || othertelemqueued;
11367       /* Update external (to links) transmitter PTT state with everything but */
11368       /* ID, CT, local messages, and tailmessage telemetry */
11369       myrpt->exttx = totx;
11370       totx = totx || myrpt->dtmf_local_timer;
11371       /* If half or 3/4 duplex, add localtx to external link tx */
11372       if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
11373       /* Add in ID telemetry to local transmitter */
11374       totx = totx || remrx;
11375       /* If 3/4 or full duplex, add in ident, CT telemetry, and local messages */
11376       if (myrpt->p.duplex > 0)
11377          totx = totx || identqueued || ctqueued || localmsgqueued;
11378       /* If full duplex, add local dtmf stuff active */
11379       if (myrpt->p.duplex > 1) 
11380       {
11381          totx = totx || (myrpt->dtmfidx > -1) ||
11382             myrpt->cmdnode[0];
11383       }
11384       /* add in parrot stuff */
11385       totx = totx || (myrpt->parrotstate > 1);
11386       /* Reset time out timer variables if there is no activity */
11387       if (!totx) 
11388       {
11389          myrpt->totimer = myrpt->p.totime;
11390          myrpt->tounkeyed = 0;
11391          myrpt->tonotify = 0;
11392       }
11393       else{
11394          myrpt->tailtimer = myrpt->p.s[myrpt->p.sysstate_cur].alternatetail ?
11395             myrpt->p.althangtime : /* Initialize tail timer */
11396             myrpt->p.hangtime;
11397       }
11398       /* Disable the local transmitter if we are timed out */
11399       totx = totx && myrpt->totimer;
11400       /* if timed-out and not said already, say it */
11401       if ((!myrpt->totimer) && (!myrpt->tonotify))
11402       {
11403          myrpt->tonotify = 1;
11404          myrpt->timeouts++;
11405          rpt_mutex_unlock(&myrpt->lock);
11406          rpt_telemetry(myrpt,TIMEOUT,NULL);
11407          rpt_mutex_lock(&myrpt->lock);
11408       }
11409 
11410       /* If unkey and re-key, reset time out timer */
11411       if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
11412       {
11413          myrpt->tounkeyed = 1;
11414       }
11415       if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
11416       {
11417          myrpt->totimer = myrpt->p.totime;
11418          myrpt->tounkeyed = 0;
11419          myrpt->tonotify = 0;
11420          rpt_mutex_unlock(&myrpt->lock);
11421          continue;
11422       }
11423       /* if timed-out and in circuit busy after call */
11424       if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
11425       {
11426           if(debug)
11427             ast_log(LOG_NOTICE, "timed-out and in circuit busy after call\n");
11428          myrpt->callmode = 0;
11429          myrpt->macropatch=0;
11430          channel_revert(myrpt);
11431       }
11432       /* get rid of tail if timed out */
11433       if (!myrpt->totimer) myrpt->tailtimer = 0;
11434       /* if not timed-out, add in tail */
11435       if (myrpt->totimer) totx = totx || myrpt->tailtimer;
11436       /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
11437       /* If tail message, kill the message if someone keys up over it */ 
11438       if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
11439          int hasid = 0,hastalkover = 0;
11440 
11441          telem = myrpt->tele.next;
11442          while(telem != &myrpt->tele){
11443             if(telem->mode == ID){
11444                if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
11445                hasid = 1;
11446             }
11447             if(telem->mode == TAILMSG){
11448                                         if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
11449                                 }
11450             if (telem->mode == IDTALKOVER) hastalkover = 1;
11451             telem = telem->next;
11452          }
11453          rpt_mutex_unlock(&myrpt->lock);
11454          if (hasid && (!hastalkover)) rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
11455          rpt_mutex_lock(&myrpt->lock);
11456       }
11457       /* Try to be polite */
11458       /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
11459       /* If within 30 seconds of the time to ID, try do it in the tail */
11460       /* else if at ID time limit, do it right over the top of them */
11461       /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
11462       if(myrpt->mustid && (!myrpt->idtimer))
11463          queue_id(myrpt);
11464 
11465       if ((myrpt->p.idtime && totx && (!myrpt->exttx) &&
11466           (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) /* ID time must be non-zero */ 
11467          {
11468             myrpt->tailid = 1;
11469          }
11470 
11471       /* If tail timer expires, then check for tail messages */
11472 
11473       if(myrpt->tailevent){
11474          myrpt->tailevent = 0;
11475          if(myrpt->tailid){
11476             totx = 1;
11477             queue_id(myrpt);
11478          }
11479          else if ((myrpt->p.tailmessages[0]) &&
11480             (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
11481                totx = 1;
11482                myrpt->tmsgtimer = myrpt->p.tailmessagetime; 
11483                rpt_mutex_unlock(&myrpt->lock);
11484                rpt_telemetry(myrpt, TAILMSG, NULL);
11485                rpt_mutex_lock(&myrpt->lock);
11486          }  
11487       }
11488 
11489       /* Main TX control */
11490 
11491       /* let telemetry transmit anyway (regardless of timeout) */
11492       if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
11493       totx = totx && !myrpt->p.s[myrpt->p.sysstate_cur].txdisable;
11494       myrpt->txrealkeyed = totx;
11495       totx = totx || (!AST_LIST_EMPTY(&myrpt->txq));
11496       if (totx && (!lasttx))
11497       {
11498          char mydate[100],myfname[100];
11499          time_t myt;
11500 
11501          if (myrpt->monstream) ast_closestream(myrpt->monstream);
11502          if (myrpt->p.archivedir)
11503          {
11504             long blocksleft;
11505 
11506             time(&myt);
11507             strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
11508                localtime(&myt));
11509             sprintf(myfname,"%s/%s/%s",myrpt->p.archivedir,
11510                myrpt->name,mydate);
11511             myrpt->monstream = ast_writefile(myfname,"wav49",
11512                "app_rpt Air Archive",O_CREAT | O_APPEND,0,0600);
11513             if (myrpt->p.monminblocks)
11514             {
11515                blocksleft = diskavail(myrpt);
11516                if (blocksleft >= myrpt->p.monminblocks)
11517                   donodelog(myrpt,"TXKEY,MAIN");
11518             } else donodelog(myrpt,"TXKEY,MAIN");
11519          }
11520          lasttx = 1;
11521          myrpt->txkeyed = 1;
11522          time(&myrpt->lasttxkeyedtime);
11523          myrpt->dailykeyups++;
11524          myrpt->totalkeyups++;
11525          rpt_mutex_unlock(&myrpt->lock);
11526          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
11527          rpt_mutex_lock(&myrpt->lock);
11528       }
11529       if ((!totx) && lasttx)
11530       {
11531          if (myrpt->monstream) ast_closestream(myrpt->monstream);
11532          myrpt->monstream = NULL;
11533 
11534          lasttx = 0;
11535          myrpt->txkeyed = 0;
11536          time(&myrpt->lasttxkeyedtime);
11537          rpt_mutex_unlock(&myrpt->lock);
11538          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
11539          rpt_mutex_lock(&myrpt->lock);
11540          donodelog(myrpt,"TXUNKEY,MAIN");
11541       }
11542       time(&t);
11543       /* if DTMF timeout */
11544       if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t))
11545       {
11546          myrpt->inpadtest = 0;
11547          myrpt->dtmfidx = -1;
11548          myrpt->dtmfbuf[0] = 0;
11549       }        
11550       /* if remote DTMF timeout */
11551       if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
11552       {
11553          myrpt->inpadtest = 0;
11554          myrpt->rem_dtmfidx = -1;
11555          myrpt->rem_dtmfbuf[0] = 0;
11556       }  
11557 
11558       if (myrpt->exttx && myrpt->parrotchannel && 
11559          myrpt->p.parrotmode && (!myrpt->parrotstate))
11560       {
11561          char myfname[300];
11562 
11563          ci.confno = myrpt->conf;
11564          ci.confmode = DAHDI_CONF_CONFANNMON;
11565          ci.chan = 0;
11566 
11567          /* first put the channel on the conference in announce mode */
11568          if (ioctl(myrpt->parrotchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11569          {
11570             ast_log(LOG_WARNING, "Unable to set conference mode for parrot\n");
11571             break;
11572          }
11573 
11574          sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
11575          strcat(myfname,".wav");
11576          unlink(myfname);        
11577          sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
11578          myrpt->parrotstate = 1;
11579          myrpt->parrottimer = myrpt->p.parrottime;
11580          if (myrpt->parrotstream) 
11581             ast_closestream(myrpt->parrotstream);
11582          myrpt->parrotstream = NULL;
11583          myrpt->parrotstream = ast_writefile(myfname,"wav",
11584             "app_rpt Parrot",O_CREAT | O_TRUNC,0,0600);
11585       }
11586 
11587       /* Reconnect */
11588    
11589       l = myrpt->links.next;
11590       while(l != &myrpt->links)
11591       {
11592          if (l->killme)
11593          {
11594             /* remove from queue */
11595             remque((struct qelem *) l);
11596             if (!strcmp(myrpt->cmdnode,l->name))
11597                myrpt->cmdnode[0] = 0;
11598             rpt_mutex_unlock(&myrpt->lock);
11599             /* hang-up on call to device */
11600             if (l->chan) ast_hangup(l->chan);
11601             ast_hangup(l->pchan);
11602             ast_free(l);
11603             rpt_mutex_lock(&myrpt->lock);
11604             /* re-start link traversal */
11605             l = myrpt->links.next;
11606             continue;
11607          }
11608          l = l->next;
11609       }
11610       n = 0;
11611       cs[n++] = myrpt->rxchannel;
11612       cs[n++] = myrpt->pchannel;
11613       cs[n++] = myrpt->monchannel;
11614       if (myrpt->parrotchannel) cs[n++] = myrpt->parrotchannel;
11615       if (myrpt->voxchannel) cs[n++] = myrpt->voxchannel;
11616       cs[n++] = myrpt->txpchannel;
11617       if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
11618       if (myrpt->dahditxchannel != myrpt->txchannel)
11619          cs[n++] = myrpt->dahditxchannel;
11620       l = myrpt->links.next;
11621       while(l != &myrpt->links)
11622       {
11623          if ((!l->killme) && (!l->disctime) && l->chan)
11624          {
11625             cs[n++] = l->chan;
11626             cs[n++] = l->pchan;
11627          }
11628          l = l->next;
11629       }
11630       if ((myrpt->topkeystate == 1) && 
11631           ((t - myrpt->topkeytime) > TOPKEYWAIT))
11632       {
11633          myrpt->topkeystate = 2;
11634          qsort(myrpt->topkey,TOPKEYN,sizeof(struct rpt_topkey),
11635             topcompar);
11636       }
11637       rpt_mutex_unlock(&myrpt->lock);
11638 
11639       if (myrpt->topkeystate == 2)
11640       {
11641          rpt_telemetry(myrpt,TOPKEY,NULL);
11642          myrpt->topkeystate = 3;
11643       }
11644       ms = MSWAIT;
11645       for(x = 0; x < n; x++)
11646       {
11647          int s = -(-x - myrpt->scram - 1) % n;
11648          cs1[x] = cs[s];
11649       }
11650       myrpt->scram++;
11651       who = ast_waitfor_n(cs1,n,&ms);
11652       if (who == NULL) ms = 0;
11653       elap = MSWAIT - ms;
11654       rpt_mutex_lock(&myrpt->lock);
11655       l = myrpt->links.next;
11656       while(l != &myrpt->links)
11657       {
11658          int myrx;
11659 
11660          if (l->voxtotimer) l->voxtotimer -= elap;
11661          if (l->voxtotimer < 0) l->voxtotimer = 0;
11662 
11663          if (l->lasttx != l->lasttx1)
11664          {
11665             voxinit_link(l,!l->lasttx);
11666             l->lasttx1 = l->lasttx;
11667          }
11668          myrx = l->lastrealrx;
11669          if ((l->phonemode) && (l->phonevox))
11670          {
11671             myrx = myrx || (!AST_LIST_EMPTY(&l->rxq));
11672             if (l->voxtotimer <= 0)
11673             {
11674                if (l->voxtostate)
11675                {
11676                   l->voxtotimer = myrpt->p.voxtimeout_ms;
11677                   l->voxtostate = 0;
11678                }           
11679                else
11680                {
11681                   l->voxtotimer = myrpt->p.voxrecover_ms;
11682                   l->voxtostate = 1;
11683                }
11684             }
11685             if (!l->voxtostate)
11686                myrx = myrx || l->wasvox ;
11687          }
11688          l->lastrx = myrx;
11689          if (l->linklisttimer)
11690          {
11691             l->linklisttimer -= elap;
11692             if (l->linklisttimer < 0) l->linklisttimer = 0;
11693          }
11694          if ((!l->linklisttimer) && (l->name[0] != '0') && (!l->isremote))
11695          {
11696             struct   ast_frame lf;
11697 
11698             memset(&lf,0,sizeof(lf));
11699             lf.frametype = AST_FRAME_TEXT;
11700             lf.subclass.integer = 0;
11701             lf.offset = 0;
11702             lf.mallocd = 0;
11703             lf.samples = 0;
11704             l->linklisttimer = LINKLISTTIME;
11705             strcpy(lstr,"L ");
11706             __mklinklist(myrpt,l,lstr + 2);
11707             if (l->chan)
11708             {
11709                lf.datalen = strlen(lstr) + 1;
11710                lf.data.ptr = lstr;
11711                ast_write(l->chan,&lf);
11712                if (debug > 6) ast_log(LOG_NOTICE,
11713                   "@@@@ node %s sent node string %s to node %s\n",
11714                      myrpt->name,lstr,l->name);
11715             }
11716          }
11717          if (l->newkey)
11718          {
11719             if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
11720             {
11721                l->retxtimer = 0;
11722                if (l->chan && l->phonemode == 0) 
11723                {
11724                   if (l->lasttx)
11725                      ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
11726                   else
11727                      ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
11728                }
11729             }
11730             if ((l->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 5))
11731             {
11732                if (debug == 7) printf("@@@@ rx un-key\n");
11733                l->lastrealrx = 0;
11734                l->rerxtimer = 0;
11735                if (l->lastrx1)
11736                {
11737                   if (myrpt->p.archivedir)
11738                   {
11739                      char str[100];
11740    
11741                      sprintf(str,"RXUNKEY(T),%s",l->name);
11742                      donodelog(myrpt,str);
11743                   }
11744                   if(myrpt->p.duplex) 
11745                      rpt_telemetry(myrpt,LINKUNKEY,l);
11746                   l->lastrx1 = 0;
11747                }
11748             }
11749          }
11750          if (l->disctime) /* Disconnect timer active on a channel ? */
11751          {
11752             l->disctime -= elap;
11753             if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
11754                l->disctime = 0; /* Yep */
11755          }
11756 
11757          if (l->retrytimer)
11758          {
11759             l->retrytimer -= elap;
11760             if (l->retrytimer < 0) l->retrytimer = 0;
11761          }
11762 
11763          /* Tally connect time */
11764          l->connecttime += elap;
11765 
11766          /* ignore non-timing channels */
11767          if (l->elaptime < 0)
11768          {
11769             l = l->next;
11770             continue;
11771          }
11772          l->elaptime += elap;
11773          /* if connection has taken too long */
11774          if ((l->elaptime > MAXCONNECTTIME) && 
11775             ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
11776          {
11777             l->elaptime = 0;
11778             rpt_mutex_unlock(&myrpt->lock);
11779             if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
11780             rpt_mutex_lock(&myrpt->lock);
11781             break;
11782          }
11783          if ((!l->chan) && (!l->retrytimer) && l->outbound && 
11784             (l->retries++ < l->max_retries) && (l->hasconnected))
11785          {
11786             if (l->chan) ast_hangup(l->chan);
11787             l->chan = 0;
11788             rpt_mutex_unlock(&myrpt->lock);
11789             if ((l->name[0] != '0') && (!l->isremote))
11790             {
11791                if (attempt_reconnect(myrpt,l) == -1)
11792                {
11793                   l->retrytimer = RETRY_TIMER_MS;
11794                } 
11795             }
11796             else 
11797             {
11798                l->retrytimer = l->max_retries + 1;
11799             }
11800 
11801             rpt_mutex_lock(&myrpt->lock);
11802             break;
11803          }
11804          if ((!l->chan) && (!l->retrytimer) && l->outbound &&
11805             (l->retries >= l->max_retries))
11806          {
11807             /* remove from queue */
11808             remque((struct qelem *) l);
11809             if (!strcmp(myrpt->cmdnode,l->name))
11810                myrpt->cmdnode[0] = 0;
11811             rpt_mutex_unlock(&myrpt->lock);
11812             if (l->name[0] != '0')
11813             {
11814                if (!l->hasconnected)
11815                   rpt_telemetry(myrpt,CONNFAIL,l);
11816                else rpt_telemetry(myrpt,REMDISC,l);
11817             }
11818             if (myrpt->p.archivedir)
11819             {
11820                char str[100];
11821 
11822                if (!l->hasconnected)
11823                   sprintf(str,"LINKFAIL,%s",l->name);
11824                else
11825                   sprintf(str,"LINKDISC,%s",l->name);
11826                donodelog(myrpt,str);
11827             }
11828             /* hang-up on call to device */
11829             ast_hangup(l->pchan);
11830             ast_free(l);
11831                                 rpt_mutex_lock(&myrpt->lock);
11832             break;
11833          }
11834             if ((!l->chan) && (!l->disctime) && (!l->outbound))
11835             {
11836             if(debug)ast_log(LOG_NOTICE, "LINKDISC AA\n");
11837                 /* remove from queue */
11838                 remque((struct qelem *) l);
11839             if(myrpt->links.next==&myrpt->links)channel_revert(myrpt);
11840                 if (!strcmp(myrpt->cmdnode,l->name))myrpt->cmdnode[0] = 0;
11841                 rpt_mutex_unlock(&myrpt->lock);
11842             if (l->name[0] != '0') 
11843             {
11844                   rpt_telemetry(myrpt,REMDISC,l);
11845             }
11846             if (myrpt->p.archivedir)
11847             {
11848                char str[100];
11849                sprintf(str,"LINKDISC,%s",l->name);
11850                donodelog(myrpt,str);
11851             }
11852                 /* hang-up on call to device */
11853                 ast_hangup(l->pchan);
11854                 ast_free(l);
11855                 rpt_mutex_lock(&myrpt->lock);
11856                 break;
11857             }
11858          l = l->next;
11859       }
11860       if (myrpt->linkposttimer)
11861       {
11862          myrpt->linkposttimer -= elap;
11863          if (myrpt->linkposttimer < 0) myrpt->linkposttimer = 0;
11864       }
11865       if (myrpt->linkposttimer <= 0)
11866       {
11867          int nstr;
11868          char lst,*str;
11869          time_t now;
11870 
11871          myrpt->linkposttimer = LINKPOSTTIME;
11872          nstr = 0;
11873          for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
11874          {
11875             /* if is not a real link, ignore it */
11876             if (l->name[0] == '0') continue;
11877             nstr += strlen(l->name) + 1;
11878          }
11879          str = ast_malloc(nstr + 256);
11880          if (!str)
11881          {
11882             ast_log(LOG_NOTICE,"Cannot ast_malloc()\n");
11883             break;
11884          }
11885          nstr = 0;
11886          strcpy(str,"nodes=");
11887          for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
11888          {
11889             /* if is not a real link, ignore it */
11890             if (l->name[0] == '0') continue;
11891             lst = 'T';
11892             if (!l->mode) lst = 'R';
11893             if (!l->thisconnected) lst = 'C';
11894             if (nstr) strcat(str,",");
11895             sprintf(str + strlen(str),"%c%s",lst,l->name);
11896             nstr = 1;
11897          }
11898                   p = strstr(tdesc, "version");
11899                   if(p){
11900             int vmajor,vminor;
11901             if(sscanf(p, "version %30d.%30d", &vmajor, &vminor) == 2)
11902                sprintf(str + strlen(str),"&apprptvers=%d.%d",vmajor,vminor);
11903          }
11904          time(&now);
11905          sprintf(str + strlen(str),"&apprptuptime=%d",(int)(now-starttime));
11906          sprintf(str + strlen(str),
11907          "&totalkerchunks=%d&totalkeyups=%d&totaltxtime=%d&timeouts=%d&totalexecdcommands=%d",
11908          myrpt->totalkerchunks,myrpt->totalkeyups,(int) myrpt->totaltxtime/1000,
11909          myrpt->timeouts,myrpt->totalexecdcommands);
11910          rpt_mutex_unlock(&myrpt->lock);
11911          statpost(myrpt,str);
11912          rpt_mutex_lock(&myrpt->lock);
11913          ast_free(str);
11914       }
11915       if (myrpt->keyposttimer)
11916       {
11917          myrpt->keyposttimer -= elap;
11918          if (myrpt->keyposttimer < 0) myrpt->keyposttimer = 0;
11919       }
11920       if (myrpt->keyposttimer <= 0)
11921       {
11922          char str[100];
11923          int diff = 0;
11924          time_t now;
11925 
11926          myrpt->keyposttimer = KEYPOSTTIME;
11927          time(&now);
11928          if (myrpt->lastkeyedtime)
11929          {
11930             diff = (int)(now - myrpt->lastkeyedtime);
11931          }
11932          sprintf(str,"keyed=%d&keytime=%d",myrpt->keyed,diff);
11933          rpt_mutex_unlock(&myrpt->lock);
11934          statpost(myrpt,str);
11935          rpt_mutex_lock(&myrpt->lock);
11936       }
11937       if(totx){
11938          myrpt->dailytxtime += elap;
11939          myrpt->totaltxtime += elap;
11940       }
11941       i = myrpt->tailtimer;
11942       if (myrpt->tailtimer) myrpt->tailtimer -= elap;
11943       if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
11944       if((i) && (myrpt->tailtimer == 0))
11945          myrpt->tailevent = 1;
11946       if ((!myrpt->p.s[myrpt->p.sysstate_cur].totdisable) && myrpt->totimer) myrpt->totimer -= elap;
11947       if (myrpt->totimer < 0) myrpt->totimer = 0;
11948       if (myrpt->idtimer) myrpt->idtimer -= elap;
11949       if (myrpt->idtimer < 0) myrpt->idtimer = 0;
11950       if (myrpt->tmsgtimer) myrpt->tmsgtimer -= elap;
11951       if (myrpt->tmsgtimer < 0) myrpt->tmsgtimer = 0;
11952       if (myrpt->voxtotimer) myrpt->voxtotimer -= elap;
11953       if (myrpt->voxtotimer < 0) myrpt->voxtotimer = 0;
11954       if (myrpt->exttx)
11955       {
11956          myrpt->parrottimer = myrpt->p.parrottime;
11957       }
11958       else
11959       {
11960          if (myrpt->parrottimer) myrpt->parrottimer -= elap;
11961          if (myrpt->parrottimer < 0) myrpt->parrottimer = 0;
11962       }
11963       /* do macro timers */
11964       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
11965       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
11966       /* do local dtmf timer */
11967       if (myrpt->dtmf_local_timer)
11968       {
11969          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
11970          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
11971       }
11972       do_dtmf_local(myrpt,0);
11973       /* Execute scheduler appx. every 2 tenths of a second */
11974       if (myrpt->skedtimer <= 0){
11975          myrpt->skedtimer = 200;
11976          do_scheduler(myrpt);
11977       }
11978       else
11979          myrpt->skedtimer -=elap;
11980       if (!ms) 
11981       {
11982          rpt_mutex_unlock(&myrpt->lock);
11983          continue;
11984       }
11985       if (myrpt->p.parrotmode && (myrpt->parrotstate == 1) &&
11986          (myrpt->parrottimer <= 0))
11987       {
11988 
11989          ci.confno = 0;
11990          ci.confmode = 0;
11991          ci.chan = 0;
11992 
11993          /* first put the channel on the conference in announce mode */
11994          if (ioctl(myrpt->parrotchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11995          {
11996             ast_log(LOG_WARNING, "Unable to set conference mode for parrot\n");
11997             break;
11998          }
11999          if (myrpt->parrotstream) 
12000             ast_closestream(myrpt->parrotstream);
12001          myrpt->parrotstream = NULL;
12002          myrpt->parrotstate = 2;
12003          rpt_telemetry(myrpt,PARROT,(void *) ((intptr_t)myrpt->parrotcnt++)); 
12004       }        
12005       if (myrpt->cmdAction.state == CMD_STATE_READY)
12006       { /* there is a command waiting to be processed */
12007          int status;
12008          myrpt->cmdAction.state = CMD_STATE_EXECUTING;
12009          // lose the lock
12010          rpt_mutex_unlock(&myrpt->lock);
12011          // do the function
12012          status = (*function_table[myrpt->cmdAction.functionNumber].function)(myrpt,myrpt->cmdAction.param, myrpt->cmdAction.digits, myrpt->cmdAction.command_source, NULL);
12013          // get the lock again
12014          rpt_mutex_lock(&myrpt->lock);
12015          myrpt->cmdAction.state = CMD_STATE_IDLE;
12016       } /* if myrpt->cmdAction.state == CMD_STATE_READY */
12017       
12018       c = myrpt->macrobuf[0];
12019       time(&t);
12020       if (c && (!myrpt->macrotimer) && 
12021          starttime && (t > (starttime + START_DELAY)))
12022       {
12023          char cin = c & 0x7f;
12024          myrpt->macrotimer = MACROTIME;
12025          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
12026          if ((cin == 'p') || (cin == 'P'))
12027             myrpt->macrotimer = MACROPTIME;
12028          rpt_mutex_unlock(&myrpt->lock);
12029          if (myrpt->p.archivedir)
12030          {
12031             char str[100];
12032 
12033             sprintf(str,"DTMF(M),MAIN,%c",cin);
12034             donodelog(myrpt,str);
12035          }
12036          local_dtmf_helper(myrpt,c);
12037       } else rpt_mutex_unlock(&myrpt->lock);
12038       if (who == myrpt->rxchannel) /* if it was a read from rx */
12039       {
12040          int ismuted;
12041 
12042          f = ast_read(myrpt->rxchannel);
12043          if (!f)
12044          {
12045             if (debug) printf("@@@@ rpt:Hung Up\n");
12046             break;
12047          }
12048          if (f->frametype == AST_FRAME_VOICE)
12049          {
12050 #ifdef   _MDC_DECODE_H_
12051             unsigned char ubuf[2560];
12052             short *sp;
12053             int n;
12054 #endif
12055 
12056             if ((!myrpt->localtx) && (!myrpt->p.linktolink)) {
12057                memset(f->data.ptr,0,f->datalen);
12058             }
12059 
12060 #ifdef   _MDC_DECODE_H_
12061             sp = (short *) f->data;
12062             /* convert block to unsigned char */
12063             for(n = 0; n < f->datalen / 2; n++)
12064             {
12065                ubuf[n] = (*sp++ >> 8) + 128;
12066             }
12067             n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
12068             if (n == 1)
12069             {
12070                   unsigned char op,arg;
12071                   unsigned short unitID;
12072 
12073                   mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
12074                   if (debug > 2)
12075                   {
12076                      ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
12077                      ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
12078                         op & 255,arg & 255,unitID);
12079                   }
12080                   if ((op == 1) && (arg == 0))
12081                   {
12082                      myrpt->lastunit = unitID;
12083                      mdc1200_notify(myrpt,NULL,myrpt->lastunit);
12084                      mdc1200_send(myrpt,myrpt->lastunit);
12085                   }
12086             }
12087             if ((debug > 2) && (i == 2))
12088             {
12089                unsigned char op,arg,ex1,ex2,ex3,ex4;
12090                unsigned short unitID;
12091 
12092                mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
12093                   &ex1,&ex2,&ex3,&ex4);
12094                ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
12095                ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
12096                   op & 255,arg & 255,unitID);
12097                ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
12098                   ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
12099             }
12100 #endif
12101 #ifdef   __RPT_NOTCH
12102             /* apply inbound filters, if any */
12103             rpt_filter(myrpt,f->data,f->datalen / 2);
12104 #endif
12105             if (ioctl(myrpt->dahdirxchannel->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
12106             {
12107                ismuted = 0;
12108             }
12109             if (dtmfed) ismuted = 1;
12110             dtmfed = 0;
12111             if (ismuted)
12112             {
12113                memset(f->data.ptr,0,f->datalen);
12114                if (myrpt->lastf1)
12115                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12116                if (myrpt->lastf2)
12117                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12118             } 
12119             if (f) f2 = ast_frdup(f);
12120             else f2 = NULL;
12121             f1 = myrpt->lastf2;
12122             myrpt->lastf2 = myrpt->lastf1;
12123             myrpt->lastf1 = f2;
12124             if (ismuted)
12125             {
12126                if (myrpt->lastf1)
12127                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12128                if (myrpt->lastf2)
12129                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12130             }
12131             if (f1)
12132             {
12133                ast_write(myrpt->pchannel,f1);
12134                ast_frfree(f1);
12135             }
12136          }
12137 #ifndef  OLD_ASTERISK
12138          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
12139          {
12140             if (myrpt->lastf1)
12141                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12142             if (myrpt->lastf2)
12143                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12144             dtmfed = 1;
12145          }
12146 #endif
12147          else if (f->frametype == AST_FRAME_DTMF)
12148          {
12149             c = (char) f->subclass.integer; /* get DTMF char */
12150             ast_frfree(f);
12151             if (myrpt->lastf1)
12152                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12153             if (myrpt->lastf2)
12154                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12155             dtmfed = 1;
12156             if (!myrpt->keyed) continue;
12157             c = func_xlat(myrpt,c,&myrpt->p.inxlat);
12158             if (c) local_dtmf_helper(myrpt,c);
12159             continue;
12160          }                 
12161          else if (f->frametype == AST_FRAME_CONTROL)
12162          {
12163             if (f->subclass.integer == AST_CONTROL_HANGUP)
12164             {
12165                if (debug) printf("@@@@ rpt:Hung Up\n");
12166                ast_frfree(f);
12167                break;
12168             }
12169             /* if RX key */
12170             if (f->subclass.integer == AST_CONTROL_RADIO_KEY)
12171             {
12172                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink)) 
12173                {
12174                   if (debug == 7) printf("@@@@ rx key\n");
12175                   myrpt->keyed = 1;
12176                   time(&myrpt->lastkeyedtime);
12177                   myrpt->keyposttimer = KEYPOSTSHORTTIME;
12178                }
12179                if (myrpt->p.archivedir)
12180                {
12181                   donodelog(myrpt,"RXKEY,MAIN");
12182                }
12183                if (f->datalen && f->data.ptr)
12184                {
12185                   char busy = 0;
12186 
12187                   if (debug) ast_log(LOG_NOTICE,"Got PL %s on node %s\n",(char *)f->data.ptr,myrpt->name);
12188                   // ctcss code autopatch initiate
12189                   if (strstr((char *)f->data.ptr,"/M/")&& !myrpt->macropatch)
12190                   {
12191                       char value[16];
12192                      strcat(value,"*6");
12193                      myrpt->macropatch=1;
12194                      rpt_mutex_lock(&myrpt->lock);
12195                      if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(value)){
12196                         rpt_mutex_unlock(&myrpt->lock);
12197                         busy=1;
12198                      }
12199                      if(!busy){
12200                         myrpt->macrotimer = MACROTIME;
12201                         strncat(myrpt->macrobuf,value,MAXMACRO - 1);
12202                         if (!busy) strcpy(myrpt->lasttone,(char*)f->data.ptr);
12203                      }
12204                      rpt_mutex_unlock(&myrpt->lock);
12205                   }
12206                   else if (strcmp((char *)f->data.ptr,myrpt->lasttone))
12207                   {
12208                      char *value = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.tonemacro, (char *)f->data.ptr);
12209                      if (value)
12210                      {
12211                         if (debug) ast_log(LOG_NOTICE,"Tone %s doing %s on node %s\n",(char *) f->data.ptr,value,myrpt->name);
12212                         rpt_mutex_lock(&myrpt->lock);
12213                         if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(value)){
12214                            rpt_mutex_unlock(&myrpt->lock);
12215                            busy=1;
12216                         }
12217                         if(!busy){
12218                            myrpt->macrotimer = MACROTIME;
12219                            strncat(myrpt->macrobuf,value,MAXMACRO - 1);
12220                         }
12221                         rpt_mutex_unlock(&myrpt->lock);
12222                      }
12223                      if (!busy) strcpy(myrpt->lasttone,(char*)f->data.ptr);
12224                   }
12225                } else myrpt->lasttone[0] = 0;
12226             }
12227             /* if RX un-key */
12228             if (f->subclass.integer == AST_CONTROL_RADIO_UNKEY)
12229             {
12230                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
12231                {
12232                   if (debug == 7) printf("@@@@ rx un-key\n");
12233                   if(myrpt->p.duplex && myrpt->keyed) {
12234                      rpt_telemetry(myrpt,UNKEY,NULL);
12235                   }
12236                }
12237                myrpt->keyed = 0;
12238                time(&myrpt->lastkeyedtime);
12239                myrpt->keyposttimer = KEYPOSTSHORTTIME;
12240                if (myrpt->p.archivedir)
12241                {
12242                   donodelog(myrpt,"RXUNKEY,MAIN");
12243                }
12244             }
12245          }
12246          ast_frfree(f);
12247          continue;
12248       }
12249       if (who == myrpt->pchannel) /* if it was a read from pseudo */
12250       {
12251          f = ast_read(myrpt->pchannel);
12252          if (!f)
12253          {
12254             if (debug) printf("@@@@ rpt:Hung Up\n");
12255             break;
12256          }
12257          if (f->frametype == AST_FRAME_VOICE)
12258          {
12259             ast_write(myrpt->txpchannel,f);
12260          }
12261          if (f->frametype == AST_FRAME_CONTROL)
12262          {
12263             if (f->subclass.integer == AST_CONTROL_HANGUP)
12264             {
12265                if (debug) printf("@@@@ rpt:Hung Up\n");
12266                ast_frfree(f);
12267                break;
12268             }
12269          }
12270          ast_frfree(f);
12271          continue;
12272       }
12273       if (who == myrpt->txchannel) /* if it was a read from tx */
12274       {
12275          f = ast_read(myrpt->txchannel);
12276          if (!f)
12277          {
12278             if (debug) printf("@@@@ rpt:Hung Up\n");
12279             break;
12280          }
12281          if (f->frametype == AST_FRAME_CONTROL)
12282          {
12283             if (f->subclass.integer == AST_CONTROL_HANGUP)
12284             {
12285                if (debug) printf("@@@@ rpt:Hung Up\n");
12286                ast_frfree(f);
12287                break;
12288             }
12289          }
12290          ast_frfree(f);
12291          continue;
12292       }
12293       if (who == myrpt->dahditxchannel) /* if it was a read from pseudo-tx */
12294       {
12295          f = ast_read(myrpt->dahditxchannel);
12296          if (!f)
12297          {
12298             if (debug) printf("@@@@ rpt:Hung Up\n");
12299             break;
12300          }
12301          if (f->frametype == AST_FRAME_VOICE)
12302          {
12303             struct ast_frame *vframe;
12304 
12305             if (myrpt->p.duplex < 2)
12306             {
12307                if (myrpt->txrealkeyed) 
12308                {
12309                   if ((!myfirst) && myrpt->callmode)
12310                   {
12311                       x = 0;
12312                       AST_LIST_TRAVERSE(&myrpt->txq, vframe,
12313                      frame_list) x++;
12314                       for(;x < myrpt->p.simplexpatchdelay; x++)
12315                       {
12316                         vframe = ast_frdup(f);
12317                         memset(vframe->data.ptr,0,vframe->datalen);
12318                         AST_LIST_INSERT_TAIL(&myrpt->txq,vframe,frame_list);
12319                       }
12320                       myfirst = 1;
12321                   }
12322                   vframe = ast_frdup(f);
12323                   AST_LIST_INSERT_TAIL(&myrpt->txq,
12324                      vframe,frame_list);
12325                } else myfirst = 0;
12326                x = 0;
12327                AST_LIST_TRAVERSE(&myrpt->txq, vframe,
12328                   frame_list) x++;
12329                if (!x)
12330                {
12331                   memset(f->data.ptr,0,f->datalen);
12332                }
12333                else
12334                {
12335                   ast_frfree(f);
12336                   f = AST_LIST_REMOVE_HEAD(&myrpt->txq,
12337                      frame_list);
12338                }
12339             }
12340             else
12341             {
12342                while((vframe = AST_LIST_REMOVE_HEAD(&myrpt->txq,
12343                   frame_list))) ast_frfree(vframe);
12344             }
12345             ast_write(myrpt->txchannel,f);
12346          }
12347          if (f->frametype == AST_FRAME_CONTROL)
12348          {
12349             if (f->subclass.integer == AST_CONTROL_HANGUP)
12350             {
12351                if (debug) printf("@@@@ rpt:Hung Up\n");
12352                ast_frfree(f);
12353                break;
12354             }
12355          }
12356          ast_frfree(f);
12357          continue;
12358       }
12359       toexit = 0;
12360       rpt_mutex_lock(&myrpt->lock);
12361       l = myrpt->links.next;
12362       while(l != &myrpt->links)
12363       {
12364          int remnomute;
12365          struct timeval now;
12366 
12367          if (l->disctime)
12368          {
12369             l = l->next;
12370             continue;
12371          }
12372 
12373          remrx = 0;
12374          /* see if any other links are receiving */
12375          m = myrpt->links.next;
12376          while(m != &myrpt->links)
12377          {
12378             /* if not us, count it */
12379             if ((m != l) && (m->lastrx)) remrx = 1;
12380             m = m->next;
12381          }
12382          rpt_mutex_unlock(&myrpt->lock);
12383          now = ast_tvnow();
12384          if ((who == l->chan) || (!l->lastlinktv.tv_sec) ||
12385             (ast_tvdiff_ms(now,l->lastlinktv) >= 19))
12386          {
12387             l->lastlinktv = now;
12388             remnomute = myrpt->localtx && 
12389                 (!(myrpt->cmdnode[0] || 
12390                (myrpt->dtmfidx > -1)));
12391             totx = (((l->isremote) ? (remnomute) : 
12392                myrpt->exttx) || remrx) && l->mode;
12393             if (l->phonemode == 0 && l->chan && (l->lasttx != totx))
12394             {
12395                if (totx)
12396                {
12397                   ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
12398                }
12399                else
12400                {
12401                   ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
12402                }
12403                if (myrpt->p.archivedir)
12404                {
12405                   char str[100];
12406 
12407                   if (totx)
12408                      sprintf(str,"TXKEY,%s",l->name);
12409                   else
12410                      sprintf(str,"TXUNKEY,%s",l->name);
12411                   donodelog(myrpt,str);
12412                }
12413             }
12414             l->lasttx = totx;
12415          }
12416          rpt_mutex_lock(&myrpt->lock);
12417          if (who == l->chan) /* if it was a read from rx */
12418          {
12419             rpt_mutex_unlock(&myrpt->lock);
12420             f = ast_read(l->chan);
12421             if (!f)
12422             {
12423                rpt_mutex_lock(&myrpt->lock);
12424                __kickshort(myrpt);
12425                rpt_mutex_unlock(&myrpt->lock);
12426                if ((!l->disced) && (!l->outbound))
12427                {
12428                   if ((l->name[0] == '0') || l->isremote)
12429                      l->disctime = 1;
12430                   else
12431                      l->disctime = DISC_TIME;
12432                   rpt_mutex_lock(&myrpt->lock);
12433                   ast_hangup(l->chan);
12434                   l->chan = 0;
12435                   break;
12436                }
12437 
12438                if (l->retrytimer) 
12439                {
12440                   ast_hangup(l->chan);
12441                   l->chan = 0;
12442                   rpt_mutex_lock(&myrpt->lock);
12443                   break; 
12444                }
12445                if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
12446                {
12447                   rpt_mutex_lock(&myrpt->lock);
12448                   if (l->chan) ast_hangup(l->chan);
12449                   l->chan = 0;
12450                   l->hasconnected = 1;
12451                   l->retrytimer = RETRY_TIMER_MS;
12452                   l->elaptime = 0;
12453                   l->connecttime = 0;
12454                   l->thisconnected = 0;
12455                   break;
12456                }
12457                rpt_mutex_lock(&myrpt->lock);
12458                /* remove from queue */
12459                remque((struct qelem *) l);
12460                if (!strcmp(myrpt->cmdnode,l->name))
12461                   myrpt->cmdnode[0] = 0;
12462                __kickshort(myrpt);
12463                rpt_mutex_unlock(&myrpt->lock);
12464                if (!l->hasconnected)
12465                   rpt_telemetry(myrpt,CONNFAIL,l);
12466                else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
12467                if (myrpt->p.archivedir)
12468                {
12469                   char str[100];
12470 
12471                   if (!l->hasconnected)
12472                      sprintf(str,"LINKFAIL,%s",l->name);
12473                   else
12474                      sprintf(str,"LINKDISC,%s",l->name);
12475                   donodelog(myrpt,str);
12476                }
12477                if (l->lastf1) ast_frfree(l->lastf1);
12478                l->lastf1 = NULL;
12479                if (l->lastf2) ast_frfree(l->lastf2);
12480                l->lastf2 = NULL;
12481                /* hang-up on call to device */
12482                ast_hangup(l->chan);
12483                ast_hangup(l->pchan);
12484                ast_free(l);
12485                rpt_mutex_lock(&myrpt->lock);
12486                break;
12487             }
12488             if (f->frametype == AST_FRAME_VOICE)
12489             {
12490                int ismuted,n1;
12491 
12492                if ((l->phonemode) && (l->phonevox))
12493                {
12494                   n1 = dovox(&l->vox,
12495                      f->data.ptr,f->datalen / 2);
12496                   if (n1 != l->wasvox)
12497                   {
12498                      if (debug)ast_log(LOG_DEBUG,"Link Node %s, vox %d\n",l->name,n1);
12499                      l->wasvox = n1;
12500                      l->voxtostate = 0;
12501                      if (n1) l->voxtotimer = myrpt->p.voxtimeout_ms;
12502                      else l->voxtotimer = 0;
12503                   }
12504                   if (l->lastrealrx || n1)
12505                   {
12506                      if (!myfirst)
12507                      {
12508                          x = 0;
12509                          AST_LIST_TRAVERSE(&l->rxq, f1,
12510                         frame_list) x++;
12511                          for(;x < myrpt->p.simplexphonedelay; x++)
12512                         {
12513                            f1 = ast_frdup(f);
12514                            memset(f1->data.ptr,0,f1->datalen);
12515                            AST_LIST_INSERT_TAIL(&l->rxq,
12516                               f1,frame_list);
12517                          }
12518                          myfirst = 1;
12519                      }
12520                      f1 = ast_frdup(f);
12521                      AST_LIST_INSERT_TAIL(&l->rxq,f1,frame_list);
12522                   } else myfirst = 0; 
12523                   x = 0;
12524                   AST_LIST_TRAVERSE(&l->rxq, f1,frame_list) x++;
12525                   if (!x)
12526                   {
12527                      memset(f->data.ptr,0,f->datalen);
12528                   }
12529                   else
12530                   {
12531                      ast_frfree(f);
12532                      f = AST_LIST_REMOVE_HEAD(&l->rxq,frame_list);
12533                   }
12534                   if (ioctl(l->chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
12535                   {
12536                      ismuted = 0;
12537                   }
12538                   /* if not receiving, zero-out audio */
12539                   ismuted |= (!l->lastrx);
12540                   if (l->dtmfed && l->phonemode) ismuted = 1;
12541                   l->dtmfed = 0;
12542                   if (ismuted)
12543                   {
12544                      memset(f->data.ptr,0,f->datalen);
12545                      if (l->lastf1)
12546                         memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12547                      if (l->lastf2)
12548                         memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12549                   } 
12550                   if (f) f2 = ast_frdup(f);
12551                   else f2 = NULL;
12552                   f1 = l->lastf2;
12553                   l->lastf2 = l->lastf1;
12554                   l->lastf1 = f2;
12555                   if (ismuted)
12556                   {
12557                      if (l->lastf1)
12558                         memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12559                      if (l->lastf2)
12560                         memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12561                   }
12562                   if (f1)
12563                   {
12564                      ast_write(l->pchan,f1);
12565                      ast_frfree(f1);
12566                   }
12567                }
12568                else
12569                {
12570                   if (!l->lastrx)
12571                      memset(f->data.ptr,0,f->datalen);
12572                   ast_write(l->pchan,f);
12573                }
12574             }
12575 #ifndef  OLD_ASTERISK
12576             else if (f->frametype == AST_FRAME_DTMF_BEGIN)
12577             {
12578                if (l->lastf1)
12579                   memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12580                if (l->lastf2)
12581                   memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12582                l->dtmfed = 1;
12583             }
12584 #endif
12585             if (f->frametype == AST_FRAME_TEXT)
12586             {
12587                handle_link_data(myrpt,l,f->data.ptr);
12588             }
12589             if (f->frametype == AST_FRAME_DTMF)
12590             {
12591                if (l->lastf1)
12592                   memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12593                if (l->lastf2)
12594                   memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12595                l->dtmfed = 1;
12596                handle_link_phone_dtmf(myrpt,l,f->subclass.integer);
12597             }
12598             if (f->frametype == AST_FRAME_CONTROL)
12599             {
12600                if (f->subclass.integer == AST_CONTROL_ANSWER)
12601                {
12602                   char lconnected = l->connected;
12603 
12604                   __kickshort(myrpt);
12605                   l->connected = 1;
12606                   l->hasconnected = 1;
12607                   l->thisconnected = 1;
12608                   l->elaptime = -1;
12609                   if (!l->phonemode) send_newkey(l->chan);
12610                   if (!l->isremote) l->retries = 0;
12611                   if (!lconnected) 
12612                   {
12613                      rpt_telemetry(myrpt,CONNECTED,l);
12614                      if (myrpt->p.archivedir)
12615                      {
12616                         char str[100];
12617 
12618                         if (l->mode)
12619                            sprintf(str,"LINKTRX,%s",l->name);
12620                         else
12621                            sprintf(str,"LINKMONITOR,%s",l->name);
12622                         donodelog(myrpt,str);
12623                      }
12624                   }     
12625                   else
12626                      l->reconnects++;
12627                }
12628                /* if RX key */
12629                if (f->subclass.integer == AST_CONTROL_RADIO_KEY)
12630                {
12631                   if (debug == 7 ) printf("@@@@ rx key\n");
12632                   l->lastrealrx = 1;
12633                   l->rerxtimer = 0;
12634                   if (!l->lastrx1)
12635                   {
12636                      if (myrpt->p.archivedir)
12637                      {
12638                         char str[100];
12639 
12640                         sprintf(str,"RXKEY,%s",l->name);
12641                         donodelog(myrpt,str);
12642                      }
12643                      l->lastrx1 = 1;
12644                   }
12645                }
12646                /* if RX un-key */
12647                if (f->subclass.integer == AST_CONTROL_RADIO_UNKEY)
12648                {
12649                   if (debug == 7) printf("@@@@ rx un-key\n");
12650                   l->lastrealrx = 0;
12651                   l->rerxtimer = 0;
12652                   if (l->lastrx1)
12653                   {
12654                      if (myrpt->p.archivedir)
12655                      {
12656                         char str[100];
12657 
12658                         sprintf(str,"RXUNKEY,%s",l->name);
12659                         donodelog(myrpt,str);
12660                      }
12661                      l->lastrx1 = 0;
12662                      if(myrpt->p.duplex) 
12663                         rpt_telemetry(myrpt,LINKUNKEY,l);
12664                   }
12665                }
12666                if (f->subclass.integer == AST_CONTROL_HANGUP)
12667                {
12668                   ast_frfree(f);
12669                   rpt_mutex_lock(&myrpt->lock);
12670                   __kickshort(myrpt);
12671                   rpt_mutex_unlock(&myrpt->lock);
12672                   if ((!l->outbound) && (!l->disced))
12673                   {
12674                      if ((l->name[0] == '0') || l->isremote)
12675                         l->disctime = 1;
12676                      else
12677                         l->disctime = DISC_TIME;
12678                      rpt_mutex_lock(&myrpt->lock);
12679                      ast_hangup(l->chan);
12680                      l->chan = 0;
12681                      break;
12682                   }
12683                   if (l->retrytimer) 
12684                   {
12685                      if (l->chan) ast_hangup(l->chan);
12686                      l->chan = 0;
12687                      rpt_mutex_lock(&myrpt->lock);
12688                      break;
12689                   }
12690                   if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
12691                   {
12692                      rpt_mutex_lock(&myrpt->lock);
12693                      if (l->chan) ast_hangup(l->chan);
12694                      l->chan = 0;
12695                      l->hasconnected = 1;
12696                      l->elaptime = 0;
12697                      l->retrytimer = RETRY_TIMER_MS;
12698                      l->connecttime = 0;
12699                      l->thisconnected = 0;
12700                      break;
12701                   }
12702                   rpt_mutex_lock(&myrpt->lock);
12703                   /* remove from queue */
12704                   remque((struct qelem *) l);
12705                   if (!strcmp(myrpt->cmdnode,l->name))
12706                      myrpt->cmdnode[0] = 0;
12707                   __kickshort(myrpt);
12708                   rpt_mutex_unlock(&myrpt->lock);
12709                   if (!l->hasconnected)
12710                      rpt_telemetry(myrpt,CONNFAIL,l);
12711                   else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
12712                   if (myrpt->p.archivedir)
12713                   {
12714                      char str[100];
12715 
12716                      if (!l->hasconnected)
12717                         sprintf(str,"LINKFAIL,%s",l->name);
12718                      else
12719                         sprintf(str,"LINKDISC,%s",l->name);
12720                      donodelog(myrpt,str);
12721                   }
12722                   if (l->lastf1) ast_frfree(l->lastf1);
12723                   l->lastf1 = NULL;
12724                   if (l->lastf2) ast_frfree(l->lastf2);
12725                   l->lastf2 = NULL;
12726                   /* hang-up on call to device */
12727                   ast_hangup(l->chan);
12728                   ast_hangup(l->pchan);
12729                   ast_free(l);
12730                   rpt_mutex_lock(&myrpt->lock);
12731                   break;
12732                }
12733             }
12734             ast_frfree(f);
12735             rpt_mutex_lock(&myrpt->lock);
12736             break;
12737          }
12738          if (who == l->pchan) 
12739          {
12740             rpt_mutex_unlock(&myrpt->lock);
12741             f = ast_read(l->pchan);
12742             if (!f)
12743             {
12744                if (debug) printf("@@@@ rpt:Hung Up\n");
12745                toexit = 1;
12746                rpt_mutex_lock(&myrpt->lock);
12747                break;
12748             }
12749             if (f->frametype == AST_FRAME_VOICE)
12750             {
12751                if (l->chan) ast_write(l->chan,f);
12752             }
12753             if (f->frametype == AST_FRAME_CONTROL)
12754             {
12755                if (f->subclass.integer == AST_CONTROL_HANGUP)
12756                {
12757                   if (debug) printf("@@@@ rpt:Hung Up\n");
12758                   ast_frfree(f);
12759                   toexit = 1;
12760                   rpt_mutex_lock(&myrpt->lock);
12761                   break;
12762                }
12763             }
12764             ast_frfree(f);
12765             rpt_mutex_lock(&myrpt->lock);
12766             break;
12767          }
12768          l = l->next;
12769       }
12770       rpt_mutex_unlock(&myrpt->lock);
12771       if (toexit) break;
12772       if (who == myrpt->monchannel) 
12773       {
12774          f = ast_read(myrpt->monchannel);
12775          if (!f)
12776          {
12777             if (debug) printf("@@@@ rpt:Hung Up\n");
12778             break;
12779          }
12780          if (f->frametype == AST_FRAME_VOICE)
12781          {
12782             if (myrpt->monstream) 
12783                ast_writestream(myrpt->monstream,f);
12784          }
12785          if (f->frametype == AST_FRAME_CONTROL)
12786          {
12787             if (f->subclass.integer == AST_CONTROL_HANGUP)
12788             {
12789                if (debug) printf("@@@@ rpt:Hung Up\n");
12790                ast_frfree(f);
12791                break;
12792             }
12793          }
12794          ast_frfree(f);
12795          continue;
12796       }
12797       if (myrpt->parrotchannel && (who == myrpt->parrotchannel))
12798       {
12799          f = ast_read(myrpt->parrotchannel);
12800          if (!f)
12801          {
12802             if (debug) printf("@@@@ rpt:Hung Up\n");
12803             break;
12804          }
12805          if (!myrpt->p.parrotmode)
12806          {
12807             char myfname[300];
12808 
12809             if (myrpt->parrotstream)
12810             {
12811                ast_closestream(myrpt->parrotstream);
12812                myrpt->parrotstream = 0;
12813             }
12814             sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
12815             strcat(myfname,".wav");
12816             unlink(myfname);        
12817          } else if (f->frametype == AST_FRAME_VOICE)
12818          {
12819             if (myrpt->parrotstream) 
12820                ast_writestream(myrpt->parrotstream,f);
12821          }
12822          if (f->frametype == AST_FRAME_CONTROL)
12823          {
12824             if (f->subclass.integer == AST_CONTROL_HANGUP)
12825             {
12826                if (debug) printf("@@@@ rpt:Hung Up\n");
12827                ast_frfree(f);
12828                break;
12829             }
12830          }
12831          ast_frfree(f);
12832          continue;
12833       }
12834       if (myrpt->voxchannel && (who == myrpt->voxchannel))
12835       {
12836          f = ast_read(myrpt->voxchannel);
12837          if (!f)
12838          {
12839             if (debug) printf("@@@@ rpt:Hung Up\n");
12840             break;
12841          }
12842          if (f->frametype == AST_FRAME_VOICE)
12843          {
12844             n = dovox(&myrpt->vox,f->data.ptr,f->datalen / 2);
12845             if (n != myrpt->wasvox)
12846             {
12847                if (debug) ast_log(LOG_DEBUG,"Node %s, vox %d\n",myrpt->name,n);
12848                myrpt->wasvox = n;
12849                myrpt->voxtostate = 0;
12850                if (n) myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
12851                else myrpt->voxtotimer = 0;
12852             }
12853          }
12854          if (f->frametype == AST_FRAME_CONTROL)
12855          {
12856             if (f->subclass.integer == AST_CONTROL_HANGUP)
12857             {
12858                if (debug) printf("@@@@ rpt:Hung Up\n");
12859                ast_frfree(f);
12860                break;
12861             }
12862          }
12863          ast_frfree(f);
12864          continue;
12865       }
12866       if (who == myrpt->txpchannel) /* if it was a read from remote tx */
12867       {
12868          f = ast_read(myrpt->txpchannel);
12869          if (!f)
12870          {
12871             if (debug) printf("@@@@ rpt:Hung Up\n");
12872             break;
12873          }
12874          if (f->frametype == AST_FRAME_CONTROL)
12875          {
12876             if (f->subclass.integer == AST_CONTROL_HANGUP)
12877             {
12878                if (debug) printf("@@@@ rpt:Hung Up\n");
12879                ast_frfree(f);
12880                break;
12881             }
12882          }
12883          ast_frfree(f);
12884          continue;
12885       }
12886    }
12887    usleep(100000);
12888    ast_hangup(myrpt->pchannel);
12889    ast_hangup(myrpt->monchannel);
12890    if (myrpt->parrotchannel) ast_hangup(myrpt->parrotchannel);
12891    myrpt->parrotstate = 0;
12892    if (myrpt->voxchannel) ast_hangup(myrpt->voxchannel);
12893    ast_hangup(myrpt->txpchannel);
12894    if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
12895    if (myrpt->dahditxchannel != myrpt->txchannel) ast_hangup(myrpt->dahditxchannel);
12896    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
12897    myrpt->lastf1 = NULL;
12898    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
12899    myrpt->lastf2 = NULL;
12900    ast_hangup(myrpt->rxchannel);
12901    rpt_mutex_lock(&myrpt->lock);
12902    l = myrpt->links.next;
12903    while(l != &myrpt->links)
12904    {
12905       struct rpt_link *ll = l;
12906       /* remove from queue */
12907       remque((struct qelem *) l);
12908       /* hang-up on call to device */
12909       if (l->chan) ast_hangup(l->chan);
12910       ast_hangup(l->pchan);
12911       l = l->next;
12912       ast_free(ll);
12913    }
12914    if (myrpt->xlink  == 1) myrpt->xlink = 2;
12915    rpt_mutex_unlock(&myrpt->lock);
12916    if (debug) printf("@@@@ rpt:Hung up channel\n");
12917    myrpt->rpt_thread = AST_PTHREADT_STOP;
12918    pthread_exit(NULL); 
12919    return NULL;
12920 }
12921 
12922    
12923 static void *rpt_master(void *ignore)
12924 {
12925 int   i,n;
12926 pthread_attr_t attr;
12927 struct ast_config *cfg;
12928 char *this,*val;
12929 
12930    /* init nodelog queue */
12931    nodelog.next = nodelog.prev = &nodelog;
12932    /* go thru all the specified repeaters */
12933    this = NULL;
12934    n = 0;
12935 #ifndef OLD_ASTERISK
12936    /* wait until asterisk starts */
12937         while(!ast_test_flag(&ast_options,AST_OPT_FLAG_FULLY_BOOTED))
12938                 usleep(250000);
12939 #endif
12940 #ifdef   NEW_ASTERISK
12941    rpt_vars[n].cfg = ast_config_load("rpt.conf",config_flags);
12942 #else
12943    rpt_vars[n].cfg = ast_config_load("rpt.conf");
12944 #endif
12945    cfg = rpt_vars[n].cfg;
12946    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
12947       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
12948       pthread_exit(NULL);
12949    }
12950    while((this = ast_category_browse(cfg,this)) != NULL)
12951    {
12952       for(i = 0 ; i < strlen(this) ; i++){
12953          if((this[i] < '0') || (this[i] > '9'))
12954             break;
12955       }
12956       if(i != strlen(this)) continue; /* Not a node defn */
12957       memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
12958       rpt_vars[n].name = ast_strdup(this);
12959       val = (char *) ast_variable_retrieve(cfg,this,"rxchannel");
12960       if (val) rpt_vars[n].rxchanname = ast_strdup(val);
12961       val = (char *) ast_variable_retrieve(cfg,this,"txchannel");
12962       if (val) rpt_vars[n].txchanname = ast_strdup(val);
12963       rpt_vars[n].remote = 0;
12964       rpt_vars[n].remoterig = "";
12965       val = (char *) ast_variable_retrieve(cfg,this,"remote");
12966       if (val) 
12967       {
12968          rpt_vars[n].remoterig = ast_strdup(val);
12969          rpt_vars[n].remote = 1;
12970       }
12971       val = (char *) ast_variable_retrieve(cfg,this,"radiotype");
12972       if (val) rpt_vars[n].remoterig = ast_strdup(val);
12973       ast_mutex_init(&rpt_vars[n].lock);
12974       ast_mutex_init(&rpt_vars[n].remlock);
12975       ast_mutex_init(&rpt_vars[n].statpost_lock);
12976       rpt_vars[n].tele.next = &rpt_vars[n].tele;
12977       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
12978       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
12979       rpt_vars[n].tailmessagen = 0;
12980 #ifdef   _MDC_DECODE_H_
12981       rpt_vars[n].mdc = mdc_decoder_new(8000);
12982 #endif
12983       n++;
12984    }
12985    nrpts = n;
12986    ast_config_destroy(cfg);
12987 
12988    /* start em all */
12989    for(i = 0; i < n; i++)
12990    {
12991       load_rpt_vars(i,1);
12992 
12993       /* if is a remote, don't start one for it */
12994       if (rpt_vars[i].remote)
12995       {
12996          if(retreive_memory(&rpt_vars[i],"init")){ /* Try to retreive initial memory channel */
12997             if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx450))
12998                strncpy(rpt_vars[i].freq, "446.500", sizeof(rpt_vars[i].freq) - 1);
12999             else
13000                strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
13001             strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
13002 
13003             strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
13004             rpt_vars[i].remmode = REM_MODE_FM;
13005             rpt_vars[i].offset = REM_SIMPLEX;
13006             rpt_vars[i].powerlevel = REM_LOWPWR;
13007          }
13008          continue;
13009       }
13010       else /* is a normal repeater */
13011       {
13012           rpt_vars[i].p.memory = rpt_vars[i].name;
13013          if(retreive_memory(&rpt_vars[i],"radiofreq")){ /* Try to retreive initial memory channel */
13014             if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx450))
13015                strncpy(rpt_vars[i].freq, "446.500", sizeof(rpt_vars[i].freq) - 1);
13016             else if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx150))
13017                strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
13018             strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
13019 
13020             strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
13021             rpt_vars[i].remmode = REM_MODE_FM;
13022             rpt_vars[i].offset = REM_SIMPLEX;
13023             rpt_vars[i].powerlevel = REM_LOWPWR;
13024          }
13025          ast_log(LOG_NOTICE,"Normal Repeater Init  %s  %s  %s\n",rpt_vars[i].name, rpt_vars[i].remoterig, rpt_vars[i].freq);
13026       }
13027       if (!rpt_vars[i].p.ident)
13028       {
13029          ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
13030          ast_config_destroy(cfg);
13031          pthread_exit(NULL);
13032       }
13033            pthread_attr_init(&attr);
13034            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13035       ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
13036    }
13037    usleep(500000);
13038    time(&starttime);
13039    for(;;)
13040    {
13041       /* Now monitor each thread, and restart it if necessary */
13042       for(i = 0; i < n; i++)
13043       { 
13044          int rv;
13045          if (rpt_vars[i].remote) continue;
13046          if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP) 
13047             rv = -1;
13048          else
13049             rv = pthread_kill(rpt_vars[i].rpt_thread,0);
13050          if (rv)
13051          {
13052             if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15)
13053             {
13054                if(rpt_vars[i].threadrestarts >= 5)
13055                {
13056                   ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n");
13057                   exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
13058                }
13059                else
13060                {
13061                   ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name);
13062                   rpt_vars[i].threadrestarts++;
13063                }
13064             }
13065             else
13066                rpt_vars[i].threadrestarts = 0;
13067 
13068             rpt_vars[i].lastthreadrestarttime = time(NULL);
13069                  pthread_attr_init(&attr);
13070                  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13071             ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
13072             /* if (!rpt_vars[i].xlink) */
13073                ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
13074          }
13075 
13076       }
13077       for(;;)
13078       {
13079          struct nodelog *nodep;
13080          char *space,datestr[100],fname[300];
13081          int fd;
13082 
13083          ast_mutex_lock(&nodeloglock);
13084          nodep = nodelog.next;
13085          if(nodep == &nodelog) /* if nothing in queue */
13086          {
13087             ast_mutex_unlock(&nodeloglock);
13088             break;
13089          }
13090          remque((struct qelem *)nodep);
13091          ast_mutex_unlock(&nodeloglock);
13092          space = strchr(nodep->str,' ');
13093          if (!space) 
13094          {
13095             ast_free(nodep);
13096             continue;
13097          }
13098          *space = 0;
13099          strftime(datestr,sizeof(datestr) - 1,"%Y%m%d",
13100             localtime(&nodep->timestamp));
13101          sprintf(fname,"%s/%s/%s.txt",nodep->archivedir,
13102             nodep->str,datestr);
13103          fd = open(fname,O_WRONLY | O_CREAT | O_APPEND,0600);
13104          if (fd == -1)
13105          {
13106             ast_log(LOG_ERROR,"Cannot open node log file %s for write",space + 1);
13107             ast_free(nodep);
13108             continue;
13109          }
13110          if (write(fd,space + 1,strlen(space + 1)) !=
13111             strlen(space + 1))
13112          {
13113             ast_log(LOG_ERROR,"Cannot write node log file %s for write",space + 1);
13114             ast_free(nodep);
13115             continue;
13116          }
13117          close(fd);
13118          ast_free(nodep);
13119       }
13120       sleep(2);
13121    }
13122    ast_config_destroy(cfg);
13123    pthread_exit(NULL);
13124 }
13125 
13126 static int rpt_exec(struct ast_channel *chan, const char *data)
13127 {
13128    int res=-1,i,rem_totx,rem_rx,remkeyed,n,phone_mode = 0;
13129    int iskenwood_pci4,authtold,authreq,setting,notremming,reming;
13130    int ismuted,dtmfed,phone_vox = 0;
13131 #ifdef   OLD_ASTERISK
13132    struct localuser *u;
13133 #endif
13134    char tmp[256], keyed = 0,keyed1 = 0;
13135    char *options,*stringp,*tele,c,*altp,*memp;
13136    char sx[320],*sy;
13137    struct   rpt *myrpt;
13138    struct ast_frame *f,*f1,*f2;
13139    struct ast_channel *who;
13140    struct ast_channel *cs[20];
13141    struct   rpt_link *l;
13142    struct dahdi_confinfo ci;  /* conference info */
13143    struct dahdi_params par;
13144    int ms,elap,nullfd;
13145    time_t t,last_timeout_warning;
13146    struct   dahdi_radio_param z;
13147    struct rpt_tele *telem;
13148    int   numlinks;
13149 
13150    nullfd = open("/dev/null",O_RDWR);
13151    if (ast_strlen_zero(data)) {
13152       ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
13153       return -1;
13154    }
13155 
13156    strncpy(tmp, (char *)data, sizeof(tmp)-1);
13157    time(&t);
13158    /* if time has externally shifted negative, screw it */
13159    if (t < starttime) t = starttime + START_DELAY;
13160    if ((!starttime) || (t < (starttime + START_DELAY)))
13161    {
13162       ast_log(LOG_NOTICE,"Node %s rejecting call: too soon!\n",tmp);
13163       ast_safe_sleep(chan,3000);
13164       return -1;
13165    }
13166 
13167    ast_log(LOG_NOTICE,"parsing argument=%s \n",tmp);
13168 
13169    altp=strstr(tmp, "|*");
13170    if(altp){
13171       altp[0]=0;
13172       altp++;
13173     }
13174 
13175    memp=strstr(tmp, "|M");
13176    if(memp){
13177       memp[0]=0;
13178       memp+=2;
13179     }
13180 
13181    stringp=tmp;
13182    strsep(&stringp, "|");
13183    options = stringp;
13184 
13185    ast_log(LOG_NOTICE,"options=%s \n",options);
13186    if(memp>0)ast_log(LOG_NOTICE,"memp=%s \n",memp);
13187    if(altp>0)ast_log(LOG_NOTICE,"altp=%s \n",altp);
13188 
13189    myrpt = NULL;
13190    /* see if we can find our specified one */
13191    for(i = 0; i < nrpts; i++)
13192    {
13193       /* if name matches, assign it and exit loop */
13194       if (!strcmp(tmp,rpt_vars[i].name))
13195       {
13196          myrpt = &rpt_vars[i];
13197          break;
13198       }
13199    }
13200 
13201    pbx_builtin_setvar_helper(chan, "RPT_STAT_ERR", "");
13202 
13203    if (myrpt == NULL)
13204    {
13205       pbx_builtin_setvar_helper(chan, "RPT_STAT_ERR", "NODE_NOT_FOUND");
13206       ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
13207       return (priority_jump(NULL,chan));
13208    }
13209 
13210    numlinks=linkcount(myrpt);
13211 
13212    if(options && *options == 'q')
13213    {
13214       char buf2[128];
13215 
13216       if(myrpt->keyed)
13217          pbx_builtin_setvar_helper(chan, "RPT_STAT_RXKEYED", "1");
13218       else
13219          pbx_builtin_setvar_helper(chan, "RPT_STAT_RXKEYED", "0");   
13220 
13221       if(myrpt->txkeyed)
13222          pbx_builtin_setvar_helper(chan, "RPT_STAT_TXKEYED", "1");
13223       else
13224          pbx_builtin_setvar_helper(chan, "RPT_STAT_TXKEYED", "0");   
13225 
13226       snprintf(buf2,sizeof(buf2),"%s=%i", "RPT_STAT_XLINK", myrpt->xlink);
13227       pbx_builtin_setvar(chan, buf2);
13228       snprintf(buf2,sizeof(buf2),"%s=%i", "RPT_STAT_LINKS", numlinks);
13229       pbx_builtin_setvar(chan, buf2);
13230       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_WASCHAN", myrpt->waschan);
13231       pbx_builtin_setvar(chan, buf2);
13232       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_NOWCHAN", myrpt->nowchan);
13233       pbx_builtin_setvar(chan, buf2);
13234       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_DUPLEX", myrpt->p.duplex);
13235       pbx_builtin_setvar(chan, buf2);
13236       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_PARROT", myrpt->p.parrotmode);
13237       pbx_builtin_setvar(chan, buf2);
13238       //snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_PHONEVOX", myrpt->phonevox);
13239       //pbx_builtin_setvar(chan, buf2);
13240       //snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_CONNECTED", myrpt->connected);
13241       //pbx_builtin_setvar(chan, buf2);
13242       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_CALLMODE", myrpt->callmode);
13243       pbx_builtin_setvar(chan, buf2);
13244       snprintf(buf2,sizeof(buf2),"%s=%s", "RPT_STAT_LASTTONE", myrpt->lasttone);
13245       pbx_builtin_setvar(chan, buf2);
13246 
13247       return priority_jump(myrpt,chan);
13248    }
13249 
13250    if(options && *options == 'o')
13251    {
13252       return(channel_revert(myrpt));
13253    }
13254 
13255    #if 0
13256    if((altp)&&(*options == 'Z'))
13257    {
13258       rpt_push_alt_macro(myrpt,altp);
13259       return 0;
13260    }
13261    #endif
13262 
13263 
13264    /* if not phone access, must be an IAX connection */
13265    if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R') || (*options == 'S')))
13266    {
13267       int val;
13268 
13269       pbx_builtin_setvar_helper(chan, "RPT_STAT_BUSY", "0");
13270        
13271       myrpt->bargechan=0;
13272       if(options && strstr(options, "f")>0)
13273       {
13274          myrpt->bargechan=1;     
13275       }
13276 
13277       if(memp>0)
13278       {
13279          char radiochan;
13280          radiochan=strtod(data,NULL);
13281          // if(myrpt->nowchan!=0 && radiochan!=myrpt->nowchan && !myrpt->bargechan)
13282 
13283          if(numlinks>0 && radiochan!=myrpt->nowchan && !myrpt->bargechan)
13284          {
13285             pbx_builtin_setvar_helper(chan, "RPT_STAT_BUSY", "1");
13286             ast_log(LOG_NOTICE, "Radio Channel Busy.\n");
13287             return (priority_jump(myrpt,chan));
13288          }
13289          else if(radiochan!=myrpt->nowchan || myrpt->bargechan)
13290          {
13291             channel_steer(myrpt,memp); 
13292          }
13293       }
13294       if(altp)rpt_push_alt_macro(myrpt,altp);
13295       phone_mode = 1;
13296       if (*options == 'D') phone_mode = 2;
13297       if (*options == 'S') phone_mode = 3;
13298       ast_set_callerid(chan,"0","app_rpt user","0");
13299       val = 1;
13300       ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
13301       if ((*(options + 1) == 'V') || (*(options + 1) == 'v')) phone_vox = 1;
13302    }
13303    else
13304    {
13305 #ifdef ALLOW_LOCAL_CHANNELS
13306            /* Check to insure the connection is IAX2 or Local*/
13307            if ( (strncmp(chan->name,"IAX2",4)) && (strncmp(chan->name,"Local",5)) ) {
13308                ast_log(LOG_WARNING, "We only accept links via IAX2 or Local!!\n");
13309                return -1;
13310            }
13311 #else
13312       if (strncmp(chan->name,"IAX2",4))
13313       {
13314          ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
13315          return -1;
13316       }
13317 #endif
13318            if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable){ /* Do not allow incoming radio connections if disabled */
13319                  ast_log(LOG_NOTICE, "Connect attempt to node %s  with tx disabled", myrpt->name);
13320                   return -1;
13321          }  
13322    }
13323    if (options && (*options == 'R'))
13324    {
13325       /* Parts of this section taken from app_parkandannounce */
13326       char *return_context;
13327       int length, m, lot, timeout = 0;
13328       char buffer[256],*template;
13329       char *working, *context, *exten, *priority;
13330       char *s,*orig_s;
13331 
13332       rpt_mutex_lock(&myrpt->lock);
13333       m = myrpt->callmode;
13334       rpt_mutex_unlock(&myrpt->lock);
13335 
13336       if ((!myrpt->p.nobusyout) && m)
13337       {
13338          if (chan->_state != AST_STATE_UP)
13339          {
13340             ast_indicate(chan,AST_CONTROL_BUSY);
13341          }
13342          while(ast_safe_sleep(chan,10000) != -1);
13343          return -1;
13344       }
13345 
13346       if (chan->_state != AST_STATE_UP)
13347       {
13348          ast_answer(chan);
13349          if (!phone_mode) send_newkey(chan);
13350       }
13351 
13352       length=strlen(options)+2;
13353       orig_s=ast_malloc(length);
13354       if(!orig_s) {
13355          ast_log(LOG_WARNING, "Out of memory\n");
13356          return -1;
13357       }
13358       s=orig_s;
13359       strncpy(s,options,length);
13360 
13361       template=strsep(&s,"|");
13362       if(!template) {
13363          ast_log(LOG_WARNING, "An announce template must be defined\n");
13364          ast_free(orig_s);
13365          return -1;
13366       } 
13367   
13368       if(s) {
13369          timeout = atoi(strsep(&s, "|"));
13370          timeout *= 1000;
13371       }
13372    
13373       return_context = s;
13374   
13375       if(return_context != NULL) {
13376          /* set the return context. Code borrowed from the Goto builtin */
13377     
13378          working = return_context;
13379          context = strsep(&working, "|");
13380          exten = strsep(&working, "|");
13381          if(!exten) {
13382             /* Only a priority in this one */
13383             priority = context;
13384             exten = NULL;
13385             context = NULL;
13386          } else {
13387             priority = strsep(&working, "|");
13388             if(!priority) {
13389                /* Only an extension and priority in this one */
13390                priority = exten;
13391                exten = context;
13392                context = NULL;
13393          }
13394       }
13395       if(atoi(priority) < 0) {
13396          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
13397          ast_free(orig_s);
13398          return -1;
13399       }
13400       /* At this point we have a priority and maybe an extension and a context */
13401       chan->priority = atoi(priority);
13402 #ifdef OLD_ASTERISK
13403       if(exten && strcasecmp(exten, "BYEXTENSION"))
13404 #else
13405       if(exten)
13406 #endif
13407          strncpy(chan->exten, exten, sizeof(chan->exten)-1);
13408       if(context)
13409          strncpy(chan->context, context, sizeof(chan->context)-1);
13410       } else {  /* increment the priority by default*/
13411          chan->priority++;
13412       }
13413 
13414       if(option_verbose > 2) {
13415          ast_verbose(VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n",
13416             chan->context, chan->exten, chan->priority,
13417             S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""));
13418          if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority,
13419             S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
13420             ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
13421          }
13422       }
13423   
13424       /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
13425       before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
13426 
13427       ast_masq_park_call(chan, NULL, timeout, &lot);
13428 
13429       if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
13430 
13431       snprintf(buffer, sizeof(buffer) - 1, "%d,%s", lot, template + 1);
13432 
13433       rpt_telemetry(myrpt,REV_PATCH,buffer);
13434 
13435       ast_free(orig_s);
13436 
13437       return 0;
13438 
13439    }
13440 
13441    if (!options)
13442    {
13443         struct ast_hostent ahp;
13444         struct hostent *hp;
13445         struct in_addr ia;
13446         char hisip[100],nodeip[100],*val, *s, *s1, *s2, *s3, *b,*b1;
13447 
13448       /* look at callerid to see what node this comes from */
13449       b = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL);
13450       if (!b) /* if doesn't have caller id */
13451       {
13452          ast_log(LOG_WARNING, "Does not have callerid on %s\n",tmp);
13453          return -1;
13454       }
13455       /* get his IP from IAX2 module */
13456       memset(hisip,0,sizeof(hisip));
13457 #ifdef ALLOW_LOCAL_CHANNELS
13458         /* set IP address if this is a local connection*/
13459         if (strncmp(chan->name,"Local",5)==0) {
13460             strcpy(hisip,"127.0.0.1");
13461         } else {
13462          pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
13463       }
13464 #else
13465       pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
13466 #endif
13467 
13468       if (!hisip[0])
13469       {
13470          ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
13471          return -1;
13472       }
13473       
13474       b1 = ast_strdupa(b);
13475       ast_shrink_phone_number(b1);
13476       if (!strcmp(myrpt->name,b1))
13477       {
13478          ast_log(LOG_WARNING, "Trying to link to self!!\n");
13479          return -1;
13480       }
13481 
13482       if (*b1 < '1')
13483       {
13484          ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n",b1);
13485          return -1;
13486       }
13487 
13488 
13489       /* look for his reported node string */
13490       val = node_lookup(myrpt,b1);
13491       if (!val)
13492       {
13493          ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
13494          return -1;
13495       }
13496       strncpy(tmp,val,sizeof(tmp) - 1);
13497       s = tmp;
13498       s1 = strsep(&s,",");
13499       if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
13500       {
13501          sy = strchr(s1,'/');    
13502          *sy = 0;
13503          sprintf(sx,"%s:4569/%s",s1,sy + 1);
13504          s1 = sx;
13505       }
13506       s2 = strsep(&s,",");
13507       if (!s2)
13508       {
13509          ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n",b1);
13510          return -1;
13511       }
13512                 if (strcmp(s2,"NONE")) {
13513          hp = ast_gethostbyname(s2, &ahp);
13514          if (!hp)
13515          {
13516             ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s2);
13517             return -1;
13518          }
13519          memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
13520 #ifdef   OLD_ASTERISK
13521          ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
13522 #else
13523          strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
13524 #endif
13525          s3 = strchr(hisip,':');
13526          if (s3) *s3 = 0;
13527          if (strcmp(hisip,nodeip))
13528          {
13529             s3 = strchr(s1,'@');
13530             if (s3) s1 = s3 + 1;
13531             s3 = strchr(s1,'/');
13532             if (s3) *s3 = 0;
13533             s3 = strchr(s1,':');
13534             if (s3) *s3 = 0;
13535             hp = ast_gethostbyname(s1, &ahp);
13536             if (!hp)
13537             {
13538                ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s1);
13539                return -1;
13540             }
13541             memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
13542 #ifdef   OLD_ASTERISK
13543             ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
13544 #else
13545             strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
13546 #endif
13547             if (strcmp(hisip,nodeip))
13548             {
13549                ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip);
13550                return -1;
13551             }
13552          }
13553       }
13554    }
13555 
13556    /* if is not a remote */
13557    if (!myrpt->remote)
13558    {
13559       char *b,*b1;
13560       int reconnects = 0;
13561 
13562       rpt_mutex_lock(&myrpt->lock);
13563       i = myrpt->xlink;
13564       rpt_mutex_unlock(&myrpt->lock);
13565       if (i)
13566       {
13567          ast_log(LOG_WARNING, "Cannot connect to node %s, system busy\n",myrpt->name);
13568          return -1;
13569       }
13570       /* look at callerid to see what node this comes from */
13571       b = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL);
13572       if (!b) /* if doesn't have caller id */
13573       {
13574          ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
13575          return -1;
13576       }
13577 
13578       b1 = ast_strdupa(b);
13579       ast_shrink_phone_number(b1);
13580       if (!strcmp(myrpt->name,b1))
13581       {
13582          ast_log(LOG_WARNING, "Trying to link to self!!\n");
13583          return -1;
13584       }
13585       rpt_mutex_lock(&myrpt->lock);
13586       l = myrpt->links.next;
13587       /* try to find this one in queue */
13588       while(l != &myrpt->links)
13589       {
13590          if (l->name[0] == '0') 
13591          {
13592             l = l->next;
13593             continue;
13594          }
13595          /* if found matching string */
13596          if (!strcmp(l->name,b1)) break;
13597          l = l->next;
13598       }
13599       /* if found */
13600       if (l != &myrpt->links) 
13601       {
13602          l->killme = 1;
13603          l->retries = l->max_retries + 1;
13604          l->disced = 2;
13605          reconnects = l->reconnects;
13606          reconnects++;
13607                         rpt_mutex_unlock(&myrpt->lock);
13608          usleep(500000);   
13609       } else 
13610          rpt_mutex_unlock(&myrpt->lock);
13611       /* establish call in tranceive mode */
13612       l = ast_malloc(sizeof(struct rpt_link));
13613       if (!l)
13614       {
13615          ast_log(LOG_WARNING, "Unable to malloc\n");
13616          pthread_exit(NULL);
13617       }
13618       /* zero the silly thing */
13619       memset((char *)l,0,sizeof(struct rpt_link));
13620       l->mode = 1;
13621       strncpy(l->name,b1,MAXNODESTR - 1);
13622       l->isremote = 0;
13623       l->chan = chan;
13624       l->connected = 1;
13625       l->thisconnected = 1;
13626       l->hasconnected = 1;
13627       l->reconnects = reconnects;
13628       l->phonemode = phone_mode;
13629       l->phonevox = phone_vox;
13630       l->lastf1 = NULL;
13631       l->lastf2 = NULL;
13632       l->dtmfed = 0;
13633       voxinit_link(l,1);
13634       ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
13635       ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
13636       /* allocate a pseudo-channel thru asterisk */
13637       l->pchan = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
13638       if (!l->pchan)
13639       {
13640          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
13641          pthread_exit(NULL);
13642       }
13643       ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
13644       ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
13645 #ifdef   AST_CDR_FLAG_POST_DISABLED
13646       if (l->pchan->cdr)
13647          ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
13648 #endif
13649       /* make a conference for the tx */
13650       ci.chan = 0;
13651       ci.confno = myrpt->conf;
13652       ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
13653       /* first put the channel on the conference in proper mode */
13654       if (ioctl(l->pchan->fds[0],DAHDI_SETCONF,&ci) == -1)
13655       {
13656          ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
13657          pthread_exit(NULL);
13658       }
13659       rpt_mutex_lock(&myrpt->lock);
13660       if ((phone_mode == 2) && (!phone_vox)) l->lastrealrx = 1;
13661       l->max_retries = MAX_RETRIES;
13662       /* insert at end of queue */
13663       insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
13664       __kickshort(myrpt);
13665       rpt_mutex_unlock(&myrpt->lock);
13666       if (chan->_state != AST_STATE_UP) {
13667          ast_answer(chan);
13668          if (!phone_mode) send_newkey(chan);
13669       }
13670       if (myrpt->p.archivedir)
13671       {
13672          char str[100];
13673 
13674          if (l->phonemode)
13675             sprintf(str,"LINK(P),%s",l->name);
13676          else
13677             sprintf(str,"LINK,%s",l->name);
13678          donodelog(myrpt,str);
13679       }
13680       if (!phone_mode) send_newkey(chan);
13681       return 0;
13682    }
13683    /* well, then it is a remote */
13684    rpt_mutex_lock(&myrpt->lock);
13685    /* if remote, error if anyone else already linked */
13686    if (myrpt->remoteon)
13687    {
13688       rpt_mutex_unlock(&myrpt->lock);
13689       usleep(500000);
13690       if (myrpt->remoteon)
13691       {
13692          ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
13693 #ifdef   AST_CDR_FLAG_POST_DISABLED
13694          if (chan->cdr)
13695             ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13696 #endif
13697          return -1;
13698       }     
13699       rpt_mutex_lock(&myrpt->lock);
13700    }
13701    if (myrpt->p.rptnode)
13702    {
13703       char killedit = 0;
13704       time_t now;
13705 
13706       time(&now);
13707       for(i = 0; i < nrpts; i++)
13708       {
13709          if (!strcasecmp(rpt_vars[i].name,myrpt->p.rptnode))
13710          {
13711             if ((rpt_vars[i].links.next != &rpt_vars[i].links) ||
13712                rpt_vars[i].keyed ||
13713                 ((rpt_vars[i].lastkeyedtime + RPT_LOCKOUT_SECS) > now) ||
13714                  rpt_vars[i].txkeyed ||
13715                   ((rpt_vars[i].lasttxkeyedtime + RPT_LOCKOUT_SECS) > now))
13716             {
13717                rpt_mutex_unlock(&myrpt->lock);
13718                ast_log(LOG_WARNING, "Trying to use busy link (repeater node %s) on %s\n",rpt_vars[i].name,tmp);
13719 #ifdef   AST_CDR_FLAG_POST_DISABLED
13720                if (chan->cdr)
13721                   ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13722 #endif
13723                return -1;
13724             }
13725             while(rpt_vars[i].xlink != 3)
13726             {
13727                if (!killedit)
13728                {
13729                   ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
13730                   rpt_vars[i].xlink = 1;
13731                   killedit = 1;
13732                }
13733                rpt_mutex_unlock(&myrpt->lock);
13734                if (ast_safe_sleep(chan,500) == -1)
13735                {
13736 #ifdef   AST_CDR_FLAG_POST_DISABLED
13737                   if (chan->cdr)
13738                      ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13739 #endif
13740                   return -1;
13741                }
13742                rpt_mutex_lock(&myrpt->lock);
13743             }
13744             break;
13745          }
13746       }
13747    }
13748 
13749 #ifdef HAVE_IOPERM
13750    if ( (!strcmp(myrpt->remoterig, remote_rig_rbi)||!strcmp(myrpt->remoterig, remote_rig_ppp16)) &&
13751      (ioperm(myrpt->p.iobase,1,1) == -1))
13752    {
13753       rpt_mutex_unlock(&myrpt->lock);
13754       ast_log(LOG_WARNING, "Can't get io permission on IO port %x hex\n",myrpt->p.iobase);
13755       return -1;
13756    }
13757 #endif
13758    myrpt->remoteon = 1;
13759 #ifdef   OLD_ASTERISK
13760    LOCAL_USER_ADD(u);
13761 #endif
13762    rpt_mutex_unlock(&myrpt->lock);
13763    /* find our index, and load the vars initially */
13764    for(i = 0; i < nrpts; i++)
13765    {
13766       if (&rpt_vars[i] == myrpt)
13767       {
13768          load_rpt_vars(i,0);
13769          break;
13770       }
13771    }
13772    rpt_mutex_lock(&myrpt->lock);
13773    tele = strchr(myrpt->rxchanname,'/');
13774    if (!tele)
13775    {
13776       fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
13777       rpt_mutex_unlock(&myrpt->lock);
13778       pthread_exit(NULL);
13779    }
13780    *tele++ = 0;
13781    myrpt->rxchannel = ast_request(myrpt->rxchanname, AST_FORMAT_SLINEAR, NULL, tele, NULL);
13782    myrpt->dahdirxchannel = NULL;
13783    if (!strcasecmp(myrpt->rxchanname,"DAHDI"))
13784       myrpt->dahdirxchannel = myrpt->rxchannel;
13785    if (myrpt->rxchannel)
13786    {
13787       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
13788       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
13789 #ifdef   AST_CDR_FLAG_POST_DISABLED
13790       if (myrpt->rxchannel->cdr)
13791          ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13792 #endif
13793 #ifndef  NEW_ASTERISK
13794       myrpt->rxchannel->whentohangup = 0;
13795 #endif
13796       myrpt->rxchannel->appl = "Apprpt";
13797       myrpt->rxchannel->data = "(Link Rx)";
13798       if (option_verbose > 2)
13799          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
13800             myrpt->rxchanname,tele,myrpt->rxchannel->name);
13801       rpt_mutex_unlock(&myrpt->lock);
13802       ast_call(myrpt->rxchannel,tele,999);
13803       rpt_mutex_lock(&myrpt->lock);
13804    }
13805    else
13806    {
13807       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
13808       rpt_mutex_unlock(&myrpt->lock);
13809       pthread_exit(NULL);
13810    }
13811    *--tele = '/';
13812    myrpt->dahditxchannel = NULL;
13813    if (myrpt->txchanname)
13814    {
13815       tele = strchr(myrpt->txchanname,'/');
13816       if (!tele)
13817       {
13818          fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
13819          rpt_mutex_unlock(&myrpt->lock);
13820          ast_hangup(myrpt->rxchannel);
13821          pthread_exit(NULL);
13822       }
13823       *tele++ = 0;
13824       myrpt->txchannel = ast_request(myrpt->txchanname, AST_FORMAT_SLINEAR, NULL, tele, NULL);
13825       if (!strncasecmp(myrpt->txchanname,"DAHDI",3))
13826          myrpt->dahditxchannel = myrpt->txchannel;
13827       if (myrpt->txchannel)
13828       {
13829          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
13830          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
13831 #ifdef   AST_CDR_FLAG_POST_DISABLED
13832          if (myrpt->txchannel->cdr)
13833             ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13834 #endif
13835 #ifndef  NEW_ASTERISK
13836          myrpt->txchannel->whentohangup = 0;
13837 #endif
13838          myrpt->txchannel->appl = "Apprpt";
13839          myrpt->txchannel->data = "(Link Tx)";
13840          if (option_verbose > 2)
13841             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
13842                myrpt->txchanname,tele,myrpt->txchannel->name);
13843          rpt_mutex_unlock(&myrpt->lock);
13844          ast_call(myrpt->txchannel,tele,999);
13845          rpt_mutex_lock(&myrpt->lock);
13846       }
13847       else
13848       {
13849          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
13850          rpt_mutex_unlock(&myrpt->lock);
13851          ast_hangup(myrpt->rxchannel);
13852          pthread_exit(NULL);
13853       }
13854       *--tele = '/';
13855    }
13856    else
13857    {
13858       myrpt->txchannel = myrpt->rxchannel;
13859       if (!strncasecmp(myrpt->rxchanname,"DAHDI",3))
13860          myrpt->dahditxchannel = myrpt->rxchannel;
13861    }
13862    /* allocate a pseudo-channel thru asterisk */
13863    myrpt->pchannel = ast_request("DAHDI", AST_FORMAT_SLINEAR, NULL, "pseudo", NULL);
13864    if (!myrpt->pchannel)
13865    {
13866       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
13867       rpt_mutex_unlock(&myrpt->lock);
13868       if (myrpt->txchannel != myrpt->rxchannel) 
13869          ast_hangup(myrpt->txchannel);
13870       ast_hangup(myrpt->rxchannel);
13871       pthread_exit(NULL);
13872    }
13873    ast_set_read_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
13874    ast_set_write_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
13875 #ifdef   AST_CDR_FLAG_POST_DISABLED
13876    if (myrpt->pchannel->cdr)
13877       ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13878 #endif
13879    if (!myrpt->dahdirxchannel) myrpt->dahdirxchannel = myrpt->pchannel;
13880    if (!myrpt->dahditxchannel) myrpt->dahditxchannel = myrpt->pchannel;
13881    /* make a conference for the pseudo */
13882    ci.chan = 0;
13883    ci.confno = -1; /* make a new conf */
13884    ci.confmode = DAHDI_CONF_CONFANNMON ;
13885    /* first put the channel on the conference in announce/monitor mode */
13886    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
13887    {
13888       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
13889       rpt_mutex_unlock(&myrpt->lock);
13890       ast_hangup(myrpt->pchannel);
13891       if (myrpt->txchannel != myrpt->rxchannel) 
13892          ast_hangup(myrpt->txchannel);
13893       ast_hangup(myrpt->rxchannel);
13894       pthread_exit(NULL);
13895    }
13896    /* save pseudo channel conference number */
13897    myrpt->conf = myrpt->txconf = ci.confno;
13898    /* if serial io port, open it */
13899    myrpt->iofd = -1;
13900    if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt,myrpt->p.ioport)) == -1))
13901    {
13902       rpt_mutex_unlock(&myrpt->lock);
13903       ast_hangup(myrpt->pchannel);
13904       if (myrpt->txchannel != myrpt->rxchannel) 
13905          ast_hangup(myrpt->txchannel);
13906       ast_hangup(myrpt->rxchannel);
13907       pthread_exit(NULL);
13908    }
13909    iskenwood_pci4 = 0;
13910    memset(&z,0,sizeof(z));
13911    if ((myrpt->iofd < 1) && (myrpt->txchannel == myrpt->dahditxchannel))
13912    {
13913       z.radpar = DAHDI_RADPAR_REMMODE;
13914       z.data = DAHDI_RADPAR_REM_NONE;
13915       res = ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z);
13916       /* if PCIRADIO and kenwood selected */
13917       if ((!res) && (!strcmp(myrpt->remoterig,remote_rig_kenwood)))
13918       {
13919          z.radpar = DAHDI_RADPAR_UIOMODE;
13920          z.data = 1;
13921          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13922          {
13923             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
13924             return -1;
13925          }
13926          z.radpar = DAHDI_RADPAR_UIODATA;
13927          z.data = 3;
13928          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13929          {
13930             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
13931             return -1;
13932          }
13933          i = DAHDI_OFFHOOK;
13934          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i) == -1)
13935          {
13936             ast_log(LOG_ERROR,"Cannot set hook\n");
13937             return -1;
13938          }
13939          iskenwood_pci4 = 1;
13940       }
13941    }
13942    if (myrpt->txchannel == myrpt->dahditxchannel)
13943    {
13944       i = DAHDI_ONHOOK;
13945       ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i);
13946       /* if PCIRADIO and Yaesu ft897/ICOM IC-706 selected */
13947       if ((myrpt->iofd < 1) && (!res) &&
13948          ((!strcmp(myrpt->remoterig,remote_rig_ft897)) ||
13949             (!strcmp(myrpt->remoterig,remote_rig_ic706)) ||
13950                (!strcmp(myrpt->remoterig,remote_rig_tm271))))
13951       {
13952          z.radpar = DAHDI_RADPAR_UIOMODE;
13953          z.data = 1;
13954          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13955          {
13956             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
13957             return -1;
13958          }
13959          z.radpar = DAHDI_RADPAR_UIODATA;
13960          z.data = 3;
13961          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13962          {
13963             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
13964             return -1;
13965          }
13966       }
13967    }
13968    myrpt->remoterx = 0;
13969    myrpt->remotetx = 0;
13970    myrpt->retxtimer = 0;
13971    myrpt->rerxtimer = 0;
13972    myrpt->remoteon = 1;
13973    myrpt->dtmfidx = -1;
13974    myrpt->dtmfbuf[0] = 0;
13975    myrpt->dtmf_time_rem = 0;
13976    myrpt->hfscanmode = 0;
13977    myrpt->hfscanstatus = 0;
13978    if (myrpt->p.startupmacro)
13979    {
13980       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
13981    }
13982    time(&myrpt->start_time);
13983    myrpt->last_activity_time = myrpt->start_time;
13984    last_timeout_warning = 0;
13985    myrpt->reload = 0;
13986    myrpt->tele.next = &myrpt->tele;
13987    myrpt->tele.prev = &myrpt->tele;
13988    myrpt->newkey = 0;
13989    rpt_mutex_unlock(&myrpt->lock);
13990    ast_set_write_format(chan, AST_FORMAT_SLINEAR);
13991    ast_set_read_format(chan, AST_FORMAT_SLINEAR);
13992    rem_rx = 0;
13993    remkeyed = 0;
13994    /* if we are on 2w loop and are a remote, turn EC on */
13995    if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
13996    {
13997       i = 128;
13998       ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_ECHOCANCEL,&i);
13999    }
14000    if (chan->_state != AST_STATE_UP) {
14001       ast_answer(chan);
14002       if (!phone_mode) send_newkey(chan);
14003    }
14004 
14005    if (myrpt->rxchannel == myrpt->dahdirxchannel)
14006    {
14007       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_GET_PARAMS,&par) != -1)
14008       {
14009          if (par.rxisoffhook)
14010          {
14011             ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14012             myrpt->remoterx = 1;
14013             remkeyed = 1;
14014          }
14015       }
14016    }
14017    if (myrpt->p.archivedir)
14018    {
14019       char mycmd[100],mydate[100],*b,*b1;
14020       time_t myt;
14021       long blocksleft;
14022 
14023 
14024       mkdir(myrpt->p.archivedir,0600);
14025       sprintf(mycmd,"%s/%s",myrpt->p.archivedir,myrpt->name);
14026       mkdir(mycmd,0600);
14027       time(&myt);
14028       strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
14029          localtime(&myt));
14030       sprintf(mycmd,"mixmonitor start %s %s/%s/%s.wav49 a",chan->name,
14031          myrpt->p.archivedir,myrpt->name,mydate);
14032       if (myrpt->p.monminblocks)
14033       {
14034          blocksleft = diskavail(myrpt);
14035          if (myrpt->p.remotetimeout)
14036          {
14037             blocksleft -= (myrpt->p.remotetimeout *
14038                MONITOR_DISK_BLOCKS_PER_MINUTE) / 60;
14039          }
14040          if (blocksleft >= myrpt->p.monminblocks)
14041             ast_cli_command(nullfd,mycmd);
14042       } else ast_cli_command(nullfd,mycmd);
14043       /* look at callerid to see what node this comes from */
14044       b = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL);
14045       if (!b) /* if doesn't have caller id */
14046       {
14047          b1 = "0";
14048       } else {
14049          b1 = ast_strdupa(b);
14050          ast_shrink_phone_number(b1);
14051       }
14052       sprintf(mycmd,"CONNECT,%s",b1);
14053       donodelog(myrpt,mycmd);
14054    }
14055    myrpt->loginuser[0] = 0;
14056    myrpt->loginlevel[0] = 0;
14057    myrpt->authtelltimer = 0;
14058    myrpt->authtimer = 0;
14059    authtold = 0;
14060    authreq = 0;
14061    if (myrpt->p.authlevel > 1) authreq = 1;
14062    setrem(myrpt); 
14063    n = 0;
14064    dtmfed = 0;
14065    cs[n++] = chan;
14066    cs[n++] = myrpt->rxchannel;
14067    cs[n++] = myrpt->pchannel;
14068    if (myrpt->rxchannel != myrpt->txchannel)
14069       cs[n++] = myrpt->txchannel;
14070    if (!phone_mode) send_newkey(chan);
14071    /* start un-locked */
14072    for(;;) 
14073    {
14074       if (ast_check_hangup(chan)) break;
14075       if (ast_check_hangup(myrpt->rxchannel)) break;
14076       notremming = 0;
14077       setting = 0;
14078       reming = 0;
14079       telem = myrpt->tele.next;
14080       while(telem != &myrpt->tele)
14081       {
14082          if (telem->mode == SETREMOTE) setting = 1;
14083          if ((telem->mode == SETREMOTE) ||
14084              (telem->mode == SCAN) ||
14085             (telem->mode == TUNE))  reming = 1;
14086          else notremming = 1;
14087          telem = telem->next;
14088       }
14089       if (myrpt->reload)
14090       {
14091          myrpt->reload = 0;
14092          /* find our index, and load the vars */
14093          for(i = 0; i < nrpts; i++)
14094          {
14095             if (&rpt_vars[i] == myrpt)
14096             {
14097                load_rpt_vars(i,0);
14098                break;
14099             }
14100          }
14101       }
14102       time(&t);
14103       if (myrpt->p.remotetimeout)
14104       { 
14105          time_t r;
14106 
14107          r = (t - myrpt->start_time);
14108          if (r >= myrpt->p.remotetimeout)
14109          {
14110             saynode(myrpt,chan,myrpt->name);
14111             sayfile(chan,"rpt/timeout");
14112             ast_safe_sleep(chan,1000);
14113             break;
14114          }
14115          if ((myrpt->p.remotetimeoutwarning) && 
14116              (r >= (myrpt->p.remotetimeout -
14117             myrpt->p.remotetimeoutwarning)) &&
14118                 (r <= (myrpt->p.remotetimeout - 
14119                   myrpt->p.remotetimeoutwarningfreq)))
14120          {
14121             if (myrpt->p.remotetimeoutwarningfreq)
14122             {
14123                 if ((t - last_timeout_warning) >=
14124                myrpt->p.remotetimeoutwarningfreq)
14125                 {
14126                time(&last_timeout_warning);
14127                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
14128                 }
14129             }
14130             else
14131             {
14132                 if (!last_timeout_warning)
14133                 {
14134                time(&last_timeout_warning);
14135                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
14136                 }
14137             }
14138          }
14139       }
14140       if (myrpt->p.remoteinacttimeout && myrpt->last_activity_time)
14141       { 
14142          time_t r;
14143 
14144          r = (t - myrpt->last_activity_time);
14145          if (r >= myrpt->p.remoteinacttimeout)
14146          {
14147             saynode(myrpt,chan,myrpt->name);
14148             ast_safe_sleep(chan,1000);
14149             break;
14150          }
14151          if ((myrpt->p.remotetimeoutwarning) && 
14152              (r >= (myrpt->p.remoteinacttimeout -
14153             myrpt->p.remotetimeoutwarning)) &&
14154                 (r <= (myrpt->p.remoteinacttimeout - 
14155                   myrpt->p.remotetimeoutwarningfreq)))
14156          {
14157             if (myrpt->p.remotetimeoutwarningfreq)
14158             {
14159                 if ((t - last_timeout_warning) >=
14160                myrpt->p.remotetimeoutwarningfreq)
14161                 {
14162                time(&last_timeout_warning);
14163                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
14164                 }
14165             }
14166             else
14167             {
14168                 if (!last_timeout_warning)
14169                 {
14170                time(&last_timeout_warning);
14171                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
14172                 }
14173             }
14174          }
14175       }
14176       ms = MSWAIT;
14177       who = ast_waitfor_n(cs,n,&ms);
14178       if (who == NULL) ms = 0;
14179       elap = MSWAIT - ms;
14180       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
14181       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
14182       if (!ms) continue;
14183       /* do local dtmf timer */
14184       if (myrpt->dtmf_local_timer)
14185       {
14186          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
14187          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
14188       }
14189       rpt_mutex_lock(&myrpt->lock);
14190       do_dtmf_local(myrpt,0);
14191       rpt_mutex_unlock(&myrpt->lock);
14192       //
14193       rem_totx =  myrpt->dtmf_local_timer && (!phone_mode);
14194       rem_totx |= keyed && (!myrpt->tunerequest);
14195       rem_rx = (remkeyed && (!setting)) || (myrpt->tele.next != &myrpt->tele);
14196       if(!strcmp(myrpt->remoterig, remote_rig_ic706))
14197          rem_totx |= myrpt->tunerequest;
14198       //
14199        if((debug > 6) && rem_totx) {
14200          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);
14201       }
14202       if (keyed && (!keyed1))
14203       {
14204          keyed1 = 1;
14205       }
14206 
14207       if (!keyed && (keyed1))
14208       {
14209          time_t myt;
14210 
14211          keyed1 = 0;
14212          time(&myt);
14213          /* if login necessary, and not too soon */
14214          if ((myrpt->p.authlevel) && 
14215              (!myrpt->loginlevel[0]) &&
14216             (myt > (t + 3)))
14217          {
14218             authreq = 1;
14219             authtold = 0;
14220             myrpt->authtelltimer = AUTHTELLTIME - AUTHTXTIME;
14221          }
14222       }
14223 
14224       if (rem_rx && (!myrpt->remoterx))
14225       {
14226          myrpt->remoterx = 1;
14227          ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14228       }
14229       if ((!rem_rx) && (myrpt->remoterx))
14230       {
14231          myrpt->remoterx = 0;
14232          ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
14233       }
14234       /* if auth requested, and not authed yet */
14235       if (authreq && (!myrpt->loginlevel[0]))
14236       {
14237          if ((!authtold) && ((myrpt->authtelltimer += elap)
14238              >= AUTHTELLTIME))
14239          {
14240             authtold = 1;
14241             rpt_telemetry(myrpt,LOGINREQ,NULL);
14242          }
14243          if ((myrpt->authtimer += elap) >= AUTHLOGOUTTIME)
14244          {
14245             break; /* if not logged in, hang up after a time */
14246          }
14247       }
14248       if (myrpt->newkey)
14249       {
14250          if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
14251          {
14252             myrpt->retxtimer = 0;
14253             if ((myrpt->remoterx) && (!myrpt->remotetx))
14254                ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14255             else
14256                ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
14257          }
14258 
14259          if ((myrpt->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 2))
14260          {
14261             keyed = 0;
14262             myrpt->rerxtimer = 0;
14263          }
14264       }
14265       if (rem_totx && (!myrpt->remotetx))
14266       {
14267          /* if not authed, and needed, do not transmit */
14268          if ((!myrpt->p.authlevel) || myrpt->loginlevel[0])
14269          {
14270             if(debug > 6)
14271                ast_log(LOG_NOTICE,"Handle rem_totx=%i.  dtmf_local_timer=%i  tunerequest=%i\n",rem_totx,myrpt->dtmf_local_timer,myrpt->tunerequest);
14272 
14273             myrpt->remotetx = 1;
14274             /* asdf maw ??? is this really what you want? Doesn't it always get executed? */
14275             if((myrpt->remtxfreqok = check_tx_freq(myrpt)))
14276             {
14277                time(&myrpt->last_activity_time);
14278                if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14279                {
14280                   z.radpar = DAHDI_RADPAR_UIODATA;
14281                   z.data = 1;
14282                   if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14283                   {
14284                      ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14285                      return -1;
14286                   }
14287                }
14288                else
14289                {
14290                   ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
14291                }
14292                if (myrpt->p.archivedir) donodelog(myrpt,"TXKEY");
14293             }
14294          }
14295       }
14296       if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
14297       {
14298          myrpt->remotetx = 0;
14299          if(!myrpt->remtxfreqok){
14300             rpt_telemetry(myrpt,UNAUTHTX,NULL);
14301          }
14302          if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14303          {
14304             z.radpar = DAHDI_RADPAR_UIODATA;
14305             z.data = 3;
14306             if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14307             {
14308                ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14309                return -1;
14310             }
14311          }
14312          else
14313          {
14314             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
14315          }
14316          if (myrpt->p.archivedir) donodelog(myrpt,"TXUNKEY");
14317       }
14318       if (myrpt->hfscanmode){
14319          myrpt->scantimer -= elap;
14320          if(myrpt->scantimer <= 0){
14321             if (!reming)
14322             {
14323                myrpt->scantimer = REM_SCANTIME;
14324                rpt_telemetry(myrpt,SCAN,0);
14325             } else myrpt->scantimer = 1;
14326          }
14327       }
14328       rpt_mutex_lock(&myrpt->lock);
14329       c = myrpt->macrobuf[0];
14330       if (c && (!myrpt->macrotimer))
14331       {
14332          myrpt->macrotimer = MACROTIME;
14333          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
14334          if ((c == 'p') || (c == 'P'))
14335             myrpt->macrotimer = MACROPTIME;
14336          rpt_mutex_unlock(&myrpt->lock);
14337          if (myrpt->p.archivedir)
14338          {
14339             char str[100];
14340                sprintf(str,"DTMF(M),%c",c);
14341             donodelog(myrpt,str);
14342          }
14343          if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
14344          continue;
14345       } else rpt_mutex_unlock(&myrpt->lock);
14346       if (who == chan) /* if it was a read from incoming */
14347       {
14348          f = ast_read(chan);
14349          if (!f)
14350          {
14351             if (debug) printf("@@@@ link:Hung Up\n");
14352             break;
14353          }
14354          if (f->frametype == AST_FRAME_VOICE)
14355          {
14356             if (ioctl(chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
14357             {
14358                ismuted = 0;
14359             }
14360             /* if not transmitting, zero-out audio */
14361             ismuted |= (!myrpt->remotetx);
14362             if (dtmfed && phone_mode) ismuted = 1;
14363             dtmfed = 0;
14364             if (ismuted)
14365             {
14366                memset(f->data.ptr,0,f->datalen);
14367                if (myrpt->lastf1)
14368                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14369                if (myrpt->lastf2)
14370                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14371             } 
14372             if (f) f2 = ast_frdup(f);
14373             else f2 = NULL;
14374             f1 = myrpt->lastf2;
14375             myrpt->lastf2 = myrpt->lastf1;
14376             myrpt->lastf1 = f2;
14377             if (ismuted)
14378             {
14379                if (myrpt->lastf1)
14380                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14381                if (myrpt->lastf2)
14382                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14383             }
14384             if (f1)
14385             {
14386                if (phone_mode)
14387                   ast_write(myrpt->txchannel,f1);
14388                else
14389                   ast_write(myrpt->txchannel,f);
14390                ast_frfree(f1);
14391             }
14392          }
14393 #ifndef  OLD_ASTERISK
14394          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
14395          {
14396             if (myrpt->lastf1)
14397                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14398             if (myrpt->lastf2)
14399                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14400             dtmfed = 1;
14401          }
14402 #endif
14403          if (f->frametype == AST_FRAME_DTMF)
14404          {
14405             if (myrpt->lastf1)
14406                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14407             if (myrpt->lastf2)
14408                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14409             dtmfed = 1;
14410             if (handle_remote_phone_dtmf(myrpt,f->subclass.integer,&keyed,phone_mode) == -1)
14411             {
14412                if (debug) printf("@@@@ rpt:Hung Up\n");
14413                ast_frfree(f);
14414                break;
14415             }
14416          }
14417          if (f->frametype == AST_FRAME_TEXT)
14418          {
14419             if (handle_remote_data(myrpt,f->data.ptr) == -1)
14420             {
14421                if (debug) printf("@@@@ rpt:Hung Up\n");
14422                ast_frfree(f);
14423                break;
14424             }
14425          }
14426          if (f->frametype == AST_FRAME_CONTROL)
14427          {
14428             if (f->subclass.integer == AST_CONTROL_HANGUP)
14429             {
14430                if (debug) printf("@@@@ rpt:Hung Up\n");
14431                ast_frfree(f);
14432                break;
14433             }
14434             /* if RX key */
14435             if (f->subclass.integer == AST_CONTROL_RADIO_KEY)
14436             {
14437                if (debug == 7) printf("@@@@ rx key\n");
14438                keyed = 1;
14439                myrpt->rerxtimer = 0;
14440             }
14441             /* if RX un-key */
14442             if (f->subclass.integer == AST_CONTROL_RADIO_UNKEY)
14443             {
14444                myrpt->rerxtimer = 0;
14445                if (debug == 7) printf("@@@@ rx un-key\n");
14446                keyed = 0;
14447             }
14448          }
14449          ast_frfree(f);
14450          continue;
14451       }
14452       if (who == myrpt->rxchannel) /* if it was a read from radio */
14453       {
14454          f = ast_read(myrpt->rxchannel);
14455          if (!f)
14456          {
14457             if (debug) printf("@@@@ link:Hung Up\n");
14458             break;
14459          }
14460          if (f->frametype == AST_FRAME_VOICE)
14461          {
14462             int myreming = 0;
14463 
14464             if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
14465                myreming = reming;
14466 
14467             if (myreming || (!remkeyed) ||
14468             ((myrpt->remote) && (myrpt->remotetx)) ||
14469               ((myrpt->remmode != REM_MODE_FM) &&
14470                 notremming))
14471                memset(f->data.ptr,0,f->datalen); 
14472              ast_write(myrpt->pchannel,f);
14473          }
14474          else if (f->frametype == AST_FRAME_CONTROL)
14475          {
14476             if (f->subclass.integer == AST_CONTROL_HANGUP)
14477             {
14478                if (debug) printf("@@@@ rpt:Hung Up\n");
14479                ast_frfree(f);
14480                break;
14481             }
14482             /* if RX key */
14483             if (f->subclass.integer == AST_CONTROL_RADIO_KEY)
14484             {
14485                if (debug == 7) printf("@@@@ remote rx key\n");
14486                if (!myrpt->remotetx)
14487                {
14488                   remkeyed = 1;
14489                }
14490             }
14491             /* if RX un-key */
14492             if (f->subclass.integer == AST_CONTROL_RADIO_UNKEY)
14493             {
14494                if (debug == 7) printf("@@@@ remote rx un-key\n");
14495                if (!myrpt->remotetx) 
14496                {
14497                   remkeyed = 0;
14498                }
14499             }
14500          }
14501          ast_frfree(f);
14502          continue;
14503       }
14504       if (who == myrpt->pchannel) /* if is remote mix output */
14505       {
14506          f = ast_read(myrpt->pchannel);
14507          if (!f)
14508          {
14509             if (debug) printf("@@@@ link:Hung Up\n");
14510             break;
14511          }
14512          if (f->frametype == AST_FRAME_VOICE)
14513          {
14514             ast_write(chan,f);
14515          }
14516          if (f->frametype == AST_FRAME_CONTROL)
14517          {
14518             if (f->subclass.integer == AST_CONTROL_HANGUP)
14519             {
14520                if (debug) printf("@@@@ rpt:Hung Up\n");
14521                ast_frfree(f);
14522                break;
14523             }
14524          }
14525          ast_frfree(f);
14526          continue;
14527       }
14528       if ((myrpt->rxchannel != myrpt->txchannel) && 
14529          (who == myrpt->txchannel)) /* do this cuz you have to */
14530       {
14531          f = ast_read(myrpt->txchannel);
14532          if (!f)
14533          {
14534             if (debug) printf("@@@@ link:Hung Up\n");
14535             break;
14536          }
14537          if (f->frametype == AST_FRAME_CONTROL)
14538          {
14539             if (f->subclass.integer == AST_CONTROL_HANGUP)
14540             {
14541                if (debug) printf("@@@@ rpt:Hung Up\n");
14542                ast_frfree(f);
14543                break;
14544             }
14545          }
14546          ast_frfree(f);
14547          continue;
14548       }
14549    }
14550    if (myrpt->p.archivedir)
14551    {
14552       char mycmd[100],*b,*b1;
14553 
14554       /* look at callerid to see what node this comes from */
14555       b = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL);
14556       if (!b) /* if doesn't have caller id */
14557       {
14558          b1 = "0";
14559       } else {
14560          b1 = ast_strdupa(b);
14561          ast_shrink_phone_number(b1);
14562       }
14563       sprintf(mycmd,"DISCONNECT,%s",b1);
14564       donodelog(myrpt,mycmd);
14565    }
14566    /* wait for telem to be done */
14567    while(myrpt->tele.next != &myrpt->tele) usleep(100000);
14568    sprintf(tmp,"mixmonitor stop %s",chan->name);
14569    ast_cli_command(nullfd,tmp);
14570    close(nullfd);
14571    rpt_mutex_lock(&myrpt->lock);
14572    myrpt->hfscanmode = 0;
14573    myrpt->hfscanstatus = 0;
14574    myrpt->remoteon = 0;
14575    rpt_mutex_unlock(&myrpt->lock);
14576    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
14577    myrpt->lastf1 = NULL;
14578    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
14579    myrpt->lastf2 = NULL;
14580    if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14581    {
14582       z.radpar = DAHDI_RADPAR_UIOMODE;
14583       z.data = 3;
14584       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14585       {
14586          ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
14587          return -1;
14588       }
14589       z.radpar = DAHDI_RADPAR_UIODATA;
14590       z.data = 3;
14591       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14592       {
14593          ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14594          return -1;
14595       }
14596       i = DAHDI_OFFHOOK;
14597       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i) == -1)
14598       {
14599          ast_log(LOG_ERROR,"Cannot set hook\n");
14600          return -1;
14601       }
14602    }
14603    if (myrpt->iofd) close(myrpt->iofd);
14604    myrpt->iofd = -1;
14605    ast_hangup(myrpt->pchannel);
14606    if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
14607    ast_hangup(myrpt->rxchannel);
14608    closerem(myrpt);
14609    if (myrpt->p.rptnode)
14610    {
14611       rpt_mutex_lock(&myrpt->lock);
14612       for(i = 0; i < nrpts; i++)
14613       {
14614          if (!strcasecmp(rpt_vars[i].name,myrpt->p.rptnode))
14615          {
14616             rpt_vars[i].xlink = 0;
14617             break;
14618          }
14619       }
14620       rpt_mutex_unlock(&myrpt->lock);
14621    }
14622 #ifdef   OLD_ASTERISK
14623    LOCAL_USER_REMOVE(u);
14624 #endif
14625    return res;
14626 }
14627 
14628 #ifndef OLD_ASTERISK
14629 /*!\brief callback to display list of locally configured nodes
14630    \addtogroup Group_AMI
14631  */
14632 static int manager_rpt_local_nodes(struct mansession *s, const struct message *m)
14633 {
14634     int i;
14635     astman_append(s, "<?xml version=\"1.0\"?>\r\n");
14636     astman_append(s, "<nodes>\r\n");
14637     for (i=0; i< nrpts; i++)
14638     {
14639         astman_append(s, "  <node>%s</node>\r\n", rpt_vars[i].name);        
14640     } /* for i */
14641     astman_append(s, "</nodes>\r\n");
14642     astman_append(s, "\r\n"); /* Properly terminate Manager output */
14643     return RESULT_SUCCESS;
14644 } /* manager_rpt_local_nodes() */
14645 
14646 
14647 
14648 /*
14649  * Append Success and ActionID to manager response message
14650  */
14651 
14652 static void rpt_manager_success(struct mansession *s, const struct message *m)
14653 {
14654    const char *id = astman_get_header(m, "ActionID");
14655    if (!ast_strlen_zero(id))
14656       astman_append(s, "ActionID: %s\r\n", id);
14657    astman_append(s, "Response: Success\r\n");
14658 }
14659 
14660 /*
14661 * Dump statistics to manager session
14662 */
14663 
14664 static int rpt_manager_do_stats(struct mansession *s, const struct message *m, char *str)
14665 {
14666    int i,j,numoflinks;
14667    int dailytxtime, dailykerchunks;
14668    time_t now;
14669    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
14670    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
14671    long long totaltxtime;
14672    struct   rpt_link *l;
14673    char *listoflinks[MAX_STAT_LINKS];  
14674    char *lastdtmfcommand,*parrot_ena;
14675    char *tot_state, *ider_state, *patch_state;
14676    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
14677    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
14678    char *transmitterkeyed;
14679    const char *node = astman_get_header(m, "Node");
14680    struct rpt *myrpt;
14681 
14682    static char *not_applicable = "N/A";
14683 
14684    tot_state = ider_state = 
14685    patch_state = reverse_patch_state = 
14686    input_signal = not_applicable;
14687    called_number = lastdtmfcommand = transmitterkeyed = NULL;
14688 
14689    time(&now);
14690    for(i = 0; i < nrpts; i++)
14691    {
14692       if ((node)&&(!strcmp(node,rpt_vars[i].name))){
14693          rpt_manager_success(s,m);
14694 
14695          myrpt = &rpt_vars[i];
14696 
14697          if(myrpt->remote){ /* Remote base ? */
14698             char *loginuser, *loginlevel, *freq, *rxpl, *txpl, *modestr;
14699             char offset = 0, powerlevel = 0, rxplon = 0, txplon = 0, remoteon, remmode = 0, reportfmstuff;
14700             char offsetc,powerlevelc;
14701 
14702             loginuser = loginlevel = freq = rxpl = txpl = NULL;
14703             /* Make a copy of all stat variables while locked */
14704             rpt_mutex_lock(&myrpt->lock); /* LOCK */
14705             if((remoteon = myrpt->remoteon)){
14706                if(!ast_strlen_zero(myrpt->loginuser))
14707                   loginuser = ast_strdup(myrpt->loginuser);
14708                if(!ast_strlen_zero(myrpt->loginlevel))
14709                   loginlevel = ast_strdup(myrpt->loginlevel);
14710                if(!ast_strlen_zero(myrpt->freq))
14711                   freq = ast_strdup(myrpt->freq);
14712                if(!ast_strlen_zero(myrpt->rxpl))
14713                   rxpl = ast_strdup(myrpt->rxpl);
14714                if(!ast_strlen_zero(myrpt->txpl))
14715                   txpl = ast_strdup(myrpt->txpl);
14716                remmode = myrpt->remmode;
14717                offset = myrpt->offset;
14718                powerlevel = myrpt->powerlevel;
14719                rxplon = myrpt->rxplon;
14720                txplon = myrpt->txplon;       
14721             }
14722             rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
14723             astman_append(s, "IsRemoteBase: YES\r\n");
14724             astman_append(s, "RemoteOn: %s\r\n",(remoteon) ? "YES": "NO");
14725             if(remoteon){
14726                if(loginuser){
14727                   astman_append(s, "LogInUser: %s\r\n", loginuser);
14728                   ast_free(loginuser);
14729                }
14730                if(loginlevel){
14731                   astman_append(s, "LogInLevel: %s\r\n", loginlevel);
14732                   ast_free(loginlevel);
14733                }
14734                if(freq){
14735                   astman_append(s, "Freq: %s\r\n", freq);
14736                   ast_free(freq);
14737                }
14738                reportfmstuff = 0;
14739                switch(remmode){
14740                   case REM_MODE_FM:
14741                      modestr = "FM";   
14742                      reportfmstuff = 1;
14743                      break;
14744                   case REM_MODE_AM:
14745                      modestr = "AM";
14746                      break;
14747                   case REM_MODE_USB:
14748                      modestr = "USB";
14749                      break;
14750                   default:
14751                      modestr = "LSB";
14752                      break;
14753                }
14754                astman_append(s, "RemMode: %s\r\n", modestr);
14755                if(reportfmstuff){
14756                   switch(offset){
14757                      case REM_SIMPLEX:
14758                         offsetc = 'S';
14759                         break;
14760                      case REM_MINUS:
14761                         offsetc = '-';
14762                         break;
14763                      default:
14764                         offsetc = '+';
14765                         break;
14766                   }
14767                   astman_append(s, "RemOffset: %c\r\n", offsetc);
14768                   if(rxplon && rxpl){
14769                      astman_append(s, "RxPl: %s\r\n",rxpl);
14770                      ast_free(rxpl);
14771                   }
14772                   if(txplon && txpl){
14773                      astman_append(s, "TxPl: %s\r\n",txpl);
14774                      ast_free(txpl);
14775                   }
14776                }
14777                switch(powerlevel){
14778                   case REM_LOWPWR:
14779                      powerlevelc = 'L';
14780                      break;
14781                   case REM_MEDPWR:
14782                      powerlevelc = 'M';
14783                      break;
14784                   default:
14785                      powerlevelc = 'H';
14786                      break;
14787                }
14788                astman_append(s,"PowerLevel: %c\r\n", powerlevelc);
14789             }
14790             astman_append(s, "\r\n");
14791             return 0; /* End of remote base status reporting */
14792          }  
14793 
14794          /* ELSE Process as a repeater node */
14795          /* Make a copy of all stat variables while locked */
14796          rpt_mutex_lock(&myrpt->lock); /* LOCK */
14797          dailytxtime = myrpt->dailytxtime;
14798          totaltxtime = myrpt->totaltxtime;
14799          dailykeyups = myrpt->dailykeyups;
14800          totalkeyups = myrpt->totalkeyups;
14801          dailykerchunks = myrpt->dailykerchunks;
14802          totalkerchunks = myrpt->totalkerchunks;
14803          dailyexecdcommands = myrpt->dailyexecdcommands;
14804          totalexecdcommands = myrpt->totalexecdcommands;
14805          timeouts = myrpt->timeouts;
14806 
14807 
14808          /* Traverse the list of connected nodes */
14809          reverse_patch_state = "DOWN";
14810          numoflinks = 0;
14811          l = myrpt->links.next;
14812          while(l && (l != &myrpt->links)){
14813             if(numoflinks >= MAX_STAT_LINKS){
14814                ast_log(LOG_NOTICE,
14815                "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
14816                break;
14817             }
14818             if (l->name[0] == '0'){ /* Skip '0' nodes */
14819                reverse_patch_state = "UP";
14820                l = l->next;
14821                continue;
14822             }
14823             listoflinks[numoflinks] = ast_strdup(l->name);
14824             if(listoflinks[numoflinks] == NULL){
14825                break;
14826             }
14827             else{
14828                numoflinks++;
14829             }
14830             l = l->next;
14831          }
14832 
14833          if(myrpt->keyed)
14834             input_signal = "YES";
14835          else
14836             input_signal = "NO";
14837          
14838          if(myrpt->txkeyed)
14839             transmitterkeyed = "YES";
14840          else
14841             transmitterkeyed = "NO";
14842 
14843          if(myrpt->p.parrotmode)
14844             parrot_ena = "ENABLED";
14845          else
14846             parrot_ena = "DISABLED";
14847 
14848          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
14849             sys_ena = "DISABLED";
14850          else
14851             sys_ena = "ENABLED";
14852 
14853          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
14854             tot_ena = "DISABLED";
14855          else
14856             tot_ena = "ENABLED";
14857 
14858          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
14859             link_ena = "DISABLED";
14860          else
14861             link_ena = "ENABLED";
14862 
14863          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
14864             patch_ena = "DISABLED";
14865          else
14866             patch_ena = "ENABLED";
14867 
14868          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
14869             sch_ena = "DISABLED";
14870          else
14871             sch_ena = "ENABLED";
14872 
14873          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
14874             user_funs = "DISABLED";
14875          else
14876             user_funs = "ENABLED";
14877 
14878          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
14879             tail_type = "ALTERNATE";
14880          else
14881             tail_type = "STANDARD";
14882 
14883          if(!myrpt->totimer)
14884             tot_state = "TIMED OUT!";
14885          else if(myrpt->totimer != myrpt->p.totime)
14886             tot_state = "ARMED";
14887          else
14888             tot_state = "RESET";
14889 
14890          if(myrpt->tailid)
14891             ider_state = "QUEUED IN TAIL";
14892          else if(myrpt->mustid)
14893             ider_state = "QUEUED FOR CLEANUP";
14894          else
14895             ider_state = "CLEAN";
14896 
14897          switch(myrpt->callmode){
14898             case 1:
14899                patch_state = "DIALING";
14900                break;
14901             case 2:
14902                patch_state = "CONNECTING";
14903                break;
14904             case 3:
14905                patch_state = "UP";
14906                break;
14907 
14908             case 4:
14909                patch_state = "CALL FAILED";
14910                break;
14911 
14912             default:
14913                patch_state = "DOWN";
14914          }
14915 
14916          if(strlen(myrpt->exten)){
14917             called_number = ast_strdup(myrpt->exten);
14918          }
14919 
14920          if(strlen(myrpt->lastdtmfcommand)){
14921             lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
14922          }
14923          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
14924 
14925          astman_append(s, "IsRemoteBase: NO\r\n");
14926          astman_append(s, "NodeState: %d\r\n", myrpt->p.sysstate_cur);
14927          astman_append(s, "SignalOnInput: %s\r\n", input_signal);
14928          astman_append(s, "TransmitterKeyed: %s\r\n", transmitterkeyed);
14929          astman_append(s, "Transmitter: %s\r\n", sys_ena);
14930          astman_append(s, "Parrot: %s\r\n", parrot_ena);
14931          astman_append(s, "Scheduler: %s\r\n", sch_ena);
14932          astman_append(s, "TailLength: %s\r\n", tail_type);
14933          astman_append(s, "TimeOutTimer: %s\r\n", tot_ena);
14934          astman_append(s, "TimeOutTimerState: %s\r\n", tot_state);
14935          astman_append(s, "TimeOutsSinceSystemInitialization: %d\r\n", timeouts);
14936          astman_append(s, "IdentifierState: %s\r\n", ider_state);
14937          astman_append(s, "KerchunksToday: %d\r\n", dailykerchunks);
14938          astman_append(s, "KerchunksSinceSystemInitialization: %d\r\n", totalkerchunks);
14939          astman_append(s, "KeyupsToday: %d\r\n", dailykeyups);
14940          astman_append(s, "KeyupsSinceSystemInitialization: %d\r\n", totalkeyups);
14941          astman_append(s, "DtmfCommandsToday: %d\r\n", dailyexecdcommands);
14942          astman_append(s, "DtmfCommandsSinceSystemInitialization: %d\r\n", totalexecdcommands);
14943          astman_append(s, "LastDtmfCommandExecuted: %s\r\n", 
14944          (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
14945          hours = dailytxtime/3600000;
14946          dailytxtime %= 3600000;
14947          minutes = dailytxtime/60000;
14948          dailytxtime %= 60000;
14949          seconds = dailytxtime/1000;
14950          dailytxtime %= 1000;
14951 
14952          astman_append(s, "TxTimeToday: %02d:%02d:%02d.%d\r\n",
14953             hours, minutes, seconds, dailytxtime);
14954 
14955          hours = (int) totaltxtime/3600000;
14956          totaltxtime %= 3600000;
14957          minutes = (int) totaltxtime/60000;
14958          totaltxtime %= 60000;
14959          seconds = (int)  totaltxtime/1000;
14960          totaltxtime %= 1000;
14961 
14962          astman_append(s, "TxTimeSinceSystemInitialization: %02d:%02d:%02d.%d\r\n",
14963              hours, minutes, seconds, (int) totaltxtime);
14964 
14965          sprintf(str, "NodesCurrentlyConnectedToUs: ");
14966                         if(!numoflinks){
14967                          strcat(str,"<NONE>");
14968                         }
14969          else{
14970             for(j = 0 ;j < numoflinks; j++){
14971                sprintf(str+strlen(str), "%s", listoflinks[j]);
14972                if(j < numoflinks - 1)
14973                   strcat(str,",");
14974             }
14975          }
14976          astman_append(s,"%s\r\n", str);
14977 
14978          astman_append(s, "Autopatch: %s\r\n", patch_ena);
14979          astman_append(s, "AutopatchState: %s\r\n", patch_state);
14980          astman_append(s, "AutopatchCalledNumber: %s\r\n",
14981          (called_number && strlen(called_number)) ? called_number : not_applicable);
14982          astman_append(s, "ReversePatchIaxrptConnected: %s\r\n", reverse_patch_state);
14983          astman_append(s, "UserLinkingCommands: %s\r\n", link_ena);
14984          astman_append(s, "UserFunctions: %s\r\n", user_funs);
14985 
14986          for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
14987             ast_free(listoflinks[j]);
14988          }
14989          if(called_number){
14990             ast_free(called_number);
14991          }
14992          if(lastdtmfcommand){
14993             ast_free(lastdtmfcommand);
14994          }
14995          astman_append(s, "\r\n"); /* We're Done! */
14996               return 0;
14997       }
14998    }
14999    astman_send_error(s, m, "RptStatus unknown or missing node");
15000    return -1;
15001 }
15002 
15003 
15004 
15005 /*
15006  * Implement the RptStatus Manager Interface
15007  */
15008 
15009 static int manager_rpt_status(struct mansession *s, const struct message *m)
15010 {
15011    int i,res,len,idx;
15012    int uptime,hours,minutes;
15013    time_t now;
15014    const char *cmd = astman_get_header(m, "Command");
15015    char *str;
15016    enum {MGRCMD_RPTSTAT,MGRCMD_NODESTAT};
15017    struct mgrcmdtbl{
15018       const char *cmd;
15019       int index;
15020    };
15021    static struct mgrcmdtbl mct[] = {
15022       {"RptStat",MGRCMD_RPTSTAT},
15023       {"NodeStat",MGRCMD_NODESTAT},
15024       {NULL,0} /* NULL marks end of command table */
15025    };
15026 
15027    time(&now);
15028 
15029    len = 1024; /* Allocate a working buffer */
15030    if(!(str = ast_malloc(len)))
15031       return -1;
15032 
15033    /* Check for Command */
15034    if(ast_strlen_zero(cmd)){
15035       astman_send_error(s, m, "RptStatus missing command");
15036       ast_free(str);
15037       return 0;
15038    }
15039    /* Try to find the command in the table */
15040    for(i = 0 ; mct[i].cmd ; i++){
15041       if(!strcmp(mct[i].cmd, cmd))
15042          break;
15043    }
15044 
15045    if(!mct[i].cmd){ /* Found or not found ? */
15046       astman_send_error(s, m, "RptStatus unknown command");
15047       ast_free(str);
15048       return 0;
15049    }
15050    else
15051       idx = mct[i].index;
15052 
15053    switch(idx){ /* Use the index to go to the correct command */
15054 
15055       case MGRCMD_RPTSTAT:
15056          /* Return Nodes: and a comma separated list of nodes */
15057          if((res = snprintf(str, len, "Nodes: ")) > -1)
15058             len -= res;
15059          else{
15060             ast_free(str);
15061             return 0;
15062          }
15063          for(i = 0; i < nrpts; i++){
15064             if(i < nrpts - 1){
15065                if((res = snprintf(str+strlen(str), len, "%s,",rpt_vars[i].name)) < 0){
15066                   ast_free(str);
15067                   return 0;
15068                }
15069             }
15070             else{
15071                if((res = snprintf(str+strlen(str), len, "%s",rpt_vars[i].name)) < 0){
15072                   ast_free(str);
15073                   return 0;
15074                }
15075             }
15076             len -= res;
15077          }
15078 
15079          rpt_manager_success(s,m);
15080          
15081          if(!nrpts)
15082             astman_append(s, "<NONE>\r\n");
15083          else
15084             astman_append(s, "%s\r\n", str);
15085 
15086          uptime = (int)(now - starttime);
15087                         hours = uptime/3600;
15088                         uptime %= 3600;
15089                         minutes = uptime/60;
15090                         uptime %= 60;
15091 
15092                         astman_append(s, "RptUptime: %02d:%02d:%02d\r\n",
15093                                 hours, minutes, uptime);
15094 
15095          astman_append(s, "\r\n");
15096          break;      
15097 
15098       case  MGRCMD_NODESTAT:
15099          res = rpt_manager_do_stats(s,m,str);
15100          ast_free(str);
15101          return res;
15102 
15103       default:
15104          astman_send_error(s, m, "RptStatus invalid command");
15105          break;
15106    }
15107    ast_free(str);
15108    return 0;
15109 }
15110 
15111 #endif
15112 
15113 #ifdef   OLD_ASTERISK
15114 int unload_module()
15115 #else
15116 static int unload_module(void)
15117 #endif
15118 {
15119    int i, res;
15120 
15121 #ifdef   OLD_ASTERISK
15122    STANDARD_HANGUP_LOCALUSERS;
15123 #endif
15124    for(i = 0; i < nrpts; i++) {
15125       if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
15126                 ast_mutex_destroy(&rpt_vars[i].lock);
15127                 ast_mutex_destroy(&rpt_vars[i].remlock);
15128    }
15129    res = ast_unregister_application(app);
15130 
15131 #ifdef   NEW_ASTERISK
15132    ast_cli_unregister_multiple(rpt_cli, ARRAY_LEN(rpt_cli));
15133 #else
15134    /* Unregister cli extensions */
15135    ast_cli_unregister(&cli_debug);
15136    ast_cli_unregister(&cli_dump);
15137    ast_cli_unregister(&cli_stats);
15138    ast_cli_unregister(&cli_lstats);
15139    ast_cli_unregister(&cli_nodes);
15140    ast_cli_unregister(&cli_local_nodes);
15141    ast_cli_unregister(&cli_reload);
15142    ast_cli_unregister(&cli_restart);
15143    ast_cli_unregister(&cli_fun);
15144    ast_cli_unregister(&cli_fun1);
15145    res |= ast_cli_unregister(&cli_cmd);
15146 #endif
15147 #ifndef OLD_ASTERISK
15148    res |= ast_manager_unregister("RptLocalNodes");
15149    res |= ast_manager_unregister("RptStatus");
15150 #endif
15151    return res;
15152 }
15153 
15154 #ifdef   OLD_ASTERISK
15155 int load_module()
15156 #else
15157 static int load_module(void)
15158 #endif
15159 {
15160    int res;
15161    ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
15162 
15163 #ifdef   NEW_ASTERISK
15164    ast_cli_register_multiple(rpt_cli, ARRAY_LEN(rpt_cli));
15165    res = 0;
15166 #else
15167    /* Register cli extensions */
15168    ast_cli_register(&cli_debug);
15169    ast_cli_register(&cli_dump);
15170    ast_cli_register(&cli_stats);
15171    ast_cli_register(&cli_lstats);
15172    ast_cli_register(&cli_nodes);
15173    ast_cli_register(&cli_local_nodes);
15174    ast_cli_register(&cli_reload);
15175    ast_cli_register(&cli_restart);
15176    ast_cli_register(&cli_fun);
15177    ast_cli_register(&cli_fun1);
15178    res = ast_cli_register(&cli_cmd);
15179 #endif
15180 #ifndef OLD_ASTERISK
15181    res |= ast_manager_register("RptLocalNodes", 0, manager_rpt_local_nodes, "List local node numbers");
15182    res |= ast_manager_register("RptStatus", 0, manager_rpt_status, "Return Rpt Status for CGI");
15183 
15184 #endif
15185    res |= ast_register_application(app, rpt_exec, synopsis, descrip);
15186    return res;
15187 }
15188 
15189 #ifdef   OLD_ASTERISK
15190 char *description()
15191 {
15192    return tdesc;
15193 }
15194 int usecount(void)
15195 {
15196    int res;
15197    STANDARD_USECOUNT(res);
15198    return res;
15199 }
15200 
15201 char *key()
15202 {
15203    return ASTERISK_GPL_KEY;
15204 }
15205 #endif
15206 
15207 #ifdef   OLD_ASTERISK
15208 int reload()
15209 #else
15210 static int reload(void)
15211 #endif
15212 {
15213 int   n;
15214 
15215    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
15216    return(0);
15217 }
15218 
15219 
15220 #ifndef  OLD_ASTERISK
15221 /* STD_MOD(MOD_1, reload, NULL, NULL); */
15222 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application",
15223       .load = load_module,
15224       .unload = unload_module,
15225       .reload = reload,
15226           );
15227 #endif
15228 

Generated on Mon Jun 27 16:50:47 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7