Sat Feb 11 06:33:02 2012

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    <support_level>extended</support_level>
00159  ***/
00160 
00161 /* Un-comment the following to include support for MDC-1200 digital tone
00162    signalling protocol (using KA6SQG's GPL'ed implementation) */
00163 /* #include "mdc_decode.c" */
00164 
00165 /* Un-comment the following to include support for notch filters in the
00166    rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
00167 /* #include "rpt_notch.c" */
00168 
00169 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
00170 
00171 #ifdef OLD_ASTERISK
00172 #define ast_free free
00173 #define ast_malloc malloc
00174 #define ast_strdup strdup
00175 #endif
00176 
00177 
00178 #define  MAXDTMF 32
00179 #define  MAXMACRO 2048
00180 #define  MAXLINKLIST 512
00181 #define  LINKLISTTIME 10000
00182 #define  LINKLISTSHORTTIME 200
00183 #define  LINKPOSTTIME 30000
00184 #define  LINKPOSTSHORTTIME 200
00185 #define  KEYPOSTTIME 30000
00186 #define  KEYPOSTSHORTTIME 200
00187 #define  MACROTIME 100
00188 #define  MACROPTIME 500
00189 #define  DTMF_TIMEOUT 3
00190 #define  KENWOOD_RETRIES 5
00191 #define  TOPKEYN 32
00192 #define  TOPKEYWAIT 3
00193 #define  TOPKEYMAXSTR 30
00194 
00195 #define  AUTHTELLTIME 7000
00196 #define  AUTHTXTIME 1000
00197 #define  AUTHLOGOUTTIME 25000
00198 
00199 #ifdef   __RPT_NOTCH
00200 #define  MAXFILTERS 10
00201 #endif
00202 
00203 #define  DISC_TIME 10000  /* report disc after 10 seconds of no connect */
00204 #define  MAX_RETRIES 5
00205 #define  MAX_RETRIES_PERM 1000000000
00206 
00207 #define  REDUNDANT_TX_TIME 2000
00208 
00209 #define  RETRY_TIMER_MS 5000
00210 
00211 #define  PATCH_DIALPLAN_TIMEOUT 1500
00212 
00213 #ifdef OLD_ASTERISK
00214 #define  START_DELAY 10
00215 #else
00216 #define  START_DELAY 2
00217 #endif
00218 
00219 #define  RPT_LOCKOUT_SECS 10
00220 
00221 #define MAXPEERSTR 31
00222 #define  MAXREMSTR 15
00223 
00224 #define  DELIMCHR ','
00225 #define  QUOTECHR 34
00226 
00227 #define  MONITOR_DISK_BLOCKS_PER_MINUTE 38
00228 
00229 #define  DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000
00230 #define  DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60)
00231 #define  DEFAULT_REMOTE_TIMEOUT (60 * 60)
00232 #define  DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60)
00233 #define  DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30
00234 
00235 #define  NODES "nodes"
00236 #define  EXTNODES "extnodes"
00237 #define MEMORY "memory"
00238 #define MACRO "macro"
00239 #define  FUNCTIONS "functions"
00240 #define TELEMETRY "telemetry"
00241 #define MORSE "morse"
00242 #define  TONEMACRO "tonemacro"
00243 #define  FUNCCHAR '*'
00244 #define  ENDCHAR '#'
00245 #define  EXTNODEFILE "/var/lib/asterisk/rpt_extnodes"
00246 #define  NODENAMES "rpt/nodenames"
00247 #define  PARROTFILE "/tmp/parrot_%s_%u"
00248 
00249 #define  PARROTTIME 1000
00250 
00251 #define  DEFAULT_IOBASE 0x378
00252 
00253 #define  DEFAULT_CIV_ADDR 0x58
00254 
00255 #define  MAXCONNECTTIME 5000
00256 
00257 #define MAXNODESTR 300
00258 
00259 #define MAXNODELEN 16
00260 
00261 #define MAXIDENTLEN 32
00262 
00263 #define MAXPATCHCONTEXT 100
00264 
00265 #define ACTIONSIZE 32
00266 
00267 #define TELEPARAMSIZE 256
00268 
00269 #define REM_SCANTIME 100
00270 
00271 #define  DTMF_LOCAL_TIME 250
00272 #define  DTMF_LOCAL_STARTTIME 500
00273 
00274 #define  IC706_PL_MEMORY_OFFSET 50
00275 
00276 #define  VOX_ON_DEBOUNCE_COUNT 3
00277 #define  VOX_OFF_DEBOUNCE_COUNT 20
00278 #define  VOX_MAX_THRESHOLD 10000.0
00279 #define  VOX_MIN_THRESHOLD 3000.0
00280 #define  VOX_TIMEOUT_MS 5000
00281 #define  VOX_RECOVER_MS 500
00282 #define  SIMPLEX_PATCH_DELAY 25
00283 #define  SIMPLEX_PHONE_DELAY 25
00284 
00285 #define  STATPOST_PROGRAM "/usr/bin/wget,-q,--output-document=/dev/null,--no-check-certificate"
00286 
00287 #define  ALLOW_LOCAL_CHANNELS
00288 
00289 enum {REM_OFF,REM_MONITOR,REM_TX};
00290 
00291 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
00292    CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME, PLAYBACK,
00293    STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
00294    TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS,
00295    MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS,
00296    REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE, TOPKEY,
00297    TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX, PARROT,
00298    STATS_TIME_LOCAL};
00299 
00300 
00301 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
00302 
00303 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
00304 
00305 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY};
00306 
00307 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE, SOURCE_ALT};
00308 
00309 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY, DLY_PARROT};
00310 
00311 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
00312 
00313 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
00314       HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
00315 
00316 #include "asterisk.h"
00317 
00318 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 352348 $")
00319 
00320 #include <signal.h>
00321 #include <stdio.h>
00322 #include <stdint.h>
00323 #include <unistd.h>
00324 #include <string.h>
00325 #include <stdlib.h>
00326 #include <search.h>
00327 #include <sys/types.h>
00328 #include <sys/stat.h>
00329 #include <errno.h>
00330 #include <dirent.h>
00331 #include <ctype.h>
00332 #include <sys/stat.h>
00333 #include <sys/time.h>
00334 #include <sys/file.h>
00335 #include <sys/ioctl.h>
00336 #ifdef HAVE_SYS_IO_H
00337 #include <sys/io.h>
00338 #endif
00339 #include <sys/vfs.h>
00340 #include <math.h>
00341 #include <dahdi/user.h>
00342 #include <dahdi/tonezone.h>
00343 #include <netinet/in.h>
00344 #include <arpa/inet.h>
00345 
00346 #include "asterisk/utils.h"
00347 #include "asterisk/lock.h"
00348 #include "asterisk/file.h"
00349 #include "asterisk/logger.h"
00350 #include "asterisk/channel.h"
00351 #include "asterisk/callerid.h"
00352 #include "asterisk/pbx.h"
00353 #include "asterisk/module.h"
00354 #include "asterisk/translate.h"
00355 #include "asterisk/features.h"
00356 #include "asterisk/options.h"
00357 #include "asterisk/cli.h"
00358 #include "asterisk/config.h"
00359 #include "asterisk/say.h"
00360 #include "asterisk/localtime.h"
00361 #include "asterisk/cdr.h"
00362 #include "asterisk/options.h"
00363 #include "asterisk/manager.h"
00364 #include "asterisk/app.h"
00365 
00366 #include <termios.h>
00367 
00368 #ifdef   NEW_ASTERISK
00369 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
00370 #endif
00371 
00372 
00373 /* Start a tone-list going */
00374 int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
00375 /*! Stop the tones from playing */
00376 void ast_playtones_stop(struct ast_channel *chan);
00377 
00378 static  char *tdesc = "Radio Repeater / Remote Base  version 0.115  5/12/2008";
00379 
00380 static char *app = "Rpt";
00381 
00382 static char *synopsis = "Radio Repeater/Remote Base Control System";
00383 
00384 static char *descrip = 
00385 "  Rpt(nodename[|options][|M][|*]):  \n"
00386 "    Radio Remote Link or Remote Base Link Endpoint Process.\n"
00387 "\n"
00388 "    Not specifying an option puts it in normal endpoint mode (where source\n"
00389 "    IP and nodename are verified).\n"
00390 "\n"
00391 "    Options are as follows:\n"
00392 "\n"
00393 "        X - Normal endpoint mode WITHOUT security check. Only specify\n"
00394 "            this if you have checked security already (like with an IAX2\n"
00395 "            user/password or something).\n"
00396 "\n"
00397 "        Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
00398 "            Reverse Autopatch. Caller is put on hold, and announcement (as\n"
00399 "            specified by the 'announce-string') is played on radio system.\n"
00400 "            Users of radio system can access autopatch, dial specified\n"
00401 "            code, and pick up call. Announce-string is list of names of\n"
00402 "            recordings, or \"PARKED\" to substitute code for un-parking,\n"
00403 "            or \"NODE\" to substitute node number.\n"
00404 "\n"
00405 "        P - Phone Control mode. This allows a regular phone user to have\n"
00406 "            full control and audio access to the radio system. For the\n"
00407 "            user to have DTMF control, the 'phone_functions' parameter\n"
00408 "            must be specified for the node in 'rpt.conf'. An additional\n"
00409 "            function (cop,6) must be listed so that PTT control is available.\n"
00410 "\n"
00411 "        D - Dumb Phone Control mode. This allows a regular phone user to\n"
00412 "            have full control and audio access to the radio system. In this\n"
00413 "            mode, the PTT is activated for the entire length of the call.\n"
00414 "            For the user to have DTMF control (not generally recomended in\n"
00415 "            this mode), the 'dphone_functions' parameter must be specified\n"
00416 "            for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
00417 "            available to the phone user.\n"
00418 "\n"
00419 "        S - Simplex Dumb Phone Control mode. This allows a regular phone user\n"
00420 "            audio-only access to the radio system. In this mode, the\n"
00421 "            transmitter is toggled on and off when the phone user presses the\n"
00422 "            funcchar (*) key on the telephone set. In addition, the transmitter\n"
00423 "            will turn off if the endchar (#) key is pressed. When a user first\n"
00424 "            calls in, the transmitter will be off, and the user can listen for\n"
00425 "            radio traffic. When the user wants to transmit, they press the *\n" 
00426 "            key, start talking, then press the * key again or the # key to turn\n"
00427 "            the transmitter off.  No other functions can be executed by the\n"
00428 "            user on the phone when this mode is selected. Note: If your\n"
00429 "            radio system is full-duplex, we recommend using either P or D\n"
00430 "            modes as they provide more flexibility.\n"
00431 "\n"
00432 "        q - Query Status. Sets channel variables and returns + 101 in plan.\n"
00433 "\n"
00434 "        M - Memory Channel Steer as MXX where XX is the memory channel number.\n"
00435 "\n"
00436 "        * - Alt Macro to execute (e.g. *7 for status)\n"
00437 "\n";
00438 ;
00439 
00440 static int debug = 0;  /* Set this >0 for extra debug output */
00441 static int nrpts = 0;
00442 
00443 static const char remdtmfstr[] = "0123456789*#ABCD";
00444 
00445 enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
00446 
00447 int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
00448 
00449 #define NRPTSTAT 7
00450 
00451 struct rpt_chan_stat
00452 {
00453    struct timeval last;
00454    long long total;
00455    unsigned long count;
00456    unsigned long largest;
00457    struct timeval largest_time;
00458 };
00459 
00460 char *discstr = "!!DISCONNECT!!";
00461 char *newkeystr = "!NEWKEY!";
00462 static char *remote_rig_ft897="ft897";
00463 static char *remote_rig_rbi="rbi";
00464 static char *remote_rig_kenwood="kenwood";
00465 static char *remote_rig_tm271="tm271";
00466 static char *remote_rig_ic706="ic706";
00467 static char *remote_rig_rtx150="rtx150";
00468 static char *remote_rig_rtx450="rtx450";
00469 static char *remote_rig_ppp16="ppp16";       // parallel port programmable 16 channels
00470 
00471 #define ISRIG_RTX(x) ((!strcmp(x,remote_rig_rtx150)) || (!strcmp(x,remote_rig_rtx450)))
00472 #define  IS_XPMR(x) (!strncasecmp(x->rxchanname,"rad",3))
00473 
00474 #ifdef   OLD_ASTERISK
00475 STANDARD_LOCAL_USER;
00476 LOCAL_USER_DECL;
00477 #endif
00478 
00479 #define  MSWAIT 200
00480 #define  HANGTIME 5000
00481 #define  TOTIME 180000
00482 #define  IDTIME 300000
00483 #define  MAXRPTS 20
00484 #define MAX_STAT_LINKS 32
00485 #define POLITEID 30000
00486 #define FUNCTDELAY 1500
00487 
00488 #define  MAXXLAT 20
00489 #define  MAXXLATTIME 3
00490 
00491 #define MAX_SYSSTATES 10
00492 
00493 struct vox {
00494    float speech_energy;
00495    float noise_energy;
00496    int   enacount;
00497    char  voxena;
00498    char  lastvox;
00499    int   offdebcnt;
00500    int   ondebcnt;
00501 } ;
00502 
00503 #define  mymax(x,y) ((x > y) ? x : y)
00504 #define  mymin(x,y) ((x < y) ? x : y)
00505 
00506 struct rpt_topkey
00507 {
00508 char  node[TOPKEYMAXSTR];
00509 int   timesince;
00510 int   keyed;
00511 } ;
00512 
00513 struct rpt_xlat
00514 {
00515 char  funccharseq[MAXXLAT];
00516 char  endcharseq[MAXXLAT];
00517 char  passchars[MAXXLAT];
00518 int   funcindex;
00519 int   endindex;
00520 time_t   lastone;
00521 } ;
00522 
00523 static time_t  starttime = 0;
00524 
00525 static  pthread_t rpt_master_thread;
00526 
00527 struct rpt;
00528 
00529 struct rpt_link
00530 {
00531    struct rpt_link *next;
00532    struct rpt_link *prev;
00533    char  mode;       /* 1 if in tx mode */
00534    char  isremote;
00535    char  phonemode;
00536    char  phonevox;      /* vox the phone */
00537    char  name[MAXNODESTR]; /* identifier (routing) string */
00538    char  lasttx;
00539    char  lasttx1;
00540    char  lastrx;
00541    char  lastrealrx;
00542    char  lastrx1;
00543    char  connected;
00544    char  hasconnected;
00545    char  perma;
00546    char  thisconnected;
00547    char  outbound;
00548    char  disced;
00549    char  killme;
00550    long  elaptime;
00551    long  disctime;
00552    long  retrytimer;
00553    long  retxtimer;
00554    long  rerxtimer;
00555    int   retries;
00556    int   max_retries;
00557    int   reconnects;
00558    long long connecttime;
00559    struct ast_channel *chan;  
00560    struct ast_channel *pchan; 
00561    char  linklist[MAXLINKLIST];
00562    time_t   linklistreceived;
00563    long  linklisttimer;
00564    int   dtmfed;
00565    int linkunkeytocttimer;
00566    struct timeval lastlinktv;
00567    struct   ast_frame *lastf1,*lastf2;
00568    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00569    struct vox vox;
00570    char wasvox;
00571    int voxtotimer;
00572    char voxtostate;
00573    char newkey;
00574 #ifdef OLD_ASTERISK
00575         AST_LIST_HEAD(, ast_frame) rxq;
00576 #else
00577    AST_LIST_HEAD_NOLOCK(, ast_frame) rxq;
00578 #endif
00579 } ;
00580 
00581 struct rpt_lstat
00582 {
00583    struct   rpt_lstat *next;
00584    struct   rpt_lstat *prev;
00585    char  peer[MAXPEERSTR];
00586    char  name[MAXNODESTR];
00587    char  mode;
00588    char  outbound;
00589    char  reconnects;
00590    char  thisconnected;
00591    long long   connecttime;
00592    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00593 } ;
00594 
00595 struct rpt_tele
00596 {
00597    struct rpt_tele *next;
00598    struct rpt_tele *prev;
00599    struct rpt *rpt;
00600    struct ast_channel *chan;
00601    int   mode;
00602    struct rpt_link mylink;
00603    char param[TELEPARAMSIZE];
00604    intptr_t submode;
00605    uintptr_t  parrot;
00606    pthread_t threadid;
00607 } ;
00608 
00609 struct function_table_tag
00610 {
00611    char action[ACTIONSIZE];
00612    int (*function)(struct rpt *myrpt, char *param, char *digitbuf, 
00613       int command_source, struct rpt_link *mylink);
00614 } ;
00615 
00616 /* Used to store the morse code patterns */
00617 
00618 struct morse_bits
00619 {       
00620    int len;
00621    int ddcomb;
00622 } ;
00623 
00624 struct telem_defaults
00625 {
00626    char name[20];
00627    char value[80];
00628 } ;
00629 
00630 
00631 struct sysstate
00632 {
00633    char txdisable;
00634    char totdisable;
00635    char linkfundisable;
00636    char autopatchdisable;
00637    char schedulerdisable;
00638    char userfundisable;
00639    char alternatetail;
00640 };
00641 
00642 /* rpt cmd support */
00643 #define CMD_DEPTH 1
00644 #define CMD_STATE_IDLE 0
00645 #define CMD_STATE_BUSY 1
00646 #define CMD_STATE_READY 2
00647 #define CMD_STATE_EXECUTING 3
00648 
00649 struct rpt_cmd_struct
00650 {
00651     int state;
00652     int functionNumber;
00653     char param[MAXDTMF];
00654     char digits[MAXDTMF];
00655     int command_source;
00656 };
00657 
00658 static struct rpt
00659 {
00660    ast_mutex_t lock;
00661    ast_mutex_t remlock;
00662    ast_mutex_t statpost_lock;
00663    struct ast_config *cfg;
00664    char reload;
00665    char xlink;                         // cross link state of a share repeater/remote radio
00666    unsigned int statpost_seqno;
00667 
00668    char *name;
00669    char *rxchanname;
00670    char *txchanname;
00671    char remote;
00672    char *remoterig;
00673    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00674    unsigned int scram;
00675 
00676    struct {
00677       char *ourcontext;
00678       char *ourcallerid;
00679       char *acctcode;
00680       char *ident;
00681       char *tonezone;
00682       char simple;
00683       char *functions;
00684       char *link_functions;
00685       char *phone_functions;
00686       char *dphone_functions;
00687       char *alt_functions;
00688       char *nodes;
00689       char *extnodes;
00690       char *extnodefile;
00691       int hangtime;
00692       int althangtime;
00693       int totime;
00694       int idtime;
00695       int tailmessagetime;
00696       int tailsquashedtime;
00697       int duplex;
00698       int politeid;
00699       char *tailmessages[500];
00700       int tailmessagemax;
00701       char  *memory;
00702       char  *macro;
00703       char  *tonemacro;
00704       char  *startupmacro;
00705       int iobase;
00706       char *ioport;
00707       char funcchar;
00708       char endchar;
00709       char nobusyout;
00710       char notelemtx;
00711       char propagate_dtmf;
00712       char propagate_phonedtmf;
00713       char linktolink;
00714       unsigned char civaddr;
00715       struct rpt_xlat inxlat;
00716       struct rpt_xlat outxlat;
00717       char *archivedir;
00718       int authlevel;
00719       char *csstanzaname;
00720       char *skedstanzaname;
00721       char *txlimitsstanzaname;
00722       long monminblocks;
00723       int remoteinacttimeout;
00724       int remotetimeout;
00725       int remotetimeoutwarning;
00726       int remotetimeoutwarningfreq;
00727       int sysstate_cur;
00728       struct sysstate s[MAX_SYSSTATES];
00729       char parrotmode;
00730       int parrottime;
00731       char *rptnode;
00732       char remote_mars;
00733       int voxtimeout_ms;
00734       int voxrecover_ms;
00735       int simplexpatchdelay;
00736       int simplexphonedelay;
00737       char *statpost_program;
00738       char *statpost_url;
00739    } p;
00740    struct rpt_link links;
00741    int unkeytocttimer;
00742    time_t lastkeyedtime;
00743    time_t lasttxkeyedtime;
00744    char keyed;
00745    char txkeyed;
00746    char exttx;
00747    char localtx;
00748    char remoterx;
00749    char remotetx;
00750    char remoteon;
00751    char remtxfreqok;
00752    char tounkeyed;
00753    char tonotify;
00754    char dtmfbuf[MAXDTMF];
00755    char macrobuf[MAXMACRO];
00756    char rem_dtmfbuf[MAXDTMF];
00757    char lastdtmfcommand[MAXDTMF];
00758    char cmdnode[50];
00759    char nowchan;                 // channel now
00760    char waschan;                 // channel selected initially or by command
00761    char bargechan;                  // barge in channel
00762    char macropatch;              // autopatch via tonemacro state
00763    char parrotstate;
00764    int  parrottimer;
00765    unsigned int parrotcnt;
00766    struct ast_channel *rxchannel,*txchannel, *monchannel, *parrotchannel;
00767    struct ast_channel *pchannel,*txpchannel, *dahdirxchannel, *dahditxchannel;
00768    struct ast_channel *voxchannel;
00769    struct ast_frame *lastf1,*lastf2;
00770    struct rpt_tele tele;
00771    struct timeval lasttv,curtv;
00772    pthread_t rpt_call_thread,rpt_thread;
00773    time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
00774    int calldigittimer;
00775    int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
00776    int mustid,tailid;
00777    int tailevent;
00778    int telemrefcount;
00779    int dtmfidx,rem_dtmfidx;
00780    int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
00781    int totalexecdcommands, dailyexecdcommands;
00782    long  retxtimer;
00783    long  rerxtimer;
00784    long long totaltxtime;
00785    char mydtmf;
00786    char exten[AST_MAX_EXTENSION];
00787    char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
00788    char offset;
00789    char powerlevel;
00790    char txplon;
00791    char rxplon;
00792    char remmode;
00793    char tunerequest;
00794    char hfscanmode;
00795    int hfscanstatus;
00796    char hfscanstop;
00797    char lastlinknode[MAXNODESTR];
00798    char savednodes[MAXNODESTR];
00799    int stopgen;
00800    char patchfarenddisconnect;
00801    char patchnoct;
00802    char patchquiet;
00803    char patchcontext[MAXPATCHCONTEXT];
00804    int patchdialtime;
00805    int macro_longest;
00806    int phone_longestfunc;
00807    int alt_longestfunc;
00808    int dphone_longestfunc;
00809    int link_longestfunc;
00810    int longestfunc;
00811    int longestnode;
00812    int threadrestarts;     
00813    int tailmessagen;
00814    time_t disgorgetime;
00815    time_t lastthreadrestarttime;
00816    long  macrotimer;
00817    char  lastnodewhichkeyedusup[MAXNODESTR];
00818    int   dtmf_local_timer;
00819    char  dtmf_local_str[100];
00820    struct ast_filestream *monstream,*parrotstream;
00821    char  loginuser[50];
00822    char  loginlevel[10];
00823    long  authtelltimer;
00824    long  authtimer;
00825    int iofd;
00826    time_t start_time,last_activity_time;
00827    char  lasttone[32];
00828    struct rpt_tele *active_telem;
00829    struct   rpt_topkey topkey[TOPKEYN];
00830    int topkeystate;
00831    time_t topkeytime;
00832    int topkeylong;
00833    struct vox vox;
00834    char wasvox;
00835    int voxtotimer;
00836    char voxtostate;
00837    int linkposttimer;         
00838    int keyposttimer;       
00839    char newkey;
00840    char inpadtest;
00841 #ifdef OLD_ASTERISK
00842    AST_LIST_HEAD(, ast_frame) txq;
00843 #else
00844    AST_LIST_HEAD_NOLOCK(, ast_frame) txq;
00845 #endif
00846    char txrealkeyed;
00847 #ifdef   __RPT_NOTCH
00848    struct rptfilter
00849    {
00850       char  desc[100];
00851       float x0;
00852       float x1;
00853       float x2;
00854       float y0;
00855       float y1;
00856       float y2;
00857       float gain;
00858       float const0;
00859       float const1;
00860       float const2;
00861    } filters[MAXFILTERS];
00862 #endif
00863 #ifdef   _MDC_DECODE_H_
00864    mdc_decoder_t *mdc;
00865    unsigned short lastunit;
00866 #endif
00867    struct rpt_cmd_struct cmdAction;
00868 } rpt_vars[MAXRPTS]; 
00869 
00870 struct nodelog {
00871 struct nodelog *next;
00872 struct nodelog *prev;
00873 time_t   timestamp;
00874 char archivedir[MAXNODESTR];
00875 char str[MAXNODESTR * 2];
00876 } nodelog;
00877 
00878 static int service_scan(struct rpt *myrpt);
00879 static int set_mode_ft897(struct rpt *myrpt, char newmode);
00880 static int set_mode_ic706(struct rpt *myrpt, char newmode);
00881 static int simple_command_ft897(struct rpt *myrpt, char command);
00882 static int setrem(struct rpt *myrpt);
00883 static int setrtx_check(struct rpt *myrpt);
00884 static int channel_revert(struct rpt *myrpt);
00885 static int channel_steer(struct rpt *myrpt, char *data);
00886 static struct ast_format_cap *get_slin_cap(struct ast_format_cap *cap);
00887 
00888 AST_MUTEX_DEFINE_STATIC(nodeloglock);
00889 
00890 AST_MUTEX_DEFINE_STATIC(nodelookuplock);
00891 
00892 #ifdef   APP_RPT_LOCK_DEBUG
00893 
00894 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
00895 
00896 #define  MAXLOCKTHREAD 100
00897 
00898 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
00899 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
00900 
00901 struct lockthread
00902 {
00903    pthread_t id;
00904    int lockcount;
00905    int lastlock;
00906    int lastunlock;
00907 } lockthreads[MAXLOCKTHREAD];
00908 
00909 
00910 struct by_lightning
00911 {
00912    int line;
00913    struct timeval tv;
00914    struct rpt *rpt;
00915    struct lockthread lockthread;
00916 } lock_ring[32];
00917 
00918 int lock_ring_index = 0;
00919 
00920 AST_MUTEX_DEFINE_STATIC(locklock);
00921 
00922 static struct lockthread *get_lockthread(pthread_t id)
00923 {
00924 int   i;
00925 
00926    for(i = 0; i < MAXLOCKTHREAD; i++)
00927    {
00928       if (lockthreads[i].id == id) return(&lockthreads[i]);
00929    }
00930    return(NULL);
00931 }
00932 
00933 static struct lockthread *put_lockthread(pthread_t id)
00934 {
00935 int   i;
00936 
00937    for(i = 0; i < MAXLOCKTHREAD; i++)
00938    {
00939       if (lockthreads[i].id == id)
00940          return(&lockthreads[i]);
00941    }
00942    for(i = 0; i < MAXLOCKTHREAD; i++)
00943    {
00944       if (!lockthreads[i].id)
00945       {
00946          lockthreads[i].lockcount = 0;
00947          lockthreads[i].lastlock = 0;
00948          lockthreads[i].lastunlock = 0;
00949          lockthreads[i].id = id;
00950          return(&lockthreads[i]);
00951       }
00952    }
00953    return(NULL);
00954 }
00955 
00956 static void rpt_mutex_spew(void)
00957 {
00958    struct by_lightning lock_ring_copy[32];
00959    int lock_ring_index_copy;
00960    int i,j;
00961    long long diff;
00962    char a[100];
00963    struct timeval lasttv;
00964 
00965    ast_mutex_lock(&locklock);
00966    memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
00967    lock_ring_index_copy = lock_ring_index;
00968    ast_mutex_unlock(&locklock);
00969 
00970    lasttv.tv_sec = lasttv.tv_usec = 0;
00971    for(i = 0 ; i < 32 ; i++)
00972    {
00973       j = (i + lock_ring_index_copy) % 32;
00974       strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
00975          localtime(&lock_ring_copy[j].tv.tv_sec));
00976       diff = 0;
00977       if(lasttv.tv_sec)
00978       {
00979          diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
00980             * 1000000;
00981          diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
00982       }
00983       lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
00984       lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
00985       if (!lock_ring_copy[j].tv.tv_sec) continue;
00986       if (lock_ring_copy[j].line < 0)
00987       {
00988          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00989             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);
00990       }
00991       else
00992       {
00993          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00994             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);
00995       }
00996    }
00997 }
00998 
00999 
01000 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
01001 {
01002 struct lockthread *t;
01003 pthread_t id;
01004 
01005    id = pthread_self();
01006    ast_mutex_lock(&locklock);
01007    t = put_lockthread(id);
01008    if (!t)
01009    {
01010       ast_mutex_unlock(&locklock);
01011       return;
01012    }
01013    if (t->lockcount)
01014    {
01015       int lastline = t->lastlock;
01016       ast_mutex_unlock(&locklock);
01017       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);
01018       rpt_mutex_spew();
01019       return;
01020    }
01021    t->lastlock = line;
01022    t->lockcount = 1;
01023    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
01024    lock_ring[lock_ring_index].rpt = myrpt;
01025    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
01026    lock_ring[lock_ring_index++].line = line;
01027    if(lock_ring_index == 32)
01028       lock_ring_index = 0;
01029    ast_mutex_unlock(&locklock);
01030    ast_mutex_lock(lockp);
01031 }
01032 
01033 
01034 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
01035 {
01036 struct lockthread *t;
01037 pthread_t id;
01038 
01039    id = pthread_self();
01040    ast_mutex_lock(&locklock);
01041    t = put_lockthread(id);
01042    if (!t)
01043    {
01044       ast_mutex_unlock(&locklock);
01045       return;
01046    }
01047    if (!t->lockcount)
01048    {
01049       int lastline = t->lastunlock;
01050       ast_mutex_unlock(&locklock);
01051       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);
01052       rpt_mutex_spew();
01053       return;
01054    }
01055    t->lastunlock = line;
01056    t->lockcount = 0;
01057    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
01058    lock_ring[lock_ring_index].rpt = myrpt;
01059    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
01060    lock_ring[lock_ring_index++].line = -line;
01061    if(lock_ring_index == 32)
01062       lock_ring_index = 0;
01063    ast_mutex_unlock(&locklock);
01064    ast_mutex_unlock(lockp);
01065 }
01066 
01067 #else  /* APP_RPT_LOCK_DEBUG */
01068 
01069 #define rpt_mutex_lock(x) ast_mutex_lock(x)
01070 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
01071 
01072 #endif  /* APP_RPT_LOCK_DEBUG */
01073 
01074 static struct ast_format_cap *get_slin_cap(struct ast_format_cap *cap)
01075 {
01076    struct ast_format tmp;
01077    cap = ast_format_cap_alloc_nolock();
01078    if (!cap) {
01079       return NULL;
01080    }
01081    ast_format_cap_add(cap, ast_format_set(&tmp, AST_FORMAT_SLINEAR, 0));
01082 
01083    return cap;
01084 }
01085 
01086 /*
01087 * Return 1 if rig is multimode capable
01088 */
01089 
01090 static int multimode_capable(struct rpt *myrpt)
01091 {
01092    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
01093       return 1;
01094    if(!strcmp(myrpt->remoterig, remote_rig_ic706))
01095       return 1;
01096    return 0;
01097 }  
01098 
01099 static void voxinit_rpt(struct rpt *myrpt,char enable)
01100 {
01101 
01102    myrpt->vox.speech_energy = 0.0;
01103    myrpt->vox.noise_energy = 0.0;
01104    myrpt->vox.enacount = 0;
01105    myrpt->vox.voxena = 0;
01106    if (!enable) myrpt->vox.voxena = -1;
01107    myrpt->vox.lastvox = 0;
01108    myrpt->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
01109    myrpt->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
01110    myrpt->wasvox = 0;
01111    myrpt->voxtotimer = 0;
01112    myrpt->voxtostate = 0;
01113 }
01114 
01115 static void voxinit_link(struct rpt_link *mylink,char enable)
01116 {
01117 
01118    mylink->vox.speech_energy = 0.0;
01119    mylink->vox.noise_energy = 0.0;
01120    mylink->vox.enacount = 0;
01121    mylink->vox.voxena = 0;
01122    if (!enable) mylink->vox.voxena = -1;
01123    mylink->vox.lastvox = 0;
01124    mylink->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
01125    mylink->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
01126    mylink->wasvox = 0;
01127    mylink->voxtotimer = 0;
01128    mylink->voxtostate = 0;
01129 }
01130 
01131 static int dovox(struct vox *v,short *buf,int bs)
01132 {
01133 
01134    int i;
01135    float esquare = 0.0;
01136    float energy = 0.0;
01137    float threshold = 0.0;
01138    
01139    if (v->voxena < 0) return(v->lastvox);
01140    for(i = 0; i < bs; i++)
01141    {
01142       esquare += (float) buf[i] * (float) buf[i];
01143    }
01144    energy = sqrt(esquare);
01145 
01146    if (energy >= v->speech_energy)
01147       v->speech_energy += (energy - v->speech_energy) / 4;
01148    else
01149       v->speech_energy += (energy - v->speech_energy) / 64;
01150 
01151    if (energy >= v->noise_energy)
01152       v->noise_energy += (energy - v->noise_energy) / 64;
01153    else
01154       v->noise_energy += (energy - v->noise_energy) / 4;
01155    
01156    if (v->voxena) threshold = v->speech_energy / 8;
01157    else
01158    {
01159       threshold = mymax(v->speech_energy / 16,v->noise_energy * 2);
01160       threshold = mymin(threshold,VOX_MAX_THRESHOLD);
01161    }
01162    threshold = mymax(threshold,VOX_MIN_THRESHOLD);
01163    if (energy > threshold)
01164    {
01165       if (v->voxena) v->noise_energy *= 0.75;
01166       v->voxena = 1;
01167    } else   v->voxena = 0;
01168    if (v->lastvox != v->voxena)
01169    {
01170       if (v->enacount++ >= ((v->lastvox) ? v->offdebcnt : v->ondebcnt))
01171       {
01172          v->lastvox = v->voxena;
01173          v->enacount = 0;
01174       }
01175    } else v->enacount = 0;
01176    return(v->lastvox);
01177 }
01178 
01179 
01180 
01181 
01182 /*
01183 * CLI extensions
01184 */
01185 
01186 /* Debug mode */
01187 static int rpt_do_debug(int fd, int argc, const char * const *argv);
01188 static int rpt_do_dump(int fd, int argc, const char * const *argv);
01189 static int rpt_do_stats(int fd, int argc, const char * const *argv);
01190 static int rpt_do_lstats(int fd, int argc, const char * const *argv);
01191 static int rpt_do_nodes(int fd, int argc, const char * const *argv);
01192 static int rpt_do_local_nodes(int fd, int argc, const char * const *argv);
01193 static int rpt_do_reload(int fd, int argc, const char * const *argv);
01194 static int rpt_do_restart(int fd, int argc, const char * const *argv);
01195 static int rpt_do_fun(int fd, int argc, const char * const *argv);
01196 static int rpt_do_fun1(int fd, int argc, const char * const *argv);
01197 static int rpt_do_cmd(int fd, int argc, const char * const *argv);
01198 
01199 static char debug_usage[] =
01200 "Usage: rpt debug level {0-7}\n"
01201 "       Enables debug messages in app_rpt\n";
01202 
01203 static char dump_usage[] =
01204 "Usage: rpt dump <nodename>\n"
01205 "       Dumps struct debug info to log\n";
01206 
01207 static char dump_stats[] =
01208 "Usage: rpt stats <nodename>\n"
01209 "       Dumps node statistics to console\n";
01210 
01211 static char dump_lstats[] =
01212 "Usage: rpt lstats <nodename>\n"
01213 "       Dumps link statistics to console\n";
01214 
01215 static char dump_nodes[] =
01216 "Usage: rpt nodes <nodename>\n"
01217 "       Dumps a list of directly and indirectly connected nodes to the console\n";
01218 
01219 static char usage_local_nodes[] =
01220 "Usage: rpt localnodes\n"
01221 "       Dumps a list of the locally configured node numbers to the console.\n";
01222 
01223 static char reload_usage[] =
01224 "Usage: rpt reload\n"
01225 "       Reloads app_rpt running config parameters\n";
01226 
01227 static char restart_usage[] =
01228 "Usage: rpt restart\n"
01229 "       Restarts app_rpt\n";
01230 
01231 static char fun_usage[] =
01232 "Usage: rpt fun <nodename> <command>\n"
01233 "       Send a DTMF function to a node\n";
01234 
01235 static char cmd_usage[] =
01236 "Usage: rpt cmd <nodename> <cmd-name> <cmd-index> <cmd-args.\n"
01237 "       Send a command to a node.\n        i.e. rpt cmd 2000 ilink 3 2001\n";
01238 
01239 #ifndef  NEW_ASTERISK
01240 
01241 static struct ast_cli_entry  cli_debug =
01242         { { "rpt", "debug", "level" }, rpt_do_debug, 
01243       "Enable app_rpt debugging", debug_usage };
01244 
01245 static struct ast_cli_entry  cli_dump =
01246         { { "rpt", "dump" }, rpt_do_dump,
01247       "Dump app_rpt structs for debugging", dump_usage };
01248 
01249 static struct ast_cli_entry  cli_stats =
01250         { { "rpt", "stats" }, rpt_do_stats,
01251       "Dump node statistics", dump_stats };
01252 
01253 static struct ast_cli_entry  cli_nodes =
01254         { { "rpt", "nodes" }, rpt_do_nodes,
01255       "Dump node list", dump_nodes };
01256 
01257 static struct ast_cli_entry  cli_local_nodes =
01258         { { "rpt", "localnodes" }, rpt_do_local_nodes,
01259       "Dump list of local node numbers", usage_local_nodes };
01260 
01261 static struct ast_cli_entry  cli_lstats =
01262         { { "rpt", "lstats" }, rpt_do_lstats,
01263       "Dump link statistics", dump_lstats };
01264 
01265 static struct ast_cli_entry  cli_reload =
01266         { { "rpt", "reload" }, rpt_do_reload,
01267       "Reload app_rpt config", reload_usage };
01268 
01269 static struct ast_cli_entry  cli_restart =
01270         { { "rpt", "restart" }, rpt_do_restart,
01271       "Restart app_rpt", restart_usage };
01272 
01273 static struct ast_cli_entry  cli_fun =
01274         { { "rpt", "fun" }, rpt_do_fun,
01275       "Execute a DTMF function", fun_usage };
01276 
01277 static struct ast_cli_entry  cli_fun1 =
01278         { { "rpt", "fun1" }, rpt_do_fun1,
01279       "Execute a DTMF function", fun_usage };
01280 
01281 static struct ast_cli_entry  cli_cmd =
01282         { { "rpt", "cmd" }, rpt_do_cmd,
01283       "Execute a DTMF function", cmd_usage };
01284 
01285 #endif
01286 
01287 /*
01288 * Telemetry defaults
01289 */
01290 
01291 
01292 static struct telem_defaults tele_defs[] = {
01293    {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
01294    {"ct2","|t(660,880,150,3072)"},
01295    {"ct3","|t(440,0,150,3072)"},
01296    {"ct4","|t(550,0,150,3072)"},
01297    {"ct5","|t(660,0,150,3072)"},
01298    {"ct6","|t(880,0,150,3072)"},
01299    {"ct7","|t(660,440,150,3072)"},
01300    {"ct8","|t(700,1100,150,3072)"},
01301    {"remotemon","|t(1600,0,75,2048)"},
01302    {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
01303    {"cmdmode","|t(900,904,200,2048)"},
01304    {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
01305 } ;
01306 
01307 /*
01308 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
01309 */
01310 
01311 static int setrbi(struct rpt *myrpt);
01312 static int set_ft897(struct rpt *myrpt);
01313 static int set_ic706(struct rpt *myrpt);
01314 static int setkenwood(struct rpt *myrpt);
01315 static int set_tm271(struct rpt *myrpt);
01316 static int setrbi_check(struct rpt *myrpt);
01317 
01318 
01319 
01320 /*
01321 * Define function protos for function table here
01322 */
01323 
01324 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01325 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01326 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01327 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01328 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01329 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01330 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01331 static int function_playback(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01332 /*
01333 * Function table
01334 */
01335 
01336 static struct function_table_tag function_table[] = {
01337    {"cop", function_cop},
01338    {"autopatchup", function_autopatchup},
01339    {"autopatchdn", function_autopatchdn},
01340    {"ilink", function_ilink},
01341    {"status", function_status},
01342    {"remote", function_remote},
01343    {"macro", function_macro},
01344    {"playback", function_playback}
01345 } ;
01346 
01347 static long diskavail(struct rpt *myrpt)
01348 {
01349 struct   statfs statfsbuf;
01350 
01351    if (!myrpt->p.archivedir) return(0);
01352    if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
01353    {
01354       ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
01355          myrpt->p.archivedir,myrpt->name);
01356       return(-1);
01357    }
01358    return(statfsbuf.f_bavail);
01359 }
01360 
01361 static void flush_telem(struct rpt *myrpt)
01362 {
01363    struct rpt_tele *telem;
01364    if(debug > 2)
01365       ast_log(LOG_NOTICE, "flush_telem()!!");
01366    rpt_mutex_lock(&myrpt->lock);
01367    telem = myrpt->tele.next;
01368    while(telem != &myrpt->tele)
01369    {
01370       if (telem->mode != SETREMOTE) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
01371       telem = telem->next;
01372    }
01373    rpt_mutex_unlock(&myrpt->lock);
01374 }
01375 /*
01376    return via error priority
01377 */
01378 static int priority_jump(struct rpt *myrpt, struct ast_channel *chan)
01379 {
01380    int res=0;
01381 
01382    // if (ast_test_flag(&flags,OPT_JUMP) && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
01383    if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
01384       res = 0;
01385    } else {
01386       res = -1;
01387    }
01388    return res;
01389 }
01390 /*
01391 */
01392 static int linkcount(struct rpt *myrpt)
01393 {
01394    struct   rpt_link *l;
01395    char *reverse_patch_state;
01396    int numoflinks;
01397 
01398    reverse_patch_state = "DOWN";
01399    numoflinks = 0;
01400    l = myrpt->links.next;
01401    while(l && (l != &myrpt->links)){
01402       if(numoflinks >= MAX_STAT_LINKS){
01403          ast_log(LOG_WARNING,
01404          "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
01405          break;
01406       }
01407       //if (l->name[0] == '0'){ /* Skip '0' nodes */
01408       // reverse_patch_state = "UP";
01409       // l = l->next;
01410       // continue;
01411       //}
01412       numoflinks++;
01413     
01414       l = l->next;
01415    }
01416    ast_log(LOG_NOTICE, "numoflinks=%i\n",numoflinks);
01417    return numoflinks;
01418 }
01419 /*
01420  * Retrieve a memory channel
01421  * Return 0 if sucessful,
01422  * -1 if channel not found,
01423  *  1 if parse error
01424  */
01425 static int retreive_memory(struct rpt *myrpt, char *memory)
01426 {
01427    char tmp[30], *s, *s1, *val;
01428 
01429    if (debug)ast_log(LOG_NOTICE, "memory=%s block=%s\n",memory,myrpt->p.memory);
01430 
01431    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, memory);
01432    if (!val){
01433       return -1;
01434    }        
01435    strncpy(tmp,val,sizeof(tmp) - 1);
01436    tmp[sizeof(tmp)-1] = 0;
01437 
01438    s = strchr(tmp,',');
01439    if (!s)
01440       return 1; 
01441    *s++ = 0;
01442    s1 = strchr(s,',');
01443    if (!s1)
01444       return 1;
01445    *s1++ = 0;
01446    strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
01447    strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
01448    strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
01449    myrpt->remmode = REM_MODE_FM;
01450    myrpt->offset = REM_SIMPLEX;
01451    myrpt->powerlevel = REM_MEDPWR;
01452    myrpt->txplon = myrpt->rxplon = 0;
01453    while(*s1){
01454       switch(*s1++){
01455          case 'A':
01456          case 'a':
01457             strcpy(myrpt->rxpl, "100.0");
01458             strcpy(myrpt->txpl, "100.0");
01459             myrpt->remmode = REM_MODE_AM; 
01460             break;
01461          case 'B':
01462          case 'b':
01463             strcpy(myrpt->rxpl, "100.0");
01464             strcpy(myrpt->txpl, "100.0");
01465             myrpt->remmode = REM_MODE_LSB;
01466             break;
01467          case 'F':
01468             myrpt->remmode = REM_MODE_FM;
01469             break;
01470          case 'L':
01471          case 'l':
01472             myrpt->powerlevel = REM_LOWPWR;
01473             break;               
01474          case 'H':
01475          case 'h':
01476             myrpt->powerlevel = REM_HIPWR;
01477             break;
01478                
01479          case 'M':
01480          case 'm':
01481             myrpt->powerlevel = REM_MEDPWR;
01482             break;
01483                   
01484          case '-':
01485             myrpt->offset = REM_MINUS;
01486             break;
01487                   
01488          case '+':
01489             myrpt->offset = REM_PLUS;
01490             break;
01491                   
01492          case 'S':
01493          case 's':
01494             myrpt->offset = REM_SIMPLEX;
01495             break;
01496                   
01497          case 'T':
01498          case 't':
01499             myrpt->txplon = 1;
01500             break;
01501                   
01502          case 'R':
01503          case 'r':
01504             myrpt->rxplon = 1;
01505             break;
01506 
01507          case 'U':
01508          case 'u':
01509             strcpy(myrpt->rxpl, "100.0");
01510             strcpy(myrpt->txpl, "100.0");
01511             myrpt->remmode = REM_MODE_USB;
01512             break;
01513          default:
01514             return 1;
01515       }
01516    }
01517    return 0;
01518 }
01519 /*
01520 
01521 */
01522 static void birdbath(struct rpt *myrpt)
01523 {
01524    struct rpt_tele *telem;
01525    if(debug > 2)
01526       ast_log(LOG_NOTICE, "birdbath!!");
01527    rpt_mutex_lock(&myrpt->lock);
01528    telem = myrpt->tele.next;
01529    while(telem != &myrpt->tele)
01530    {
01531       if (telem->mode == PARROT) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
01532       telem = telem->next;
01533    }
01534    rpt_mutex_unlock(&myrpt->lock);
01535 }
01536 
01537 static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
01538 {
01539 struct        rpt_link *l;
01540 
01541        l = myrpt->links.next;
01542        /* go thru all the links */
01543        while(l != &myrpt->links)
01544        {
01545                if (!l->phonemode)
01546                {
01547                        l = l->next;
01548                        continue;
01549                }
01550                /* don't send to self */
01551                if (mylink && (l == mylink))
01552                {
01553                        l = l->next;
01554                        continue;
01555                }
01556 #ifdef   NEW_ASTERISK
01557                if (l->chan) ast_senddigit(l->chan,c,0);
01558 #else
01559                if (l->chan) ast_senddigit(l->chan,c);
01560 #endif
01561                l = l->next;
01562        }
01563        return;
01564 }
01565 
01566 /* node logging function */
01567 static void donodelog(struct rpt *myrpt,char *str)
01568 {
01569 struct nodelog *nodep;
01570 char  datestr[100];
01571 
01572    if (!myrpt->p.archivedir) return;
01573    nodep = (struct nodelog *)ast_malloc(sizeof(struct nodelog));
01574    if (nodep == NULL)
01575    {
01576       ast_log(LOG_ERROR,"Cannot get memory for node log");
01577       return;
01578    }
01579    time(&nodep->timestamp);
01580    strncpy(nodep->archivedir,myrpt->p.archivedir,
01581       sizeof(nodep->archivedir) - 1);
01582    strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
01583       localtime(&nodep->timestamp));
01584    snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
01585       myrpt->name,datestr,str);
01586    ast_mutex_lock(&nodeloglock);
01587    insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
01588    ast_mutex_unlock(&nodeloglock);
01589 }
01590 
01591 /* must be called locked */
01592 static void do_dtmf_local(struct rpt *myrpt, char c)
01593 {
01594 int   i;
01595 char  digit;
01596 static const char* dtmf_tones[] = {
01597    "!941+1336/200,!0/200", /* 0 */
01598    "!697+1209/200,!0/200", /* 1 */
01599    "!697+1336/200,!0/200", /* 2 */
01600    "!697+1477/200,!0/200", /* 3 */
01601    "!770+1209/200,!0/200", /* 4 */
01602    "!770+1336/200,!0/200", /* 5 */
01603    "!770+1477/200,!0/200", /* 6 */
01604    "!852+1209/200,!0/200", /* 7 */
01605    "!852+1336/200,!0/200", /* 8 */
01606    "!852+1477/200,!0/200", /* 9 */
01607    "!697+1633/200,!0/200", /* A */
01608    "!770+1633/200,!0/200", /* B */
01609    "!852+1633/200,!0/200", /* C */
01610    "!941+1633/200,!0/200", /* D */
01611    "!941+1209/200,!0/200", /* * */
01612    "!941+1477/200,!0/200" };  /* # */
01613 
01614 
01615    if (c)
01616    {
01617       snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
01618       if (!myrpt->dtmf_local_timer) 
01619           myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
01620    }
01621    /* if at timeout */
01622    if (myrpt->dtmf_local_timer == 1)
01623    {
01624       if(debug > 6)
01625          ast_log(LOG_NOTICE,"time out dtmf_local_timer=%i\n",myrpt->dtmf_local_timer);
01626 
01627       /* if anything in the string */
01628       if (myrpt->dtmf_local_str[0])
01629       {
01630          digit = myrpt->dtmf_local_str[0];
01631          myrpt->dtmf_local_str[0] = 0;
01632          for(i = 1; myrpt->dtmf_local_str[i]; i++)
01633          {
01634             myrpt->dtmf_local_str[i - 1] =
01635                myrpt->dtmf_local_str[i];
01636          }
01637          myrpt->dtmf_local_str[i - 1] = 0;
01638          myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
01639          rpt_mutex_unlock(&myrpt->lock);
01640          if (digit >= '0' && digit <='9')
01641             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
01642          else if (digit >= 'A' && digit <= 'D')
01643             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
01644          else if (digit == '*')
01645             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
01646          else if (digit == '#')
01647             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
01648          else {
01649             /* not handled */
01650             ast_debug(1, "Unable to generate DTMF tone '%c' for '%s'\n", digit, ast_channel_name(myrpt->txchannel));
01651          }
01652          rpt_mutex_lock(&myrpt->lock);
01653       }
01654       else
01655       {
01656          myrpt->dtmf_local_timer = 0;
01657       }
01658    }
01659 }
01660 
01661 static int setdtr(int fd, int enable)
01662 {
01663 struct termios mode;
01664 
01665    if (fd < 0) return -1;
01666    if (tcgetattr(fd, &mode)) {
01667       ast_log(LOG_WARNING, "Unable to get serial parameters for dtr: %s\n", strerror(errno));
01668       return -1;
01669    }
01670    if (enable)
01671    {
01672       cfsetspeed(&mode, B9600);
01673    }
01674    else
01675    {
01676       cfsetspeed(&mode, B0);
01677       usleep(100000);
01678    }
01679    if (tcsetattr(fd, TCSADRAIN, &mode)) {
01680       ast_log(LOG_WARNING, "Unable to set serial parameters for dtr: %s\n", strerror(errno));
01681       return -1;
01682    }
01683    if (enable) usleep(100000);
01684    return 0;
01685 }
01686 
01687 static int openserial(struct rpt *myrpt,char *fname)
01688 {
01689    struct termios mode;
01690    int fd;
01691 
01692    fd = open(fname,O_RDWR);
01693    if (fd == -1)
01694    {
01695       ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
01696       return -1;
01697    }
01698    memset(&mode, 0, sizeof(mode));
01699    if (tcgetattr(fd, &mode)) {
01700       ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
01701       return -1;
01702    }
01703 #ifndef  SOLARIS
01704    cfmakeraw(&mode);
01705 #else
01706         mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
01707                         |INLCR|IGNCR|ICRNL|IXON);
01708         mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
01709         mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
01710         mode.c_cflag |= CS8;
01711    mode.c_cc[VTIME] = 3;
01712    mode.c_cc[VMIN] = 1; 
01713 #endif
01714 
01715    cfsetispeed(&mode, B9600);
01716    cfsetospeed(&mode, B9600);
01717    if (tcsetattr(fd, TCSANOW, &mode)) 
01718       ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
01719    if(!strcmp(myrpt->remoterig, remote_rig_kenwood)) setdtr(fd,0); 
01720    usleep(100000);
01721    if (debug)ast_log(LOG_NOTICE,"Opened serial port %s\n",fname);
01722    return(fd); 
01723 }
01724 
01725 static void mdc1200_notify(struct rpt *myrpt,char *fromnode, unsigned int unit)
01726 {
01727    if (!fromnode)
01728    {
01729       ast_verbose("Got MDC-1200 ID %04X from local system (%s)\n",
01730          unit,myrpt->name);
01731    }
01732    else
01733    {
01734       ast_verbose("Got MDC-1200 ID %04X from node %s (%s)\n",
01735          unit,fromnode,myrpt->name);
01736    }
01737 }
01738 
01739 #ifdef   _MDC_DECODE_H_
01740 
01741 static void mdc1200_send(struct rpt *myrpt, unsigned int unit)
01742 {
01743 struct rpt_link *l;
01744 struct   ast_frame wf;
01745 char  str[200];
01746 
01747 
01748    sprintf(str,"I %s %04X",myrpt->name,unit);
01749 
01750    wf.frametype = AST_FRAME_TEXT;
01751    wf.subclass.integer = 0;
01752    wf.offset = 0;
01753    wf.mallocd = 0;
01754    wf.datalen = strlen(str) + 1;
01755    wf.samples = 0;
01756 
01757 
01758    l = myrpt->links.next;
01759    /* otherwise, send it to all of em */
01760    while(l != &myrpt->links)
01761    {
01762       if (l->name[0] == '0') 
01763       {
01764          l = l->next;
01765          continue;
01766       }
01767       wf.data = str;
01768       if (l->chan) ast_write(l->chan,&wf); 
01769       l = l->next;
01770    }
01771    return;
01772 }
01773 
01774 #endif
01775 
01776 static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
01777 {
01778 time_t   now;
01779 int   gotone;
01780 
01781    time(&now);
01782    gotone = 0;
01783    /* if too much time, reset the skate machine */
01784    if ((now - xlat->lastone) > MAXXLATTIME)
01785    {
01786       xlat->funcindex = xlat->endindex = 0;
01787    }
01788    if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
01789    {
01790       time(&xlat->lastone);
01791       gotone = 1;
01792       if (!xlat->funccharseq[xlat->funcindex])
01793       {
01794          xlat->funcindex = xlat->endindex = 0;
01795          return(myrpt->p.funcchar);
01796       }
01797    } else xlat->funcindex = 0;
01798    if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
01799    {
01800       time(&xlat->lastone);
01801       gotone = 1;
01802       if (!xlat->endcharseq[xlat->endindex])
01803       {
01804          xlat->funcindex = xlat->endindex = 0;
01805          return(myrpt->p.endchar);
01806       }
01807    } else xlat->endindex = 0;
01808    /* if in middle of decode seq, send nothing back */
01809    if (gotone) return(0);
01810    /* if no pass chars specified, return em all */
01811    if (!xlat->passchars[0]) return(c);
01812    /* if a "pass char", pass it */
01813    if (strchr(xlat->passchars,c)) return(c);
01814    return(0);
01815 }
01816 
01817 /*
01818  * Return a pointer to the first non-whitespace character
01819  */
01820 
01821 static char *eatwhite(char *s)
01822 {
01823    while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
01824       if(!*s)
01825          break;
01826       s++;
01827    }
01828    return s;
01829 }
01830 
01831 /*
01832 * Break up a delimited string into a table of substrings
01833 *
01834 * str - delimited string ( will be modified )
01835 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
01836 * limit- maximum number of substrings to process
01837 */
01838    
01839 
01840 
01841 static int finddelim(char *str, char *strp[], int limit)
01842 {
01843 int     i,l,inquo;
01844 
01845         inquo = 0;
01846         i = 0;
01847         strp[i++] = str;
01848         if (!*str)
01849            {
01850                 strp[0] = 0;
01851                 return(0);
01852            }
01853         for(l = 0; *str && (l < limit) ; str++)
01854            {
01855                 if (*str == QUOTECHR)
01856                    {
01857                         if (inquo)
01858                            {
01859                                 *str = 0;
01860                                 inquo = 0;
01861                            }
01862                         else
01863                            {
01864                                 strp[i - 1] = str + 1;
01865                                 inquo = 1;
01866                            }
01867       }
01868                 if ((*str == DELIMCHR) && (!inquo))
01869                 {
01870                         *str = 0;
01871          l++;
01872                         strp[i++] = str + 1;
01873                 }
01874            }
01875         strp[i] = 0;
01876         return(i);
01877 
01878 }
01879 /*
01880    send asterisk frame text message on the current tx channel
01881 */
01882 static int send_usb_txt(struct rpt *myrpt, char *txt) 
01883 {
01884    struct ast_frame wf;
01885  
01886    if (debug)ast_log(LOG_NOTICE, "send_usb_txt %s\n",txt);
01887    wf.frametype = AST_FRAME_TEXT;
01888    wf.subclass.integer = 0;
01889    wf.offset = 0;
01890    wf.mallocd = 0;
01891    wf.datalen = strlen(txt) + 1;
01892    wf.data.ptr = txt;
01893    wf.samples = 0;
01894    ast_write(myrpt->txchannel,&wf); 
01895    return 0;
01896 }
01897 /* must be called locked */
01898 static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
01899 {
01900 struct rpt_link *l;
01901 char mode;
01902 int   i,spos;
01903 
01904    buf[0] = 0; /* clear output buffer */
01905    if (myrpt->remote) return;
01906    /* go thru all links */
01907    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01908    {
01909       /* if is not a real link, ignore it */
01910       if (l->name[0] == '0') continue;
01911       /* don't count our stuff */
01912       if (l == mylink) continue;
01913       if (mylink && (!strcmp(l->name,mylink->name))) continue;
01914       /* figure out mode to report */
01915       mode = 'T'; /* use Tranceive by default */
01916       if (!l->mode) mode = 'R'; /* indicate RX for our mode */
01917       if (!l->thisconnected)  mode = 'C'; /* indicate connecting */
01918       spos = strlen(buf); /* current buf size (b4 we add our stuff) */
01919       if (spos)
01920       {
01921          strcat(buf,",");
01922          spos++;
01923       }
01924       /* add nodes into buffer */
01925       if (l->linklist[0])
01926       {
01927          snprintf(buf + spos,MAXLINKLIST - spos,
01928             "%c%s,%s",mode,l->name,l->linklist);
01929       }
01930       else /* if no nodes, add this node into buffer */
01931       {
01932          snprintf(buf + spos,MAXLINKLIST - spos,
01933             "%c%s",mode,l->name);
01934       }
01935       /* if we are in tranceive mode, let all modes stand */
01936       if (mode == 'T') continue;
01937       /* downgrade everyone on this node if appropriate */
01938       for(i = spos; buf[i]; i++)
01939       {
01940          if (buf[i] == 'T') buf[i] = mode;
01941          if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
01942       }
01943    }
01944    return;
01945 }
01946 
01947 /* must be called locked */
01948 static void __kickshort(struct rpt *myrpt)
01949 {
01950 struct rpt_link *l;
01951 
01952    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01953    {
01954       /* if is not a real link, ignore it */
01955       if (l->name[0] == '0') continue;
01956       l->linklisttimer = LINKLISTSHORTTIME;
01957    }
01958    myrpt->linkposttimer = LINKPOSTSHORTTIME;
01959    return;
01960 }
01961 
01962 static void statpost(struct rpt *myrpt,char *pairs)
01963 {
01964 char *str,*astr;
01965 char *astrs[100];
01966 int   n,pid;
01967 time_t   now;
01968 unsigned int seq;
01969 
01970    if (!myrpt->p.statpost_url) return;
01971    str = ast_malloc(strlen(pairs) + strlen(myrpt->p.statpost_url) + 200);
01972    astr = ast_strdup(myrpt->p.statpost_program);
01973    if ((!str) || (!astr)) {
01974       ast_free(str);
01975       ast_free(astr);
01976       return;
01977    }
01978    n = finddelim(astr,astrs,100);
01979    if (n < 1) {
01980       ast_free(str);
01981       ast_free(astr);
01982       return;
01983    }
01984    ast_mutex_lock(&myrpt->statpost_lock);
01985    seq = ++myrpt->statpost_seqno;
01986    ast_mutex_unlock(&myrpt->statpost_lock);
01987    astrs[n++] = str;
01988    astrs[n] = NULL;
01989    time(&now);
01990    sprintf(str,"%s?node=%s&time=%u&seqno=%u",myrpt->p.statpost_url,
01991       myrpt->name,(unsigned int) now,seq);
01992    if (pairs) sprintf(str + strlen(str),"&%s",pairs);
01993    if (!(pid = ast_safe_fork(0)))
01994    {
01995       execv(astrs[0],astrs);
01996       ast_log(LOG_ERROR, "exec of %s failed.\n", astrs[0]);
01997       perror("asterisk");
01998       exit(0);
01999    }
02000    ast_free(astr);
02001    ast_free(str);
02002    return;
02003 }
02004 
02005 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
02006 {
02007 
02008 char *val;
02009 int longestnode,j;
02010 struct stat mystat;
02011 static time_t last = 0;
02012 static struct ast_config *ourcfg = NULL;
02013 struct ast_variable *vp;
02014 
02015    /* try to look it up locally first */
02016    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
02017    if (val) return(val);
02018    ast_mutex_lock(&nodelookuplock);
02019    /* if file does not exist */
02020    if (stat(myrpt->p.extnodefile,&mystat) == -1)
02021    {
02022       if (ourcfg) ast_config_destroy(ourcfg);
02023       ourcfg = NULL;
02024       ast_mutex_unlock(&nodelookuplock);
02025       return(NULL);
02026    }
02027    /* if we need to reload */
02028    if (mystat.st_mtime > last)
02029    {
02030       if (ourcfg) ast_config_destroy(ourcfg);
02031 #ifdef   NEW_ASTERISK
02032       ourcfg = ast_config_load(myrpt->p.extnodefile,config_flags);
02033 #else
02034       ourcfg = ast_config_load(myrpt->p.extnodefile);
02035 #endif
02036       /* if file not there, just bail */
02037       if (!ourcfg || ourcfg == CONFIG_STATUS_FILEINVALID)
02038       {
02039          ast_mutex_unlock(&nodelookuplock);
02040          return(NULL);
02041       }
02042       /* reset "last" time */
02043       last = mystat.st_mtime;
02044 
02045       /* determine longest node length again */    
02046       longestnode = 0;
02047       vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
02048       while(vp){
02049          j = strlen(vp->name);
02050          if (j > longestnode)
02051             longestnode = j;
02052          vp = vp->next;
02053       }
02054 
02055       vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
02056       while(vp){
02057          j = strlen(vp->name);
02058          if (j > longestnode)
02059             longestnode = j;
02060          vp = vp->next;
02061       }
02062 
02063       myrpt->longestnode = longestnode;
02064    }
02065    val = NULL;
02066    if (ourcfg)
02067       val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
02068    ast_mutex_unlock(&nodelookuplock);
02069    return(val);
02070 }
02071 
02072 /*
02073 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
02074 * If param is passed in non-null, then it will be set to the first character past the match
02075 */
02076 
02077 static int matchkeyword(char *string, char **param, char *keywords[])
02078 {
02079 int   i,ls;
02080    for( i = 0 ; keywords[i] ; i++){
02081       ls = strlen(keywords[i]);
02082       if(!ls){
02083          *param = NULL;
02084          return 0;
02085       }
02086       if(!strncmp(string, keywords[i], ls)){
02087          if(param)
02088             *param = string + ls;
02089          return i + 1; 
02090       }
02091    }
02092    *param = NULL;
02093    return 0;
02094 }
02095 
02096 /*
02097 * Skip characters in string which are in charlist, and return a pointer to the
02098 * first non-matching character
02099 */
02100 
02101 static char *skipchars(char *string, char *charlist)
02102 {
02103 int i;   
02104    while(*string){
02105       for(i = 0; charlist[i] ; i++){
02106          if(*string == charlist[i]){
02107             string++;
02108             break;
02109          }
02110       }
02111       if(!charlist[i])
02112          return string;
02113    }
02114    return string;
02115 }
02116 
02117 static int myatoi(const char *str)
02118 {
02119    int   ret;
02120 
02121    if (!str) {
02122       return -1;
02123    }
02124 
02125    /* leave this %i alone, non-base-10 input is useful here */
02126    if (sscanf(str, "%30i", &ret) != 1) {
02127       return -1;
02128    }
02129 
02130    return ret;
02131 }
02132 
02133 static int mycompar(const void *a, const void *b)
02134 {
02135 char  **x = (char **) a;
02136 char  **y = (char **) b;
02137 int   xoff,yoff;
02138 
02139    if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
02140    if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
02141    return(strcmp((*x) + xoff,(*y) + yoff));
02142 }
02143 
02144 static int topcompar(const void *a, const void *b)
02145 {
02146 struct rpt_topkey *x = (struct rpt_topkey *) a;
02147 struct rpt_topkey *y = (struct rpt_topkey *) b;
02148 
02149    return(x->timesince - y->timesince);
02150 }
02151 
02152 #ifdef   __RPT_NOTCH
02153 
02154 /* rpt filter routine */
02155 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
02156 {
02157 int   i,j;
02158 struct   rptfilter *f;
02159 
02160    for(i = 0; i < len; i++)
02161    {
02162       for(j = 0; j < MAXFILTERS; j++)
02163       {
02164          f = &myrpt->filters[j];
02165          if (!*f->desc) continue;
02166          f->x0 = f->x1; f->x1 = f->x2;
02167               f->x2 = ((float)buf[i]) / f->gain;
02168               f->y0 = f->y1; f->y1 = f->y2;
02169               f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
02170                            + (f->const1 * f->y0) + (f->const2 * f->y1);
02171          buf[i] = (short)f->y2;
02172       }
02173    }
02174 }
02175 
02176 #endif
02177 
02178 
02179 /*
02180  Get the time for the machine's time zone
02181  Note: Asterisk requires a copy of localtime
02182  in the /etc directory for this to work properly.
02183  If /etc/localtime is not present, you will get
02184  GMT time! This is especially important on systems
02185  running embedded linux distributions as they don't usually
02186  have support for locales. 
02187 
02188  If OLD_ASTERISK is defined, then the older localtime_r
02189  function will be used. The /etc/localtime file is not
02190  required in this case. This provides backward compatibility
02191  with Asterisk 1.2 systems.
02192 
02193 */
02194 
02195 #ifdef   NEW_ASTERISK
02196 static void rpt_localtime( time_t * t, struct ast_tm *lt)
02197 {
02198    struct timeval when;
02199 
02200    when.tv_sec = *t;
02201    when.tv_usec = 0;
02202    ast_localtime(&when, lt, NULL);
02203 }
02204 
02205 #else
02206 static void rpt_localtime( time_t * t, struct tm *lt)
02207 {
02208 #ifdef OLD_ASTERISK
02209    localtime_r(t, lt);
02210 #else
02211    ast_localtime(t, lt, NULL);
02212 #endif
02213 }
02214 #endif
02215 
02216 
02217 /* Retrieve an int from a config file */
02218                                                                                 
02219 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
02220 {
02221         char *var;
02222         int ret;
02223    char include_zero = 0;
02224 
02225    if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
02226       min = -min;
02227       include_zero = 1;
02228    }           
02229                                                                      
02230         var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
02231         if(var){
02232                 ret = myatoi(var);
02233       if(include_zero && !ret)
02234          return 0;
02235                 if(ret < min)
02236                         ret = min;
02237                 if(ret > max)
02238                         ret = max;
02239         }
02240         else
02241                 ret = defl;
02242         return ret;
02243 }
02244 
02245 
02246 static void load_rpt_vars(int n,int init)
02247 {
02248 char *this,*val;
02249 int   i,j,longestnode;
02250 struct ast_variable *vp;
02251 struct ast_config *cfg;
02252 char *strs[100];
02253 char s1[256];
02254 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
02255             "ufena","ufdis","atena","atdis",NULL};
02256 
02257    ast_verb(3, "%s config for repeater %s\n",
02258          (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
02259    ast_mutex_lock(&rpt_vars[n].lock);
02260    if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
02261 #ifdef   NEW_ASTERISK
02262    cfg = ast_config_load("rpt.conf",config_flags);
02263 #else
02264    cfg = ast_config_load("rpt.conf");
02265 #endif
02266    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
02267       ast_mutex_unlock(&rpt_vars[n].lock);
02268       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
02269       pthread_exit(NULL);
02270    }
02271    rpt_vars[n].cfg = cfg; 
02272    this = rpt_vars[n].name;
02273    memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
02274    if (init)
02275    {
02276       char *cp;
02277       int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
02278 
02279       cp = (char *) &rpt_vars[n].p;
02280       memset(cp + sizeof(rpt_vars[n].p),0,
02281          sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
02282       rpt_vars[n].tele.next = &rpt_vars[n].tele;
02283       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
02284       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
02285       rpt_vars[n].tailmessagen = 0;
02286    }
02287 #ifdef   __RPT_NOTCH
02288    /* zot out filters stuff */
02289    memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
02290 #endif
02291    val = (char *) ast_variable_retrieve(cfg,this,"context");
02292    if (val) rpt_vars[n].p.ourcontext = val;
02293    else rpt_vars[n].p.ourcontext = this;
02294    val = (char *) ast_variable_retrieve(cfg,this,"callerid");
02295    if (val) rpt_vars[n].p.ourcallerid = val;
02296    val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
02297    if (val) rpt_vars[n].p.acctcode = val;
02298    val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
02299    if (val) rpt_vars[n].p.ident = val;
02300    val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
02301    if (val) rpt_vars[n].p.hangtime = atoi(val);
02302       else rpt_vars[n].p.hangtime = HANGTIME;
02303    val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
02304    if (val) rpt_vars[n].p.althangtime = atoi(val);
02305       else rpt_vars[n].p.althangtime = HANGTIME;
02306    val = (char *) ast_variable_retrieve(cfg,this,"totime");
02307    if (val) rpt_vars[n].p.totime = atoi(val);
02308       else rpt_vars[n].p.totime = TOTIME;
02309    val = (char *) ast_variable_retrieve(cfg,this,"voxtimeout");
02310    if (val) rpt_vars[n].p.voxtimeout_ms = atoi(val);
02311       else rpt_vars[n].p.voxtimeout_ms = VOX_TIMEOUT_MS;
02312    val = (char *) ast_variable_retrieve(cfg,this,"voxrecover");
02313    if (val) rpt_vars[n].p.voxrecover_ms = atoi(val);
02314       else rpt_vars[n].p.voxrecover_ms = VOX_RECOVER_MS;
02315    val = (char *) ast_variable_retrieve(cfg,this,"simplexpatchdelay");
02316    if (val) rpt_vars[n].p.simplexpatchdelay = atoi(val);
02317       else rpt_vars[n].p.simplexpatchdelay = SIMPLEX_PATCH_DELAY;
02318    val = (char *) ast_variable_retrieve(cfg,this,"simplexphonedelay");
02319    if (val) rpt_vars[n].p.simplexphonedelay = atoi(val);
02320       else rpt_vars[n].p.simplexphonedelay = SIMPLEX_PHONE_DELAY;
02321    val = (char *) ast_variable_retrieve(cfg,this,"statpost_program");
02322    if (val) rpt_vars[n].p.statpost_program = val;
02323       else rpt_vars[n].p.statpost_program = STATPOST_PROGRAM;
02324    rpt_vars[n].p.statpost_url = 
02325       (char *) ast_variable_retrieve(cfg,this,"statpost_url");
02326    rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);    
02327    rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);     
02328    rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
02329    rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME);   /* Enforce a min max including zero */
02330    rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
02331    val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
02332    if (val) rpt_vars[n].p.tonezone = val;
02333    rpt_vars[n].p.tailmessages[0] = 0;
02334    rpt_vars[n].p.tailmessagemax = 0;
02335    val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
02336    if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
02337    val = (char *) ast_variable_retrieve(cfg,this,"memory");
02338    if (!val) val = MEMORY;
02339    rpt_vars[n].p.memory = val;
02340    val = (char *) ast_variable_retrieve(cfg,this,"macro");
02341    if (!val) val = MACRO;
02342    rpt_vars[n].p.macro = val;
02343    val = (char *) ast_variable_retrieve(cfg,this,"tonemacro");
02344    if (!val) val = TONEMACRO;
02345    rpt_vars[n].p.tonemacro = val;
02346    val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
02347    if (val) rpt_vars[n].p.startupmacro = val;
02348    val = (char *) ast_variable_retrieve(cfg,this,"iobase");
02349    /* do not use atoi() here, we need to be able to have
02350       the input specified in hex or decimal so we use
02351       sscanf with a %i */
02352    if ((!val) || (sscanf(val,"%30i",&rpt_vars[n].p.iobase) != 1))
02353       rpt_vars[n].p.iobase = DEFAULT_IOBASE;
02354    val = (char *) ast_variable_retrieve(cfg,this,"ioport");
02355    rpt_vars[n].p.ioport = val;
02356    val = (char *) ast_variable_retrieve(cfg,this,"functions");
02357    if (!val)
02358       {
02359          val = FUNCTIONS;
02360          rpt_vars[n].p.simple = 1;
02361       } 
02362    rpt_vars[n].p.functions = val;
02363    val =  (char *) ast_variable_retrieve(cfg,this,"link_functions");
02364    if (val) rpt_vars[n].p.link_functions = val;
02365    else 
02366       rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
02367    val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
02368    if (val) rpt_vars[n].p.phone_functions = val;
02369    val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
02370    if (val) rpt_vars[n].p.dphone_functions = val;
02371    val = (char *) ast_variable_retrieve(cfg,this,"alt_functions");
02372    if (val) rpt_vars[n].p.alt_functions = val;
02373    val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
02374    if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
02375       rpt_vars[n].p.funcchar = *val;      
02376    val = (char *) ast_variable_retrieve(cfg,this,"endchar");
02377    if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
02378       rpt_vars[n].p.endchar = *val;    
02379    val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
02380    if (val) rpt_vars[n].p.nobusyout = ast_true(val);
02381    val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
02382    if (val) rpt_vars[n].p.notelemtx = ast_true(val);
02383    val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
02384    if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
02385    val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
02386    if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
02387    val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
02388    if (val) rpt_vars[n].p.linktolink = ast_true(val);
02389    val = (char *) ast_variable_retrieve(cfg,this,"nodes");
02390    if (!val) val = NODES;
02391    rpt_vars[n].p.nodes = val;
02392    val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
02393    if (!val) val = EXTNODES;
02394    rpt_vars[n].p.extnodes = val;
02395    val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
02396    if (!val) val = EXTNODEFILE;
02397    rpt_vars[n].p.extnodefile = val;
02398    val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
02399    if (val) rpt_vars[n].p.archivedir = val;
02400    val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
02401    if (val) rpt_vars[n].p.authlevel = atoi(val); 
02402    else rpt_vars[n].p.authlevel = 0;
02403    val = (char *) ast_variable_retrieve(cfg,this,"parrot");
02404    if (val) rpt_vars[n].p.parrotmode = ast_true(val) * 2;
02405    else rpt_vars[n].p.parrotmode = 0;
02406    val = (char *) ast_variable_retrieve(cfg,this,"parrottime");
02407    if (val) rpt_vars[n].p.parrottime = atoi(val); 
02408    else rpt_vars[n].p.parrottime = PARROTTIME;
02409    val = (char *) ast_variable_retrieve(cfg,this,"rptnode");
02410    rpt_vars[n].p.rptnode = val;
02411    val = (char *) ast_variable_retrieve(cfg,this,"mars");
02412    if (val) rpt_vars[n].p.remote_mars = atoi(val); 
02413    else rpt_vars[n].p.remote_mars = 0;
02414    val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
02415    if (val) rpt_vars[n].p.monminblocks = atol(val); 
02416    else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
02417    val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
02418    if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); 
02419    else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
02420    val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
02421    if (val) rpt_vars[n].p.civaddr = atoi(val); 
02422    else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
02423    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
02424    if (val) rpt_vars[n].p.remotetimeout = atoi(val); 
02425    else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
02426    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
02427    if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); 
02428    else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
02429    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
02430    if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); 
02431    else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
02432 #ifdef   __RPT_NOTCH
02433    val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
02434    if (val) {
02435       i = finddelim(val,strs,MAXFILTERS * 2);
02436       i &= ~1; /* force an even number, rounded down */
02437       if (i >= 2) for(j = 0; j < i; j += 2)
02438       {
02439          rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
02440            &rpt_vars[n].filters[j >> 1].gain,
02441              &rpt_vars[n].filters[j >> 1].const0,
02442             &rpt_vars[n].filters[j >> 1].const1,
02443                 &rpt_vars[n].filters[j >> 1].const2);
02444          sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
02445             strs[j],strs[j + 1]);
02446       }
02447 
02448    }
02449 #endif
02450    val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
02451    if (val) {
02452       memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
02453       i = finddelim(val,strs,3);
02454       if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
02455       if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
02456       if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
02457    }
02458    val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
02459    if (val) {
02460       memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
02461       i = finddelim(val,strs,3);
02462       if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
02463       if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
02464       if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
02465    }
02466    /* retreive the stanza name for the control states if there is one */
02467    val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
02468    rpt_vars[n].p.csstanzaname = val;
02469       
02470    /* retreive the stanza name for the scheduler if there is one */
02471    val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
02472    rpt_vars[n].p.skedstanzaname = val;
02473 
02474    /* retreive the stanza name for the txlimits */
02475    val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
02476    rpt_vars[n].p.txlimitsstanzaname = val;
02477 
02478    longestnode = 0;
02479 
02480    vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
02481       
02482    while(vp){
02483       j = strlen(vp->name);
02484       if (j > longestnode)
02485          longestnode = j;
02486       vp = vp->next;
02487    }
02488 
02489    rpt_vars[n].longestnode = longestnode;
02490       
02491    /*
02492    * For this repeater, Determine the length of the longest function 
02493    */
02494    rpt_vars[n].longestfunc = 0;
02495    vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
02496    while(vp){
02497       j = strlen(vp->name);
02498       if (j > rpt_vars[n].longestfunc)
02499          rpt_vars[n].longestfunc = j;
02500       vp = vp->next;
02501    }
02502    /*
02503    * For this repeater, Determine the length of the longest function 
02504    */
02505    rpt_vars[n].link_longestfunc = 0;
02506    vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
02507    while(vp){
02508       j = strlen(vp->name);
02509       if (j > rpt_vars[n].link_longestfunc)
02510          rpt_vars[n].link_longestfunc = j;
02511       vp = vp->next;
02512    }
02513    rpt_vars[n].phone_longestfunc = 0;
02514    if (rpt_vars[n].p.phone_functions)
02515    {
02516       vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
02517       while(vp){
02518          j = strlen(vp->name);
02519          if (j > rpt_vars[n].phone_longestfunc)
02520             rpt_vars[n].phone_longestfunc = j;
02521          vp = vp->next;
02522       }
02523    }
02524    rpt_vars[n].dphone_longestfunc = 0;
02525    if (rpt_vars[n].p.dphone_functions)
02526    {
02527       vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
02528       while(vp){
02529          j = strlen(vp->name);
02530          if (j > rpt_vars[n].dphone_longestfunc)
02531             rpt_vars[n].dphone_longestfunc = j;
02532          vp = vp->next;
02533       }
02534    }
02535    rpt_vars[n].alt_longestfunc = 0;
02536    if (rpt_vars[n].p.alt_functions)
02537    {
02538       vp = ast_variable_browse(cfg, rpt_vars[n].p.alt_functions);
02539       while(vp){
02540          j = strlen(vp->name);
02541          if (j > rpt_vars[n].alt_longestfunc)
02542             rpt_vars[n].alt_longestfunc = j;
02543          vp = vp->next;
02544       }
02545    }
02546    rpt_vars[n].macro_longest = 1;
02547    vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
02548    while(vp){
02549       j = strlen(vp->name);
02550       if (j > rpt_vars[n].macro_longest)
02551          rpt_vars[n].macro_longest = j;
02552       vp = vp->next;
02553    }
02554    
02555    /* Browse for control states */
02556    if(rpt_vars[n].p.csstanzaname)
02557       vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
02558    else
02559       vp = NULL;
02560    for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
02561       int k,nukw,statenum;
02562       statenum=atoi(vp->name);
02563       strncpy(s1, vp->value, 255);
02564       s1[255] = 0;
02565       nukw  = finddelim(s1,strs,32);
02566       
02567       for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */  
02568          for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
02569             if(!strcmp(strs[k],cs_keywords[j])){
02570                switch(j){
02571                   case 0: /* rptena */
02572                      rpt_vars[n].p.s[statenum].txdisable = 0;
02573                      break;
02574                   case 1: /* rptdis */
02575                      rpt_vars[n].p.s[statenum].txdisable = 1;
02576                      break;
02577          
02578                   case 2: /* apena */
02579                      rpt_vars[n].p.s[statenum].autopatchdisable = 0;
02580                      break;
02581 
02582                   case 3: /* apdis */
02583                      rpt_vars[n].p.s[statenum].autopatchdisable = 1;
02584                      break;
02585 
02586                   case 4: /* lnkena */
02587                      rpt_vars[n].p.s[statenum].linkfundisable = 0;
02588                      break;
02589    
02590                   case 5: /* lnkdis */
02591                      rpt_vars[n].p.s[statenum].linkfundisable = 1;
02592                      break;
02593 
02594                   case 6: /* totena */
02595                      rpt_vars[n].p.s[statenum].totdisable = 0;
02596                      break;
02597                
02598                   case 7: /* totdis */
02599                      rpt_vars[n].p.s[statenum].totdisable = 1;
02600                      break;
02601 
02602                   case 8: /* skena */
02603                      rpt_vars[n].p.s[statenum].schedulerdisable = 0;
02604                      break;
02605 
02606                   case 9: /* skdis */
02607                      rpt_vars[n].p.s[statenum].schedulerdisable = 1;
02608                      break;
02609 
02610                   case 10: /* ufena */
02611                      rpt_vars[n].p.s[statenum].userfundisable = 0;
02612                      break;
02613 
02614                   case 11: /* ufdis */
02615                      rpt_vars[n].p.s[statenum].userfundisable = 1;
02616                      break;
02617 
02618                   case 12: /* atena */
02619                      rpt_vars[n].p.s[statenum].alternatetail = 1;
02620                      break;
02621 
02622                   case 13: /* atdis */
02623                      rpt_vars[n].p.s[statenum].alternatetail = 0;
02624                      break;
02625          
02626                   default:
02627                      ast_log(LOG_WARNING,
02628                         "Unhandled control state keyword %s", cs_keywords[i]);
02629                      break;
02630                }
02631             }
02632          }
02633       }
02634       vp = vp->next;
02635    }
02636    ast_mutex_unlock(&rpt_vars[n].lock);
02637 }
02638 
02639 /*
02640 * Enable or disable debug output at a given level at the console
02641 */
02642 static int rpt_do_debug(int fd, int argc, const char * const *argv)
02643 {
02644    int newlevel;
02645 
02646    if (argc != 4) {
02647       return RESULT_SHOWUSAGE;
02648    }
02649 
02650    newlevel = myatoi(argv[3]);
02651 
02652    if (newlevel < 0 || newlevel > 7) {
02653       return RESULT_SHOWUSAGE;
02654    }
02655 
02656    if (newlevel) {
02657       ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
02658    } else {
02659       ast_cli(fd, "app_rpt Debugging disabled\n");
02660    }
02661 
02662    debug = newlevel;
02663 
02664    return RESULT_SUCCESS;
02665 }
02666 
02667 /*
02668 * Dump rpt struct debugging onto console
02669 */
02670                                                                                                                                  
02671 static int rpt_do_dump(int fd, int argc, const char * const *argv)
02672 {
02673    int i;
02674 
02675         if (argc != 3)
02676                 return RESULT_SHOWUSAGE;
02677 
02678    for(i = 0; i < nrpts; i++)
02679    {
02680       if (!strcmp(argv[2],rpt_vars[i].name))
02681       {
02682          rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
02683               ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
02684               return RESULT_SUCCESS;
02685       }
02686    }
02687    return RESULT_FAILURE;
02688 }
02689 
02690 /*
02691 * Dump statistics onto console
02692 */
02693 
02694 static int rpt_do_stats(int fd, int argc, const char * const *argv)
02695 {
02696    int i,j,numoflinks;
02697    int dailytxtime, dailykerchunks;
02698    time_t now;
02699    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
02700    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
02701    int uptime;
02702    long long totaltxtime;
02703    struct   rpt_link *l;
02704    char *listoflinks[MAX_STAT_LINKS];  
02705    char *lastdtmfcommand,*parrot_ena;
02706    char *tot_state, *ider_state, *patch_state;
02707    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
02708    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
02709    struct rpt *myrpt;
02710 
02711    static char *not_applicable = "N/A";
02712 
02713    if(argc != 3)
02714       return RESULT_SHOWUSAGE;
02715 
02716    tot_state = ider_state = 
02717    patch_state = reverse_patch_state = 
02718    input_signal = not_applicable;
02719    called_number = lastdtmfcommand = NULL;
02720 
02721    time(&now);
02722    for(i = 0; i < nrpts; i++)
02723    {
02724       if (!strcmp(argv[2],rpt_vars[i].name)){
02725          /* Make a copy of all stat variables while locked */
02726          myrpt = &rpt_vars[i];
02727          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02728          uptime = (int)(now - starttime);
02729          dailytxtime = myrpt->dailytxtime;
02730          totaltxtime = myrpt->totaltxtime;
02731          dailykeyups = myrpt->dailykeyups;
02732          totalkeyups = myrpt->totalkeyups;
02733          dailykerchunks = myrpt->dailykerchunks;
02734          totalkerchunks = myrpt->totalkerchunks;
02735          dailyexecdcommands = myrpt->dailyexecdcommands;
02736          totalexecdcommands = myrpt->totalexecdcommands;
02737          timeouts = myrpt->timeouts;
02738 
02739          /* Traverse the list of connected nodes */
02740          reverse_patch_state = "DOWN";
02741          numoflinks = 0;
02742          l = myrpt->links.next;
02743          while(l && (l != &myrpt->links)){
02744             if(numoflinks >= MAX_STAT_LINKS){
02745                ast_log(LOG_NOTICE,
02746                "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
02747                break;
02748             }
02749             if (l->name[0] == '0'){ /* Skip '0' nodes */
02750                reverse_patch_state = "UP";
02751                l = l->next;
02752                continue;
02753             }
02754             listoflinks[numoflinks] = ast_strdup(l->name);
02755             if(listoflinks[numoflinks] == NULL){
02756                break;
02757             }
02758             else{
02759                numoflinks++;
02760             }
02761             l = l->next;
02762          }
02763 
02764          if(myrpt->keyed)
02765             input_signal = "YES";
02766          else
02767             input_signal = "NO";
02768 
02769          if(myrpt->p.parrotmode)
02770             parrot_ena = "ENABLED";
02771          else
02772             parrot_ena = "DISABLED";
02773 
02774          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
02775             sys_ena = "DISABLED";
02776          else
02777             sys_ena = "ENABLED";
02778 
02779          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
02780             tot_ena = "DISABLED";
02781          else
02782             tot_ena = "ENABLED";
02783 
02784          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
02785             link_ena = "DISABLED";
02786          else
02787             link_ena = "ENABLED";
02788 
02789          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
02790             patch_ena = "DISABLED";
02791          else
02792             patch_ena = "ENABLED";
02793 
02794          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
02795             sch_ena = "DISABLED";
02796          else
02797             sch_ena = "ENABLED";
02798 
02799          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
02800             user_funs = "DISABLED";
02801          else
02802             user_funs = "ENABLED";
02803 
02804          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
02805             tail_type = "ALTERNATE";
02806          else
02807             tail_type = "STANDARD";
02808 
02809          if(!myrpt->totimer)
02810             tot_state = "TIMED OUT!";
02811          else if(myrpt->totimer != myrpt->p.totime)
02812             tot_state = "ARMED";
02813          else
02814             tot_state = "RESET";
02815 
02816          if(myrpt->tailid)
02817             ider_state = "QUEUED IN TAIL";
02818          else if(myrpt->mustid)
02819             ider_state = "QUEUED FOR CLEANUP";
02820          else
02821             ider_state = "CLEAN";
02822 
02823          switch(myrpt->callmode){
02824             case 1:
02825                patch_state = "DIALING";
02826                break;
02827             case 2:
02828                patch_state = "CONNECTING";
02829                break;
02830             case 3:
02831                patch_state = "UP";
02832                break;
02833 
02834             case 4:
02835                patch_state = "CALL FAILED";
02836                break;
02837 
02838             default:
02839                patch_state = "DOWN";
02840          }
02841 
02842          if(strlen(myrpt->exten)){
02843             called_number = ast_strdup(myrpt->exten);
02844          }
02845 
02846          if(strlen(myrpt->lastdtmfcommand)){
02847             lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
02848          }
02849          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02850 
02851          ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
02852          ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
02853          ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
02854          ast_cli(fd, "System...........................................: %s\n", sys_ena);
02855          ast_cli(fd, "Parrot Mode......................................: %s\n", parrot_ena);
02856          ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
02857          ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
02858          ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
02859          ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
02860          ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
02861          ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
02862          ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
02863          ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
02864          ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
02865          ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
02866          ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
02867          ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
02868          ast_cli(fd, "Last DTMF command executed.......................: %s\n", 
02869          (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
02870          hours = dailytxtime/3600000;
02871          dailytxtime %= 3600000;
02872          minutes = dailytxtime/60000;
02873          dailytxtime %= 60000;
02874          seconds = dailytxtime/1000;
02875          dailytxtime %= 1000;
02876 
02877          ast_cli(fd, "TX time today....................................: %02d:%02d:%02d.%d\n",
02878             hours, minutes, seconds, dailytxtime);
02879 
02880          hours = (int) totaltxtime/3600000;
02881          totaltxtime %= 3600000;
02882          minutes = (int) totaltxtime/60000;
02883          totaltxtime %= 60000;
02884          seconds = (int)  totaltxtime/1000;
02885          totaltxtime %= 1000;
02886 
02887          ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
02888              hours, minutes, seconds, (int) totaltxtime);
02889 
02890                         hours = uptime/3600;
02891                         uptime %= 3600;
02892                         minutes = uptime/60;
02893                         uptime %= 60;
02894 
02895                         ast_cli(fd, "Uptime...........................................: %02d:%02d:%02d\n",
02896                                 hours, minutes, uptime);
02897 
02898          ast_cli(fd, "Nodes currently connected to us..................: ");
02899                         if(!numoflinks){
02900                          ast_cli(fd,"<NONE>");
02901                         }
02902          else{
02903             for(j = 0 ;j < numoflinks; j++){
02904                ast_cli(fd, "%s", listoflinks[j]);
02905                if(j % 4 == 3){
02906                   ast_cli(fd, "\n");
02907                   ast_cli(fd, "                                                 : ");
02908                }  
02909                else{
02910                   if((numoflinks - 1) - j  > 0)
02911                      ast_cli(fd, ", ");
02912                }
02913             }
02914          }
02915          ast_cli(fd,"\n");
02916 
02917          ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
02918          ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
02919          ast_cli(fd, "Autopatch called number..........................: %s\n",
02920          (called_number && strlen(called_number)) ? called_number : not_applicable);
02921          ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
02922          ast_cli(fd, "User linking commands............................: %s\n", link_ena);
02923          ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
02924 
02925          for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
02926             ast_free(listoflinks[j]);
02927          }
02928          ast_free(called_number);
02929          ast_free(lastdtmfcommand);
02930               return RESULT_SUCCESS;
02931       }
02932    }
02933    return RESULT_FAILURE;
02934 }
02935 
02936 /*
02937 * Link stats function
02938 */
02939 
02940 static int rpt_do_lstats(int fd, int argc, const char * const *argv)
02941 {
02942    int i,j;
02943    char *connstate;
02944    struct rpt *myrpt;
02945    struct rpt_link *l;
02946    struct rpt_lstat *s,*t;
02947    struct rpt_lstat s_head;
02948    if(argc != 3)
02949       return RESULT_SHOWUSAGE;
02950 
02951    s = NULL;
02952    s_head.next = &s_head;
02953    s_head.prev = &s_head;
02954 
02955    for(i = 0; i < nrpts; i++)
02956    {
02957       if (!strcmp(argv[2],rpt_vars[i].name)){
02958          /* Make a copy of all stat variables while locked */
02959          myrpt = &rpt_vars[i];
02960          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02961          /* Traverse the list of connected nodes */
02962          j = 0;
02963          l = myrpt->links.next;
02964          while(l && (l != &myrpt->links)){
02965             if (l->name[0] == '0'){ /* Skip '0' nodes */
02966                l = l->next;
02967                continue;
02968             }
02969             if((s = (struct rpt_lstat *) ast_malloc(sizeof(struct rpt_lstat))) == NULL){
02970                ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
02971                rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02972                return RESULT_FAILURE;
02973             }
02974             memset(s, 0, sizeof(struct rpt_lstat));
02975             strncpy(s->name, l->name, MAXREMSTR - 1);
02976             if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
02977             else strcpy(s->peer,"(none)");
02978             s->mode = l->mode;
02979             s->outbound = l->outbound;
02980             s->reconnects = l->reconnects;
02981             s->connecttime = l->connecttime;
02982             s->thisconnected = l->thisconnected;
02983             memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
02984             insque((struct qelem *) s, (struct qelem *) s_head.next);
02985             memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
02986             l = l->next;
02987          }
02988          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02989          ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME        CONNECT STATE\n");
02990          ast_cli(fd, "----      ----                ----------  ---------  ------------        -------------\n");
02991 
02992          for(s = s_head.next; s != &s_head; s = s->next){
02993             int hours, minutes, seconds;
02994             long long connecttime = s->connecttime;
02995             char conntime[21];
02996             hours = (int) connecttime/3600000;
02997             connecttime %= 3600000;
02998             minutes = (int) connecttime/60000;
02999             connecttime %= 60000;
03000             seconds = (int)  connecttime/1000;
03001             connecttime %= 1000;
03002             snprintf(conntime, 20, "%02d:%02d:%02d.%d",
03003                hours, minutes, seconds, (int) connecttime);
03004             conntime[20] = 0;
03005             if(s->thisconnected)
03006                connstate  = "ESTABLISHED";
03007             else
03008                connstate = "CONNECTING";
03009             ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
03010                s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
03011          }  
03012          /* destroy our local link queue */
03013          s = s_head.next;
03014          while(s != &s_head){
03015             t = s;
03016             s = s->next;
03017             remque((struct qelem *)t);
03018             ast_free(t);
03019          }        
03020          return RESULT_SUCCESS;
03021       }
03022    }
03023    return RESULT_FAILURE;
03024 }
03025 
03026 /*
03027 * List all nodes connected, directly or indirectly
03028 */
03029 
03030 static int rpt_do_nodes(int fd, int argc, const char * const *argv)
03031 {
03032    int i,j;
03033    char ns;
03034    char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
03035    struct rpt *myrpt;
03036    if(argc != 3)
03037       return RESULT_SHOWUSAGE;
03038 
03039    for(i = 0; i < nrpts; i++)
03040    {
03041       if (!strcmp(argv[2],rpt_vars[i].name)){
03042          /* Make a copy of all stat variables while locked */
03043          myrpt = &rpt_vars[i];
03044          rpt_mutex_lock(&myrpt->lock); /* LOCK */
03045          __mklinklist(myrpt,NULL,lbuf);
03046          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
03047          /* parse em */
03048          ns = finddelim(lbuf,strs,MAXLINKLIST);
03049          /* sort em */
03050          if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
03051          ast_cli(fd,"\n");
03052          ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
03053          for(j = 0 ;; j++){
03054             if(!strs[j]){
03055                if(!j){
03056                   ast_cli(fd,"<NONE>");
03057                }
03058                break;
03059             }
03060             ast_cli(fd, "%s", strs[j]);
03061             if(j % 8 == 7){
03062                ast_cli(fd, "\n");
03063             }
03064             else{
03065                if(strs[j + 1])
03066                   ast_cli(fd, ", ");
03067             }
03068          }
03069          ast_cli(fd,"\n\n");
03070          return RESULT_SUCCESS;
03071       }
03072    }
03073    return RESULT_FAILURE;
03074 }
03075 
03076 /*
03077 * List all locally configured nodes
03078 */
03079 
03080 static int rpt_do_local_nodes(int fd, int argc, const char * const *argv)
03081 {
03082 
03083     int i;
03084     ast_cli(fd, "\nNode\n----\n");
03085     for (i=0; i< nrpts; i++)
03086     {
03087         ast_cli(fd, "%s\n", rpt_vars[i].name);        
03088     } /* for i */
03089     ast_cli(fd,"\n");
03090     return RESULT_SUCCESS;
03091 } 
03092 
03093 
03094 /*
03095 * reload vars 
03096 */
03097 
03098 static int rpt_do_reload(int fd, int argc, const char * const *argv)
03099 {
03100 int   n;
03101 
03102         if (argc > 2) return RESULT_SHOWUSAGE;
03103 
03104    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
03105 
03106    return RESULT_FAILURE;
03107 }
03108 
03109 /*
03110 * restart app_rpt
03111 */
03112                                                                                                                                  
03113 static int rpt_do_restart(int fd, int argc, const char * const *argv)
03114 {
03115 int   i;
03116 
03117         if (argc > 2) return RESULT_SHOWUSAGE;
03118    for(i = 0; i < nrpts; i++)
03119    {
03120       if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
03121    }
03122    return RESULT_FAILURE;
03123 }
03124 
03125 
03126 /*
03127 * send an app_rpt DTMF function from the CLI
03128 */
03129                                                                                                                                  
03130 static int rpt_do_fun(int fd, int argc, const char * const *argv)
03131 {
03132    int   i,busy=0;
03133 
03134         if (argc != 4) return RESULT_SHOWUSAGE;
03135 
03136    for(i = 0; i < nrpts; i++){
03137       if(!strcmp(argv[2], rpt_vars[i].name)){
03138          struct rpt *myrpt = &rpt_vars[i];
03139          rpt_mutex_lock(&myrpt->lock);
03140          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
03141             rpt_mutex_unlock(&myrpt->lock);
03142             busy=1;
03143          }
03144          if(!busy){
03145             myrpt->macrotimer = MACROTIME;
03146             strncat(myrpt->macrobuf,argv[3],MAXMACRO - 1);
03147          }
03148          rpt_mutex_unlock(&myrpt->lock);
03149       }
03150    }
03151    if(busy){
03152       ast_cli(fd, "Function decoder busy");
03153    }
03154    return RESULT_FAILURE;
03155 }
03156 /*
03157    the convention is that macros in the data from the rpt() application
03158    are all at the end of the data, separated by the | and start with a *
03159    when put into the macro buffer, the characters have their high bit
03160    set so the macro processor knows they came from the application data
03161    and to use the alt-functions table.
03162    sph:
03163 */
03164 static int rpt_push_alt_macro(struct rpt *myrpt, char *sptr)
03165 {
03166    int   busy=0;
03167 
03168    rpt_mutex_lock(&myrpt->lock);
03169    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(sptr)){
03170       rpt_mutex_unlock(&myrpt->lock);
03171       busy=1;
03172    }
03173    if(!busy){
03174       int x;
03175       if (debug)ast_log(LOG_NOTICE, "rpt_push_alt_macro %s\n",sptr);
03176       myrpt->macrotimer = MACROTIME;
03177       for(x = 0; *(sptr + x); x++)
03178           myrpt->macrobuf[x] = *(sptr + x) | 0x80;
03179       *(sptr + x) = 0;
03180    }
03181    rpt_mutex_unlock(&myrpt->lock);
03182 
03183    if(busy)ast_log(LOG_WARNING, "Function decoder busy on app_rpt command macro.\n");
03184 
03185    return busy;
03186 }
03187 /*
03188    allows us to test rpt() application data commands
03189 */
03190 static int rpt_do_fun1(int fd, int argc, const char * const *argv)
03191 {
03192    int   i;
03193 
03194     if (argc != 4) return RESULT_SHOWUSAGE;
03195 
03196    for(i = 0; i < nrpts; i++){
03197       if(!strcmp(argv[2], rpt_vars[i].name)){
03198          struct rpt *myrpt = &rpt_vars[i];
03199          rpt_push_alt_macro(myrpt, (char *) argv[3]);
03200       }
03201    }
03202    return RESULT_FAILURE;
03203 }
03204 /*
03205 * send an app_rpt **command** from the CLI
03206 */
03207 
03208 static int rpt_do_cmd(int fd, int argc, const char * const *argv)
03209 {
03210    int i, l;
03211    int busy=0;
03212    int maxActions = sizeof(function_table)/sizeof(struct function_table_tag);
03213 
03214    int thisRpt = -1;
03215    int thisAction = -1;
03216    struct rpt *myrpt = NULL;
03217    if (argc != 6) return RESULT_SHOWUSAGE;
03218    
03219    for(i = 0; i < nrpts; i++)
03220    {
03221       if(!strcmp(argv[2], rpt_vars[i].name))
03222       {
03223          thisRpt = i;
03224          myrpt = &rpt_vars[i];
03225          break;
03226       } /* if !strcmp... */
03227    } /* for i */
03228 
03229    if (thisRpt < 0)
03230    {
03231       ast_cli(fd, "Unknown node number %s.\n", argv[2]);
03232       return RESULT_FAILURE;
03233    } /* if thisRpt < 0 */
03234    
03235    /* Look up the action */
03236    l = strlen(argv[3]);
03237    for(i = 0 ; i < maxActions; i++)
03238    {
03239       if(!strncasecmp(argv[3], function_table[i].action, l))
03240       {
03241          thisAction = i;
03242          break;
03243       } /* if !strncasecmp... */
03244    } /* for i */
03245    
03246    if (thisAction < 0)
03247    {
03248       ast_cli(fd, "Unknown action name %s.\n", argv[3]);
03249       return RESULT_FAILURE;
03250    } /* if thisAction < 0 */
03251 
03252    /* at this point, it looks like all the arguments make sense... */
03253 
03254    rpt_mutex_lock(&myrpt->lock);
03255 
03256    if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE)
03257    {
03258       rpt_vars[thisRpt].cmdAction.state = CMD_STATE_BUSY;
03259       rpt_vars[thisRpt].cmdAction.functionNumber = thisAction;
03260       strncpy(rpt_vars[thisRpt].cmdAction.param, argv[4], MAXDTMF);
03261       strncpy(rpt_vars[thisRpt].cmdAction.digits, argv[5], MAXDTMF);
03262       rpt_vars[thisRpt].cmdAction.command_source = SOURCE_RPT;
03263       rpt_vars[thisRpt].cmdAction.state = CMD_STATE_READY;
03264    } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
03265    else
03266    {
03267       busy = 1;
03268    } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
03269    rpt_mutex_unlock(&myrpt->lock);
03270 
03271    return (busy ? RESULT_FAILURE : RESULT_SUCCESS);
03272 } /* rpt_do_cmd() */
03273 
03274 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
03275 {
03276    int res;
03277 
03278         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
03279                 return res;
03280                                                                                                                                             
03281         while(chan->generatordata) {
03282       if (ast_safe_sleep(chan,1)) return -1;
03283    }
03284 
03285         return 0;
03286 }
03287 
03288 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
03289 {
03290    return play_tone_pair(chan, freq, 0, duration, amplitude);
03291 }
03292 
03293 static int play_silence(struct ast_channel *chan, int duration)
03294 {
03295    return play_tone_pair(chan, 0, 0, duration, 0);
03296 }
03297 
03298 #ifdef   NEW_ASTERISK
03299 
03300 static char *res2cli(int r)
03301 
03302 {
03303    switch (r)
03304    {
03305        case RESULT_SUCCESS:
03306       return(CLI_SUCCESS);
03307        case RESULT_SHOWUSAGE:
03308       return(CLI_SHOWUSAGE);
03309        default:
03310       return(CLI_FAILURE);
03311    }
03312 }
03313 
03314 static char *handle_cli_debug(struct ast_cli_entry *e,
03315    int cmd, struct ast_cli_args *a)
03316 {
03317         switch (cmd) {
03318         case CLI_INIT:
03319                 e->command = "rpt debug level";
03320                 e->usage = debug_usage;
03321                 return NULL;
03322         case CLI_GENERATE:
03323                 return NULL;
03324    }
03325    return res2cli(rpt_do_debug(a->fd, a->argc, a->argv));
03326 }
03327 
03328 static char *handle_cli_dump(struct ast_cli_entry *e,
03329    int cmd, struct ast_cli_args *a)
03330 {
03331         switch (cmd) {
03332         case CLI_INIT:
03333                 e->command = "rpt dump level";
03334                 e->usage = dump_usage;
03335                 return NULL;
03336         case CLI_GENERATE:
03337                 return NULL;
03338    }
03339    return res2cli(rpt_do_dump(a->fd,a->argc,a->argv));
03340 }
03341 
03342 
03343 static char *handle_cli_stats(struct ast_cli_entry *e,
03344    int cmd, struct ast_cli_args *a)
03345 {
03346         switch (cmd) {
03347         case CLI_INIT:
03348                 e->command = "rpt stats";
03349                 e->usage = dump_stats;
03350                 return NULL;
03351         case CLI_GENERATE:
03352                 return NULL;
03353    }
03354    return res2cli(rpt_do_stats(a->fd,a->argc,a->argv));
03355 }
03356 
03357 static char *handle_cli_nodes(struct ast_cli_entry *e,
03358    int cmd, struct ast_cli_args *a)
03359 {
03360         switch (cmd) {
03361         case CLI_INIT:
03362                 e->command = "rpt nodes";
03363                 e->usage = dump_nodes;
03364                 return NULL;
03365         case CLI_GENERATE:
03366                 return NULL;
03367    }
03368    return res2cli(rpt_do_nodes(a->fd,a->argc,a->argv));
03369 }
03370 
03371 static char *handle_cli_local_nodes(struct ast_cli_entry *e,
03372    int cmd, struct ast_cli_args *a)
03373 {
03374         switch (cmd) {
03375         case CLI_INIT:
03376                 e->command = "rpt localnodes";
03377                 e->usage = usage_local_nodes;
03378                 return NULL;
03379         case CLI_GENERATE:
03380                 return NULL;
03381    }
03382    return res2cli(rpt_do_local_nodes(a->fd,a->argc,a->argv));
03383 }
03384 
03385 static char *handle_cli_lstats(struct ast_cli_entry *e,
03386    int cmd, struct ast_cli_args *a)
03387 {
03388         switch (cmd) {
03389         case CLI_INIT:
03390                 e->command = "rpt lstats";
03391                 e->usage = dump_lstats;
03392                 return NULL;
03393         case CLI_GENERATE:
03394                 return NULL;
03395    }
03396    return res2cli(rpt_do_lstats(a->fd,a->argc,a->argv));
03397 }
03398 
03399 static char *handle_cli_reload(struct ast_cli_entry *e,
03400    int cmd, struct ast_cli_args *a)
03401 {
03402         switch (cmd) {
03403         case CLI_INIT:
03404                 e->command = "rpt reload";
03405                 e->usage = reload_usage;
03406                 return NULL;
03407         case CLI_GENERATE:
03408                 return NULL;
03409    }
03410    return res2cli(rpt_do_reload(a->fd,a->argc,a->argv));
03411 }
03412 
03413 static char *handle_cli_restart(struct ast_cli_entry *e,
03414    int cmd, struct ast_cli_args *a)
03415 {
03416         switch (cmd) {
03417         case CLI_INIT:
03418                 e->command = "rpt restart";
03419                 e->usage = restart_usage;
03420                 return NULL;
03421         case CLI_GENERATE:
03422                 return NULL;
03423    }
03424    return res2cli(rpt_do_restart(a->fd,a->argc,a->argv));
03425 }
03426 
03427 static char *handle_cli_fun(struct ast_cli_entry *e,
03428    int cmd, struct ast_cli_args *a)
03429 {
03430         switch (cmd) {
03431         case CLI_INIT:
03432                 e->command = "rpt fun";
03433                 e->usage = fun_usage;
03434                 return NULL;
03435         case CLI_GENERATE:
03436                 return NULL;
03437    }
03438    return res2cli(rpt_do_fun(a->fd,a->argc,a->argv));
03439 }
03440 
03441 static char *handle_cli_fun1(struct ast_cli_entry *e,
03442    int cmd, struct ast_cli_args *a)
03443 {
03444         switch (cmd) {
03445         case CLI_INIT:
03446                 e->command = "rpt fun1";
03447                 e->usage = fun_usage;
03448                 return NULL;
03449         case CLI_GENERATE:
03450                 return NULL;
03451    }
03452    return res2cli(rpt_do_fun1(a->fd,a->argc,a->argv));
03453 }
03454 
03455 static char *handle_cli_cmd(struct ast_cli_entry *e,
03456    int cmd, struct ast_cli_args *a)
03457 {
03458         switch (cmd) {
03459         case CLI_INIT:
03460                 e->command = "rpt cmd";
03461                 e->usage = cmd_usage;
03462                 return NULL;
03463         case CLI_GENERATE:
03464                 return NULL;
03465    }
03466    return res2cli(rpt_do_cmd(a->fd,a->argc,a->argv));
03467 }
03468 
03469 static struct ast_cli_entry rpt_cli[] = {
03470    AST_CLI_DEFINE(handle_cli_debug,"Enable app_rpt debugging"),
03471    AST_CLI_DEFINE(handle_cli_dump,"Dump app_rpt structs for debugging"),
03472    AST_CLI_DEFINE(handle_cli_stats,"Dump node statistics"),
03473    AST_CLI_DEFINE(handle_cli_nodes,"Dump node list"),
03474    AST_CLI_DEFINE(handle_cli_local_nodes, "Dump list of local node numbers"),
03475    AST_CLI_DEFINE(handle_cli_lstats,"Dump link statistics"),
03476    AST_CLI_DEFINE(handle_cli_reload,"Reload app_rpt config"),
03477    AST_CLI_DEFINE(handle_cli_restart,"Restart app_rpt"),
03478    AST_CLI_DEFINE(handle_cli_fun,"Execute a DTMF function"),
03479    AST_CLI_DEFINE(handle_cli_fun1,"Execute a DTMF function"),
03480    AST_CLI_DEFINE(handle_cli_cmd,"Execute a DTMF function")
03481 };
03482 
03483 #endif
03484 
03485 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
03486 {
03487 
03488 static struct morse_bits mbits[] = {
03489       {0, 0}, /* SPACE */
03490       {0, 0}, 
03491       {6, 18},/* " */
03492       {0, 0},
03493       {7, 72},/* $ */
03494       {0, 0},
03495       {0, 0},
03496       {6, 30},/* ' */
03497       {5, 13},/* ( */
03498       {6, 29},/* ) */
03499       {0, 0},
03500       {5, 10},/* + */
03501       {6, 51},/* , */
03502       {6, 33},/* - */
03503       {6, 42},/* . */
03504       {5, 9}, /* / */
03505       {5, 31},/* 0 */
03506       {5, 30},/* 1 */
03507       {5, 28},/* 2 */
03508       {5, 24},/* 3 */
03509       {5, 16},/* 4 */
03510       {5, 0}, /* 5 */
03511       {5, 1}, /* 6 */
03512       {5, 3}, /* 7 */
03513       {5, 7}, /* 8 */
03514       {5, 15},/* 9 */
03515       {6, 7}, /* : */
03516       {6, 21},/* ; */
03517       {0, 0},
03518       {5, 33},/* = */
03519       {0, 0},
03520       {6, 12},/* ? */
03521       {0, 0},
03522          {2, 2}, /* A */
03523       {4, 1}, /* B */
03524       {4, 5}, /* C */
03525       {3, 1}, /* D */
03526       {1, 0}, /* E */
03527       {4, 4}, /* F */
03528       {3, 3}, /* G */
03529       {4, 0}, /* H */
03530       {2, 0}, /* I */
03531       {4, 14},/* J */
03532       {3, 5}, /* K */
03533       {4, 2}, /* L */
03534       {2, 3}, /* M */
03535       {2, 1}, /* N */
03536       {3, 7}, /* O */
03537       {4, 6}, /* P */
03538       {4, 11},/* Q */
03539       {3, 2}, /* R */
03540       {3, 0}, /* S */
03541       {1, 1}, /* T */
03542       {3, 4}, /* U */
03543       {4, 8}, /* V */
03544       {3, 6}, /* W */
03545       {4, 9}, /* X */
03546       {4, 13},/* Y */
03547       {4, 3}  /* Z */
03548    };
03549 
03550 
03551    int dottime;
03552    int dashtime;
03553    int intralettertime;
03554    int interlettertime;
03555    int interwordtime;
03556    int len, ddcomb;
03557    int res;
03558    int c;
03559    int i;
03560    int flags;
03561          
03562    res = 0;
03563    
03564    /* Approximate the dot time from the speed arg. */
03565    
03566    dottime = 900/speed;
03567    
03568    /* Establish timing releationships */
03569    
03570    dashtime = 3 * dottime;
03571    intralettertime = dottime;
03572    interlettertime = dottime * 4 ;
03573    interwordtime = dottime * 7;
03574    
03575    for(;(*string) && (!res); string++){
03576    
03577       c = *string;
03578       
03579       /* Convert lower case to upper case */
03580       
03581       if((c >= 'a') && (c <= 'z'))
03582          c -= 0x20;
03583       
03584       /* Can't deal with any char code greater than Z, skip it */
03585       
03586       if(c  > 'Z')
03587          continue;
03588       
03589       /* If space char, wait the inter word time */
03590                
03591       if(c == ' '){
03592          if(!res)
03593             res = play_silence(chan, interwordtime);
03594          continue;
03595       }
03596       
03597       /* Subtract out control char offset to match our table */
03598       
03599       c -= 0x20;
03600       
03601       /* Get the character data */
03602       
03603       len = mbits[c].len;
03604       ddcomb = mbits[c].ddcomb;
03605       
03606       /* Send the character */
03607       
03608       for(; len ; len--){
03609          if(!res)
03610             res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
03611          if(!res)
03612             res = play_silence(chan, intralettertime);
03613          ddcomb >>= 1;
03614       }
03615       
03616       /* Wait the interletter time */
03617       
03618       if(!res)
03619          res = play_silence(chan, interlettertime - intralettertime);
03620    }
03621    
03622    /* Wait for all the frames to be sent */
03623    
03624    if (!res) 
03625       res = ast_waitstream(chan, "");
03626    ast_stopstream(chan);
03627    
03628    /*
03629    * Wait for the DAHDI driver to physically write the tone blocks to the hardware
03630    */
03631 
03632    for(i = 0; i < 20 ; i++){
03633       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
03634       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
03635       if(flags & DAHDI_IOMUX_WRITEEMPTY)
03636          break;
03637       if( ast_safe_sleep(chan, 50)){
03638          res = -1;
03639          break;
03640       }
03641    }
03642 
03643    
03644    return res;
03645 }
03646 
03647 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
03648 {
03649    char *p,*stringp;
03650    char *tonesubset;
03651    int f1,f2;
03652    int duration;
03653    int amplitude;
03654    int res;
03655    int i;
03656    int flags;
03657    
03658    res = 0;
03659 
03660    if(!tonestring)
03661       return res;
03662    
03663    p = stringp = ast_strdup(tonestring);
03664 
03665    for(;tonestring;){
03666       tonesubset = strsep(&stringp,")");
03667       if(!tonesubset)
03668          break;
03669       if(sscanf(tonesubset,"(%30d,%30d,%30d,%30d", &f1, &f2, &duration, &amplitude) != 4)
03670          break;
03671       res = play_tone_pair(chan, f1, f2, duration, amplitude);
03672       if(res)
03673          break;
03674    }
03675    ast_free(p);
03676    if(!res)
03677       res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
03678    
03679    if (!res) 
03680       res = ast_waitstream(chan, "");
03681 
03682    ast_stopstream(chan);
03683 
03684    /*
03685    * Wait for the DAHDI driver to physically write the tone blocks to the hardware
03686    */
03687 
03688    for(i = 0; i < 20 ; i++){
03689       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
03690       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
03691       if(flags & DAHDI_IOMUX_WRITEEMPTY)
03692          break;
03693       if( ast_safe_sleep(chan, 50)){
03694          res = -1;
03695          break;
03696       }
03697    }
03698       
03699    return res;
03700       
03701 }
03702 
03703 static int sayfile(struct ast_channel *mychannel,char *fname)
03704 {
03705 int   res;
03706 
03707    res = ast_streamfile(mychannel, fname, ast_channel_language(mychannel));
03708    if (!res) 
03709       res = ast_waitstream(mychannel, "");
03710    else
03711        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
03712    ast_stopstream(mychannel);
03713    return res;
03714 }
03715 
03716 static int saycharstr(struct ast_channel *mychannel,char *str)
03717 {
03718 int   res;
03719 
03720    res = ast_say_character_str(mychannel,str,NULL,ast_channel_language(mychannel));
03721    if (!res) 
03722       res = ast_waitstream(mychannel, "");
03723    else
03724        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
03725    ast_stopstream(mychannel);
03726    return res;
03727 }
03728 
03729 static int saynum(struct ast_channel *mychannel, int num)
03730 {
03731    int res;
03732    res = ast_say_number(mychannel, num, NULL, ast_channel_language(mychannel), NULL);
03733    if(!res)
03734       res = ast_waitstream(mychannel, "");
03735    else
03736       ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
03737    ast_stopstream(mychannel);
03738    return res;
03739 }
03740 
03741 /* say a node and nodename. Try to look in dir referred to by nodenames in
03742 config, and see if there's a custom node file to play, and if so, play it */
03743 
03744 static int saynode(struct rpt *myrpt, struct ast_channel *mychannel, char *name)
03745 {
03746 int   res;
03747 char  *val,fname[300];
03748 
03749    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "nodenames");
03750    if (!val) val = NODENAMES;
03751    snprintf(fname,sizeof(fname) - 1,"%s/%s",val,name);
03752    if (ast_fileexists(fname,NULL,ast_channel_language(mychannel)) > 0)
03753       return(sayfile(mychannel,fname));
03754    res = sayfile(mychannel,"rpt/node");
03755    if (!res) 
03756       res = ast_say_character_str(mychannel,name,NULL,ast_channel_language(mychannel));
03757    return res;
03758 }
03759 
03760 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
03761 {
03762    int res;
03763    char c;
03764    
03765    static int morsespeed;
03766    static int morsefreq;
03767    static int morseampl;
03768    static int morseidfreq = 0;
03769    static int morseidampl;
03770    static char mcat[] = MORSE;
03771    
03772    res = 0;
03773    
03774    if(!morseidfreq){ /* Get the morse parameters if not already loaded */
03775       morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
03776          morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
03777          morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
03778       morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
03779       morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330); 
03780    }
03781    
03782    /* Is it a file, or a tone sequence? */
03783          
03784    if(entry[0] == '|'){
03785       c = entry[1];
03786       if((c >= 'a')&&(c <= 'z'))
03787          c -= 0x20;
03788    
03789       switch(c){
03790          case 'I': /* Morse ID */
03791             res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
03792             break;
03793          
03794          case 'M': /* Morse Message */
03795             res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
03796             break;
03797          
03798          case 'T': /* Tone sequence */
03799             res = send_tone_telemetry(chan, entry + 2);
03800             break;
03801          default:
03802             res = -1;
03803       }
03804    }
03805    else
03806       res = sayfile(chan, entry); /* File */
03807    return res;
03808 }
03809 
03810 /*
03811 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
03812 *
03813 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
03814 */
03815 
03816 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
03817 {
03818    
03819    int res;
03820    int i;
03821    char *entry;
03822    char *telemetry;
03823    char *telemetry_save;
03824 
03825    res = 0;
03826    telemetry_save = NULL;
03827    entry = NULL;
03828    
03829    /* Retrieve the section name for telemetry from the node section */
03830    telemetry = (char *) ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
03831    if(telemetry ){
03832       telemetry_save = ast_strdup(telemetry);
03833       if(!telemetry_save){
03834          ast_log(LOG_WARNING,"ast_strdup() failed in telem_lookup()\n");
03835          return res;
03836       }
03837       entry = (char *) ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
03838    }
03839    
03840    /* Try to look up the telemetry name */   
03841 
03842    if(!entry){
03843       /* Telemetry name wasn't found in the config file, use the default */
03844       for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
03845          if(!strcasecmp(tele_defs[i].name, name))
03846             entry = tele_defs[i].value;
03847       }
03848    }
03849    if(entry){  
03850       if(strlen(entry))
03851          if (chan) telem_any(myrpt,chan, entry);
03852    }
03853    else{
03854       res = -1;
03855    }
03856    ast_free(telemetry_save);
03857    return res;
03858 }
03859 
03860 /*
03861 * Retrieve a wait interval
03862 */
03863 
03864 static int get_wait_interval(struct rpt *myrpt, int type)
03865 {
03866         int interval;
03867         char *wait_times;
03868         char *wait_times_save;
03869                                                                                                                   
03870         wait_times_save = NULL;
03871         wait_times = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
03872                                                                                                                   
03873         if(wait_times){
03874                 wait_times_save = ast_strdup(wait_times);
03875                 if(!wait_times_save)
03876          return 0;
03877                 
03878         }
03879                                                                                                                   
03880         switch(type){
03881                 case DLY_TELEM:
03882                         if(wait_times)
03883                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
03884                         else
03885                                 interval = 1000;
03886                         break;
03887                                                                                                                   
03888                 case DLY_ID:
03889                         if(wait_times)
03890                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
03891                         else
03892                                 interval = 500;
03893                         break;
03894                                                                                                                   
03895                 case DLY_UNKEY:
03896                         if(wait_times)
03897                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",50,5000,1000);
03898                         else
03899                                 interval = 1000;
03900                         break;
03901                                                                                                                   
03902                 case DLY_LINKUNKEY:
03903                         if(wait_times)
03904                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "linkunkeywait",500,5000,1000);
03905                         else
03906                                 interval = 1000;
03907                         break;
03908                                                                                                                   
03909                 case DLY_CALLTERM:
03910                         if(wait_times)
03911                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
03912                         else
03913                                 interval = 1500;
03914                         break;
03915                                                                                                                   
03916                 case DLY_COMP:
03917                         if(wait_times)
03918                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "compwait",500,5000,200);
03919                         else
03920                                 interval = 200;
03921                         break;
03922                                                                                                                   
03923                 case DLY_PARROT:
03924                         if(wait_times)
03925                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "parrotwait",500,5000,200);
03926                         else
03927                                 interval = 200;
03928                         break;
03929                                                                                                                   
03930                 default:
03931          interval = 0;
03932          break;
03933         }
03934    ast_free(wait_times_save);
03935    return interval;
03936 }                                                                                                                  
03937 
03938 
03939 /*
03940 * Wait a configurable interval of time 
03941 */
03942 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
03943 {
03944    int interval;
03945    interval = get_wait_interval(myrpt, type);
03946    if(debug)
03947       ast_log(LOG_NOTICE,"Delay interval = %d\n", interval);
03948    if(interval)
03949       ast_safe_sleep(chan,interval);
03950    if(debug)
03951       ast_log(LOG_NOTICE,"Delay complete\n");
03952    return;
03953 }
03954 
03955 static int split_freq(char *mhz, char *decimals, char *freq);
03956 
03957 static void *rpt_tele_thread(void *this)
03958 {
03959 struct dahdi_confinfo ci;  /* conference info */
03960 int   res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
03961 struct   rpt_tele *mytele = (struct rpt_tele *)this;
03962 struct  rpt_tele *tlist;
03963 struct   rpt *myrpt;
03964 struct   rpt_link *l,*l1,linkbase;
03965 struct   ast_channel *mychannel;
03966 int vmajor, vminor, m;
03967 char *p,*ct,*ct_copy,*ident, *nodename,*cp;
03968 time_t t;
03969 #ifdef   NEW_ASTERISK
03970 struct ast_tm localtm;
03971 #else
03972 struct tm localtm;
03973 #endif
03974 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
03975 int   i,ns,rbimode;
03976 char mhz[MAXREMSTR];
03977 char decimals[MAXREMSTR];
03978 char  mystr[200];
03979 struct dahdi_params par;
03980 struct ast_format_cap *cap = NULL;
03981 
03982    /* get a pointer to myrpt */
03983    myrpt = mytele->rpt;
03984 
03985    /* Snag copies of a few key myrpt variables */
03986    rpt_mutex_lock(&myrpt->lock);
03987    nodename = ast_strdup(myrpt->name);
03988    if(!nodename)
03989    {
03990        fprintf(stderr,"rpt:Sorry unable strdup nodename\n");
03991        rpt_mutex_lock(&myrpt->lock);
03992        remque((struct qelem *)mytele);
03993        ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03994        rpt_mutex_unlock(&myrpt->lock);
03995        ast_free(mytele);
03996        pthread_exit(NULL);
03997    }
03998 
03999    if (myrpt->p.ident){
04000       ident = ast_strdup(myrpt->p.ident);
04001          if(!ident)
04002       {
04003                  fprintf(stderr,"rpt:Sorry unable strdup ident\n");
04004          rpt_mutex_lock(&myrpt->lock);
04005                   remque((struct qelem *)mytele);
04006                   ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",
04007          __LINE__, mytele->mode); /*@@@@@@@@@@@*/
04008                   rpt_mutex_unlock(&myrpt->lock);
04009          ast_free(nodename);
04010                   ast_free(mytele);
04011                   pthread_exit(NULL);
04012          }
04013    }
04014    else
04015    {
04016       ident = "";
04017    }
04018    rpt_mutex_unlock(&myrpt->lock);
04019       
04020 
04021 
04022    /* allocate a pseudo-channel thru asterisk */
04023    mychannel = ast_request("DAHDI", get_slin_cap(cap), NULL, "pseudo", NULL);
04024    cap = ast_format_cap_destroy(cap);
04025    if (!mychannel)
04026    {
04027       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
04028       rpt_mutex_lock(&myrpt->lock);
04029       remque((struct qelem *)mytele);
04030       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04031       rpt_mutex_unlock(&myrpt->lock);
04032       ast_free(nodename);
04033       ast_free(ident);
04034       ast_free(mytele);    
04035       pthread_exit(NULL);
04036    }
04037 #ifdef   AST_CDR_FLAG_POST_DISABLED
04038    if (mychannel->cdr) 
04039       ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
04040 #endif
04041    rpt_mutex_lock(&myrpt->lock);
04042    mytele->chan = mychannel;
04043    rpt_mutex_unlock(&myrpt->lock);
04044 
04045    while((mytele->mode != SETREMOTE) && (mytele->mode != UNKEY) &&
04046       (mytele->mode != LINKUNKEY))
04047    {  
04048                 rpt_mutex_lock(&myrpt->lock);
04049       if (!myrpt->active_telem)
04050       {
04051          myrpt->active_telem = mytele;
04052                    rpt_mutex_unlock(&myrpt->lock);
04053          break;
04054       }
04055                 rpt_mutex_unlock(&myrpt->lock);
04056       usleep(100000);
04057    }
04058 
04059    /* make a conference for the tx */
04060    ci.chan = 0;
04061    /* If the telemetry is only intended for a local audience, */
04062    /* only connect the ID audio to the local tx conference so */
04063    /* linked systems can't hear it */
04064    ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
04065       (mytele->mode == TAILMSG) || (mytele->mode == LINKUNKEY) || (mytele->mode == TIMEOUT) || 
04066       (mytele->mode == PARROT) || (mytele->mode == STATS_TIME_LOCAL)) ? 
04067          myrpt->txconf : myrpt->conf);
04068    ci.confmode = DAHDI_CONF_CONFANN;
04069    /* first put the channel on the conference in announce mode */
04070    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04071    {
04072       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04073       rpt_mutex_lock(&myrpt->lock);
04074       myrpt->active_telem = NULL;
04075       remque((struct qelem *)mytele);
04076       rpt_mutex_unlock(&myrpt->lock);
04077       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04078       ast_free(nodename);
04079       ast_free(ident);
04080       ast_free(mytele);    
04081       ast_hangup(mychannel);
04082       pthread_exit(NULL);
04083    }
04084    ast_stopstream(mychannel);
04085    switch(mytele->mode)
04086    {
04087        case ID:
04088        case ID1:
04089       /* wait a bit */
04090       wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
04091       res = telem_any(myrpt,mychannel, ident); 
04092       imdone=1;   
04093       break;
04094       
04095        case TAILMSG:
04096       res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], ast_channel_language(mychannel)); 
04097       break;
04098       
04099        case IDTALKOVER:
04100          p = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
04101          if(p)
04102          res = telem_any(myrpt,mychannel, p); 
04103       imdone=1;   
04104          break;
04105             
04106        case PROC:
04107       /* wait a little bit longer */
04108       wait_interval(myrpt, DLY_TELEM, mychannel);
04109       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
04110       if(res < 0){ /* Then default message */
04111          res = ast_streamfile(mychannel, "rpt/callproceeding", ast_channel_language(mychannel));
04112       }
04113       break;
04114        case TERM:
04115       /* wait a little bit longer */
04116       wait_interval(myrpt, DLY_CALLTERM, mychannel);
04117       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
04118       if(res < 0){ /* Then default message */
04119          res = ast_streamfile(mychannel, "rpt/callterminated", ast_channel_language(mychannel));
04120       }
04121       break;
04122        case COMPLETE:
04123       /* wait a little bit */
04124       wait_interval(myrpt, DLY_TELEM, mychannel);
04125       res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04126       break;
04127        case MACRO_NOTFOUND:
04128       /* wait a little bit */
04129       wait_interval(myrpt, DLY_TELEM, mychannel);
04130       res = ast_streamfile(mychannel, "rpt/macro_notfound", ast_channel_language(mychannel));
04131       break;
04132        case MACRO_BUSY:
04133       /* wait a little bit */
04134       wait_interval(myrpt, DLY_TELEM, mychannel);
04135       res = ast_streamfile(mychannel, "rpt/macro_busy", ast_channel_language(mychannel));
04136       break;
04137        case UNKEY:
04138       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
04139          imdone = 1;
04140          break;
04141       }
04142          
04143       /*
04144       * Reset the Unkey to CT timer
04145       */
04146 
04147       x = get_wait_interval(myrpt, DLY_UNKEY);
04148       rpt_mutex_lock(&myrpt->lock);
04149       myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
04150       rpt_mutex_unlock(&myrpt->lock);
04151 
04152       /*
04153       * If there's one already queued, don't do another
04154       */
04155 
04156       tlist = myrpt->tele.next;
04157       unkeys_queued = 0;
04158                 if (tlist != &myrpt->tele)
04159                 {
04160                         rpt_mutex_lock(&myrpt->lock);
04161                         while(tlist != &myrpt->tele){
04162                                 if (tlist->mode == UNKEY) unkeys_queued++;
04163                                 tlist = tlist->next;
04164                         }
04165                         rpt_mutex_unlock(&myrpt->lock);
04166       }
04167       if( unkeys_queued > 1){
04168          imdone = 1;
04169          break;
04170       }
04171 
04172       /* Wait for the telemetry timer to expire */
04173       /* Periodically check the timer since it can be re-initialized above */
04174       while(myrpt->unkeytocttimer)
04175       {
04176          int ctint;
04177          if(myrpt->unkeytocttimer > 100)
04178             ctint = 100;
04179          else
04180             ctint = myrpt->unkeytocttimer;
04181          ast_safe_sleep(mychannel, ctint);
04182          rpt_mutex_lock(&myrpt->lock);
04183          if(myrpt->unkeytocttimer < ctint)
04184             myrpt->unkeytocttimer = 0;
04185          else
04186             myrpt->unkeytocttimer -= ctint;
04187          rpt_mutex_unlock(&myrpt->lock);
04188       }
04189    
04190       /*
04191       * Now, the carrier on the rptr rx should be gone. 
04192       * If it re-appeared, then forget about sending the CT
04193       */
04194       if(myrpt->keyed){
04195          imdone = 1;
04196          break;
04197       }
04198       
04199       rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
04200       myrpt->dailykerchunks++;
04201       myrpt->totalkerchunks++;
04202       rpt_mutex_unlock(&myrpt->lock);
04203    
04204       haslink = 0;
04205       hastx = 0;
04206       hasremote = 0;    
04207       l = myrpt->links.next;
04208       if (l != &myrpt->links)
04209       {
04210          rpt_mutex_lock(&myrpt->lock);
04211          while(l != &myrpt->links)
04212          {
04213             if (l->name[0] == '0')
04214             {
04215                l = l->next;
04216                continue;
04217             }
04218             haslink = 1;
04219             if (l->mode) {
04220                hastx++;
04221                if (l->isremote) hasremote++;
04222             }
04223             l = l->next;
04224          }
04225          rpt_mutex_unlock(&myrpt->lock);
04226       }
04227       if (haslink)
04228       {
04229 
04230          res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
04231          if(res)
04232             ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", ast_channel_name(mychannel));
04233          
04234       
04235          /* if in remote cmd mode, indicate it */
04236          if (myrpt->cmdnode[0])
04237          {
04238             ast_safe_sleep(mychannel,200);
04239             res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
04240             if(res)
04241                ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", ast_channel_name(mychannel));
04242             ast_stopstream(mychannel);
04243          }
04244       }
04245       else if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
04246          ct_copy = ast_strdup(ct);
04247          if(ct_copy)
04248          {
04249             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04250             ast_free(ct_copy);
04251          }
04252          else
04253             res = -1;
04254          if(res)
04255             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", ast_channel_name(mychannel));     
04256       }  
04257       if (hasremote && (!myrpt->cmdnode[0]))
04258       {
04259          /* set for all to hear */
04260          ci.chan = 0;
04261          ci.confno = myrpt->conf;
04262          ci.confmode = DAHDI_CONF_CONFANN;
04263          /* first put the channel on the conference in announce mode */
04264          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04265          {
04266             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04267             rpt_mutex_lock(&myrpt->lock);
04268             myrpt->active_telem = NULL;
04269             remque((struct qelem *)mytele);
04270             rpt_mutex_unlock(&myrpt->lock);
04271             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04272             ast_free(nodename);
04273             ast_free(ident);
04274             ast_free(mytele);    
04275             ast_hangup(mychannel);
04276             pthread_exit(NULL);
04277          }
04278          if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
04279             ast_safe_sleep(mychannel,200);
04280             ct_copy = ast_strdup(ct);
04281             if(ct_copy)
04282             {
04283                res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04284                ast_free(ct_copy);
04285             }
04286             else
04287                res = -1;
04288       
04289             if(res)
04290                ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", ast_channel_name(mychannel));     
04291          }  
04292       }
04293 #if   defined(_MDC_DECODE_H_) && defined(MDC_SAY_WHEN_DOING_CT)
04294       if (myrpt->lastunit)
04295       {
04296          char mystr[10];
04297 
04298          ast_safe_sleep(mychannel,200);
04299          /* set for all to hear */
04300          ci.chan = 0;
04301          ci.confno = myrpt->txconf;
04302          ci.confmode = DAHDI_CONF_CONFANN;
04303          /* first put the channel on the conference in announce mode */
04304          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04305          {
04306             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04307             rpt_mutex_lock(&myrpt->lock);
04308             myrpt->active_telem = NULL;
04309             remque((struct qelem *)mytele);
04310             rpt_mutex_unlock(&myrpt->lock);
04311             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04312             ast_free(nodename);
04313             ast_free(ident);
04314             ast_free(mytele);    
04315             ast_hangup(mychannel);
04316             pthread_exit(NULL);
04317          }
04318          sprintf(mystr,"%04x",myrpt->lastunit);
04319          myrpt->lastunit = 0;
04320          ast_say_character_str(mychannel,mystr,NULL,ast_channel_language(mychannel));
04321          break;
04322       }
04323 #endif
04324       imdone = 1;
04325       break;
04326        case LINKUNKEY:
04327       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
04328          imdone = 1;
04329          break;
04330       }
04331          
04332       /*
04333       * Reset the Unkey to CT timer
04334       */
04335 
04336       x = get_wait_interval(myrpt, DLY_LINKUNKEY);
04337       mytele->mylink.linkunkeytocttimer = x; /* Must be protected as it is changed below */
04338 
04339       /*
04340       * If there's one already queued, don't do another
04341       */
04342 
04343       tlist = myrpt->tele.next;
04344       unkeys_queued = 0;
04345                 if (tlist != &myrpt->tele)
04346                 {
04347                         rpt_mutex_lock(&myrpt->lock);
04348                         while(tlist != &myrpt->tele){
04349                                 if (tlist->mode == LINKUNKEY) unkeys_queued++;
04350                                 tlist = tlist->next;
04351                         }
04352                         rpt_mutex_unlock(&myrpt->lock);
04353       }
04354       if( unkeys_queued > 1){
04355          imdone = 1;
04356          break;
04357       }
04358 
04359       /* Wait for the telemetry timer to expire */
04360       /* Periodically check the timer since it can be re-initialized above */
04361       while(mytele->mylink.linkunkeytocttimer)
04362       {
04363          int ctint;
04364          if(mytele->mylink.linkunkeytocttimer > 100)
04365             ctint = 100;
04366          else
04367             ctint = mytele->mylink.linkunkeytocttimer;
04368          ast_safe_sleep(mychannel, ctint);
04369          rpt_mutex_lock(&myrpt->lock);
04370          if(mytele->mylink.linkunkeytocttimer < ctint)
04371             mytele->mylink.linkunkeytocttimer = 0;
04372          else
04373             mytele->mylink.linkunkeytocttimer -= ctint;
04374          rpt_mutex_unlock(&myrpt->lock);
04375       }
04376    
04377       if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "linkunkeyct"))){ /* Unlinked Courtesy Tone */
04378          ct_copy = ast_strdup(ct);
04379          if(ct_copy){
04380             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04381             ast_free(ct_copy);
04382          }
04383          else
04384             res = -1;
04385          if(res)
04386             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", ast_channel_name(mychannel));     
04387       }  
04388       imdone = 1;
04389       break;
04390        case REMDISC:
04391       /* wait a little bit */
04392       wait_interval(myrpt, DLY_TELEM, mychannel);
04393       l = myrpt->links.next;
04394       haslink = 0;
04395       /* don't report if a link for this one still on system */
04396       if (l != &myrpt->links)
04397       {
04398          rpt_mutex_lock(&myrpt->lock);
04399          while(l != &myrpt->links)
04400          {
04401             if (l->name[0] == '0')
04402             {
04403                l = l->next;
04404                continue;
04405             }
04406             if (!strcmp(l->name,mytele->mylink.name))
04407             {
04408                haslink = 1;
04409                break;
04410             }
04411             l = l->next;
04412          }
04413          rpt_mutex_unlock(&myrpt->lock);
04414       }
04415       if (haslink)
04416       {
04417          imdone = 1;
04418          break;
04419       }
04420       res = saynode(myrpt,mychannel,mytele->mylink.name);
04421       if (!res) 
04422           res = ast_streamfile(mychannel, ((mytele->mylink.hasconnected) ? 
04423          "rpt/remote_disc" : "rpt/remote_busy"), ast_channel_language(mychannel));
04424       break;
04425        case REMALREADY:
04426       /* wait a little bit */
04427       wait_interval(myrpt, DLY_TELEM, mychannel);
04428       res = ast_streamfile(mychannel, "rpt/remote_already", ast_channel_language(mychannel));
04429       break;
04430        case REMNOTFOUND:
04431       /* wait a little bit */
04432       wait_interval(myrpt, DLY_TELEM, mychannel);
04433       res = ast_streamfile(mychannel, "rpt/remote_notfound", ast_channel_language(mychannel));
04434       break;
04435        case REMGO:
04436       /* wait a little bit */
04437       wait_interval(myrpt, DLY_TELEM, mychannel);
04438       res = ast_streamfile(mychannel, "rpt/remote_go", ast_channel_language(mychannel));
04439       break;
04440        case CONNECTED:
04441       /* wait a little bit */
04442       wait_interval(myrpt, DLY_TELEM,  mychannel);
04443       res = saynode(myrpt,mychannel,mytele->mylink.name);
04444       if (!res)
04445           res = ast_streamfile(mychannel, "rpt/connected", ast_channel_language(mychannel));
04446       if (!res) 
04447          res = ast_waitstream(mychannel, "");
04448       else
04449           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
04450       ast_stopstream(mychannel);
04451       res = ast_streamfile(mychannel, "digits/2", ast_channel_language(mychannel));
04452       if (!res) 
04453          res = ast_waitstream(mychannel, "");
04454       else
04455           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
04456       ast_stopstream(mychannel);
04457       res = saynode(myrpt,mychannel,myrpt->name);
04458       imdone = 1;
04459       break;
04460        case CONNFAIL:
04461       res = saynode(myrpt,mychannel,mytele->mylink.name);
04462       if (!res) 
04463           res = ast_streamfile(mychannel, "rpt/connection_failed", ast_channel_language(mychannel));
04464       break;
04465        case MEMNOTFOUND:
04466       /* wait a little bit */
04467       wait_interval(myrpt, DLY_TELEM, mychannel);
04468       res = ast_streamfile(mychannel, "rpt/memory_notfound", ast_channel_language(mychannel));
04469       break;
04470        case PLAYBACK:
04471       /* wait a little bit */
04472       wait_interval(myrpt, DLY_TELEM, mychannel);
04473       res = ast_streamfile(mychannel, mytele->param, ast_channel_language(mychannel));
04474       break;
04475        case TOPKEY:
04476       /* wait a little bit */
04477       wait_interval(myrpt, DLY_TELEM, mychannel);
04478       for(i = 0; i < TOPKEYN; i++)
04479       {
04480          if (!myrpt->topkey[i].node[0]) continue;
04481          if ((!myrpt->topkeylong) && (myrpt->topkey[i].keyed)) continue;
04482          res = saynode(myrpt, mychannel,  myrpt->topkey[i].node);
04483          if (!res) res = sayfile(mychannel,(myrpt->topkey[i].keyed) ?
04484             "rpt/keyedfor" : "rpt/unkeyedfor");
04485          if (!res) res = saynum(mychannel,
04486             myrpt->topkey[i].timesince);
04487          if (!res) res = sayfile(mychannel,"rpt/seconds");
04488          if (!myrpt->topkeylong) break;
04489       }
04490       imdone = 1;
04491       break;
04492        case SETREMOTE:
04493       ast_mutex_lock(&myrpt->remlock);
04494       res = 0;
04495       if(!strcmp(myrpt->remoterig, remote_rig_ft897))
04496       {
04497          res = set_ft897(myrpt);
04498       }
04499       else if(!strcmp(myrpt->remoterig, remote_rig_tm271))
04500       {
04501          res = set_tm271(myrpt);
04502       }
04503       else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
04504       {
04505          res = set_ic706(myrpt);
04506       }
04507 #ifdef HAVE_IOPERM
04508       else if(!strcmp(myrpt->remoterig, remote_rig_rbi)||!strcmp(myrpt->remoterig, remote_rig_ppp16))
04509       {
04510          if (ioperm(myrpt->p.iobase,1,1) == -1)
04511          {
04512             rpt_mutex_unlock(&myrpt->lock);
04513             ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
04514             res = -1;
04515          }
04516          else res = setrbi(myrpt);
04517       }
04518 #endif
04519       else if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
04520       {
04521          if (myrpt->iofd >= 0) setdtr(myrpt->iofd,1);
04522          res = setkenwood(myrpt);
04523          if (myrpt->iofd >= 0) setdtr(myrpt->iofd,0);
04524          if (ast_safe_sleep(mychannel,200) == -1)
04525          {
04526             ast_mutex_unlock(&myrpt->remlock);
04527             res = -1;
04528             break;
04529          }
04530          if (myrpt->iofd < 0)
04531          {
04532             i = DAHDI_FLUSH_EVENT;
04533             if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_FLUSH,&i) == -1)
04534             {
04535                ast_mutex_unlock(&myrpt->remlock);
04536                ast_log(LOG_ERROR,"Cant flush events");
04537                res = -1;
04538                break;
04539             }
04540             if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_GET_PARAMS,&par) == -1)
04541             {
04542                ast_mutex_unlock(&myrpt->remlock);
04543                ast_log(LOG_ERROR,"Cant get params");
04544                res = -1;
04545                break;
04546             }
04547             myrpt->remoterx = 
04548                (par.rxisoffhook || (myrpt->tele.next != &myrpt->tele));
04549          }
04550       }
04551 
04552       ast_mutex_unlock(&myrpt->remlock);
04553       if (!res)
04554       {
04555          imdone = 1;
04556          break;
04557       }
04558       /* fall thru to invalid freq */
04559        case INVFREQ:
04560       /* wait a little bit */
04561       wait_interval(myrpt, DLY_TELEM, mychannel);
04562       res = ast_streamfile(mychannel, "rpt/invalid-freq", ast_channel_language(mychannel));
04563       break;
04564        case REMMODE:
04565       cp = 0;
04566       wait_interval(myrpt, DLY_TELEM, mychannel);
04567       switch(myrpt->remmode)
04568       {
04569           case REM_MODE_FM:
04570          saycharstr(mychannel,"FM");
04571          break;
04572           case REM_MODE_USB:
04573          saycharstr(mychannel,"USB");
04574          break;
04575           case REM_MODE_LSB:
04576          saycharstr(mychannel,"LSB");
04577          break;
04578           case REM_MODE_AM:
04579          saycharstr(mychannel,"AM");
04580          break;
04581       }
04582       wait_interval(myrpt, DLY_COMP, mychannel);
04583       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04584       break;
04585        case LOGINREQ:
04586       wait_interval(myrpt, DLY_TELEM, mychannel);
04587       sayfile(mychannel,"rpt/login");
04588       saycharstr(mychannel,myrpt->name);
04589       break;
04590        case REMLOGIN:
04591       wait_interval(myrpt, DLY_TELEM, mychannel);
04592       saycharstr(mychannel,myrpt->loginuser);
04593       saynode(myrpt,mychannel,myrpt->name);
04594       wait_interval(myrpt, DLY_COMP, mychannel);
04595       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04596       break;
04597        case REMXXX:
04598       wait_interval(myrpt, DLY_TELEM, mychannel);
04599       res = 0;
04600       switch(mytele->submode)
04601       {
04602           case 100: /* RX PL Off */
04603          sayfile(mychannel, "rpt/rxpl");
04604          sayfile(mychannel, "rpt/off");
04605          break;
04606           case 101: /* RX PL On */
04607          sayfile(mychannel, "rpt/rxpl");
04608          sayfile(mychannel, "rpt/on");
04609          break;
04610           case 102: /* TX PL Off */
04611          sayfile(mychannel, "rpt/txpl");
04612          sayfile(mychannel, "rpt/off");
04613          break;
04614           case 103: /* TX PL On */
04615          sayfile(mychannel, "rpt/txpl");
04616          sayfile(mychannel, "rpt/on");
04617          break;
04618           case 104: /* Low Power */
04619          sayfile(mychannel, "rpt/lopwr");
04620          break;
04621           case 105: /* Medium Power */
04622          sayfile(mychannel, "rpt/medpwr");
04623          break;
04624           case 106: /* Hi Power */
04625          sayfile(mychannel, "rpt/hipwr");
04626          break;
04627           case 113: /* Scan down slow */
04628          sayfile(mychannel,"rpt/down");
04629          sayfile(mychannel, "rpt/slow");
04630          break;
04631           case 114: /* Scan down quick */
04632          sayfile(mychannel,"rpt/down");
04633          sayfile(mychannel, "rpt/quick");
04634          break;
04635           case 115: /* Scan down fast */
04636          sayfile(mychannel,"rpt/down");
04637          sayfile(mychannel, "rpt/fast");
04638          break;
04639           case 116: /* Scan up slow */
04640          sayfile(mychannel,"rpt/up");
04641          sayfile(mychannel, "rpt/slow");
04642          break;
04643           case 117: /* Scan up quick */
04644          sayfile(mychannel,"rpt/up");
04645          sayfile(mychannel, "rpt/quick");
04646          break;
04647           case 118: /* Scan up fast */
04648          sayfile(mychannel,"rpt/up");
04649          sayfile(mychannel, "rpt/fast");
04650          break;
04651           default:
04652          res = -1;
04653       }
04654       wait_interval(myrpt, DLY_COMP, mychannel);
04655       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04656       break;
04657        case SCAN:
04658       ast_mutex_lock(&myrpt->remlock);
04659       if (myrpt->hfscanstop)
04660       {
04661          myrpt->hfscanstatus = 0;
04662          myrpt->hfscanmode = 0;
04663          myrpt->hfscanstop = 0;
04664          mytele->mode = SCANSTAT;
04665          ast_mutex_unlock(&myrpt->remlock);
04666          if (ast_safe_sleep(mychannel,1000) == -1) break;
04667          sayfile(mychannel, "rpt/stop"); 
04668          imdone = 1;
04669          break;
04670       }
04671       if (myrpt->hfscanstatus > -2) service_scan(myrpt);
04672       i = myrpt->hfscanstatus;
04673       myrpt->hfscanstatus = 0;
04674       if (i) mytele->mode = SCANSTAT;
04675       ast_mutex_unlock(&myrpt->remlock);
04676       if (i < 0) sayfile(mychannel, "rpt/stop"); 
04677       else if (i > 0) saynum(mychannel,i);
04678       imdone = 1;
04679       break;
04680        case TUNE:
04681       ast_mutex_lock(&myrpt->remlock);
04682       if (!strcmp(myrpt->remoterig,remote_rig_ic706))
04683       {
04684          set_mode_ic706(myrpt, REM_MODE_AM);
04685          if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
04686          ast_safe_sleep(mychannel,500);
04687          set_mode_ic706(myrpt, myrpt->remmode);
04688          myrpt->tunerequest = 0;
04689          ast_mutex_unlock(&myrpt->remlock);
04690          imdone = 1;
04691          break;
04692       }
04693       set_mode_ft897(myrpt, REM_MODE_AM);
04694       simple_command_ft897(myrpt, 8);
04695       if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
04696       simple_command_ft897(myrpt, 0x88);
04697       ast_safe_sleep(mychannel,500);
04698       set_mode_ft897(myrpt, myrpt->remmode);
04699       myrpt->tunerequest = 0;
04700       ast_mutex_unlock(&myrpt->remlock);
04701       imdone = 1;
04702       break;
04703        case REMSHORTSTATUS:
04704        case REMLONGSTATUS: 
04705       wait_interval(myrpt, DLY_TELEM, mychannel);
04706       res = saynode(myrpt,mychannel,myrpt->name);
04707       if(!res)
04708          res = sayfile(mychannel,"rpt/frequency");
04709       if(!res)
04710          res = split_freq(mhz, decimals, myrpt->freq);
04711       if (!multimode_capable(myrpt)) decimals[3] = 0;
04712       if(!res){
04713          m = atoi(mhz);
04714          if(m < 100)
04715             res = saynum(mychannel, m);
04716          else
04717             res = saycharstr(mychannel, mhz);
04718       }
04719       if(!res)
04720          res = sayfile(mychannel, "letters/dot");
04721       if(!res)
04722          res = saycharstr(mychannel, decimals);
04723    
04724       if(res)  break;
04725       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
04726          switch(myrpt->offset){
04727    
04728             case REM_MINUS:
04729                res = sayfile(mychannel,"rpt/minus");
04730                break;
04731             
04732             case REM_SIMPLEX:
04733                res = sayfile(mychannel,"rpt/simplex");
04734                break;
04735                
04736             case REM_PLUS:
04737                res = sayfile(mychannel,"rpt/plus");
04738                break;
04739                
04740             default:
04741                break;
04742          }
04743       }
04744       else{ /* Must be USB, LSB, or AM */
04745          switch(myrpt->remmode){
04746 
04747             case REM_MODE_USB:
04748                res = saycharstr(mychannel, "USB");
04749                break;
04750 
04751             case REM_MODE_LSB:
04752                res = saycharstr(mychannel, "LSB");
04753                break;
04754 
04755             case REM_MODE_AM:
04756                res = saycharstr(mychannel, "AM");
04757                break;
04758 
04759 
04760             default:
04761                break;
04762          }
04763       }
04764 
04765       if (res == -1) break;
04766 
04767       if(mytele->mode == REMSHORTSTATUS){ /* Short status? */
04768          wait_interval(myrpt, DLY_COMP, mychannel);
04769          if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04770          break;
04771       }
04772 
04773       if (strcmp(myrpt->remoterig,remote_rig_ic706))
04774       {
04775          switch(myrpt->powerlevel){
04776 
04777             case REM_LOWPWR:
04778                res = sayfile(mychannel,"rpt/lopwr") ;
04779                break;
04780             case REM_MEDPWR:
04781                res = sayfile(mychannel,"rpt/medpwr");
04782                break;
04783             case REM_HIPWR:
04784                res = sayfile(mychannel,"rpt/hipwr"); 
04785                break;
04786             }
04787       }
04788 
04789       rbimode = ((!strncmp(myrpt->remoterig,remote_rig_rbi,3))
04790         || (!strncmp(myrpt->remoterig,remote_rig_ic706,3)));
04791       if (res || (sayfile(mychannel,"rpt/rxpl") == -1)) break;
04792       if (rbimode && (sayfile(mychannel,"rpt/txpl") == -1)) break;
04793       if ((sayfile(mychannel,"rpt/frequency") == -1) ||
04794          (saycharstr(mychannel,myrpt->rxpl) == -1)) break;
04795       if ((!rbimode) && ((sayfile(mychannel,"rpt/txpl") == -1) ||
04796          (sayfile(mychannel,"rpt/frequency") == -1) ||
04797          (saycharstr(mychannel,myrpt->txpl) == -1))) break;
04798       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
04799          if ((sayfile(mychannel,"rpt/rxpl") == -1) ||
04800             (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1) ||
04801             (sayfile(mychannel,"rpt/txpl") == -1) ||
04802             (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1))
04803             {
04804                break;
04805             }
04806       }
04807       wait_interval(myrpt, DLY_COMP, mychannel);
04808       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04809       break;
04810        case STATUS:
04811       /* wait a little bit */
04812       wait_interval(myrpt, DLY_TELEM, mychannel);
04813       hastx = 0;
04814       linkbase.next = &linkbase;
04815       linkbase.prev = &linkbase;
04816       rpt_mutex_lock(&myrpt->lock);
04817       /* make our own list of links */
04818       l = myrpt->links.next;
04819       while(l != &myrpt->links)
04820       {
04821          if (l->name[0] == '0')
04822          {
04823             l = l->next;
04824             continue;
04825          }
04826          l1 = ast_malloc(sizeof(struct rpt_link));
04827          if (!l1)
04828          {
04829             ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", ast_channel_name(mychannel));
04830             remque((struct qelem *)mytele);
04831             myrpt->active_telem = NULL;
04832             rpt_mutex_unlock(&myrpt->lock);
04833             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04834             ast_free(nodename);
04835             ast_free(ident);
04836             ast_free(mytele);    
04837             ast_hangup(mychannel);
04838             pthread_exit(NULL);
04839          }
04840          memcpy(l1,l,sizeof(struct rpt_link));
04841          l1->next = l1->prev = NULL;
04842          insque((struct qelem *)l1,(struct qelem *)linkbase.next);
04843          l = l->next;
04844       }
04845       rpt_mutex_unlock(&myrpt->lock);
04846       res = saynode(myrpt,mychannel,myrpt->name);
04847       if (myrpt->callmode)
04848       {
04849          hastx = 1;
04850          res = ast_streamfile(mychannel, "rpt/autopatch_on", ast_channel_language(mychannel));
04851          if (!res) 
04852             res = ast_waitstream(mychannel, "");
04853          else
04854              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
04855          ast_stopstream(mychannel);
04856       }
04857       l = linkbase.next;
04858       while(l != &linkbase)
04859       {
04860          char *s;
04861 
04862          hastx = 1;
04863          res = saynode(myrpt,mychannel,l->name);
04864          s = "rpt/tranceive";
04865          if (!l->mode) s = "rpt/monitor";
04866          if (!l->thisconnected) s = "rpt/connecting";
04867          res = ast_streamfile(mychannel, s, ast_channel_language(mychannel));
04868          if (!res) 
04869             res = ast_waitstream(mychannel, "");
04870          else
04871             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
04872          ast_stopstream(mychannel);
04873          l = l->next;
04874       }        
04875       if (!hastx)
04876       {
04877          res = ast_streamfile(mychannel, "rpt/repeat_only", ast_channel_language(mychannel));
04878          if (!res) 
04879             res = ast_waitstream(mychannel, "");
04880          else
04881              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
04882          ast_stopstream(mychannel);
04883       }
04884       /* destroy our local link queue */
04885       l = linkbase.next;
04886       while(l != &linkbase)
04887       {
04888          l1 = l;
04889          l = l->next;
04890          remque((struct qelem *)l1);
04891          ast_free(l1);
04892       }        
04893       imdone = 1;
04894       break;
04895        case FULLSTATUS:
04896       rpt_mutex_lock(&myrpt->lock);
04897       /* get all the nodes */
04898       __mklinklist(myrpt,NULL,lbuf);
04899       rpt_mutex_unlock(&myrpt->lock);
04900       /* parse em */
04901       ns = finddelim(lbuf,strs,MAXLINKLIST);
04902       /* sort em */
04903       if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
04904       /* wait a little bit */
04905       wait_interval(myrpt, DLY_TELEM, mychannel);
04906       hastx = 0;
04907       res = saynode(myrpt,mychannel,myrpt->name);
04908       if (myrpt->callmode)
04909       {
04910          hastx = 1;
04911          res = ast_streamfile(mychannel, "rpt/autopatch_on", ast_channel_language(mychannel));
04912          if (!res) 
04913             res = ast_waitstream(mychannel, "");
04914          else
04915              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
04916          ast_stopstream(mychannel);
04917       }
04918       /* go thru all the nodes in list */
04919       for(i = 0; i < ns; i++)
04920       {
04921          char *s,mode = 'T';
04922 
04923          /* if a mode spec at first, handle it */
04924          if ((*strs[i] < '0') || (*strs[i] > '9'))
04925          {
04926             mode = *strs[i];
04927             strs[i]++;
04928          }
04929 
04930          hastx = 1;
04931          res = saynode(myrpt,mychannel,strs[i]);
04932          s = "rpt/tranceive";
04933          if (mode == 'R') s = "rpt/monitor";
04934          if (mode == 'C') s = "rpt/connecting";
04935          res = ast_streamfile(mychannel, s, ast_channel_language(mychannel));
04936          if (!res) 
04937             res = ast_waitstream(mychannel, "");
04938          else
04939             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
04940          ast_stopstream(mychannel);
04941       }        
04942       if (!hastx)
04943       {
04944          res = ast_streamfile(mychannel, "rpt/repeat_only", ast_channel_language(mychannel));
04945          if (!res) 
04946             res = ast_waitstream(mychannel, "");
04947          else
04948              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
04949          ast_stopstream(mychannel);
04950       }
04951       imdone = 1;
04952       break;
04953 
04954        case LASTNODEKEY: /* Identify last node which keyed us up */
04955       rpt_mutex_lock(&myrpt->lock);
04956       if(myrpt->lastnodewhichkeyedusup){
04957          p = ast_strdup(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
04958          if(!p){
04959             ast_log(LOG_WARNING, "ast_strdup failed in telemetery LASTNODEKEY");
04960             imdone = 1;
04961             break;
04962          }
04963       }
04964       else
04965          p = NULL;
04966       rpt_mutex_unlock(&myrpt->lock);
04967       if(!p){
04968          imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
04969          break;
04970       }
04971       wait_interval(myrpt, DLY_TELEM, mychannel);
04972       res = saynode(myrpt,mychannel,p);
04973       ast_free(p);
04974       imdone = 1;
04975       break;      
04976 
04977        case UNAUTHTX: /* Say unauthorized transmit frequency */
04978       wait_interval(myrpt, DLY_TELEM, mychannel);
04979       res = ast_streamfile(mychannel, "rpt/unauthtx", ast_channel_language(mychannel));
04980       if (!res) 
04981          res = ast_waitstream(mychannel, "");
04982       else
04983           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
04984       ast_stopstream(mychannel);
04985       imdone = 1;
04986       break;
04987 
04988        case PARROT: /* Repeat stuff */
04989 
04990       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04991       if (ast_fileexists(mystr,NULL,ast_channel_language(mychannel)) <= 0)
04992       {
04993          imdone = 1;
04994          myrpt->parrotstate = 0;
04995          break;
04996       }
04997       wait_interval(myrpt, DLY_PARROT, mychannel);
04998       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04999       res = ast_streamfile(mychannel, mystr, ast_channel_language(mychannel));
05000       if (!res) 
05001          res = ast_waitstream(mychannel, "");
05002       else
05003           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
05004       ast_stopstream(mychannel);
05005       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
05006       strcat(mystr,".wav");
05007       unlink(mystr);       
05008       imdone = 1;
05009       myrpt->parrotstate = 0;
05010       break;
05011 
05012        case TIMEOUT:
05013       res = saynode(myrpt,mychannel,myrpt->name);
05014       if (!res)
05015          res = ast_streamfile(mychannel, "rpt/timeout", ast_channel_language(mychannel));
05016       break;
05017       
05018        case TIMEOUT_WARNING:
05019       time(&t);
05020       res = saynode(myrpt,mychannel,myrpt->name);
05021       if (!res)
05022          res = ast_streamfile(mychannel, "rpt/timeout-warning", ast_channel_language(mychannel));
05023       if (!res) 
05024          res = ast_waitstream(mychannel, "");
05025       else
05026           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
05027       ast_stopstream(mychannel);
05028       if(!res) /* Say number of seconds */
05029          ast_say_number(mychannel, myrpt->p.remotetimeout - 
05030              (t - myrpt->last_activity_time), 
05031             "", ast_channel_language(mychannel), (char *) NULL);
05032       if (!res) 
05033          res = ast_waitstream(mychannel, "");
05034       ast_stopstream(mychannel); 
05035       res = ast_streamfile(mychannel, "queue-seconds", ast_channel_language(mychannel));
05036       break;
05037 
05038        case ACT_TIMEOUT_WARNING:
05039       time(&t);
05040       res = saynode(myrpt,mychannel,myrpt->name);
05041       if (!res)
05042           res = ast_streamfile(mychannel, "rpt/act-timeout-warning", ast_channel_language(mychannel));
05043       if (!res) 
05044          res = ast_waitstream(mychannel, "");
05045       else
05046           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
05047       ast_stopstream(mychannel);
05048       if(!res) /* Say number of seconds */
05049          ast_say_number(mychannel, myrpt->p.remoteinacttimeout - 
05050              (t - myrpt->last_activity_time), 
05051             "", ast_channel_language(mychannel), (char *) NULL);
05052       if (!res) 
05053          res = ast_waitstream(mychannel, "");
05054       ast_stopstream(mychannel); 
05055       res = ast_streamfile(mychannel, "queue-seconds", ast_channel_language(mychannel));
05056       break;
05057       
05058        case STATS_TIME:
05059             case STATS_TIME_LOCAL:
05060          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05061       t = time(NULL);
05062       rpt_localtime(&t, &localtm);
05063       /* Say the phase of the day is before the time */
05064       if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
05065          p = "rpt/goodmorning";
05066       else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
05067          p = "rpt/goodafternoon";
05068       else
05069          p = "rpt/goodevening";
05070       if (sayfile(mychannel,p) == -1)
05071       {
05072          imdone = 1;
05073          break;
05074       }
05075       /* Say the time is ... */     
05076       if (sayfile(mychannel,"rpt/thetimeis") == -1)
05077       {
05078          imdone = 1;
05079          break;
05080       }
05081       /* Say the time */            
05082          res = ast_say_time(mychannel, t, "", ast_channel_language(mychannel));
05083       if (!res) 
05084          res = ast_waitstream(mychannel, "");
05085       ast_stopstream(mychannel);    
05086       imdone = 1;
05087          break;
05088        case STATS_VERSION:
05089       p = strstr(tdesc, "version"); 
05090       if(!p)
05091          break;   
05092       if(sscanf(p, "version %30d.%30d", &vmajor, &vminor) != 2)
05093          break;
05094          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05095       /* Say "version" */
05096       if (sayfile(mychannel,"rpt/version") == -1)
05097       {
05098          imdone = 1;
05099          break;
05100       }
05101       if(!res) /* Say "X" */
05102          ast_say_number(mychannel, vmajor, "", ast_channel_language(mychannel), (char *) NULL);
05103       if (!res) 
05104          res = ast_waitstream(mychannel, "");
05105       ast_stopstream(mychannel); 
05106       if (saycharstr(mychannel,".") == -1)
05107       {
05108          imdone = 1;
05109          break;
05110       }
05111       if(!res) /* Say "Y" */
05112          ast_say_number(mychannel, vminor, "", ast_channel_language(mychannel), (char *) NULL);
05113       if (!res){
05114          res = ast_waitstream(mychannel, "");
05115          ast_stopstream(mychannel);
05116       }  
05117       else
05118           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
05119       imdone = 1;
05120          break;
05121        case ARB_ALPHA:
05122          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05123          if(mytele->param)
05124             saycharstr(mychannel, mytele->param);
05125          imdone = 1;
05126       break;
05127        case REV_PATCH:
05128          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05129          if(mytele->param) {
05130 
05131          /* Parts of this section taken from app_parkandannounce */
05132          char *tpl_working, *tpl_current;
05133          char *tmp[100], *myparm;
05134          int looptemp=0,idx=0, dres = 0;
05135    
05136 
05137          tpl_working = ast_strdup(mytele->param);
05138          myparm = strsep(&tpl_working,",");
05139          tpl_current=strsep(&tpl_working, ":");
05140 
05141          while(tpl_current && looptemp < sizeof(tmp)) {
05142             tmp[looptemp]=tpl_current;
05143             looptemp++;
05144             tpl_current=strsep(&tpl_working,":");
05145          }
05146 
05147          for(idx=0; idx<looptemp; idx++) {
05148             if(!strcmp(tmp[idx], "PARKED")) {
05149                ast_say_digits(mychannel, atoi(myparm), "", ast_channel_language(mychannel));
05150             } else if(!strcmp(tmp[idx], "NODE")) {
05151                ast_say_digits(mychannel, atoi(myrpt->name), "", ast_channel_language(mychannel));
05152             } else {
05153                dres = ast_streamfile(mychannel, tmp[idx], ast_channel_language(mychannel));
05154                if(!dres) {
05155                   dres = ast_waitstream(mychannel, "");
05156                } else {
05157                   ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[idx], ast_channel_name(mychannel));
05158                   dres = 0;
05159                }
05160             }
05161          }
05162          ast_free(tpl_working);
05163       }
05164          imdone = 1;
05165       break;
05166        case TEST_TONE:
05167       imdone = 1;
05168       if (myrpt->stopgen) break;
05169       myrpt->stopgen = -1;
05170            if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
05171       {
05172          myrpt->stopgen = 0;
05173          break;
05174       }
05175            while(mychannel->generatordata && (myrpt->stopgen <= 0)) {
05176          if (ast_safe_sleep(mychannel,1)) break;
05177             imdone = 1;
05178          }
05179       myrpt->stopgen = 0;
05180       break;
05181        default:
05182          break;
05183    }
05184    if (!imdone)
05185    {
05186       if (!res) 
05187          res = ast_waitstream(mychannel, "");
05188       else {
05189          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", ast_channel_name(mychannel));
05190          res = 0;
05191       }
05192    }
05193    ast_stopstream(mychannel);
05194    rpt_mutex_lock(&myrpt->lock);
05195    if (mytele->mode == TAILMSG)
05196    {
05197       if (!res)
05198       {
05199          myrpt->tailmessagen++;
05200          if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
05201       }
05202       else
05203       {
05204          myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
05205       }
05206    }
05207    remque((struct qelem *)mytele);
05208    myrpt->active_telem = NULL;
05209    rpt_mutex_unlock(&myrpt->lock);
05210    ast_free(nodename);
05211    ast_free(ident);
05212    ast_free(mytele);    
05213    ast_hangup(mychannel);
05214 #ifdef  APP_RPT_LOCK_DEBUG
05215    {
05216       struct lockthread *t;
05217 
05218       sleep(5);
05219       ast_mutex_lock(&locklock);
05220       t = get_lockthread(pthread_self());
05221       if (t) memset(t,0,sizeof(struct lockthread));
05222       ast_mutex_unlock(&locklock);
05223    }        
05224 #endif
05225    pthread_exit(NULL);
05226 }
05227 
05228 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
05229 {
05230 struct rpt_tele *tele;
05231 struct rpt_link *mylink = NULL;
05232 int res;
05233 pthread_attr_t attr;
05234 char *v1, *v2;
05235 
05236    if(debug > 6)
05237       ast_log(LOG_NOTICE,"mode=%i  data=%s\n",mode, (char *)data);
05238 
05239    switch(mode)
05240    {
05241        case UNKEY:
05242       /* if any of the following are defined, go ahead and do it,
05243          otherwise, don't bother */
05244       v1 = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, 
05245          "unlinkedct");
05246       v2 = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, 
05247          "remotect");
05248       if (telem_lookup(myrpt,NULL, myrpt->name, "remotemon") &&
05249         telem_lookup(myrpt,NULL, myrpt->name, "remotetx") &&
05250         telem_lookup(myrpt,NULL, myrpt->name, "cmdmode") &&
05251         (!(v1 && telem_lookup(myrpt,NULL, myrpt->name, v1))) && 
05252         (!(v2 && telem_lookup(myrpt,NULL, myrpt->name, v2)))) return;
05253       break;
05254        case LINKUNKEY:
05255       if (!ast_variable_retrieve(myrpt->cfg, myrpt->name, "linkunkeyct"))
05256          return;
05257       break;
05258        default:
05259       break;
05260    }
05261    tele = ast_malloc(sizeof(struct rpt_tele));
05262    if (!tele)
05263    {
05264       ast_log(LOG_WARNING, "Unable to allocate memory\n");
05265       pthread_exit(NULL);
05266       return;
05267    }
05268    /* zero it out */
05269    memset((char *)tele,0,sizeof(struct rpt_tele));
05270    tele->rpt = myrpt;
05271    tele->mode = mode;
05272    if (mode == PARROT) tele->parrot = (uintptr_t) data;
05273    else mylink = (struct rpt_link *) data;
05274    rpt_mutex_lock(&myrpt->lock);
05275    if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED) ||
05276        (mode == LINKUNKEY)){
05277       memset(&tele->mylink,0,sizeof(struct rpt_link));
05278       if (mylink){
05279          memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
05280       }
05281    }
05282    else if ((mode == ARB_ALPHA) || (mode == REV_PATCH) || (mode == PLAYBACK)) {
05283       strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
05284       tele->param[TELEPARAMSIZE - 1] = 0;
05285    }
05286    if (mode == REMXXX) tele->submode = (intptr_t) data;
05287    insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
05288    rpt_mutex_unlock(&myrpt->lock);
05289         pthread_attr_init(&attr);
05290         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05291    res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
05292    if(res < 0){
05293       rpt_mutex_lock(&myrpt->lock);
05294       remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
05295       rpt_mutex_unlock(&myrpt->lock);  
05296       ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
05297    }
05298    return;
05299 }
05300 
05301 static void *rpt_call(void *this)
05302 {
05303 struct dahdi_confinfo ci;  /* conference info */
05304 struct   rpt *myrpt = (struct rpt *)this;
05305 int   res;
05306 int stopped,congstarted,dialtimer,lastcidx,aborted;
05307 struct ast_channel *mychannel,*genchannel;
05308 struct ast_format_cap *cap = NULL;
05309 
05310    myrpt->mydtmf = 0;
05311    /* allocate a pseudo-channel thru asterisk */
05312    mychannel = ast_request("DAHDI", get_slin_cap(cap), NULL, "pseudo", NULL);
05313    cap = ast_format_cap_destroy(cap);
05314    if (!mychannel)
05315    {
05316       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
05317       pthread_exit(NULL);
05318    }
05319 #ifdef   AST_CDR_FLAG_POST_DISABLED
05320    if (mychannel->cdr)
05321       ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
05322 #endif
05323    ci.chan = 0;
05324    ci.confno = myrpt->conf; /* use the pseudo conference */
05325 #if   0
05326    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
05327       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
05328 #endif
05329    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
05330    /* first put the channel on the conference */
05331    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05332    {
05333       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05334       ast_hangup(mychannel);
05335       myrpt->callmode = 0;
05336       pthread_exit(NULL);
05337    }
05338    /* allocate a pseudo-channel thru asterisk */
05339    genchannel = ast_request("DAHDI", get_slin_cap(cap), NULL, "pseudo", NULL);
05340    cap = ast_format_cap_destroy(cap);
05341    if (!genchannel)
05342    {
05343       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
05344       ast_hangup(mychannel);
05345       pthread_exit(NULL);
05346    }
05347 #ifdef   AST_CDR_FLAG_POST_DISABLED
05348    if (genchannel->cdr)
05349       ast_set_flag(genchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
05350 #endif
05351    ci.chan = 0;
05352    ci.confno = myrpt->conf;
05353    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
05354       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
05355    /* first put the channel on the conference */
05356    if (ioctl(genchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05357    {
05358       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05359       ast_hangup(mychannel);
05360       ast_hangup(genchannel);
05361       myrpt->callmode = 0;
05362       pthread_exit(NULL);
05363    }
05364    if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
05365    {
05366       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
05367       ast_hangup(mychannel);
05368       ast_hangup(genchannel);
05369       myrpt->callmode = 0;
05370       pthread_exit(NULL);
05371    }
05372    if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
05373    {
05374       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
05375       ast_hangup(mychannel);
05376       ast_hangup(genchannel);
05377       myrpt->callmode = 0;
05378       pthread_exit(NULL);
05379    }
05380    /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
05381    if ((!myrpt->patchquiet) && (tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_DIALTONE) < 0))
05382    {
05383       ast_log(LOG_WARNING, "Cannot start dialtone\n");
05384       ast_hangup(mychannel);
05385       ast_hangup(genchannel);
05386       myrpt->callmode = 0;
05387       pthread_exit(NULL);
05388    }
05389    stopped = 0;
05390    congstarted = 0;
05391    dialtimer = 0;
05392    lastcidx = 0;
05393    myrpt->calldigittimer = 0;
05394    aborted = 0;
05395 
05396    while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
05397    {
05398       if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
05399          dialtimer = 0;
05400          lastcidx = myrpt->cidx;
05401       }     
05402 
05403       if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){ 
05404           if(debug)
05405             ast_log(LOG_NOTICE, "dialtimer %i > patchdialtime %i\n", dialtimer,myrpt->patchdialtime);
05406          rpt_mutex_lock(&myrpt->lock);
05407          aborted = 1;
05408          myrpt->callmode = 0;
05409          rpt_mutex_unlock(&myrpt->lock);
05410          break;
05411       }
05412    
05413       if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
05414       {
05415          stopped = 1;
05416          /* stop dial tone */
05417          tone_zone_play_tone(genchannel->fds[0],-1);
05418       }
05419       if (myrpt->callmode == 1)
05420       {
05421          if(myrpt->calldigittimer > PATCH_DIALPLAN_TIMEOUT)
05422          {
05423             myrpt->callmode = 2;
05424             break;
05425          }
05426          /* bump timer if active */
05427          if (myrpt->calldigittimer) 
05428             myrpt->calldigittimer += MSWAIT;
05429       }
05430       if (myrpt->callmode == 4)
05431       {
05432          if(!congstarted){
05433             congstarted = 1;
05434             /* start congestion tone */
05435             tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
05436          }
05437       }
05438       res = ast_safe_sleep(mychannel, MSWAIT);
05439       if (res < 0)
05440       {
05441           if(debug)
05442             ast_log(LOG_NOTICE, "ast_safe_sleep=%i\n", res);
05443          ast_hangup(mychannel);
05444          ast_hangup(genchannel);
05445          rpt_mutex_lock(&myrpt->lock);
05446          myrpt->callmode = 0;
05447          rpt_mutex_unlock(&myrpt->lock);
05448          pthread_exit(NULL);
05449       }
05450       dialtimer += MSWAIT;
05451    }
05452    /* stop any tone generation */
05453    tone_zone_play_tone(genchannel->fds[0],-1);
05454    /* end if done */
05455    if (!myrpt->callmode)
05456    {
05457       if(debug)
05458          ast_log(LOG_NOTICE, "callmode==0\n");
05459       ast_hangup(mychannel);
05460       ast_hangup(genchannel);
05461       rpt_mutex_lock(&myrpt->lock);
05462       myrpt->callmode = 0;
05463       myrpt->macropatch=0;
05464       channel_revert(myrpt);
05465       rpt_mutex_unlock(&myrpt->lock);
05466       if((!myrpt->patchquiet) && aborted)
05467          rpt_telemetry(myrpt, TERM, NULL);
05468       pthread_exit(NULL);        
05469    }
05470 
05471    if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
05472       char *name, *loc, *instr;
05473       instr = ast_strdup(myrpt->p.ourcallerid);
05474       if(instr){
05475          ast_callerid_parse(instr, &name, &loc);
05476          if(loc){
05477             mychannel->caller.id.number.valid = 1;
05478             ast_free(mychannel->caller.id.number.str);
05479             mychannel->caller.id.number.str = ast_strdup(loc);
05480          }
05481          if(name){
05482             mychannel->caller.id.name.valid = 1;
05483             ast_free(mychannel->caller.id.name.str);
05484             mychannel->caller.id.name.str = ast_strdup(name);
05485          }
05486          ast_free(instr);
05487       }
05488    }
05489 
05490    ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
05491    ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
05492    
05493    if (myrpt->p.acctcode)
05494       ast_cdr_setaccount(mychannel,myrpt->p.acctcode);
05495    mychannel->priority = 1;
05496    ast_channel_undefer_dtmf(mychannel);
05497    if (ast_pbx_start(mychannel) < 0)
05498    {
05499       ast_log(LOG_WARNING, "Unable to start PBX!!\n");
05500       ast_hangup(mychannel);
05501       ast_hangup(genchannel);
05502       rpt_mutex_lock(&myrpt->lock);
05503       myrpt->callmode = 0;
05504       rpt_mutex_unlock(&myrpt->lock);
05505       pthread_exit(NULL);
05506    }
05507    usleep(10000);
05508    rpt_mutex_lock(&myrpt->lock);
05509    myrpt->callmode = 3;
05510    /* set appropriate conference for the pseudo */
05511    ci.chan = 0;
05512    ci.confno = myrpt->conf;
05513    ci.confmode = (myrpt->p.duplex == 2) ? DAHDI_CONF_CONFANNMON :
05514       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
05515    /* first put the channel on the conference in announce mode */
05516    if (ioctl(myrpt->pchannel->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       ast_hangup(genchannel);
05521       myrpt->callmode = 0;
05522       pthread_exit(NULL);
05523    }
05524    /* get its channel number */
05525    if (ioctl(mychannel->fds[0],DAHDI_CHANNO,&res) == -1)
05526    {
05527       ast_log(LOG_WARNING, "Unable to get autopatch channel number\n");
05528       ast_hangup(mychannel);
05529       myrpt->callmode = 0;
05530       pthread_exit(NULL);
05531    }
05532    ci.chan = 0;
05533    ci.confno = res;
05534    ci.confmode = DAHDI_CONF_MONITOR;
05535    /* put vox channel monitoring on the channel  */
05536    if (ioctl(myrpt->voxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05537    {
05538       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05539       ast_hangup(mychannel);
05540       myrpt->callmode = 0;
05541       pthread_exit(NULL);
05542    }
05543    while(myrpt->callmode)
05544    {
05545       if ((!mychannel->pbx) && (myrpt->callmode != 4))
05546       {
05547           /* If patch is setup for far end disconnect */
05548          if(myrpt->patchfarenddisconnect || (myrpt->p.duplex < 2)){ 
05549             if(debug)ast_log(LOG_NOTICE,"callmode=%i, patchfarenddisconnect=%i, duplex=%i\n",\
05550                   myrpt->callmode,myrpt->patchfarenddisconnect,myrpt->p.duplex);
05551             myrpt->callmode = 0;
05552             myrpt->macropatch=0;
05553             if(!myrpt->patchquiet){
05554                rpt_mutex_unlock(&myrpt->lock);
05555                rpt_telemetry(myrpt, TERM, NULL);
05556                rpt_mutex_lock(&myrpt->lock);
05557             }
05558          }
05559          else{ /* Send congestion until patch is downed by command */
05560             myrpt->callmode = 4;
05561             rpt_mutex_unlock(&myrpt->lock);
05562             /* start congestion tone */
05563             tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
05564             rpt_mutex_lock(&myrpt->lock);
05565          }
05566       }
05567       if (myrpt->mydtmf)
05568       {
05569          struct ast_frame wf = {AST_FRAME_DTMF, } ;
05570          wf.subclass.integer = myrpt->mydtmf;
05571          rpt_mutex_unlock(&myrpt->lock);
05572          ast_queue_frame(mychannel,&wf);
05573 #ifdef   NEW_ASTERISK
05574          ast_senddigit(genchannel,myrpt->mydtmf,0);
05575 #else
05576          ast_senddigit(genchannel,myrpt->mydtmf);
05577 #endif
05578          rpt_mutex_lock(&myrpt->lock);
05579          myrpt->mydtmf = 0;
05580       }
05581       rpt_mutex_unlock(&myrpt->lock);
05582       usleep(MSWAIT * 1000);
05583       rpt_mutex_lock(&myrpt->lock);
05584    }
05585    if(debug)
05586       ast_log(LOG_NOTICE, "exit channel loop\n");
05587    rpt_mutex_unlock(&myrpt->lock);
05588    tone_zone_play_tone(genchannel->fds[0],-1);
05589    if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
05590    ast_hangup(genchannel);
05591    rpt_mutex_lock(&myrpt->lock);
05592    myrpt->callmode = 0;
05593    myrpt->macropatch=0;
05594    channel_revert(myrpt);
05595    rpt_mutex_unlock(&myrpt->lock);
05596    /* set appropriate conference for the pseudo */
05597    ci.chan = 0;
05598    ci.confno = myrpt->conf;
05599    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
05600       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
05601    /* first put the channel on the conference in announce mode */
05602    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05603    {
05604       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05605    }
05606    pthread_exit(NULL);
05607 }
05608 
05609 static void send_link_dtmf(struct rpt *myrpt,char c)
05610 {
05611 char  str[300];
05612 struct   ast_frame wf;
05613 struct   rpt_link *l;
05614 
05615    snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
05616    wf.frametype = AST_FRAME_TEXT;
05617    wf.subclass.integer = 0;
05618    wf.offset = 0;
05619    wf.mallocd = 0;
05620    wf.datalen = strlen(str) + 1;
05621    wf.samples = 0;
05622    l = myrpt->links.next;
05623    /* first, see if our dude is there */
05624    while(l != &myrpt->links)
05625    {
05626       if (l->name[0] == '0') 
05627       {
05628          l = l->next;
05629          continue;
05630       }
05631       /* if we found it, write it and were done */
05632       if (!strcmp(l->name,myrpt->cmdnode))
05633       {
05634          wf.data.ptr = str;
05635          if (l->chan) ast_write(l->chan,&wf);
05636          return;
05637       }
05638       l = l->next;
05639    }
05640    l = myrpt->links.next;
05641    /* if not, give it to everyone */
05642    while(l != &myrpt->links)
05643    {
05644       wf.data.ptr = str;
05645       if (l->chan) ast_write(l->chan,&wf);
05646       l = l->next;
05647    }
05648    return;
05649 }
05650 
05651 static void send_link_keyquery(struct rpt *myrpt)
05652 {
05653 char  str[300];
05654 struct   ast_frame wf;
05655 struct   rpt_link *l;
05656 
05657    rpt_mutex_lock(&myrpt->lock);
05658    memset(myrpt->topkey,0,sizeof(myrpt->topkey));
05659    myrpt->topkeystate = 1;
05660    time(&myrpt->topkeytime);
05661    rpt_mutex_unlock(&myrpt->lock);
05662    snprintf(str, sizeof(str), "K? * %s 0 0", myrpt->name);
05663    wf.frametype = AST_FRAME_TEXT;
05664    wf.subclass.integer = 0;
05665    wf.offset = 0;
05666    wf.mallocd = 0;
05667    wf.datalen = strlen(str) + 1;
05668    wf.samples = 0;
05669    l = myrpt->links.next;
05670    /* give it to everyone */
05671    while(l != &myrpt->links)
05672    {
05673       wf.data.ptr = str;
05674       if (l->chan) ast_write(l->chan,&wf);
05675       l = l->next;
05676    }
05677    return;
05678 }
05679 
05680 /* send newkey request */
05681 
05682 static void send_newkey(struct ast_channel *chan)
05683 {
05684 
05685    /* ast_safe_sleep(chan,10); */
05686    ast_sendtext(chan,newkeystr);
05687    return;
05688 }
05689 
05690 
05691 /* 
05692  * Connect a link 
05693  *
05694  * Return values:
05695  * -2: Attempt to connect to self 
05696  * -1: No such node
05697  *  0: Success
05698  *  1: No match yet
05699  *  2: Already connected to this node
05700  */
05701 
05702 static int connect_link(struct rpt *myrpt, char* node, int mode, int perma)
05703 {
05704    char *val, *s, *s1, *s2, *tele;
05705    char lstr[MAXLINKLIST],*strs[MAXLINKLIST];
05706    char tmp[300], deststr[300] = "",modechange = 0;
05707    char sx[320],*sy;
05708    struct rpt_link *l;
05709    int reconnects = 0;
05710    int i,n;
05711    struct dahdi_confinfo ci;  /* conference info */
05712    struct ast_format_cap *cap = NULL;
05713 
05714    val = node_lookup(myrpt,node);
05715    if (!val){
05716       if(strlen(node) >= myrpt->longestnode)
05717          return -1; /* No such node */
05718       return 1; /* No match yet */
05719    }
05720 
05721    if(!strcmp(myrpt->name,node)) /* Do not allow connections to self */
05722       return -2;
05723       
05724    if(debug > 3){
05725       ast_log(LOG_NOTICE,"Connect attempt to node %s\n", node);
05726       ast_log(LOG_NOTICE,"Mode: %s\n",(mode)?"Transceive":"Monitor");
05727       ast_log(LOG_NOTICE,"Connection type: %s\n",(perma)?"Permalink":"Normal");
05728    }
05729 
05730    strncpy(tmp,val,sizeof(tmp) - 1);
05731    s = tmp;
05732    s1 = strsep(&s,",");
05733    if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
05734    {
05735       sy = strchr(s1,'/');    
05736       *sy = 0;
05737       sprintf(sx,"%s:4569/%s",s1,sy + 1);
05738       s1 = sx;
05739    }
05740    s2 = strsep(&s,",");
05741    rpt_mutex_lock(&myrpt->lock);
05742    l = myrpt->links.next;
05743    /* try to find this one in queue */
05744    while(l != &myrpt->links){
05745       if (l->name[0] == '0') 
05746       {
05747          l = l->next;
05748          continue;
05749       }
05750    /* if found matching string */
05751       if (!strcmp(l->name, node))
05752          break;
05753       l = l->next;
05754    }
05755    /* if found */
05756    if (l != &myrpt->links){ 
05757    /* if already in this mode, just ignore */
05758       if ((l->mode) || (!l->chan)) {
05759          rpt_mutex_unlock(&myrpt->lock);
05760          return 2; /* Already linked */
05761       }
05762       reconnects = l->reconnects;
05763       rpt_mutex_unlock(&myrpt->lock);
05764       if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
05765       l->retries = l->max_retries + 1;
05766       l->disced = 2;
05767       modechange = 1;
05768    } else
05769    {
05770       __mklinklist(myrpt,NULL,lstr);
05771       rpt_mutex_unlock(&myrpt->lock);
05772       n = finddelim(lstr,strs,MAXLINKLIST);
05773       for(i = 0; i < n; i++)
05774       {
05775          if ((*strs[i] < '0') || 
05776              (*strs[i] > '9')) strs[i]++;
05777          if (!strcmp(strs[i],node))
05778          {
05779             return 2; /* Already linked */
05780          }
05781       }
05782    }
05783    strncpy(myrpt->lastlinknode,node,MAXNODESTR - 1);
05784    /* establish call */
05785    l = ast_malloc(sizeof(struct rpt_link));
05786    if (!l)
05787    {
05788       ast_log(LOG_WARNING, "Unable to malloc\n");
05789       return -1;
05790    }
05791    /* zero the silly thing */
05792    memset((char *)l,0,sizeof(struct rpt_link));
05793    l->mode = mode;
05794    l->outbound = 1;
05795    l->thisconnected = 0;
05796    voxinit_link(l,1);
05797    strncpy(l->name, node, MAXNODESTR - 1);
05798    l->isremote = (s && ast_true(s));
05799    if (modechange) l->connected = 1;
05800    l->hasconnected = l->perma = perma;
05801 #ifdef ALLOW_LOCAL_CHANNELS
05802    if ((strncasecmp(s1,"iax2/", 5) == 0) || (strncasecmp(s1, "local/", 6) == 0))
05803          strncpy(deststr, s1, sizeof(deststr));
05804    else
05805            snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
05806 #else
05807    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
05808 #endif
05809    tele = strchr(deststr, '/');
05810    if (!tele){
05811       ast_log(LOG_WARNING,"link3:Dial number (%s) must be in format tech/number\n",deststr);
05812       ast_free(l);
05813       return -1;
05814    }
05815    *tele++ = 0;
05816    l->chan = ast_request(deststr, get_slin_cap(cap), NULL, tele, NULL);
05817    cap = ast_format_cap_destroy(cap);
05818    if (l->chan){
05819       ast_set_read_format_by_id(l->chan, AST_FORMAT_SLINEAR);
05820       ast_set_write_format_by_id(l->chan, AST_FORMAT_SLINEAR);
05821 #ifdef   AST_CDR_FLAG_POST_DISABLED
05822       if (l->chan->cdr)
05823          ast_set_flag(l->chan->cdr,AST_CDR_FLAG_POST_DISABLED);
05824 #endif
05825 #ifndef  NEW_ASTERISK
05826       l->chan->whentohangup = 0;
05827 #endif
05828       l->chan->appl = "Apprpt";
05829       l->chan->data = "(Remote Rx)";
05830       if (debug > 3)
05831          ast_log(LOG_NOTICE, "rpt (remote) initiating call to %s/%s on %s\n",
05832       deststr, tele, ast_channel_name(l->chan));
05833       l->chan->caller.id.number.valid = 1;
05834       ast_free(l->chan->caller.id.number.str);
05835       l->chan->caller.id.number.str = ast_strdup(myrpt->name);
05836       ast_call(l->chan,tele,999);
05837    }
05838    else {
05839       if(debug > 3) 
05840          ast_log(LOG_NOTICE, "Unable to place call to %s/%s on %s\n",
05841       deststr,tele,ast_channel_name(l->chan));
05842       if (myrpt->p.archivedir)
05843       {
05844          char str[100];
05845          sprintf(str,"LINKFAIL,%s",l->name);
05846          donodelog(myrpt,str);
05847       }
05848       ast_free(l);
05849       return -1;
05850    }
05851    /* allocate a pseudo-channel thru asterisk */
05852    l->pchan = ast_request("DAHDI", get_slin_cap(cap), NULL, "pseudo", NULL);
05853    cap = ast_format_cap_destroy(cap);
05854    if (!l->pchan){
05855       ast_log(LOG_WARNING,"rpt connect: Sorry unable to obtain pseudo channel\n");
05856       ast_hangup(l->chan);
05857       ast_free(l);
05858       return -1;
05859    }
05860    ast_set_read_format_by_id(l->pchan, AST_FORMAT_SLINEAR);
05861    ast_set_write_format_by_id(l->pchan, AST_FORMAT_SLINEAR);
05862 #ifdef   AST_CDR_FLAG_POST_DISABLED
05863    if (l->pchan->cdr)
05864       ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
05865 #endif
05866    /* make a conference for the tx */
05867    ci.chan = 0;
05868    ci.confno = myrpt->conf;
05869    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
05870    /* first put the channel on the conference in proper mode */
05871    if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1)
05872    {
05873       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05874       ast_hangup(l->chan);
05875       ast_hangup(l->pchan);
05876       ast_free(l);
05877       return -1;
05878    }
05879    rpt_mutex_lock(&myrpt->lock);
05880    l->reconnects = reconnects;
05881    /* insert at end of queue */
05882    l->max_retries = MAX_RETRIES;
05883    if (perma)
05884       l->max_retries = MAX_RETRIES_PERM;
05885    if (l->isremote) l->retries = l->max_retries + 1;
05886    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
05887    __kickshort(myrpt);
05888    rpt_mutex_unlock(&myrpt->lock);
05889    if (!l->phonemode) send_newkey(l->chan);
05890    return 0;
05891 }
05892 
05893 
05894 
05895 /*
05896 * Internet linking function 
05897 */
05898 
05899 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
05900 {
05901 
05902    char *val, *s, *s1, *s2;
05903    char tmp[300];
05904    char digitbuf[MAXNODESTR],*strs[MAXLINKLIST];
05905    char mode,perma;
05906    char sx[320],*sy;
05907    struct rpt_link *l;
05908    int i,r;
05909 
05910    if(!param)
05911       return DC_ERROR;
05912       
05913          
05914    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable )
05915       return DC_ERROR;
05916 
05917    strncpy(digitbuf,digits,MAXNODESTR - 1);
05918 
05919    if(debug > 6)
05920       printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
05921       
05922    switch(myatoi(param)){
05923       case 11: /* Perm Link off */
05924       case 1: /* Link off */
05925          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
05926             strcpy(digitbuf,myrpt->lastlinknode);
05927          val = node_lookup(myrpt,digitbuf);
05928          if (!val){
05929             if(strlen(digitbuf) >= myrpt->longestnode)
05930                return DC_ERROR;
05931             break;
05932          }
05933          strncpy(tmp,val,sizeof(tmp) - 1);
05934          s = tmp;
05935          s1 = strsep(&s,",");
05936          if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
05937          {
05938             sy = strchr(s1,'/');    
05939             *sy = 0;
05940             sprintf(sx,"%s:4569/%s",s1,sy + 1);
05941             s1 = sx;
05942          }
05943          s2 = strsep(&s,",");
05944          rpt_mutex_lock(&myrpt->lock);
05945          l = myrpt->links.next;
05946          /* try to find this one in queue */
05947          while(l != &myrpt->links){
05948             if (l->name[0] == '0') 
05949             {
05950                l = l->next;
05951                continue;
05952             }
05953             /* if found matching string */
05954             if (!strcmp(l->name, digitbuf))
05955                break;
05956             l = l->next;
05957          }
05958          if (l != &myrpt->links){ /* if found */
05959             struct   ast_frame wf;
05960 
05961             /* must use perm command on perm link */
05962             if ((myatoi(param) < 10) && 
05963                 (l->max_retries > MAX_RETRIES))
05964             {
05965                rpt_mutex_unlock(&myrpt->lock);
05966                return DC_COMPLETE;
05967             }
05968             strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
05969             l->retries = l->max_retries + 1;
05970             l->disced = 1;
05971             rpt_mutex_unlock(&myrpt->lock);
05972             wf.frametype = AST_FRAME_TEXT;
05973             wf.subclass.integer = 0;
05974             wf.offset = 0;
05975             wf.mallocd = 0;
05976             wf.datalen = strlen(discstr) + 1;
05977             wf.samples = 0;
05978             wf.data.ptr = discstr;
05979             if (l->chan)
05980             {
05981                ast_write(l->chan,&wf);
05982                if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
05983                ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
05984             }
05985             rpt_telemetry(myrpt, COMPLETE, NULL);
05986             return DC_COMPLETE;
05987          }
05988          rpt_mutex_unlock(&myrpt->lock);  
05989          return DC_COMPLETE;
05990       case 2: /* Link Monitor */
05991       case 3: /* Link transceive */
05992       case 12: /* Link Monitor permanent */
05993       case 13: /* Link transceive permanent */
05994          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
05995             strcpy(digitbuf,myrpt->lastlinknode);
05996          /* Attempt connection  */
05997          perma = (atoi(param) > 10) ? 1 : 0;
05998          mode = (atoi(param) & 1) ? 1 : 0;
05999          r = connect_link(myrpt, digitbuf, mode, perma);
06000          switch(r){
06001             case -2: /* Attempt to connect to self */
06002                return DC_COMPLETE; /* Silent error */
06003 
06004             case 0:
06005                rpt_telemetry(myrpt, COMPLETE, NULL);
06006                return DC_COMPLETE;
06007 
06008             case 1:
06009                break;
06010             
06011             case 2:
06012                rpt_telemetry(myrpt, REMALREADY, NULL);
06013                return DC_COMPLETE;
06014             
06015             default:
06016                rpt_telemetry(myrpt, CONNFAIL, NULL);
06017                return DC_COMPLETE;
06018          }
06019          break;
06020 
06021       case 4: /* Enter Command Mode */
06022       
06023          /* if doesnt allow link cmd, or no links active, return */
06024          if (((command_source != SOURCE_RPT) && 
06025             (command_source != SOURCE_PHONE) &&
06026             (command_source != SOURCE_ALT) &&
06027             (command_source != SOURCE_DPHONE)) ||
06028              (myrpt->links.next == &myrpt->links))
06029             return DC_COMPLETE;
06030          
06031          /* if already in cmd mode, or selected self, fughetabahtit */
06032          if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
06033          
06034             rpt_telemetry(myrpt, REMALREADY, NULL);
06035             return DC_COMPLETE;
06036          }
06037          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
06038             strcpy(digitbuf,myrpt->lastlinknode);
06039          /* node must at least exist in list */
06040          val = node_lookup(myrpt,digitbuf);
06041          if (!val){
06042             if(strlen(digitbuf) >= myrpt->longestnode)
06043                return DC_ERROR;
06044             break;
06045          
06046          }
06047          rpt_mutex_lock(&myrpt->lock);
06048          strcpy(myrpt->lastlinknode,digitbuf);
06049          strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
06050          rpt_mutex_unlock(&myrpt->lock);
06051          rpt_telemetry(myrpt, REMGO, NULL);  
06052          return DC_COMPLETE;
06053          
06054       case 5: /* Status */
06055          rpt_telemetry(myrpt, STATUS, NULL);
06056          return DC_COMPLETE;
06057 
06058       case 15: /* Full Status */
06059          rpt_telemetry(myrpt, FULLSTATUS, NULL);
06060          return DC_COMPLETE;
06061          
06062          
06063       case 6: /* All Links Off, including permalinks */
06064                        rpt_mutex_lock(&myrpt->lock);
06065          myrpt->savednodes[0] = 0;
06066                         l = myrpt->links.next;
06067                         /* loop through all links */
06068                         while(l != &myrpt->links){
06069             struct   ast_frame wf;
06070                                 if (l->name[0] == '0') /* Skip any IAXRPT monitoring */
06071                                 {
06072                                         l = l->next;
06073                                         continue;
06074                                 }
06075             /* Make a string of disconnected nodes for possible restoration */
06076             sprintf(tmp,"%c%c%s",(l->mode) ? 'X' : 'M',(l->perma) ? 'P':'T',l->name);
06077             if(strlen(tmp) + strlen(myrpt->savednodes) + 1 < MAXNODESTR){ 
06078                if(myrpt->savednodes[0])
06079                   strcat(myrpt->savednodes, ",");
06080                strcat(myrpt->savednodes, tmp);
06081             }
06082                               l->retries = l->max_retries + 1;
06083                                 l->disced = 2; /* Silently disconnect */
06084                                 rpt_mutex_unlock(&myrpt->lock);
06085             /* ast_log(LOG_NOTICE,"dumping link %s\n",l->name); */
06086                                 
06087                                 wf.frametype = AST_FRAME_TEXT;
06088                                 wf.subclass.integer = 0;
06089                                 wf.offset = 0;
06090                                 wf.mallocd = 0;
06091                                 wf.datalen = strlen(discstr) + 1;
06092                                 wf.samples = 0;
06093                                 wf.data.ptr = discstr;
06094                                 if (l->chan)
06095                                 {
06096                                         ast_write(l->chan,&wf);
06097                                         ast_safe_sleep(l->chan,250); /* It's dead already, why check the return value? */
06098                                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
06099                                 }
06100             rpt_mutex_lock(&myrpt->lock);
06101                                 l = l->next;
06102                         }
06103          rpt_mutex_unlock(&myrpt->lock);
06104          if(debug > 3)
06105             ast_log(LOG_NOTICE,"Nodes disconnected: %s\n",myrpt->savednodes);
06106                         rpt_telemetry(myrpt, COMPLETE, NULL);
06107          return DC_COMPLETE;
06108 
06109       case 7: /* Identify last node which keyed us up */
06110          rpt_telemetry(myrpt, LASTNODEKEY, NULL);
06111          break;
06112 
06113 
06114 #ifdef   _MDC_DECODE_H_
06115       case 8:
06116          myrpt->lastunit = 0xd00d; 
06117          mdc1200_notify(myrpt,NULL,myrpt->lastunit);
06118          mdc1200_send(myrpt,myrpt->lastunit);
06119          break;
06120 #endif
06121 
06122       case 16: /* Restore links disconnected with "disconnect all links" command */
06123          strcpy(tmp, myrpt->savednodes); /* Make a copy */
06124          finddelim(tmp, strs, MAXLINKLIST); /* convert into substrings */
06125          for(i = 0; tmp[0] && strs[i] != NULL && i < MAXLINKLIST; i++){
06126             s1 = strs[i];
06127             mode = (s1[0] == 'X') ? 1 : 0;
06128             perma = (s1[1] == 'P') ? 1 : 0;
06129             connect_link(myrpt, s1 + 2, mode, perma); /* Try to reconnect */
06130          }
06131                         rpt_telemetry(myrpt, COMPLETE, NULL);
06132          break;
06133    
06134       case 200:
06135       case 201:
06136       case 202:
06137       case 203:
06138       case 204:
06139       case 205:
06140       case 206:
06141       case 207:
06142       case 208:
06143       case 209:
06144       case 210:
06145       case 211:
06146       case 212:
06147       case 213:
06148       case 214:
06149       case 215:
06150          if (((myrpt->p.propagate_dtmf) && 
06151               (command_source == SOURCE_LNK)) ||
06152              ((myrpt->p.propagate_phonedtmf) &&
06153             ((command_source == SOURCE_PHONE) ||
06154               (command_source == SOURCE_ALT) ||
06155                 (command_source == SOURCE_DPHONE))))
06156                do_dtmf_local(myrpt,
06157                   remdtmfstr[myatoi(param) - 200]);
06158       default:
06159          return DC_ERROR;
06160          
06161    }
06162    
06163    return DC_INDETERMINATE;
06164 }  
06165 
06166 /*
06167 * Autopatch up
06168 */
06169 
06170 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06171 {
06172    pthread_attr_t attr;
06173    int i, idx, paramlength;
06174    char *lparam;
06175    char *value = NULL;
06176    char *paramlist[20];
06177 
06178    static char *keywords[] = {
06179    "context",
06180    "dialtime",
06181    "farenddisconnect",
06182    "noct",
06183    "quiet",
06184    NULL
06185    };
06186       
06187    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
06188       return DC_ERROR;
06189       
06190    if(debug)
06191       printf("@@@@ Autopatch up\n");
06192 
06193    if(!myrpt->callmode){
06194       /* Set defaults */
06195       myrpt->patchnoct = 0;
06196       myrpt->patchdialtime = 0;
06197       myrpt->patchfarenddisconnect = 0;
06198       myrpt->patchquiet = 0;
06199       strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
06200 
06201       if(param){
06202          /* Process parameter list */
06203          lparam = ast_strdup(param);
06204          if(!lparam){
06205             ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
06206             return DC_ERROR;  
06207          }
06208          paramlength = finddelim(lparam, paramlist, 20);          
06209          for(i = 0; i < paramlength; i++){
06210             idx = matchkeyword(paramlist[i], &value, keywords);
06211             if(value)
06212                value = skipchars(value, "= ");
06213             switch(idx){
06214 
06215                case 1: /* context */
06216                   strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ;
06217                   break;
06218                   
06219                case 2: /* dialtime */
06220                   myrpt->patchdialtime = atoi(value);
06221                   break;
06222 
06223                case 3: /* farenddisconnect */
06224                   myrpt->patchfarenddisconnect = atoi(value);
06225                   break;
06226 
06227                case 4:  /* noct */
06228                   myrpt->patchnoct = atoi(value);
06229                   break;
06230 
06231                case 5: /* quiet */
06232                   myrpt->patchquiet = atoi(value);
06233                   break;
06234                            
06235                default:
06236                   break;
06237             }
06238          }
06239       ast_free(lparam);
06240       }
06241    }
06242                
06243    rpt_mutex_lock(&myrpt->lock);
06244 
06245    /* if on call, force * into current audio stream */
06246    
06247    if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
06248       myrpt->mydtmf = myrpt->p.endchar;
06249    }
06250    if (myrpt->callmode){
06251       rpt_mutex_unlock(&myrpt->lock);
06252       return DC_COMPLETE;
06253    }
06254    myrpt->callmode = 1;
06255    myrpt->cidx = 0;
06256    myrpt->exten[myrpt->cidx] = 0;
06257    rpt_mutex_unlock(&myrpt->lock);
06258    pthread_attr_init(&attr);
06259    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
06260    ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
06261    return DC_COMPLETE;
06262 }
06263 
06264 /*
06265 * Autopatch down
06266 */
06267 
06268 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06269 {
06270    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
06271       return DC_ERROR;
06272    
06273    if(debug)
06274       printf("@@@@ Autopatch down\n");
06275       
06276    rpt_mutex_lock(&myrpt->lock);
06277    
06278    myrpt->macropatch=0;
06279 
06280    if (!myrpt->callmode){
06281       rpt_mutex_unlock(&myrpt->lock);
06282       return DC_COMPLETE;
06283    }
06284    
06285    myrpt->callmode = 0;
06286    channel_revert(myrpt);
06287    rpt_mutex_unlock(&myrpt->lock);
06288    rpt_telemetry(myrpt, TERM, NULL);
06289    return DC_COMPLETE;
06290 }
06291 
06292 /*
06293 * Status
06294 */
06295 
06296 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06297 {
06298 
06299    if (!param)
06300       return DC_ERROR;
06301 
06302    if ((myrpt->p.s[myrpt->p.sysstate_cur].txdisable) || (myrpt->p.s[myrpt->p.sysstate_cur].userfundisable))
06303       return DC_ERROR;
06304 
06305    if(debug)
06306       printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06307    
06308    switch(myatoi(param)){
06309       case 1: /* System ID */
06310          rpt_telemetry(myrpt, ID1, NULL);
06311          return DC_COMPLETE;
06312       case 2: /* System Time */
06313          rpt_telemetry(myrpt, STATS_TIME, NULL);
06314          return DC_COMPLETE;
06315       case 3: /* app_rpt.c version */
06316          rpt_telemetry(myrpt, STATS_VERSION, NULL);
06317          return DC_COMPLETE;
06318       case 11: /* System ID (local only)*/
06319           rpt_telemetry(myrpt, ID , NULL);
06320             return DC_COMPLETE;
06321         case 12: /* System Time (local only)*/
06322             rpt_telemetry(myrpt, STATS_TIME_LOCAL, NULL);
06323             return DC_COMPLETE;
06324       default:
06325          return DC_ERROR;
06326    }
06327    return DC_INDETERMINATE;
06328 }
06329 /*
06330 *  Macro-oni (without Salami)
06331 */
06332 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06333 {
06334 char  *val;
06335 int   i;
06336    if (myrpt->remote)
06337       return DC_ERROR;
06338 
06339    if(debug) 
06340       printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06341    
06342    if(strlen(digitbuf) < 1) /* needs 1 digit */
06343       return DC_INDETERMINATE;
06344          
06345    for(i = 0 ; i < digitbuf[i] ; i++) {
06346       if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06347          return DC_ERROR;
06348    }
06349    
06350    if (*digitbuf == '0') val = myrpt->p.startupmacro;
06351    else val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
06352    /* param was 1 for local buf */
06353    if (!val){
06354                 if (strlen(digitbuf) < myrpt->macro_longest)
06355                         return DC_INDETERMINATE;
06356       rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
06357       return DC_COMPLETE;
06358    }        
06359    rpt_mutex_lock(&myrpt->lock);
06360    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
06361    {
06362       rpt_mutex_unlock(&myrpt->lock);
06363       rpt_telemetry(myrpt, MACRO_BUSY, NULL);
06364       return DC_ERROR;
06365    }
06366    myrpt->macrotimer = MACROTIME;
06367    strncat(myrpt->macrobuf,val,MAXMACRO - 1);
06368    rpt_mutex_unlock(&myrpt->lock);
06369    return DC_COMPLETE;  
06370 }
06371 
06372 /*
06373 *  Playback a recording
06374 */
06375 
06376 static int function_playback(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06377 {
06378 
06379    if (myrpt->remote)
06380       return DC_ERROR;
06381 
06382    if(debug) 
06383       printf("@@@@ playback param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06384    
06385    if (ast_fileexists(param,NULL,ast_channel_language(myrpt->rxchannel)) <= 0)
06386       return DC_ERROR;
06387 
06388    rpt_telemetry(myrpt,PLAYBACK,param);
06389    return DC_COMPLETE;
06390 }
06391 
06392 /*
06393 * COP - Control operator
06394 */
06395 
06396 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06397 {
06398    char string[16];
06399    int res;
06400 
06401    int i, r;
06402 
06403    if(!param)
06404       return DC_ERROR;
06405    
06406    switch(myatoi(param)){
06407       case 1: /* System reset */
06408          res = system("killall -9 asterisk");
06409          return DC_COMPLETE;
06410 
06411       case 2:
06412          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 0;
06413          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
06414          return DC_COMPLETE;
06415          
06416       case 3:
06417          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 1;
06418          return DC_COMPLETE;
06419          
06420       case 4: /* test tone on */
06421          if (myrpt->stopgen < 0) 
06422          {
06423             myrpt->stopgen = 1;
06424          }
06425          else 
06426          {
06427             myrpt->stopgen = 0;
06428             rpt_telemetry(myrpt, TEST_TONE, NULL);
06429          }
06430          return DC_COMPLETE;
06431 
06432       case 5: /* Disgorge variables to log for debug purposes */
06433          myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
06434          return DC_COMPLETE;
06435 
06436       case 6: /* Simulate COR being activated (phone only) */
06437          if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
06438          return DC_DOKEY;  
06439 
06440 
06441       case 7: /* Time out timer enable */
06442          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 0;
06443          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTENA");
06444          return DC_COMPLETE;
06445          
06446       case 8: /* Time out timer disable */
06447          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 1;
06448          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTDIS");
06449          return DC_COMPLETE;
06450 
06451                 case 9: /* Autopatch enable */
06452                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 0;
06453                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APENA");
06454                         return DC_COMPLETE;
06455 
06456                 case 10: /* Autopatch disable */
06457                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 1;
06458                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APDIS");
06459                         return DC_COMPLETE;
06460 
06461                 case 11: /* Link Enable */
06462                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 0;
06463                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKENA");
06464                         return DC_COMPLETE;
06465 
06466                 case 12: /* Link Disable */
06467                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 1;
06468                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKDIS");
06469                         return DC_COMPLETE;
06470 
06471       case 13: /* Query System State */
06472          string[0] = string[1] = 'S';
06473          string[2] = myrpt->p.sysstate_cur + '0';
06474          string[3] = '\0';
06475          rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
06476          return DC_COMPLETE;
06477 
06478       case 14: /* Change System State */
06479          if(strlen(digitbuf) == 0)
06480             break;
06481          if((digitbuf[0] < '0') || (digitbuf[0] > '9'))
06482             return DC_ERROR;
06483          myrpt->p.sysstate_cur = digitbuf[0] - '0';
06484                         string[0] = string[1] = 'S';
06485                         string[2] = myrpt->p.sysstate_cur + '0';
06486                         string[3] = '\0';
06487                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
06488                         return DC_COMPLETE;
06489 
06490                 case 15: /* Scheduler Enable */
06491                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 0;
06492                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKENA");
06493                         return DC_COMPLETE;
06494 
06495                 case 16: /* Scheduler Disable */
06496                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 1;
06497                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKDIS");
06498                         return DC_COMPLETE;
06499 
06500                 case 17: /* User functions Enable */
06501                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 0;
06502                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFENA");
06503                         return DC_COMPLETE;
06504 
06505                 case 18: /* User Functions Disable */
06506                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 1;
06507                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFDIS");
06508                         return DC_COMPLETE;
06509 
06510                 case 19: /* Alternate Tail Enable */
06511                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 1;
06512                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATENA");
06513                         return DC_COMPLETE;
06514 
06515                 case 20: /* Alternate Tail Disable */
06516                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 0;
06517                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATDIS");
06518                         return DC_COMPLETE;
06519 
06520                 case 21: /* Parrot Mode Disable */
06521          birdbath(myrpt);
06522          if (myrpt->p.parrotmode < 2)
06523          {
06524             myrpt->p.parrotmode = 0;
06525             rpt_telemetry(myrpt,COMPLETE,NULL);
06526             return DC_COMPLETE;
06527          }
06528          break;
06529 
06530                 case 22: /* Parrot Mode Enable */
06531          birdbath(myrpt);
06532          if (myrpt->p.parrotmode < 2)
06533          {
06534             myrpt->p.parrotmode = 1;
06535             rpt_telemetry(myrpt,COMPLETE,NULL);
06536             return DC_COMPLETE;
06537          }
06538          break;
06539       case 23: /* flush parrot in progress */
06540          birdbath(myrpt);
06541          rpt_telemetry(myrpt,COMPLETE,NULL);
06542          return DC_COMPLETE;
06543       case 24: /* flush all telemetry */
06544          flush_telem(myrpt);
06545          rpt_telemetry(myrpt,COMPLETE,NULL);
06546          return DC_COMPLETE;
06547       case 25: /* request keying info (brief) */
06548          send_link_keyquery(myrpt);
06549          myrpt->topkeylong = 0;
06550          rpt_telemetry(myrpt,COMPLETE,NULL);
06551          return DC_COMPLETE;
06552       case 26: /* request keying info (full) */
06553          send_link_keyquery(myrpt);
06554          myrpt->topkeylong = 1;
06555          rpt_telemetry(myrpt,COMPLETE,NULL);
06556          return DC_COMPLETE;
06557 
06558       case 30: /* recall memory location on programmable radio */
06559 
06560          if(strlen(digitbuf) < 2) /* needs 2 digits */
06561             break;
06562          
06563          for(i = 0 ; i < 2 ; i++){
06564             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06565                return DC_ERROR;
06566          }
06567        
06568          r = retreive_memory(myrpt, digitbuf);
06569          if (r < 0){
06570             rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
06571             return DC_COMPLETE;
06572          }
06573          if (r > 0){
06574             return DC_ERROR;
06575          }
06576          if (setrem(myrpt) == -1) return DC_ERROR;
06577          return DC_COMPLETE;  
06578 
06579       case 31: 
06580           /* set channel. note that it's going to change channel 
06581              then confirm on the new channel! */
06582          if(strlen(digitbuf) < 2) /* needs 2 digits */
06583             break;
06584          
06585          for(i = 0 ; i < 2 ; i++){
06586             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06587                return DC_ERROR;
06588          }
06589          channel_steer(myrpt,digitbuf);
06590          return DC_COMPLETE;  
06591 
06592       case 32: /* Touch Tone Pad Test */
06593          i = strlen(digitbuf);
06594          if(!i){
06595             if(debug > 3)
06596             ast_log(LOG_NOTICE,"Padtest entered");
06597             myrpt->inpadtest = 1;
06598          }
06599          else{
06600             if(debug > 3)
06601                ast_log(LOG_NOTICE,"Padtest len= %d digits=%s",i,digitbuf);
06602             if(digitbuf[i-1] != myrpt->p.endchar)
06603                break;
06604             rpt_telemetry(myrpt, ARB_ALPHA, digitbuf);
06605             myrpt->inpadtest = 0;
06606             if(debug > 3)
06607                ast_log(LOG_NOTICE,"Padtest exited");
06608             return DC_COMPLETE;
06609          }
06610    }  
06611    return DC_INDETERMINATE;
06612 }
06613 /*
06614 * Collect digits one by one until something matches
06615 */
06616 static int collect_function_digits(struct rpt *myrpt, char *digits, 
06617    int command_source, struct rpt_link *mylink)
06618 {
06619    int i,rv;
06620    char *stringp,*action,*param,*functiondigits;
06621    char function_table_name[30] = "";
06622    char workstring[200];
06623    
06624    struct ast_variable *vp;
06625    
06626    if (debug > 6) ast_log(LOG_NOTICE,"digits=%s  source=%d\n",digits, command_source);
06627 
06628    //if(debug) 
06629    // printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
06630    
06631    if (command_source == SOURCE_DPHONE) {
06632       if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
06633       strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1);
06634       }
06635    else if (command_source == SOURCE_ALT) {
06636       if (!myrpt->p.alt_functions) return DC_INDETERMINATE;
06637       strncpy(function_table_name, myrpt->p.alt_functions, sizeof(function_table_name) - 1);
06638       }
06639    else if (command_source == SOURCE_PHONE) {
06640       if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
06641       strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1);
06642       }
06643    else if (command_source == SOURCE_LNK)
06644       strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1);
06645    else
06646       strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1);
06647     /* find context for function table in rpt.conf file */
06648    vp = ast_variable_browse(myrpt->cfg, function_table_name);
06649    while(vp) {
06650       if(!strncasecmp(vp->name, digits, strlen(vp->name)))
06651          break;
06652       vp = vp->next;
06653    }  
06654    /* if function context not found */
06655    if(!vp) {
06656       int n;
06657 
06658       n = myrpt->longestfunc;
06659       if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
06660       else 
06661       if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
06662       else 
06663       if (command_source == SOURCE_ALT) n = myrpt->alt_longestfunc;
06664       else 
06665       if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
06666       
06667       if(strlen(digits) >= n)
06668          return DC_ERROR;
06669       else
06670          return DC_INDETERMINATE;
06671    }  
06672    /* Found a match, retrieve value part and parse */
06673    strncpy(workstring, vp->value, sizeof(workstring) - 1 );
06674    stringp = workstring;
06675    action = strsep(&stringp, ",");
06676    param = stringp;
06677    if(debug)
06678       printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
06679    /* Look up the action */
06680    for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
06681       if(!strncasecmp(action, function_table[i].action, strlen(action)))
06682          break;
06683    }
06684    if(debug)
06685       printf("@@@@ table index i = %d\n",i);
06686    if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
06687       /* Error, action not in table */
06688       return DC_ERROR;
06689    }
06690    if(function_table[i].function == NULL){
06691       /* Error, function undefined */
06692       if(debug)
06693          printf("@@@@ NULL for action: %s\n",action);
06694       return DC_ERROR;
06695    }
06696    functiondigits = digits + strlen(vp->name);
06697    rv=(*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
06698    if (debug > 6) ast_log(LOG_NOTICE,"rv=%i\n",rv);
06699    return(rv);
06700 }
06701 
06702 
06703 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
06704    char *str)
06705 {
06706 /* XXX ATTENTION: if you change the size of these arrays you MUST
06707  * change the limits in corresponding sscanf() calls below. */
06708 char  tmp[512],tmp1[512],cmd[300] = "",dest[300],src[300],c;
06709 int   i,seq, res, ts;
06710 struct rpt_link *l;
06711 struct   ast_frame wf;
06712 
06713    wf.frametype = AST_FRAME_TEXT;
06714    wf.subclass.integer = 0;
06715    wf.offset = 0;
06716    wf.mallocd = 0;
06717    wf.datalen = strlen(str) + 1;
06718    wf.samples = 0;
06719    /* put string in our buffer */
06720    strncpy(tmp,str,sizeof(tmp) - 1);
06721 
06722         if (!strcmp(tmp,discstr))
06723         {
06724                 mylink->disced = 1;
06725       mylink->retries = mylink->max_retries + 1;
06726                 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
06727                 return;
06728         }
06729         if (!strcmp(tmp,newkeystr))
06730         {
06731       mylink->newkey = 1;
06732                 return;
06733         }
06734    if (tmp[0] == 'L')
06735    {
06736       rpt_mutex_lock(&myrpt->lock);
06737       strcpy(mylink->linklist,tmp + 2);
06738       time(&mylink->linklistreceived);
06739       rpt_mutex_unlock(&myrpt->lock);
06740       if (debug > 6) ast_log(LOG_NOTICE,"@@@@ node %s received node list %s from node %s\n",
06741          myrpt->name,tmp,mylink->name);
06742       return;
06743    }
06744    if (tmp[0] == 'K')
06745    {
06746       if (sscanf(tmp, "%299s %299s %299s %30d %30d", cmd, dest, src, &seq, &ts) != 5)
06747       {
06748          ast_log(LOG_WARNING, "Unable to parse keying string %s\n",str);
06749          return;
06750       }
06751       if (dest[0] == '0')
06752       {
06753          strcpy(dest,myrpt->name);
06754       }     
06755       /* if not for me, redistribute to all links */
06756       if (strcmp(dest,myrpt->name))
06757       {
06758          l = myrpt->links.next;
06759          /* see if this is one in list */
06760          while(l != &myrpt->links)
06761          {
06762             if (l->name[0] == '0') 
06763             {
06764                l = l->next;
06765                continue;
06766             }
06767             /* don't send back from where it came */
06768             if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06769             {
06770                l = l->next;
06771                continue;
06772             }
06773             /* if it is, send it and we're done */
06774             if (!strcmp(l->name,dest))
06775             {
06776                /* send, but not to src */
06777                if (strcmp(l->name,src)) {
06778                   wf.data.ptr = str;
06779                   if (l->chan) ast_write(l->chan,&wf);
06780                }
06781                return;
06782             }
06783             l = l->next;
06784          }
06785       }
06786       /* if not for me, or is broadcast, redistribute to all links */
06787       if ((strcmp(dest,myrpt->name)) || (dest[0] == '*'))
06788       {
06789          l = myrpt->links.next;
06790          /* otherwise, send it to all of em */
06791          while(l != &myrpt->links)
06792          {
06793             if (l->name[0] == '0') 
06794             {
06795                l = l->next;
06796                continue;
06797             }
06798             /* don't send back from where it came */
06799             if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06800             {
06801                l = l->next;
06802                continue;
06803             }
06804             /* send, but not to src */
06805             if (strcmp(l->name,src)) {
06806                wf.data.ptr = str;
06807                if (l->chan) ast_write(l->chan,&wf); 
06808             }
06809             l = l->next;
06810          }
06811       }
06812       /* if not for me, end here */
06813       if (strcmp(dest,myrpt->name) && (dest[0] != '*')) return;
06814       if (cmd[1] == '?')
06815       {
06816          time_t now;
06817          int n = 0;
06818 
06819          time(&now);
06820          if (myrpt->lastkeyedtime)
06821          {
06822             n = (int)(now - myrpt->lastkeyedtime);
06823          }
06824          sprintf(tmp1,"K %s %s %d %d",src,myrpt->name,myrpt->keyed,n);
06825          wf.data.ptr = tmp1;
06826          wf.datalen = strlen(tmp1) + 1;
06827          if (mylink->chan) ast_write(mylink->chan,&wf); 
06828          return;
06829       }
06830       if (myrpt->topkeystate != 1) return;
06831       rpt_mutex_lock(&myrpt->lock);
06832       for(i = 0; i < TOPKEYN; i++)
06833       {
06834          if (!strcmp(myrpt->topkey[i].node,src)) break;
06835       }
06836       if (i >= TOPKEYN)
06837       {
06838          for(i = 0; i < TOPKEYN; i++)
06839          {
06840             if (!myrpt->topkey[i].node[0]) break;
06841          }
06842       }
06843       if (i < TOPKEYN)
06844       {
06845          strncpy(myrpt->topkey[i].node,src,TOPKEYMAXSTR - 1);
06846          myrpt->topkey[i].timesince = ts;
06847          myrpt->topkey[i].keyed = seq;
06848       }
06849       rpt_mutex_unlock(&myrpt->lock);
06850       return;
06851    }
06852    if (tmp[0] == 'I')
06853    {
06854       /* XXX WARNING: be very careful with the limits on the folowing
06855        * sscanf() call, make sure they match the values defined above */
06856       if (sscanf(tmp,"%299s %299s %30x",cmd,src,&seq) != 3)
06857       {
06858          ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
06859          return;
06860       }
06861       mdc1200_notify(myrpt,src,seq);
06862       strcpy(dest,"*");
06863    }
06864    else
06865    {
06866       /* XXX WARNING: be very careful with the limits on the folowing
06867        * sscanf() call, make sure they match the values defined above */
06868       if (sscanf(tmp,"%299s %299s %299s %30d %1c",cmd,dest,src,&seq,&c) != 5)
06869       {
06870          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
06871          return;
06872       }
06873       if (strcmp(cmd,"D"))
06874       {
06875          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
06876          return;
06877       }
06878    }
06879    if (dest[0] == '0')
06880    {
06881       strcpy(dest,myrpt->name);
06882    }     
06883 
06884    /* if not for me, redistribute to all links */
06885    if (strcmp(dest,myrpt->name))
06886    {
06887       l = myrpt->links.next;
06888       /* see if this is one in list */
06889       while(l != &myrpt->links)
06890       {
06891          if (l->name[0] == '0') 
06892          {
06893             l = l->next;
06894             continue;
06895          }
06896          /* don't send back from where it came */
06897          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06898          {
06899             l = l->next;
06900             continue;
06901          }
06902          /* if it is, send it and we're done */
06903          if (!strcmp(l->name,dest))
06904          {
06905             /* send, but not to src */
06906             if (strcmp(l->name,src)) {
06907                wf.data.ptr = str;
06908                if (l->chan) ast_write(l->chan,&wf);
06909             }
06910             return;
06911          }
06912          l = l->next;
06913       }
06914       l = myrpt->links.next;
06915       /* otherwise, send it to all of em */
06916       while(l != &myrpt->links)
06917       {
06918          if (l->name[0] == '0') 
06919          {
06920             l = l->next;
06921             continue;
06922          }
06923          /* don't send back from where it came */
06924          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06925          {
06926             l = l->next;
06927             continue;
06928          }
06929          /* send, but not to src */
06930          if (strcmp(l->name,src)) {
06931             wf.data.ptr = str;
06932             if (l->chan) ast_write(l->chan,&wf); 
06933          }
06934          l = l->next;
06935       }
06936       return;
06937    }
06938    if (myrpt->p.archivedir)
06939    {
06940       char dtmfstr[100];
06941 
06942       sprintf(dtmfstr,"DTMF,%s,%c",mylink->name,c);
06943       donodelog(myrpt,dtmfstr);
06944    }
06945    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
06946    if (!c) return;
06947    rpt_mutex_lock(&myrpt->lock);
06948    if (c == myrpt->p.endchar) myrpt->stopgen = 1;
06949    if (myrpt->callmode == 1)
06950    {
06951       myrpt->exten[myrpt->cidx++] = c;
06952       myrpt->exten[myrpt->cidx] = 0;
06953       /* if this exists */
06954       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
06955       {
06956          /* if this really it, end now */
06957          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
06958             myrpt->exten,1,NULL)) 
06959          {
06960             myrpt->callmode = 2;
06961             if(!myrpt->patchquiet)
06962             {
06963                rpt_mutex_unlock(&myrpt->lock);
06964                rpt_telemetry(myrpt,PROC,NULL); 
06965                rpt_mutex_lock(&myrpt->lock);
06966             }
06967          }
06968          else /* othewise, reset timer */
06969          {
06970             myrpt->calldigittimer = 1;
06971          }
06972       }
06973       /* if can continue, do so */
06974       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
06975       {
06976          /* call has failed, inform user */
06977          myrpt->callmode = 4;
06978       }
06979    }
06980    if ((!myrpt->inpadtest) &&(c == myrpt->p.funcchar))
06981    {
06982       myrpt->rem_dtmfidx = 0;
06983       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
06984       time(&myrpt->rem_dtmf_time);
06985       rpt_mutex_unlock(&myrpt->lock);
06986       return;
06987    } 
06988    else if (myrpt->rem_dtmfidx < 0)
06989    {
06990       if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
06991       {
06992          myrpt->mydtmf = c;
06993       }
06994       if (myrpt->p.propagate_dtmf) do_dtmf_local(myrpt,c);
06995       if (myrpt->p.propagate_phonedtmf) do_dtmf_phone(myrpt,mylink,c);
06996       rpt_mutex_unlock(&myrpt->lock);
06997       return;
06998    }
06999    else if (((myrpt->inpadtest) || (c != myrpt->p.endchar)) && (myrpt->rem_dtmfidx >= 0))
07000    {
07001       time(&myrpt->rem_dtmf_time);
07002       if (myrpt->rem_dtmfidx < MAXDTMF)
07003       {
07004          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
07005          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
07006          
07007          rpt_mutex_unlock(&myrpt->lock);
07008          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
07009          res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
07010          rpt_mutex_lock(&myrpt->lock);
07011          
07012          switch(res){
07013 
07014             case DC_INDETERMINATE:
07015                break;
07016             
07017             case DC_REQ_FLUSH:
07018                myrpt->rem_dtmfidx = 0;
07019                myrpt->rem_dtmfbuf[0] = 0;
07020                break;
07021             
07022             
07023             case DC_COMPLETE:
07024             case DC_COMPLETEQUIET:
07025                myrpt->totalexecdcommands++;
07026                myrpt->dailyexecdcommands++;
07027                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
07028                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
07029                myrpt->rem_dtmfbuf[0] = 0;
07030                myrpt->rem_dtmfidx = -1;
07031                myrpt->rem_dtmf_time = 0;
07032                break;
07033             
07034             case DC_ERROR:
07035             default:
07036                myrpt->rem_dtmfbuf[0] = 0;
07037                myrpt->rem_dtmfidx = -1;
07038                myrpt->rem_dtmf_time = 0;
07039                break;
07040          }
07041       }
07042 
07043    }
07044    rpt_mutex_unlock(&myrpt->lock);
07045    return;
07046 }
07047 
07048 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
07049    char c)
07050 {
07051 
07052 char  cmd[300];
07053 int   res;
07054 
07055    if (myrpt->p.archivedir)
07056    {
07057       char str[100];
07058 
07059       sprintf(str,"DTMF(P),%s,%c",mylink->name,c);
07060       donodelog(myrpt,str);
07061    }
07062    rpt_mutex_lock(&myrpt->lock);
07063 
07064    if (mylink->phonemode == 3) /*If in simplex dumb phone mode */
07065    {
07066       if(c == myrpt->p.endchar) /* If end char */
07067       {
07068          mylink->lastrealrx = 0; /* Keying state = off */
07069          rpt_mutex_unlock(&myrpt->lock);
07070          return;
07071       }
07072 
07073       if(c == myrpt->p.funcchar) /* If lead-in char */
07074       {
07075          mylink->lastrealrx = !mylink->lastrealrx; /* Toggle keying state */
07076          rpt_mutex_unlock(&myrpt->lock);
07077          return;
07078       }
07079    }
07080    else
07081    {
07082       if (c == myrpt->p.endchar)
07083       {
07084          if (mylink->lastrx)
07085          {
07086             mylink->lastrealrx = 0;
07087             rpt_mutex_unlock(&myrpt->lock);
07088             return;
07089          }
07090          myrpt->stopgen = 1;
07091          if (myrpt->cmdnode[0])
07092          {
07093             myrpt->cmdnode[0] = 0;
07094             myrpt->dtmfidx = -1;
07095             myrpt->dtmfbuf[0] = 0;
07096             rpt_mutex_unlock(&myrpt->lock);
07097             rpt_telemetry(myrpt,COMPLETE,NULL);
07098             return;
07099          }
07100       }
07101    }
07102    if (myrpt->cmdnode[0])
07103    {
07104       rpt_mutex_unlock(&myrpt->lock);
07105       send_link_dtmf(myrpt,c);
07106       return;
07107    }
07108    if (myrpt->callmode == 1)
07109    {
07110       myrpt->exten[myrpt->cidx++] = c;
07111       myrpt->exten[myrpt->cidx] = 0;
07112       /* if this exists */
07113       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
07114       {
07115          /* if this really it, end now */
07116          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
07117             myrpt->exten,1,NULL)) 
07118          {
07119             myrpt->callmode = 2;
07120             if(!myrpt->patchquiet)
07121             {
07122                rpt_mutex_unlock(&myrpt->lock);
07123                rpt_telemetry(myrpt,PROC,NULL); 
07124                rpt_mutex_lock(&myrpt->lock);
07125             }
07126          }
07127          else /* othewise, reset timer */
07128          {
07129             myrpt->calldigittimer = 1;
07130          }
07131       }
07132       /* if can continue, do so */
07133       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
07134       {
07135          /* call has failed, inform user */
07136          myrpt->callmode = 4;
07137       }
07138    }
07139    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
07140    {
07141       myrpt->mydtmf = c;
07142    }
07143    if ((!myrpt->inpadtest) && (c == myrpt->p.funcchar))
07144    {
07145       myrpt->rem_dtmfidx = 0;
07146       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
07147       time(&myrpt->rem_dtmf_time);
07148       rpt_mutex_unlock(&myrpt->lock);
07149       return;
07150    } 
07151    else if (((myrpt->inpadtest) || (c != myrpt->p.endchar)) && (myrpt->rem_dtmfidx >= 0))
07152    {
07153       time(&myrpt->rem_dtmf_time);
07154       if (myrpt->rem_dtmfidx < MAXDTMF)
07155       {
07156          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
07157          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
07158          
07159          rpt_mutex_unlock(&myrpt->lock);
07160          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
07161          switch(mylink->phonemode)
07162          {
07163              case 1:
07164             res = collect_function_digits(myrpt, cmd, 
07165                SOURCE_PHONE, mylink);
07166             break;
07167              case 2:
07168             res = collect_function_digits(myrpt, cmd, 
07169                SOURCE_DPHONE,mylink);
07170             break;
07171              case 4:
07172             res = collect_function_digits(myrpt, cmd, 
07173                SOURCE_ALT,mylink);
07174             break;
07175              default:
07176             res = collect_function_digits(myrpt, cmd, 
07177                SOURCE_LNK, mylink);
07178             break;
07179          }
07180 
07181          rpt_mutex_lock(&myrpt->lock);
07182          
07183          switch(res){
07184 
07185             case DC_INDETERMINATE:
07186                break;
07187             
07188             case DC_DOKEY:
07189                mylink->lastrealrx = 1;
07190                break;
07191             
07192             case DC_REQ_FLUSH:
07193                myrpt->rem_dtmfidx = 0;
07194                myrpt->rem_dtmfbuf[0] = 0;
07195                break;
07196             
07197             
07198             case DC_COMPLETE:
07199             case DC_COMPLETEQUIET:
07200                myrpt->totalexecdcommands++;
07201                myrpt->dailyexecdcommands++;
07202                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
07203                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
07204                myrpt->rem_dtmfbuf[0] = 0;
07205                myrpt->rem_dtmfidx = -1;
07206                myrpt->rem_dtmf_time = 0;
07207                break;
07208             
07209             case DC_ERROR:
07210             default:
07211                myrpt->rem_dtmfbuf[0] = 0;
07212                myrpt->rem_dtmfidx = -1;
07213                myrpt->rem_dtmf_time = 0;
07214                break;
07215          }
07216       }
07217 
07218    }
07219    rpt_mutex_unlock(&myrpt->lock);
07220    return;
07221 }
07222 
07223 /* Doug Hall RBI-1 serial data definitions:
07224  *
07225  * Byte 0: Expansion external outputs 
07226  * Byte 1: 
07227  * Bits 0-3 are BAND as follows:
07228  * Bits 4-5 are POWER bits as follows:
07229  *    00 - Low Power
07230  *    01 - Hi Power
07231  *    02 - Med Power
07232  * Bits 6-7 are always set
07233  * Byte 2:
07234  * Bits 0-3 MHZ in BCD format
07235  * Bits 4-5 are offset as follows:
07236  *    00 - minus
07237  *    01 - plus
07238  *    02 - simplex
07239  *    03 - minus minus (whatever that is)
07240  * Bit 6 is the 0/5 KHZ bit
07241  * Bit 7 is always set
07242  * Byte 3:
07243  * Bits 0-3 are 10 KHZ in BCD format
07244  * Bits 4-7 are 100 KHZ in BCD format
07245  * Byte 4: PL Tone code and encode/decode enable bits
07246  * Bits 0-5 are PL tone code (comspec binary codes)
07247  * Bit 6 is encode enable/disable
07248  * Bit 7 is decode enable/disable
07249  */
07250 
07251 /* take the frequency from the 10 mhz digits (and up) and convert it
07252    to a band number */
07253 
07254 static int rbi_mhztoband(char *str)
07255 {
07256 int   i;
07257 
07258    i = atoi(str) / 10; /* get the 10's of mhz */
07259    switch(i)
07260    {
07261        case 2:
07262       return 10;
07263        case 5:
07264       return 11;
07265        case 14:
07266       return 2;
07267        case 22:
07268       return 3;
07269        case 44:
07270       return 4;
07271        case 124:
07272       return 0;
07273        case 125:
07274       return 1;
07275        case 126:
07276       return 8;
07277        case 127:
07278       return 5;
07279        case 128:
07280       return 6;
07281        case 129:
07282       return 7;
07283        default:
07284       break;
07285    }
07286    return -1;
07287 }
07288 
07289 /* take a PL frequency and turn it into a code */
07290 static int rbi_pltocode(char *str)
07291 {
07292 int i;
07293 char *s;
07294 
07295    s = strchr(str,'.');
07296    i = 0;
07297    if (s) i = atoi(s + 1);
07298    i += atoi(str) * 10;
07299    switch(i)
07300    {
07301        case 670:
07302       return 0;
07303        case 719:
07304       return 1;
07305        case 744:
07306       return 2;
07307        case 770:
07308       return 3;
07309        case 797:
07310       return 4;
07311        case 825:
07312       return 5;
07313        case 854:
07314       return 6;
07315        case 885:
07316       return 7;
07317        case 915:
07318       return 8;
07319        case 948:
07320       return 9;
07321        case 974:
07322       return 10;
07323        case 1000:
07324       return 11;
07325        case 1035:
07326       return 12;
07327        case 1072:
07328       return 13;
07329        case 1109:
07330       return 14;
07331        case 1148:
07332       return 15;
07333        case 1188:
07334       return 16;
07335        case 1230:
07336       return 17;
07337        case 1273:
07338       return 18;
07339        case 1318:
07340       return 19;
07341        case 1365:
07342       return 20;
07343        case 1413:
07344       return 21;
07345        case 1462:
07346       return 22;
07347        case 1514:
07348       return 23;
07349        case 1567:
07350       return 24;
07351        case 1622:
07352       return 25;
07353        case 1679:
07354       return 26;
07355        case 1738:
07356       return 27;
07357        case 1799:
07358       return 28;
07359        case 1862:
07360       return 29;
07361        case 1928:
07362       return 30;
07363        case 2035:
07364       return 31;
07365        case 2107:
07366       return 32;
07367        case 2181:
07368       return 33;
07369        case 2257:
07370       return 34;
07371        case 2336:
07372       return 35;
07373        case 2418:
07374       return 36;
07375        case 2503:
07376       return 37;
07377    }
07378    return -1;
07379 }
07380 
07381 /*
07382 * Shift out a formatted serial bit stream
07383 */
07384 
07385 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
07386     {
07387 #ifdef __i386__
07388     int i,j;
07389     unsigned char od,d;
07390     static volatile long long delayvar;
07391 
07392     for(i = 0 ; i < 5 ; i++){
07393         od = *data++; 
07394         for(j = 0 ; j < 8 ; j++){
07395             d = od & 1;
07396             outb(d,myrpt->p.iobase);
07397        /* >= 15 us */
07398        for(delayvar = 1; delayvar < 15000; delayvar++); 
07399             od >>= 1;
07400             outb(d | 2,myrpt->p.iobase);
07401        /* >= 30 us */
07402        for(delayvar = 1; delayvar < 30000; delayvar++); 
07403             outb(d,myrpt->p.iobase);
07404        /* >= 10 us */
07405        for(delayvar = 1; delayvar < 10000; delayvar++); 
07406             }
07407         }
07408    /* >= 50 us */
07409         for(delayvar = 1; delayvar < 50000; delayvar++); 
07410 #endif
07411     }
07412 
07413 static void rbi_out(struct rpt *myrpt,unsigned char *data)
07414 {
07415 struct dahdi_radio_param r;
07416 
07417    memset(&r,0,sizeof(struct dahdi_radio_param));
07418    r.radpar = DAHDI_RADPAR_REMMODE;
07419    r.data = DAHDI_RADPAR_REM_RBI1;
07420    /* if setparam ioctl fails, its probably not a pciradio card */
07421    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
07422    {
07423       rbi_out_parallel(myrpt,data);
07424       return;
07425    }
07426    r.radpar = DAHDI_RADPAR_REMCOMMAND;
07427    memcpy(&r.data,data,5);
07428    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
07429    {
07430       ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",ast_channel_name(myrpt->dahdirxchannel));
07431       return;
07432    }
07433 }
07434 
07435 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, 
07436    unsigned char *rxbuf, int rxmaxbytes, int asciiflag)
07437 {
07438    int i,j,idx,oldmode,olddata;
07439    struct dahdi_radio_param prm;
07440    char c;
07441 
07442     if(debug) {
07443        ast_log(LOG_NOTICE, "ioport=%s  iofd=0x%x\n",myrpt->p.ioport,myrpt->iofd);
07444       printf("String output was:\n");
07445       for(i = 0; i < txbytes; i++)
07446          printf("%02X ", (unsigned char ) txbuf[i]);
07447       printf("\n");
07448    }
07449 
07450    if (myrpt->iofd >= 0)  /* if to do out a serial port */
07451    {
07452       if (write(myrpt->iofd,txbuf,txbytes) != txbytes)
07453       {
07454          return -1;
07455       }
07456       if ((!rxmaxbytes) || (rxbuf == NULL)) 
07457       {
07458          return(0);
07459       }
07460       memset(rxbuf,0,rxmaxbytes);
07461       for(i = 0; i < rxmaxbytes; i++)
07462       {
07463          j = read(myrpt->iofd,&c,1);
07464          if (j < 1) 
07465          {
07466             return(i);
07467          }
07468          rxbuf[i] = c;
07469          if (asciiflag & 1)
07470          {
07471             rxbuf[i + 1] = 0;
07472             if (c == '\r') break;
07473          }
07474       }              
07475       if(debug) {
07476          printf("String returned was:\n");
07477          for(j = 0; j < i; j++)
07478             printf("%02X ", (unsigned char ) rxbuf[j]);
07479          printf("\n");
07480       }
07481       return(i);
07482    }
07483 
07484    /* if not a DAHDI channel, cant use pciradio stuff */
07485    if (myrpt->rxchannel != myrpt->dahdirxchannel) return -1;   
07486 
07487    prm.radpar = DAHDI_RADPAR_UIOMODE;
07488    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
07489    oldmode = prm.data;
07490    prm.radpar = DAHDI_RADPAR_UIODATA;
07491    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
07492    olddata = prm.data;
07493         prm.radpar = DAHDI_RADPAR_REMMODE;
07494         if (asciiflag & 1)  prm.data = DAHDI_RADPAR_REM_SERIAL_ASCII;
07495         else prm.data = DAHDI_RADPAR_REM_SERIAL;
07496    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07497    if (asciiflag & 2)
07498    {
07499       i = DAHDI_ONHOOK;
07500       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
07501       usleep(100000);
07502    }
07503         prm.radpar = DAHDI_RADPAR_REMCOMMAND;
07504         prm.data = rxmaxbytes;
07505         memcpy(prm.buf,txbuf,txbytes);
07506         prm.index = txbytes;
07507    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07508         if (rxbuf)
07509         {
07510                 *rxbuf = 0;
07511                 memcpy(rxbuf,prm.buf,prm.index);
07512         }
07513    idx = prm.index;
07514         prm.radpar = DAHDI_RADPAR_REMMODE;
07515         prm.data = DAHDI_RADPAR_REM_NONE;
07516    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07517    if (asciiflag & 2)
07518    {
07519       i = DAHDI_OFFHOOK;
07520       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
07521    }
07522    prm.radpar = DAHDI_RADPAR_UIOMODE;
07523    prm.data = oldmode;
07524    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07525    prm.radpar = DAHDI_RADPAR_UIODATA;
07526    prm.data = olddata;
07527    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07528         return(idx);
07529 }
07530 
07531 static int civ_cmd(struct rpt *myrpt,unsigned char *cmd, int cmdlen)
07532 {
07533 unsigned char rxbuf[100];
07534 int   i,rv ;
07535 
07536    rv = serial_remote_io(myrpt,cmd,cmdlen,rxbuf,cmdlen + 6,0);
07537    if (rv == -1) return(-1);
07538    if (rv != (cmdlen + 6)) return(1);
07539    for(i = 0; i < 6; i++)
07540       if (rxbuf[i] != cmd[i]) return(1);
07541    if (rxbuf[cmdlen] != 0xfe) return(1);
07542    if (rxbuf[cmdlen + 1] != 0xfe) return(1);
07543    if (rxbuf[cmdlen + 4] != 0xfb) return(1);
07544    if (rxbuf[cmdlen + 5] != 0xfd) return(1);
07545    return(0);
07546 }
07547 
07548 static int sendkenwood(struct rpt *myrpt,char *txstr, char *rxstr)
07549 {
07550 int   i;
07551 
07552 ast_log(LOG_NOTICE,"Sent to kenwood: %s\n",txstr);
07553    if (debug) printf("Send to kenwood: %s\n",txstr);
07554    i = serial_remote_io(myrpt, (unsigned char *)txstr, strlen(txstr), 
07555       (unsigned char *)rxstr,RAD_SERIAL_BUFLEN - 1,3);
07556    if (i < 0) return -1;
07557    if ((i > 0) && (rxstr[i - 1] == '\r'))
07558       rxstr[i-- - 1] = 0;
07559    if (debug) printf("Got from kenwood: %s\n",rxstr);
07560 ast_log(LOG_NOTICE,"Got from kenwood: %s\n",rxstr);
07561    return(i);
07562 }
07563 
07564 /* take a PL frequency and turn it into a code */
07565 static int kenwood_pltocode(char *str)
07566 {
07567 int i;
07568 char *s;
07569 
07570    s = strchr(str,'.');
07571    i = 0;
07572    if (s) i = atoi(s + 1);
07573    i += atoi(str) * 10;
07574    switch(i)
07575    {
07576        case 670:
07577       return 1;
07578        case 719:
07579       return 3;
07580        case 744:
07581       return 4;
07582        case 770:
07583       return 5;
07584        case 797:
07585       return 6;
07586        case 825:
07587       return 7;
07588        case 854:
07589       return 8;
07590        case 885:
07591       return 9;
07592        case 915:
07593       return 10;
07594        case 948:
07595       return 11;
07596        case 974:
07597       return 12;
07598        case 1000:
07599       return 13;
07600        case 1035:
07601       return 14;
07602        case 1072:
07603       return 15;
07604        case 1109:
07605       return 16;
07606        case 1148:
07607       return 17;
07608        case 1188:
07609       return 18;
07610        case 1230:
07611       return 19;
07612        case 1273:
07613       return 20;
07614        case 1318:
07615       return 21;
07616        case 1365:
07617       return 22;
07618        case 1413:
07619       return 23;
07620        case 1462:
07621       return 24;
07622        case 1514:
07623       return 25;
07624        case 1567:
07625       return 26;
07626        case 1622:
07627       return 27;
07628        case 1679:
07629       return 28;
07630        case 1738:
07631       return 29;
07632        case 1799:
07633       return 30;
07634        case 1862:
07635       return 31;
07636        case 1928:
07637       return 32;
07638        case 2035:
07639       return 33;
07640        case 2107:
07641       return 34;
07642        case 2181:
07643       return 35;
07644        case 2257:
07645       return 36;
07646        case 2336:
07647       return 37;
07648        case 2418:
07649       return 38;
07650        case 2503:
07651       return 39;
07652    }
07653    return -1;
07654 }
07655 
07656 static int sendrxkenwood(struct rpt *myrpt, char *txstr, char *rxstr, 
07657    char *cmpstr)
07658 {
07659 int   i,j;
07660 
07661    for(i = 0;i < KENWOOD_RETRIES;i++)
07662    {
07663       j = sendkenwood(myrpt,txstr,rxstr);
07664       if (j < 0) return(j);
07665       if (j == 0) continue;
07666       if (!strncmp(rxstr,cmpstr,strlen(cmpstr))) return(0);
07667    }
07668    return(-1);
07669 }     
07670 
07671 static int setkenwood(struct rpt *myrpt)
07672 {
07673 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
07674 char mhz[MAXREMSTR],offset[20],band,decimals[MAXREMSTR],band1,band2;
07675 int myrxpl;
07676    
07677 int offsets[] = {0,2,1};
07678 int powers[] = {2,1,0};
07679 
07680    if (sendrxkenwood(myrpt,"VMC 0,0\r",rxstr,"VMC") < 0) return -1;
07681    split_freq(mhz, decimals, myrpt->freq);
07682    if (atoi(mhz) > 400)
07683    {
07684       band = '6';
07685       band1 = '1';
07686       band2 = '5';
07687       strcpy(offset,"005000000");
07688    }
07689    else
07690    {
07691       band = '2';
07692       band1 = '0';
07693       band2 = '2';
07694       strcpy(offset,"000600000");
07695    }
07696    strcpy(freq,"000000");
07697    strncpy(freq,decimals,strlen(decimals));
07698    myrxpl = myrpt->rxplon;
07699    if (IS_XPMR(myrpt)) myrxpl = 0;
07700    sprintf(txstr,"VW %c,%05d%s,0,%d,0,%d,%d,,%02d,,%02d,%s\r",
07701       band,atoi(mhz),freq,offsets[(int)myrpt->offset],
07702       (myrpt->txplon != 0),myrxpl,
07703       kenwood_pltocode(myrpt->txpl),kenwood_pltocode(myrpt->rxpl),
07704       offset);
07705    if (sendrxkenwood(myrpt,txstr,rxstr,"VW") < 0) return -1;
07706    sprintf(txstr,"RBN %c\r",band2);
07707    if (sendrxkenwood(myrpt,txstr,rxstr,"RBN") < 0) return -1;
07708    sprintf(txstr,"PC %c,%d\r",band1,powers[(int)myrpt->powerlevel]);
07709    if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
07710    return 0;
07711 }
07712 
07713 static int set_tm271(struct rpt *myrpt)
07714 {
07715 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
07716 char mhz[MAXREMSTR],decimals[MAXREMSTR];
07717    
07718 int offsets[] = {0,2,1};
07719 int powers[] = {2,1,0};
07720 
07721    split_freq(mhz, decimals, myrpt->freq);
07722    strcpy(freq,"000000");
07723    strncpy(freq,decimals,strlen(decimals));
07724 
07725    sprintf(txstr,"VF %04d%s,4,%d,0,%d,0,0,%d,%d,000,00600000,0,0\r",
07726       atoi(mhz),freq,offsets[(int)myrpt->offset],
07727       (myrpt->txplon != 0),kenwood_pltocode(myrpt->txpl),
07728       kenwood_pltocode(myrpt->rxpl));
07729 
07730    if (sendrxkenwood(myrpt,txstr,rxstr,"VF") < 0) return -1;
07731    if (sendrxkenwood(myrpt,"VM 0\r",rxstr,"VM") < 0) return -1;
07732    sprintf(txstr,"PC %d\r",powers[(int)myrpt->powerlevel]);
07733    if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
07734    return 0;
07735 }
07736 
07737 static int setrbi(struct rpt *myrpt)
07738 {
07739 char tmp[MAXREMSTR] = "",*s;
07740 unsigned char rbicmd[5];
07741 int   band,txoffset = 0,txpower = 0,rxpl;
07742 
07743    /* must be a remote system */
07744    if (!myrpt->remoterig) return(0);
07745    if (!myrpt->remoterig[0]) return(0);
07746    /* must have rbi hardware */
07747    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
07748    if (setrbi_check(myrpt) == -1) return(-1);
07749    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07750    s = strchr(tmp,'.');
07751    /* if no decimal, is invalid */
07752    
07753    if (s == NULL){
07754       if(debug)
07755          printf("@@@@ Frequency needs a decimal\n");
07756       return -1;
07757    }
07758    
07759    *s++ = 0;
07760    if (strlen(tmp) < 2){
07761       if(debug)
07762          printf("@@@@ Bad MHz digits: %s\n", tmp);
07763       return -1;
07764    }
07765     
07766    if (strlen(s) < 3){
07767       if(debug)
07768          printf("@@@@ Bad KHz digits: %s\n", s);
07769       return -1;
07770    }
07771 
07772    if ((s[2] != '0') && (s[2] != '5')){
07773       if(debug)
07774          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
07775       return -1;
07776    }
07777     
07778    band = rbi_mhztoband(tmp);
07779    if (band == -1){
07780       if(debug)
07781          printf("@@@@ Bad Band: %s\n", tmp);
07782       return -1;
07783    }
07784    
07785    rxpl = rbi_pltocode(myrpt->rxpl);
07786    
07787    if (rxpl == -1){
07788       if(debug)
07789          printf("@@@@ Bad TX PL: %s\n", myrpt->rxpl);
07790       return -1;
07791    }
07792 
07793    
07794    switch(myrpt->offset)
07795    {
07796        case REM_MINUS:
07797       txoffset = 0;
07798       break;
07799        case REM_PLUS:
07800       txoffset = 0x10;
07801       break;
07802        case REM_SIMPLEX:
07803       txoffset = 0x20;
07804       break;
07805    }
07806    switch(myrpt->powerlevel)
07807    {
07808        case REM_LOWPWR:
07809       txpower = 0;
07810       break;
07811        case REM_MEDPWR:
07812       txpower = 0x20;
07813       break;
07814        case REM_HIPWR:
07815       txpower = 0x10;
07816       break;
07817    }
07818    rbicmd[0] = 0;
07819    rbicmd[1] = band | txpower | 0xc0;
07820    rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
07821    if (s[2] == '5') rbicmd[2] |= 0x40;
07822    rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
07823    rbicmd[4] = rxpl;
07824    if (myrpt->txplon) rbicmd[4] |= 0x40;
07825    if (myrpt->rxplon) rbicmd[4] |= 0x80;
07826    rbi_out(myrpt,rbicmd);
07827    return 0;
07828 }
07829 
07830 static int setrtx(struct rpt *myrpt)
07831 {
07832 char tmp[MAXREMSTR] = "",*s,rigstr[200],pwr,res = 0;
07833 int   band,txoffset = 0,txpower = 0,rxpl,txpl;
07834 float ofac;
07835 double txfreq;
07836 
07837    /* must be a remote system */
07838    if (!myrpt->remoterig) return(0);
07839    if (!myrpt->remoterig[0]) return(0);
07840    /* must have rtx hardware */
07841    if (!ISRIG_RTX(myrpt->remoterig)) return(0);
07842    /* must be a usbradio interface type */
07843    if (!IS_XPMR(myrpt)) return(0);
07844    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07845    s = strchr(tmp,'.');
07846    /* if no decimal, is invalid */
07847    
07848    if(debug)printf("setrtx() %s %s\n",myrpt->name,myrpt->remoterig);
07849 
07850    if (s == NULL){
07851       if(debug)
07852          printf("@@@@ Frequency needs a decimal\n");
07853       return -1;
07854    }
07855    *s++ = 0;
07856    if (strlen(tmp) < 2){
07857       if(debug)
07858          printf("@@@@ Bad MHz digits: %s\n", tmp);
07859       return -1;
07860    }
07861     
07862    if (strlen(s) < 3){
07863       if(debug)
07864          printf("@@@@ Bad KHz digits: %s\n", s);
07865       return -1;
07866    }
07867 
07868    if ((s[2] != '0') && (s[2] != '5')){
07869       if(debug)
07870          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
07871       return -1;
07872    }
07873     
07874    band = rbi_mhztoband(tmp);
07875    if (band == -1){
07876       if(debug)
07877          printf("@@@@ Bad Band: %s\n", tmp);
07878       return -1;
07879    }
07880    
07881    rxpl = rbi_pltocode(myrpt->rxpl);
07882    
07883    if (rxpl == -1){
07884       if(debug)
07885          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
07886       return -1;
07887    }
07888 
07889    txpl = rbi_pltocode(myrpt->txpl);
07890    
07891    if (txpl == -1){
07892       if(debug)
07893          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
07894       return -1;
07895    }
07896    
07897    switch(myrpt->offset)
07898    {
07899        case REM_MINUS:
07900       txoffset = 0;
07901       break;
07902        case REM_PLUS:
07903       txoffset = 0x10;
07904       break;
07905        case REM_SIMPLEX:
07906       txoffset = 0x20;
07907       break;
07908    }
07909    switch(myrpt->powerlevel)
07910    {
07911        case REM_LOWPWR:
07912       txpower = 0;
07913       break;
07914        case REM_MEDPWR:
07915       txpower = 0x20;
07916       break;
07917        case REM_HIPWR:
07918       txpower = 0x10;
07919       break;
07920    }
07921 
07922    res = setrtx_check(myrpt);
07923    if (res < 0) return res;
07924    ofac = 0.0;
07925    if (myrpt->offset == REM_MINUS) ofac = -1.0;
07926    if (myrpt->offset == REM_PLUS) ofac = 1.0;
07927 
07928    if (!strcmp(myrpt->remoterig,remote_rig_rtx450))
07929       txfreq = atof(myrpt->freq) +  (ofac * 5.0);
07930    else
07931       txfreq = atof(myrpt->freq) +  (ofac * 0.6);
07932 
07933    pwr = 'L';
07934    if (myrpt->powerlevel == REM_HIPWR) pwr = 'H';
07935    if (!res)
07936    {
07937       sprintf(rigstr,"SETFREQ %s %f %s %s %c",myrpt->freq,txfreq,
07938          (myrpt->rxplon) ? myrpt->rxpl : "0.0",
07939          (myrpt->txplon) ? myrpt->txpl : "0.0",pwr);
07940       send_usb_txt(myrpt,rigstr);
07941       rpt_telemetry(myrpt,COMPLETE,NULL);
07942       res = 0;
07943    }
07944    return 0;
07945 }
07946 #if 0
07947 /*
07948    sets current signaling code for xpmr routines
07949    under development for new radios.
07950 */
07951 static int setxpmr(struct rpt *myrpt)
07952 {
07953    char rigstr[200];
07954    int rxpl,txpl;
07955 
07956    /* must be a remote system */
07957    if (!myrpt->remoterig) return(0);
07958    if (!myrpt->remoterig[0]) return(0);
07959    /* must not have rtx hardware */
07960    if (ISRIG_RTX(myrpt->remoterig)) return(0);
07961    /* must be a usbradio interface type */
07962    if (!IS_XPMR(myrpt)) return(0);
07963    
07964    if(debug)printf("setxpmr() %s %s\n",myrpt->name,myrpt->remoterig );
07965 
07966    rxpl = rbi_pltocode(myrpt->rxpl);
07967    
07968    if (rxpl == -1){
07969       if(debug)
07970          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
07971       return -1;
07972    }
07973 
07974    txpl = rbi_pltocode(myrpt->txpl);
07975    if (txpl == -1){
07976       if(debug)
07977          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
07978       return -1;
07979    }
07980    sprintf(rigstr,"SETFREQ 0.0 0.0 %s %s L",
07981       (myrpt->rxplon) ? myrpt->rxpl : "0.0",
07982       (myrpt->txplon) ? myrpt->txpl : "0.0");
07983    send_usb_txt(myrpt,rigstr);
07984    return 0;
07985 }
07986 #endif
07987 
07988 static int setrbi_check(struct rpt *myrpt)
07989 {
07990 char tmp[MAXREMSTR] = "",*s;
07991 int   band,txpl;
07992 
07993    /* must be a remote system */
07994    if (!myrpt->remote) return(0);
07995    /* must have rbi hardware */
07996    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
07997    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07998    s = strchr(tmp,'.');
07999    /* if no decimal, is invalid */
08000    
08001    if (s == NULL){
08002       if(debug)
08003          printf("@@@@ Frequency needs a decimal\n");
08004       return -1;
08005    }
08006    
08007    *s++ = 0;
08008    if (strlen(tmp) < 2){
08009       if(debug)
08010          printf("@@@@ Bad MHz digits: %s\n", tmp);
08011       return -1;
08012    }
08013     
08014    if (strlen(s) < 3){
08015       if(debug)
08016          printf("@@@@ Bad KHz digits: %s\n", s);
08017       return -1;
08018    }
08019 
08020    if ((s[2] != '0') && (s[2] != '5')){
08021       if(debug)
08022          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
08023       return -1;
08024    }
08025     
08026    band = rbi_mhztoband(tmp);
08027    if (band == -1){
08028       if(debug)
08029          printf("@@@@ Bad Band: %s\n", tmp);
08030       return -1;
08031    }
08032    
08033    txpl = rbi_pltocode(myrpt->txpl);
08034    
08035    if (txpl == -1){
08036       if(debug)
08037          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
08038       return -1;
08039    }
08040    return 0;
08041 }
08042 
08043 static int setrtx_check(struct rpt *myrpt)
08044 {
08045 char tmp[MAXREMSTR] = "",*s;
08046 int   band,txpl,rxpl;
08047 
08048    /* must be a remote system */
08049    if (!myrpt->remote) return(0);
08050    /* must have rbi hardware */
08051    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
08052    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
08053    s = strchr(tmp,'.');
08054    /* if no decimal, is invalid */
08055    
08056    if (s == NULL){
08057       if(debug)
08058          printf("@@@@ Frequency needs a decimal\n");
08059       return -1;
08060    }
08061    
08062    *s++ = 0;
08063    if (strlen(tmp) < 2){
08064       if(debug)
08065          printf("@@@@ Bad MHz digits: %s\n", tmp);
08066       return -1;
08067    }
08068     
08069    if (strlen(s) < 3){
08070       if(debug)
08071          printf("@@@@ Bad KHz digits: %s\n", s);
08072       return -1;
08073    }
08074 
08075    if ((s[2] != '0') && (s[2] != '5')){
08076       if(debug)
08077          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
08078       return -1;
08079    }
08080     
08081    band = rbi_mhztoband(tmp);
08082    if (band == -1){
08083       if(debug)
08084          printf("@@@@ Bad Band: %s\n", tmp);
08085       return -1;
08086    }
08087    
08088    txpl = rbi_pltocode(myrpt->txpl);
08089    
08090    if (txpl == -1){
08091       if(debug)
08092          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
08093       return -1;
08094    }
08095 
08096    rxpl = rbi_pltocode(myrpt->rxpl);
08097    
08098    if (rxpl == -1){
08099       if(debug)
08100          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
08101       return -1;
08102    }
08103    return 0;
08104 }
08105 
08106 static int check_freq_kenwood(int m, int d, int *defmode)
08107 {
08108    int dflmd = REM_MODE_FM;
08109 
08110    if (m == 144){ /* 2 meters */
08111       if(d < 10100)
08112          return -1;
08113    }
08114    else if((m >= 145) && (m < 148)){
08115       ;
08116    }
08117    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08118       ;
08119    }
08120    else
08121       return -1;
08122    
08123    if(defmode)
08124       *defmode = dflmd; 
08125 
08126 
08127    return 0;
08128 }
08129 
08130 
08131 static int check_freq_tm271(int m, int d, int *defmode)
08132 {
08133    int dflmd = REM_MODE_FM;
08134 
08135    if (m == 144){ /* 2 meters */
08136       if(d < 10100)
08137          return -1;
08138    }
08139    else if((m >= 145) && (m < 148)){
08140       ;
08141    }
08142       return -1;
08143    
08144    if(defmode)
08145       *defmode = dflmd; 
08146 
08147 
08148    return 0;
08149 }
08150 
08151 
08152 /* Check for valid rbi frequency */
08153 /* Hard coded limits now, configurable later, maybe? */
08154 
08155 static int check_freq_rbi(int m, int d, int *defmode)
08156 {
08157    int dflmd = REM_MODE_FM;
08158 
08159    if(m == 50){ /* 6 meters */
08160       if(d < 10100)
08161          return -1;
08162    }
08163    else if((m >= 51) && ( m < 54)){
08164                 ;
08165    }
08166    else if(m == 144){ /* 2 meters */
08167       if(d < 10100)
08168          return -1;
08169    }
08170    else if((m >= 145) && (m < 148)){
08171       ;
08172    }
08173    else if((m >= 222) && (m < 225)){ /* 1.25 meters */
08174       ;
08175    }
08176    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08177       ;
08178    }
08179    else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
08180       ;
08181    }
08182    else
08183       return -1;
08184    
08185    if(defmode)
08186       *defmode = dflmd; 
08187 
08188 
08189    return 0;
08190 }
08191 
08192 /* Check for valid rtx frequency */
08193 /* Hard coded limits now, configurable later, maybe? */
08194 
08195 static int check_freq_rtx(int m, int d, int *defmode, struct rpt *myrpt)
08196 {
08197    int dflmd = REM_MODE_FM;
08198 
08199    if (!strcmp(myrpt->remoterig,remote_rig_rtx150))
08200    {
08201 
08202       if(m == 144){ /* 2 meters */
08203          if(d < 10100)
08204             return -1;
08205       }
08206       else if((m >= 145) && (m < 148)){
08207          ;
08208       }
08209       else
08210          return -1;
08211    }
08212    else 
08213    {
08214       if((m >= 430) && (m < 450)){ /* 70 centimeters */
08215          ;
08216       }
08217       else
08218          return -1;
08219    }
08220    if(defmode)
08221       *defmode = dflmd; 
08222 
08223 
08224    return 0;
08225 }
08226 
08227 /*
08228  * Convert decimals of frequency to int
08229  */
08230 
08231 static int decimals2int(char *fraction)
08232 {
08233    int i;
08234    char len = strlen(fraction);
08235    int multiplier = 100000;
08236    int res = 0;
08237 
08238    if(!len)
08239       return 0;
08240    for( i = 0 ; i < len ; i++, multiplier /= 10)
08241       res += (fraction[i] - '0') * multiplier;
08242    return res;
08243 }
08244 
08245 
08246 /*
08247 * Split frequency into mhz and decimals
08248 */
08249  
08250 static int split_freq(char *mhz, char *decimals, 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(mhz, freq_copy, MAXREMSTR);
08259       strcpy(decimals, "00000");
08260       strncpy(decimals, decp, strlen(decp));
08261       decimals[5] = 0;
08262       return 0;
08263    }
08264    else
08265       return -1;
08266 
08267 }
08268    
08269 /*
08270 * Split ctcss frequency into hertz and decimal
08271 */
08272  
08273 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
08274 {
08275    char freq_copy[MAXREMSTR];
08276    char *decp;
08277 
08278    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
08279    if(decp){
08280       *decp++ = 0;
08281       strncpy(hertz, freq_copy, MAXREMSTR);
08282       strncpy(decimal, decp, strlen(decp));
08283       decimal[strlen(decp)] = '\0';
08284       return 0;
08285    }
08286    else
08287       return -1;
08288 }
08289 
08290 
08291 
08292 /*
08293 * FT-897 I/O handlers
08294 */
08295 
08296 /* Check to see that the frequency is valid */
08297 /* Hard coded limits now, configurable later, maybe? */
08298 
08299 
08300 static int check_freq_ft897(int m, int d, int *defmode)
08301 {
08302    int dflmd = REM_MODE_FM;
08303 
08304    if(m == 1){ /* 160 meters */
08305       dflmd =  REM_MODE_LSB; 
08306       if(d < 80000)
08307          return -1;
08308    }
08309    else if(m == 3){ /* 80 meters */
08310       dflmd = REM_MODE_LSB;
08311       if(d < 50000)
08312          return -1;
08313    }
08314    else if(m == 7){ /* 40 meters */
08315       dflmd = REM_MODE_LSB;
08316       if(d > 30000)
08317          return -1;
08318    }
08319    else if(m == 14){ /* 20 meters */
08320       dflmd = REM_MODE_USB;
08321       if(d > 35000)
08322          return -1;
08323    }
08324    else if(m == 18){ /* 17 meters */
08325       dflmd = REM_MODE_USB;
08326       if((d < 6800) || (d > 16800))
08327          return -1;
08328    }
08329    else if(m == 21){ /* 15 meters */
08330       dflmd = REM_MODE_USB;
08331       if((d < 20000) || (d > 45000))
08332          return -1;
08333    }
08334    else if(m == 24){ /* 12 meters */
08335       dflmd = REM_MODE_USB;
08336       if((d < 89000) || (d > 99000))
08337          return -1;
08338    }
08339    else if(m == 28){ /* 10 meters */
08340       dflmd = REM_MODE_USB;
08341    }
08342    else if(m == 29){ 
08343       if(d >= 51000)
08344          dflmd = REM_MODE_FM;
08345       else
08346          dflmd = REM_MODE_USB;
08347       if(d > 70000)
08348          return -1;
08349    }
08350    else if(m == 50){ /* 6 meters */
08351       if(d >= 30000)
08352          dflmd = REM_MODE_FM;
08353       else
08354          dflmd = REM_MODE_USB;
08355 
08356    }
08357    else if((m >= 51) && ( m < 54)){
08358       dflmd = REM_MODE_FM;
08359    }
08360    else if(m == 144){ /* 2 meters */
08361       if(d >= 30000)
08362          dflmd = REM_MODE_FM;
08363       else
08364          dflmd = REM_MODE_USB;
08365    }
08366    else if((m >= 145) && (m < 148)){
08367       dflmd = REM_MODE_FM;
08368    }
08369    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08370       if(m  < 438)
08371          dflmd = REM_MODE_USB;
08372       else
08373          dflmd = REM_MODE_FM;
08374       ;
08375    }
08376    else
08377       return -1;
08378 
08379    if(defmode)
08380       *defmode = dflmd;
08381 
08382    return 0;
08383 }
08384 
08385 /*
08386 * Set a new frequency for the FT897
08387 */
08388 
08389 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
08390 {
08391    unsigned char cmdstr[5];
08392    int fd,m,d;
08393    char mhz[MAXREMSTR];
08394    char decimals[MAXREMSTR];
08395 
08396    fd = 0;
08397    if(debug) 
08398       printf("New frequency: %s\n",newfreq);
08399 
08400    if(split_freq(mhz, decimals, newfreq))
08401       return -1; 
08402 
08403    m = atoi(mhz);
08404    d = atoi(decimals);
08405 
08406    /* The FT-897 likes packed BCD frequencies */
08407 
08408    cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10);        /* 100MHz 10Mhz */
08409    cmdstr[1] = ((m % 10) << 4) + (d / 10000);         /* 1MHz 100KHz */
08410    cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100);  /* 10KHz 1KHz */
08411    cmdstr[3] = (((d % 100)/10) << 4) + (d % 10);         /* 100Hz 10Hz */
08412    cmdstr[4] = 0x01;                /* command */
08413 
08414    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08415 
08416 }
08417 
08418 /* ft-897 simple commands */
08419 
08420 static int simple_command_ft897(struct rpt *myrpt, char command)
08421 {
08422    unsigned char cmdstr[5];
08423    
08424    memset(cmdstr, 0, 5);
08425 
08426    cmdstr[4] = command; 
08427 
08428    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08429 
08430 }
08431 
08432 /* ft-897 offset */
08433 
08434 static int set_offset_ft897(struct rpt *myrpt, char offset)
08435 {
08436    unsigned char cmdstr[5];
08437    
08438    memset(cmdstr, 0, 5);
08439 
08440    switch(offset){
08441       case  REM_SIMPLEX:
08442          cmdstr[0] = 0x89;
08443          break;
08444 
08445       case  REM_MINUS:
08446          cmdstr[0] = 0x09;
08447          break;
08448       
08449       case  REM_PLUS:
08450          cmdstr[0] = 0x49;
08451          break;   
08452 
08453       default:
08454          return -1;
08455    }
08456 
08457    cmdstr[4] = 0x09; 
08458 
08459    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08460 }
08461 
08462 /* ft-897 mode */
08463 
08464 static int set_mode_ft897(struct rpt *myrpt, char newmode)
08465 {
08466    unsigned char cmdstr[5];
08467    
08468    memset(cmdstr, 0, 5);
08469    
08470    switch(newmode){
08471       case  REM_MODE_FM:
08472          cmdstr[0] = 0x08;
08473          break;
08474 
08475       case  REM_MODE_USB:
08476          cmdstr[0] = 0x01;
08477          break;
08478 
08479       case  REM_MODE_LSB:
08480          cmdstr[0] = 0x00;
08481          break;
08482 
08483       case  REM_MODE_AM:
08484          cmdstr[0] = 0x04;
08485          break;
08486       
08487       default:
08488          return -1;
08489    }
08490    cmdstr[4] = 0x07; 
08491 
08492    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08493 }
08494 
08495 /* Set tone encode and decode modes */
08496 
08497 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
08498 {
08499    unsigned char cmdstr[5];
08500    
08501    memset(cmdstr, 0, 5);
08502    
08503    if(rxplon && txplon)
08504       cmdstr[0] = 0x2A; /* Encode and Decode */
08505    else if (!rxplon && txplon)
08506       cmdstr[0] = 0x4A; /* Encode only */
08507    else if (rxplon && !txplon)
08508       cmdstr[0] = 0x3A; /* Encode only */
08509    else
08510       cmdstr[0] = 0x8A; /* OFF */
08511 
08512    cmdstr[4] = 0x0A; 
08513 
08514    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08515 }
08516 
08517 
08518 /* Set transmit and receive ctcss tone frequencies */
08519 
08520 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
08521 {
08522    unsigned char cmdstr[5];
08523    char hertz[MAXREMSTR],decimal[MAXREMSTR];
08524    int h,d; 
08525 
08526    memset(cmdstr, 0, 5);
08527 
08528    if(split_ctcss_freq(hertz, decimal, txtone))
08529       return -1; 
08530 
08531    h = atoi(hertz);
08532    d = atoi(decimal);
08533    
08534    cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
08535    cmdstr[1] = ((h % 10) << 4) + (d % 10);
08536    
08537    if(rxtone){
08538    
08539       if(split_ctcss_freq(hertz, decimal, rxtone))
08540          return -1; 
08541 
08542       h = atoi(hertz);
08543       d = atoi(decimal);
08544    
08545       cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
08546       cmdstr[3] = ((h % 10) << 4) + (d % 10);
08547    }
08548    cmdstr[4] = 0x0B; 
08549 
08550    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08551 }  
08552 
08553 
08554 
08555 static int set_ft897(struct rpt *myrpt)
08556 {
08557    int res;
08558    
08559    if(debug)
08560       printf("@@@@ lock on\n");
08561 
08562    res = simple_command_ft897(myrpt, 0x00);  /* LOCK on */  
08563 
08564    if(debug)
08565       printf("@@@@ ptt off\n");
08566 
08567    if(!res)
08568       res = simple_command_ft897(myrpt, 0x88);     /* PTT off */
08569 
08570    if(debug)
08571       printf("Modulation mode\n");
08572 
08573    if(!res)
08574       res = set_mode_ft897(myrpt, myrpt->remmode);    /* Modulation mode */
08575 
08576    if(debug)
08577       printf("Split off\n");
08578 
08579    if(!res)
08580       simple_command_ft897(myrpt, 0x82);        /* Split off */
08581 
08582    if(debug)
08583       printf("Frequency\n");
08584 
08585    if(!res)
08586       res = set_freq_ft897(myrpt, myrpt->freq);    /* Frequency */
08587    if((myrpt->remmode == REM_MODE_FM)){
08588       if(debug)
08589          printf("Offset\n");
08590       if(!res)
08591          res = set_offset_ft897(myrpt, myrpt->offset);   /* Offset if FM */
08592       if((!res)&&(myrpt->rxplon || myrpt->txplon)){
08593          if(debug)
08594             printf("CTCSS tone freqs.\n");
08595          res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
08596       }
08597       if(!res){
08598          if(debug)
08599             printf("CTCSS mode\n");
08600          res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
08601       }
08602    }
08603    if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
08604       if(debug)
08605          printf("Clarifier off\n");
08606       simple_command_ft897(myrpt, 0x85);        /* Clarifier off if LSB or USB */
08607    }
08608    return res;
08609 }
08610 
08611 static int closerem_ft897(struct rpt *myrpt)
08612 {
08613    simple_command_ft897(myrpt, 0x88); /* PTT off */
08614    return 0;
08615 }  
08616 
08617 /*
08618 * Bump frequency up or down by a small amount 
08619 * Return 0 if the new frequnecy is valid, or -1 if invalid
08620 * Interval is in Hz, resolution is 10Hz 
08621 */
08622 
08623 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
08624 {
08625    int m,d;
08626    char mhz[MAXREMSTR], decimals[MAXREMSTR];
08627 
08628    if(debug)
08629       printf("Before bump: %s\n", myrpt->freq);
08630 
08631    if(split_freq(mhz, decimals, myrpt->freq))
08632       return -1;
08633    
08634    m = atoi(mhz);
08635    d = atoi(decimals);
08636 
08637    d += (interval / 10); /* 10Hz resolution */
08638    if(d < 0){
08639       m--;
08640       d += 100000;
08641    }
08642    else if(d >= 100000){
08643       m++;
08644       d -= 100000;
08645    }
08646 
08647    if(check_freq_ft897(m, d, NULL)){
08648       if(debug)
08649          printf("Bump freq invalid\n");
08650       return -1;
08651    }
08652 
08653    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
08654 
08655    if(debug)
08656       printf("After bump: %s\n", myrpt->freq);
08657 
08658    return set_freq_ft897(myrpt, myrpt->freq);   
08659 }
08660 
08661 
08662 
08663 /*
08664 * IC-706 I/O handlers
08665 */
08666 
08667 /* Check to see that the frequency is valid */
08668 /* returns 0 if frequency is valid          */
08669 
08670 static int check_freq_ic706(int m, int d, int *defmode, char mars)
08671 {
08672    int dflmd = REM_MODE_FM;
08673    int rv=0;
08674 
08675    if(debug > 6)
08676       ast_log(LOG_NOTICE,"(%i,%i,%i,%i)\n",m,d,*defmode,mars);
08677 
08678    /* first test for standard amateur radio bands */
08679 
08680    if(m == 1){                /* 160 meters */
08681       dflmd =  REM_MODE_LSB; 
08682       if(d < 80000)rv=-1;
08683    }
08684    else if(m == 3){           /* 80 meters */
08685       dflmd = REM_MODE_LSB;
08686       if(d < 50000)rv=-1;
08687    }
08688    else if(m == 7){           /* 40 meters */
08689       dflmd = REM_MODE_LSB;
08690       if(d > 30000)rv=-1;
08691    }
08692    else if(m == 14){             /* 20 meters */
08693       dflmd = REM_MODE_USB;
08694       if(d > 35000)rv=-1;
08695    }
08696    else if(m == 18){                      /* 17 meters */
08697       dflmd = REM_MODE_USB;
08698       if((d < 6800) || (d > 16800))rv=-1;
08699    }
08700    else if(m == 21){ /* 15 meters */
08701       dflmd = REM_MODE_USB;
08702       if((d < 20000) || (d > 45000))rv=-1;
08703    }
08704    else if(m == 24){ /* 12 meters */
08705       dflmd = REM_MODE_USB;
08706       if((d < 89000) || (d > 99000))rv=-1;
08707    }
08708    else if(m == 28){                      /* 10 meters */
08709       dflmd = REM_MODE_USB;
08710    }
08711    else if(m == 29){ 
08712       if(d >= 51000)
08713          dflmd = REM_MODE_FM;
08714       else
08715          dflmd = REM_MODE_USB;
08716       if(d > 70000)rv=-1;
08717    }
08718    else if(m == 50){                      /* 6 meters */
08719       if(d >= 30000)
08720          dflmd = REM_MODE_FM;
08721       else
08722          dflmd = REM_MODE_USB;
08723    }
08724    else if((m >= 51) && ( m < 54)){
08725       dflmd = REM_MODE_FM;
08726    }
08727    else if(m == 144){ /* 2 meters */
08728       if(d >= 30000)
08729          dflmd = REM_MODE_FM;
08730       else
08731          dflmd = REM_MODE_USB;
08732    }
08733    else if((m >= 145) && (m < 148)){
08734       dflmd = REM_MODE_FM;
08735    }
08736    else if((m >= 430) && (m < 450)){         /* 70 centimeters */
08737       if(m  < 438)
08738          dflmd = REM_MODE_USB;
08739       else
08740          dflmd = REM_MODE_FM;
08741    }
08742 
08743    /* check expanded coverage */
08744    if(mars && rv<0){
08745       if((m >= 450) && (m < 470)){        /* LMR */
08746          dflmd = REM_MODE_FM;
08747          rv=0;
08748       }
08749       else if((m >= 148) && (m < 174)){      /* LMR */
08750          dflmd = REM_MODE_FM;
08751          rv=0;
08752       }
08753       else if((m >= 138) && (m < 144)){      /* VHF-AM AIRCRAFT */
08754          dflmd = REM_MODE_AM;
08755          rv=0;
08756       }
08757       else if((m >= 108) && (m < 138)){      /* VHF-AM AIRCRAFT */
08758          dflmd = REM_MODE_AM;
08759          rv=0;
08760       }
08761       else if( (m==0 && d>=55000) || (m==1 && d<=75000) ){  /* AM BCB*/
08762          dflmd = REM_MODE_AM;
08763          rv=0;
08764       }
08765       else if( (m == 1 && d>75000) || (m>1 && m<30) ){      /* HF SWL*/
08766          dflmd = REM_MODE_AM;
08767          rv=0;
08768       }
08769    }
08770 
08771    if(defmode)
08772       *defmode = dflmd;
08773 
08774    if(debug > 1)
08775       ast_log(LOG_NOTICE,"(%i,%i,%i,%i) returning %i\n",m,d,*defmode,mars,rv);
08776 
08777    return rv;
08778 }
08779 
08780 /* take a PL frequency and turn it into a code */
08781 static int ic706_pltocode(char *str)
08782 {
08783    int i;
08784    char *s;
08785    int rv=-1;
08786 
08787    s = strchr(str,'.');
08788    i = 0;
08789    if (s) i = atoi(s + 1);
08790    i += atoi(str) * 10;
08791    switch(i)
08792    {
08793        case 670:
08794          rv=0;
08795        case 693:
08796          rv=1;
08797        case 719:
08798          rv=2;
08799        case 744:
08800          rv=3;
08801        case 770:
08802          rv=4;
08803        case 797:
08804          rv=5;
08805        case 825:
08806          rv=6;
08807        case 854:
08808          rv=7;
08809        case 885:
08810          rv=8;
08811        case 915:
08812          rv=9;
08813        case 948:
08814          rv=10;
08815        case 974:
08816          rv=11;
08817        case 1000:
08818          rv=12;
08819        case 1035:
08820          rv=13;
08821        case 1072:
08822          rv=14;
08823        case 1109:
08824          rv=15;
08825        case 1148:
08826          rv=16;
08827        case 1188:
08828          rv=17;
08829        case 1230:
08830          rv=18;
08831        case 1273:
08832          rv=19;
08833        case 1318:
08834          rv=20;
08835        case 1365:
08836          rv=21;
08837        case 1413:
08838          rv=22;
08839        case 1462:
08840          rv=23;
08841        case 1514:
08842          rv=24;
08843        case 1567:
08844          rv=25;
08845        case 1598:
08846          rv=26;
08847        case 1622:
08848          rv=27;
08849        case 1655:
08850          rv=28;      
08851        case 1679:
08852          rv=29;
08853        case 1713:
08854          rv=30;
08855        case 1738:
08856          rv=31;
08857        case 1773:
08858          rv=32;
08859        case 1799:
08860          rv=33;
08861         case 1835:
08862          rv=34;
08863        case 1862:
08864          rv=35;
08865        case 1899:
08866          rv=36;
08867        case 1928:
08868          rv=37;
08869        case 1966:
08870          rv=38;
08871        case 1995:
08872          rv=39;
08873        case 2035:
08874          rv=40;
08875        case 2065:
08876          rv=41;
08877        case 2107:
08878          rv=42;
08879        case 2181:
08880          rv=43;
08881        case 2257:
08882          rv=44;
08883        case 2291:
08884          rv=45;
08885        case 2336:
08886          rv=46;
08887        case 2418:
08888          rv=47;
08889        case 2503:
08890          rv=48;
08891        case 2541:
08892          rv=49;
08893    }
08894    if(debug > 1)
08895       ast_log(LOG_NOTICE,"%i  rv=%i\n",i, rv);
08896 
08897    return rv;
08898 }
08899 
08900 /* ic-706 simple commands */
08901 
08902 static int simple_command_ic706(struct rpt *myrpt, char command, char subcommand)
08903 {
08904    unsigned char cmdstr[10];
08905    
08906    cmdstr[0] = cmdstr[1] = 0xfe;
08907    cmdstr[2] = myrpt->p.civaddr;
08908    cmdstr[3] = 0xe0;
08909    cmdstr[4] = command;
08910    cmdstr[5] = subcommand;
08911    cmdstr[6] = 0xfd;
08912 
08913    return(civ_cmd(myrpt,cmdstr,7));
08914 }
08915 
08916 /*
08917 * Set a new frequency for the ic706
08918 */
08919 
08920 static int set_freq_ic706(struct rpt *myrpt, char *newfreq)
08921 {
08922    unsigned char cmdstr[20];
08923    char mhz[MAXREMSTR], decimals[MAXREMSTR];
08924    int fd,m,d;
08925 
08926    fd = 0;
08927    if(debug) 
08928       ast_log(LOG_NOTICE,"newfreq:%s\n",newfreq);        
08929 
08930    if(split_freq(mhz, decimals, newfreq))
08931       return -1; 
08932 
08933    m = atoi(mhz);
08934    d = atoi(decimals);
08935 
08936    /* The ic-706 likes packed BCD frequencies */
08937 
08938    cmdstr[0] = cmdstr[1] = 0xfe;
08939    cmdstr[2] = myrpt->p.civaddr;
08940    cmdstr[3] = 0xe0;
08941    cmdstr[4] = 5;
08942    cmdstr[5] = ((d % 10) << 4);
08943    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
08944    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
08945    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
08946    cmdstr[9] = (m / 100);
08947    cmdstr[10] = 0xfd;
08948 
08949    return(civ_cmd(myrpt,cmdstr,11));
08950 }
08951 
08952 /* ic-706 offset */
08953 
08954 static int set_offset_ic706(struct rpt *myrpt, char offset)
08955 {
08956    unsigned char c;
08957 
08958    if(debug > 6)
08959       ast_log(LOG_NOTICE,"offset=%i\n",offset);
08960 
08961    switch(offset){
08962       case  REM_SIMPLEX:
08963          c = 0x10;
08964          break;
08965 
08966       case  REM_MINUS:
08967          c = 0x11;
08968          break;
08969       
08970       case  REM_PLUS:
08971          c = 0x12;
08972          break;   
08973 
08974       default:
08975          return -1;
08976    }
08977 
08978    return simple_command_ic706(myrpt,0x0f,c);
08979 
08980 }
08981 
08982 /* ic-706 mode */
08983 
08984 static int set_mode_ic706(struct rpt *myrpt, char newmode)
08985 {
08986    unsigned char c;
08987    
08988    if(debug > 6)
08989       ast_log(LOG_NOTICE,"newmode=%i\n",newmode);
08990 
08991    switch(newmode){
08992       case  REM_MODE_FM:
08993          c = 5;
08994          break;
08995 
08996       case  REM_MODE_USB:
08997          c = 1;
08998          break;
08999 
09000       case  REM_MODE_LSB:
09001          c = 0;
09002          break;
09003 
09004       case  REM_MODE_AM:
09005          c = 2;
09006          break;
09007       
09008       default:
09009          return -1;
09010    }
09011    return simple_command_ic706(myrpt,6,c);
09012 }
09013 
09014 /* Set tone encode and decode modes */
09015 
09016 static int set_ctcss_mode_ic706(struct rpt *myrpt, char txplon, char rxplon)
09017 {
09018    unsigned char cmdstr[10];
09019    int rv;
09020 
09021    if(debug > 6)
09022       ast_log(LOG_NOTICE,"txplon=%i  rxplon=%i \n",txplon,rxplon);
09023 
09024    cmdstr[0] = cmdstr[1] = 0xfe;
09025    cmdstr[2] = myrpt->p.civaddr;
09026    cmdstr[3] = 0xe0;
09027    cmdstr[4] = 0x16;
09028    cmdstr[5] = 0x42;
09029    cmdstr[6] = (txplon != 0);
09030    cmdstr[7] = 0xfd;
09031 
09032    rv = civ_cmd(myrpt,cmdstr,8);
09033    if (rv) return(-1);
09034 
09035    cmdstr[0] = cmdstr[1] = 0xfe;
09036    cmdstr[2] = myrpt->p.civaddr;
09037    cmdstr[3] = 0xe0;
09038    cmdstr[4] = 0x16;
09039    cmdstr[5] = 0x43;
09040    cmdstr[6] = (rxplon != 0);
09041    cmdstr[7] = 0xfd;
09042 
09043    return(civ_cmd(myrpt,cmdstr,8));
09044 }
09045 
09046 #if 0
09047 /* Set transmit and receive ctcss tone frequencies */
09048 
09049 static int set_ctcss_freq_ic706(struct rpt *myrpt, char *txtone, char *rxtone)
09050 {
09051    unsigned char cmdstr[10];
09052    char hertz[MAXREMSTR],decimal[MAXREMSTR];
09053    int h,d,rv;
09054 
09055    memset(cmdstr, 0, 5);
09056 
09057    if(debug > 6)
09058       ast_log(LOG_NOTICE,"txtone=%s  rxtone=%s \n",txtone,rxtone);
09059 
09060    if(split_ctcss_freq(hertz, decimal, txtone))
09061       return -1; 
09062 
09063    h = atoi(hertz);
09064    d = atoi(decimal);
09065    
09066    cmdstr[0] = cmdstr[1] = 0xfe;
09067    cmdstr[2] = myrpt->p.civaddr;
09068    cmdstr[3] = 0xe0;
09069    cmdstr[4] = 0x1b;
09070    cmdstr[5] = 0;
09071    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
09072    cmdstr[7] = ((h % 10) << 4) + (d % 10);
09073    cmdstr[8] = 0xfd;
09074 
09075    rv = civ_cmd(myrpt,cmdstr,9);
09076    if (rv) return(-1);
09077 
09078    if (!rxtone) return(0);
09079 
09080    if(split_ctcss_freq(hertz, decimal, rxtone))
09081       return -1; 
09082 
09083    h = atoi(hertz);
09084    d = atoi(decimal);
09085 
09086    cmdstr[0] = cmdstr[1] = 0xfe;
09087    cmdstr[2] = myrpt->p.civaddr;
09088    cmdstr[3] = 0xe0;
09089    cmdstr[4] = 0x1b;
09090    cmdstr[5] = 1;
09091    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
09092    cmdstr[7] = ((h % 10) << 4) + (d % 10);
09093    cmdstr[8] = 0xfd;
09094    return(civ_cmd(myrpt,cmdstr,9));
09095 }  
09096 #endif
09097 
09098 static int vfo_ic706(struct rpt *myrpt)
09099 {
09100    unsigned char cmdstr[10];
09101    
09102    cmdstr[0] = cmdstr[1] = 0xfe;
09103    cmdstr[2] = myrpt->p.civaddr;
09104    cmdstr[3] = 0xe0;
09105    cmdstr[4] = 7;
09106    cmdstr[5] = 0xfd;
09107 
09108    return(civ_cmd(myrpt,cmdstr,6));
09109 }
09110 
09111 static int mem2vfo_ic706(struct rpt *myrpt)
09112 {
09113    unsigned char cmdstr[10];
09114    
09115    cmdstr[0] = cmdstr[1] = 0xfe;
09116    cmdstr[2] = myrpt->p.civaddr;
09117    cmdstr[3] = 0xe0;
09118    cmdstr[4] = 0x0a;
09119    cmdstr[5] = 0xfd;
09120 
09121    return(civ_cmd(myrpt,cmdstr,6));
09122 }
09123 
09124 static int select_mem_ic706(struct rpt *myrpt, int slot)
09125 {
09126    unsigned char cmdstr[10];
09127    
09128    cmdstr[0] = cmdstr[1] = 0xfe;
09129    cmdstr[2] = myrpt->p.civaddr;
09130    cmdstr[3] = 0xe0;
09131    cmdstr[4] = 8;
09132    cmdstr[5] = 0;
09133    cmdstr[6] = ((slot / 10) << 4) + (slot % 10);
09134    cmdstr[7] = 0xfd;
09135 
09136    return(civ_cmd(myrpt,cmdstr,8));
09137 }
09138 
09139 static int set_ic706(struct rpt *myrpt)
09140 {
09141    int res = 0,i;
09142    
09143    if(debug)ast_log(LOG_NOTICE, "Set to VFO A iobase=%i\n",myrpt->p.iobase);
09144 
09145    if (!res)
09146       res = simple_command_ic706(myrpt,7,0);
09147 
09148    if((myrpt->remmode == REM_MODE_FM))
09149    {
09150       i = ic706_pltocode(myrpt->rxpl);
09151       if (i == -1) return -1;
09152       if(debug)
09153          printf("Select memory number\n");
09154       if (!res)
09155          res = select_mem_ic706(myrpt,i + IC706_PL_MEMORY_OFFSET);
09156       if(debug)
09157          printf("Transfer memory to VFO\n");
09158       if (!res)
09159          res = mem2vfo_ic706(myrpt);
09160    }
09161       
09162    if(debug)
09163       printf("Set to VFO\n");
09164 
09165    if (!res)
09166       res = vfo_ic706(myrpt);
09167 
09168    if(debug)
09169       printf("Modulation mode\n");
09170 
09171    if (!res)
09172       res = set_mode_ic706(myrpt, myrpt->remmode);    /* Modulation mode */
09173 
09174    if(debug)
09175       printf("Split off\n");
09176 
09177    if(!res)
09178       simple_command_ic706(myrpt, 0x82,0);         /* Split off */
09179 
09180    if(debug)
09181       printf("Frequency\n");
09182 
09183    if(!res)
09184       res = set_freq_ic706(myrpt, myrpt->freq);    /* Frequency */
09185    if((myrpt->remmode == REM_MODE_FM)){
09186       if(debug)
09187          printf("Offset\n");
09188       if(!res)
09189          res = set_offset_ic706(myrpt, myrpt->offset);   /* Offset if FM */
09190       if(!res){
09191          if(debug)
09192             printf("CTCSS mode\n");
09193          res = set_ctcss_mode_ic706(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
09194       }
09195    }
09196    return res;
09197 }
09198 
09199 /*
09200 * Bump frequency up or down by a small amount 
09201 * Return 0 if the new frequnecy is valid, or -1 if invalid
09202 * Interval is in Hz, resolution is 10Hz 
09203 */
09204 
09205 static int multimode_bump_freq_ic706(struct rpt *myrpt, int interval)
09206 {
09207    int m,d;
09208    char mhz[MAXREMSTR], decimals[MAXREMSTR];
09209    unsigned char cmdstr[20];
09210 
09211    if(debug)
09212       printf("Before bump: %s\n", myrpt->freq);
09213 
09214    if(split_freq(mhz, decimals, myrpt->freq))
09215       return -1;
09216    
09217    m = atoi(mhz);
09218    d = atoi(decimals);
09219 
09220    d += (interval / 10); /* 10Hz resolution */
09221    if(d < 0){
09222       m--;
09223       d += 100000;
09224    }
09225    else if(d >= 100000){
09226       m++;
09227       d -= 100000;
09228    }
09229 
09230    if(check_freq_ic706(m, d, NULL,myrpt->p.remote_mars)){
09231       if(debug)
09232          printf("Bump freq invalid\n");
09233       return -1;
09234    }
09235 
09236    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
09237 
09238    if(debug)
09239       printf("After bump: %s\n", myrpt->freq);
09240 
09241    /* The ic-706 likes packed BCD frequencies */
09242 
09243    cmdstr[0] = cmdstr[1] = 0xfe;
09244    cmdstr[2] = myrpt->p.civaddr;
09245    cmdstr[3] = 0xe0;
09246    cmdstr[4] = 0;
09247    cmdstr[5] = ((d % 10) << 4);
09248    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
09249    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
09250    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
09251    cmdstr[9] = (m / 100);
09252    cmdstr[10] = 0xfd;
09253 
09254    return(serial_remote_io(myrpt,cmdstr,11,NULL,0,0));
09255 }
09256 
09257 
09258 
09259 /*
09260 * Dispatch to correct I/O handler 
09261 */
09262 static int setrem(struct rpt *myrpt)
09263 {
09264 char  str[300];
09265 char  *offsets[] = {"SIMPLEX","MINUS","PLUS"};
09266 char  *powerlevels[] = {"LOW","MEDIUM","HIGH"};
09267 char  *modes[] = {"FM","USB","LSB","AM"};
09268 int   res = -1;
09269 
09270 #if   0
09271 printf("FREQ,%s,%s,%s,%s,%s,%s,%d,%d\n",myrpt->freq,
09272    modes[(int)myrpt->remmode],
09273    myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
09274    powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
09275    myrpt->rxplon);
09276 #endif
09277    if (myrpt->p.archivedir)
09278    {
09279       sprintf(str,"FREQ,%s,%s,%s,%s,%s,%s,%d,%d",myrpt->freq,
09280          modes[(int)myrpt->remmode],
09281          myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
09282          powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
09283          myrpt->rxplon);
09284       donodelog(myrpt,str);
09285    }
09286    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09287    {
09288       rpt_telemetry(myrpt,SETREMOTE,NULL);
09289       res = 0;
09290    }
09291    if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09292    {
09293       rpt_telemetry(myrpt,SETREMOTE,NULL);
09294       res = 0;
09295    }
09296    if(!strcmp(myrpt->remoterig, remote_rig_tm271))
09297    {
09298       rpt_telemetry(myrpt,SETREMOTE,NULL);
09299       res = 0;
09300    }
09301    else if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09302    {
09303       res = setrbi_check(myrpt);
09304       if (!res)
09305       {
09306          rpt_telemetry(myrpt,SETREMOTE,NULL);
09307          res = 0;
09308       }
09309    }
09310    else if(ISRIG_RTX(myrpt->remoterig))
09311    {
09312       setrtx(myrpt);
09313       res = 0;
09314    }
09315    else if(!strcmp(myrpt->remoterig, remote_rig_kenwood)) {
09316       rpt_telemetry(myrpt,SETREMOTE,NULL);
09317       res = 0;
09318    }
09319    else
09320       res = 0;
09321 
09322    if (res < 0) ast_log(LOG_ERROR,"Unable to send remote command on node %s\n",myrpt->name);
09323 
09324    return res;
09325 }
09326 
09327 static int closerem(struct rpt *myrpt)
09328 {
09329    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09330       return closerem_ft897(myrpt);
09331    else
09332       return 0;
09333 }
09334 
09335 /*
09336 * Dispatch to correct RX frequency checker
09337 */
09338 
09339 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
09340 {
09341    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09342       return check_freq_ft897(m, d, defmode);
09343    else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09344       return check_freq_ic706(m, d, defmode,myrpt->p.remote_mars);
09345    else if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09346       return check_freq_rbi(m, d, defmode);
09347    else if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
09348       return check_freq_kenwood(m, d, defmode);
09349    else if(!strcmp(myrpt->remoterig, remote_rig_tm271))
09350       return check_freq_tm271(m, d, defmode);
09351    else if(ISRIG_RTX(myrpt->remoterig))
09352       return check_freq_rtx(m, d, defmode, myrpt);
09353    else
09354       return -1;
09355 }
09356 
09357 /*
09358  * Check TX frequency before transmitting
09359    rv=1 if tx frequency in ok.
09360 */
09361 
09362 static char check_tx_freq(struct rpt *myrpt)
09363 {
09364    int i,rv=0;
09365    int radio_mhz, radio_decimals, ulimit_mhz, ulimit_decimals, llimit_mhz, llimit_decimals;
09366    char radio_mhz_char[MAXREMSTR];
09367    char radio_decimals_char[MAXREMSTR];
09368    char limit_mhz_char[MAXREMSTR];
09369    char limit_decimals_char[MAXREMSTR];
09370    char limits[256];
09371    char *limit_ranges[40];
09372    struct ast_variable *limitlist;
09373    
09374    if(debug > 3){
09375       ast_log(LOG_NOTICE, "myrpt->freq = %s\n", myrpt->freq);
09376    }
09377 
09378    /* Must have user logged in and tx_limits defined */
09379 
09380    if(!myrpt->p.txlimitsstanzaname || !myrpt->loginuser[0] || !myrpt->loginlevel[0]){
09381       if(debug > 3){
09382          ast_log(LOG_NOTICE, "No tx band table defined, or no user logged in. rv=1\n");
09383       }
09384       rv=1;
09385       return 1; /* Assume it's ok otherwise */
09386    }
09387 
09388    /* Retrieve the band table for the loginlevel */
09389    limitlist = ast_variable_browse(myrpt->cfg, myrpt->p.txlimitsstanzaname);
09390 
09391    if(!limitlist){
09392       ast_log(LOG_WARNING, "No entries in %s band table stanza. rv=0\n", myrpt->p.txlimitsstanzaname);
09393       rv=0;
09394       return 0;
09395    }
09396 
09397    split_freq(radio_mhz_char, radio_decimals_char, myrpt->freq);
09398    radio_mhz = atoi(radio_mhz_char);
09399    radio_decimals = decimals2int(radio_decimals_char);
09400 
09401    if(debug > 3){
09402       ast_log(LOG_NOTICE, "Login User = %s, login level = %s\n", myrpt->loginuser, myrpt->loginlevel);
09403    }
09404 
09405    /* Find our entry */
09406 
09407    for(;limitlist; limitlist=limitlist->next){
09408       if(!strcmp(limitlist->name, myrpt->loginlevel))
09409          break;
09410    }
09411 
09412    if(!limitlist){
09413       ast_log(LOG_WARNING, "Can't find %s entry in band table stanza %s. rv=0\n", myrpt->loginlevel, myrpt->p.txlimitsstanzaname);
09414       rv=0;
09415        return 0;
09416    }
09417    
09418    if(debug > 3){
09419       ast_log(LOG_NOTICE, "Auth: %s = %s\n", limitlist->name, limitlist->value);
09420    }
09421 
09422    /* Parse the limits */
09423 
09424    strncpy(limits, limitlist->value, 256);
09425    limits[255] = 0;
09426    finddelim(limits, limit_ranges, 40);
09427    for(i = 0; i < 40 && limit_ranges[i] ; i++){
09428       char range[40];
09429       char *r,*s;
09430       strncpy(range, limit_ranges[i], 40);
09431       range[39] = 0;
09432         if(debug > 3) 
09433          ast_log(LOG_NOTICE, "Check %s within %s\n", myrpt->freq, range);
09434    
09435       r = strchr(range, '-');
09436       if(!r){
09437          ast_log(LOG_WARNING, "Malformed range in %s tx band table entry. rv=0\n", limitlist->name);
09438          rv=0;
09439          break;
09440       }
09441       *r++ = 0;
09442       s = eatwhite(range);
09443       r = eatwhite(r);
09444       split_freq(limit_mhz_char, limit_decimals_char, s);
09445       llimit_mhz = atoi(limit_mhz_char);
09446       llimit_decimals = decimals2int(limit_decimals_char);
09447       split_freq(limit_mhz_char, limit_decimals_char, r);
09448       ulimit_mhz = atoi(limit_mhz_char);
09449       ulimit_decimals = decimals2int(limit_decimals_char);
09450          
09451       if((radio_mhz >= llimit_mhz) && (radio_mhz <= ulimit_mhz)){
09452          if(radio_mhz == llimit_mhz){ /* CASE 1: TX freq is in llimit mhz portion of band */
09453             if(radio_decimals >= llimit_decimals){ /* Cannot be below llimit decimals */
09454                if(llimit_mhz == ulimit_mhz){ /* If bandwidth < 1Mhz, check ulimit decimals */
09455                   if(radio_decimals <= ulimit_decimals){
09456                      rv=1;
09457                      break;
09458                   }
09459                   else{
09460                      if(debug > 3)
09461                         ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 1\n");
09462                      rv=0;
09463                      break;
09464                   }
09465                }
09466                else{
09467                   rv=1;
09468                   break;
09469                }
09470             }
09471             else{ /* Is below llimit decimals */
09472                if(debug > 3)
09473                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 2\n");
09474                rv=0;
09475                break;
09476             }
09477          }
09478          else if(radio_mhz == ulimit_mhz){ /* CASE 2: TX freq not in llimit mhz portion of band */
09479             if(radio_decimals <= ulimit_decimals){
09480                if(debug > 3)
09481                   ast_log(LOG_NOTICE, "radio_decimals <= ulimit_decimals\n");
09482                rv=1;
09483                break;
09484             }
09485             else{ /* Is above ulimit decimals */
09486                if(debug > 3)
09487                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 3\n");
09488                rv=0;
09489                break;
09490             }
09491          }
09492          else /* CASE 3: TX freq within a multi-Mhz band and ok */
09493             if(debug > 3)
09494                   ast_log(LOG_NOTICE, "Valid TX freq within a multi-Mhz band and ok.\n");
09495             rv=1;
09496             break;
09497       }
09498    }
09499    if(debug > 3)  
09500       ast_log(LOG_NOTICE, "rv=%i\n",rv);
09501 
09502    return rv;
09503 }
09504 
09505 
09506 /*
09507 * Dispatch to correct frequency bumping function
09508 */
09509 
09510 static int multimode_bump_freq(struct rpt *myrpt, int interval)
09511 {
09512    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09513       return multimode_bump_freq_ft897(myrpt, interval);
09514    else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09515       return multimode_bump_freq_ic706(myrpt, interval);
09516    else
09517       return -1;
09518 }
09519 
09520 
09521 /*
09522 * Queue announcment that scan has been stopped 
09523 */
09524 
09525 static void stop_scan(struct rpt *myrpt)
09526 {
09527    myrpt->hfscanstop = 1;
09528    rpt_telemetry(myrpt,SCAN,0);
09529 }
09530 
09531 /*
09532 * This is called periodically when in scan mode
09533 */
09534 
09535 
09536 static int service_scan(struct rpt *myrpt)
09537 {
09538    int res, interval;
09539    char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
09540 
09541    switch(myrpt->hfscanmode){
09542 
09543       case HF_SCAN_DOWN_SLOW:
09544          interval = -10; /* 100Hz /sec */
09545          break;
09546 
09547       case HF_SCAN_DOWN_QUICK:
09548          interval = -50; /* 500Hz /sec */
09549          break;
09550 
09551       case HF_SCAN_DOWN_FAST:
09552          interval = -200; /* 2KHz /sec */
09553          break;
09554 
09555       case HF_SCAN_UP_SLOW:
09556          interval = 10; /* 100Hz /sec */
09557          break;
09558 
09559       case HF_SCAN_UP_QUICK:
09560          interval = 50; /* 500 Hz/sec */
09561          break;
09562 
09563       case HF_SCAN_UP_FAST:
09564          interval = 200; /* 2KHz /sec */
09565          break;
09566 
09567       default:
09568          myrpt->hfscanmode = 0; /* Huh? */
09569          return -1;
09570    }
09571 
09572    res = split_freq(mhz, decimals, myrpt->freq);
09573       
09574    if(!res){
09575       k100 =decimals[0];
09576       k10 = decimals[1];
09577       res = multimode_bump_freq(myrpt, interval);
09578    }
09579 
09580    if(!res)
09581       res = split_freq(mhz, decimals, myrpt->freq);
09582 
09583 
09584    if(res){
09585       myrpt->hfscanmode = 0;
09586       myrpt->hfscanstatus = -2;
09587       return -1;
09588    }
09589 
09590    /* Announce 10KHz boundaries */
09591    if(k10 != decimals[1]){
09592       int myhund = (interval < 0) ? k100 : decimals[0];
09593       int myten = (interval < 0) ? k10 : decimals[1];
09594       myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
09595    } else myrpt->hfscanstatus = 0;
09596    return res;
09597 
09598 }
09599 /*
09600    retrieve memory setting and set radio
09601 */
09602 static int get_mem_set(struct rpt *myrpt, char *digitbuf)
09603 {
09604    int res=0;
09605    if(debug)ast_log(LOG_NOTICE," digitbuf=%s\n", digitbuf);
09606    res = retreive_memory(myrpt, digitbuf);
09607    if(!res)res=setrem(myrpt); 
09608    if(debug)ast_log(LOG_NOTICE," freq=%s  res=%i\n", myrpt->freq, res);
09609    return res;
09610 }
09611 /*
09612    steer the radio selected channel to either one programmed into the radio
09613    or if the radio is VFO agile, to an rpt.conf memory location.
09614 */
09615 static int channel_steer(struct rpt *myrpt, char *data)
09616 {
09617    int res=0;
09618 
09619    if(debug)ast_log(LOG_NOTICE,"remoterig=%s, data=%s\n",myrpt->remoterig,data);
09620    if (!myrpt->remoterig) return(0);
09621    if(data<=0)
09622    {
09623       res=-1;
09624    }
09625    else
09626    {
09627       myrpt->nowchan=strtod(data,NULL);
09628       if(!strcmp(myrpt->remoterig, remote_rig_ppp16))
09629       {
09630          char string[16];
09631          sprintf(string,"SETCHAN %d ",myrpt->nowchan);
09632          send_usb_txt(myrpt,string);   
09633       }
09634       else
09635       {
09636          if(get_mem_set(myrpt, data))res=-1;
09637       }
09638    }
09639    if(debug)ast_log(LOG_NOTICE,"nowchan=%i  res=%i\n",myrpt->nowchan, res);
09640    return res;
09641 }
09642 /*
09643 */
09644 static int channel_revert(struct rpt *myrpt)
09645 {
09646    int res=0;
09647    if(debug)ast_log(LOG_NOTICE,"remoterig=%s, nowchan=%02d, waschan=%02d\n",myrpt->remoterig,myrpt->nowchan,myrpt->waschan);
09648    if (!myrpt->remoterig) return(0);
09649    if(myrpt->nowchan!=myrpt->waschan)
09650    {
09651       char data[8];
09652         if(debug)ast_log(LOG_NOTICE,"reverting.\n");
09653       sprintf(data,"%02d",myrpt->waschan);
09654       myrpt->nowchan=myrpt->waschan;
09655       channel_steer(myrpt,data);
09656       res=1;
09657    }
09658    return(res);
09659 }
09660 /*
09661 * Remote base function
09662 */
09663 
09664 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
09665 {
09666    char *s,*s1,*s2;
09667    int i,j,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode=0;
09668    intptr_t p;
09669    char multimode = 0;
09670    char oc,*cp,*cp1,*cp2;
09671    char tmp[20], freq[20] = "", savestr[20] = "";
09672    char mhz[MAXREMSTR], decimals[MAXREMSTR];
09673 
09674     if(debug > 6) {
09675       ast_log(LOG_NOTICE,"%s param=%s digitbuf=%s source=%i\n",myrpt->name,param,digitbuf,command_source);
09676    }
09677 
09678    if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
09679       return DC_ERROR;
09680       
09681    p = myatoi(param);
09682 
09683    if ((p != 99) && (p != 5) && (p != 140) && myrpt->p.authlevel && 
09684       (!myrpt->loginlevel[0])) return DC_ERROR;
09685    multimode = multimode_capable(myrpt);
09686 
09687    switch(p){
09688 
09689       case 1:  /* retrieve memory */
09690          if(strlen(digitbuf) < 2) /* needs 2 digits */
09691             break;
09692          
09693          for(i = 0 ; i < 2 ; i++){
09694             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09695                return DC_ERROR;
09696          }
09697          r=get_mem_set(myrpt, digitbuf);
09698          if (r < 0){
09699             rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
09700             return DC_COMPLETE;
09701          }
09702          else if (r > 0){
09703             return DC_ERROR;
09704          }
09705          return DC_COMPLETE;  
09706          
09707       case 2:  /* set freq and offset */
09708       
09709          
09710             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
09711             if(digitbuf[i] == '*'){
09712                j++;
09713                continue;
09714             }
09715             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09716                goto invalid_freq;
09717             else{
09718                if(j == 0)
09719                   l++; /* # of digits before first * */
09720                if(j == 1)
09721                   k++; /* # of digits after first * */
09722             }
09723          }
09724       
09725          i = strlen(digitbuf) - 1;
09726          if(multimode){
09727             if((j > 2) || (l > 3) || (k > 6))
09728                goto invalid_freq; /* &^@#! */
09729          }
09730          else{
09731             if((j > 2) || (l > 4) || (k > 3))
09732                goto invalid_freq; /* &^@#! */
09733          }
09734 
09735          /* Wait for M+*K+* */
09736 
09737          if(j < 2)
09738             break; /* Not yet */
09739 
09740          /* We have a frequency */
09741 
09742          strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
09743          
09744          s = tmp;
09745          s1 = strsep(&s, "*"); /* Pick off MHz */
09746          s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
09747          ls2 = strlen(s2); 
09748          
09749          switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
09750             case 1:
09751                ht = 0;
09752                k = 100 * atoi(s2);
09753                break;
09754             
09755             case 2:
09756                ht = 0;
09757                k = 10 * atoi(s2);
09758                break;
09759                
09760             case 3:
09761                if(!multimode){
09762                   if((s2[2] != '0')&&(s2[2] != '5'))
09763                      goto invalid_freq;
09764                }
09765                ht = 0;
09766                k = atoi(s2);
09767                   break;
09768             case 4:
09769                k = atoi(s2)/10;
09770                ht = 10 * (atoi(s2+(ls2-1)));
09771                break;
09772 
09773             case 5:
09774                k = atoi(s2)/100;
09775                ht = (atoi(s2+(ls2-2)));
09776                break;
09777                
09778             default:
09779                goto invalid_freq;
09780          }
09781 
09782          /* Check frequency for validity and establish a default mode */
09783          
09784          snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
09785 
09786          if(debug)
09787             ast_log(LOG_NOTICE, "New frequency: %s\n", freq);
09788    
09789          split_freq(mhz, decimals, freq);
09790          m = atoi(mhz);
09791          d = atoi(decimals);
09792 
09793          if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
09794                  goto invalid_freq;
09795 
09796 
09797          if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
09798             break; /* Not yet */
09799 
09800 
09801          offset = REM_SIMPLEX; /* Assume simplex */
09802 
09803          if(defmode == REM_MODE_FM){
09804             oc = *s; /* Pick off offset */
09805          
09806             if (oc){
09807                switch(oc){
09808                   case '1':
09809                      offset = REM_MINUS;
09810                      break;
09811                   
09812                   case '2':
09813                      offset = REM_SIMPLEX;
09814                   break;
09815                   
09816                   case '3':
09817                      offset = REM_PLUS;
09818                      break;
09819                   
09820                   default:
09821                      goto invalid_freq;
09822                } 
09823             } 
09824          }  
09825          offsave = myrpt->offset;
09826          modesave = myrpt->remmode;
09827          strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
09828          strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
09829          myrpt->offset = offset;
09830          myrpt->remmode = defmode;
09831 
09832          if (setrem(myrpt) == -1){
09833             myrpt->offset = offsave;
09834             myrpt->remmode = modesave;
09835             strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
09836             goto invalid_freq;
09837          }
09838 
09839          return DC_COMPLETE;
09840 
09841 invalid_freq:
09842          rpt_telemetry(myrpt,INVFREQ,NULL);
09843          return DC_ERROR; 
09844       
09845       case 3: /* set rx PL tone */
09846             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
09847             if(digitbuf[i] == '*'){
09848                j++;
09849                continue;
09850             }
09851             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09852                return DC_ERROR;
09853             else{
09854                if(j)
09855                   l++;
09856                else
09857                   k++;
09858             }
09859          }
09860          if((j > 1) || (k > 3) || (l > 1))
09861             return DC_ERROR; /* &$@^! */
09862          i = strlen(digitbuf) - 1;
09863          if((j != 1) || (k < 2)|| (l != 1))
09864             break; /* Not yet */
09865          if(debug)
09866             printf("PL digits entered %s\n", digitbuf);
09867             
09868          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
09869          /* see if we have at least 1 */
09870          s = strchr(tmp,'*');
09871          if(s)
09872             *s = '.';
09873          strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
09874          strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
09875          if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09876          {
09877             strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
09878          }
09879          if (setrem(myrpt) == -1){
09880             strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
09881             return DC_ERROR;
09882          }
09883          return DC_COMPLETE;
09884       
09885       case 4: /* set tx PL tone */
09886          /* cant set tx tone on RBI (rx tone does both) */
09887          if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09888             return DC_ERROR;
09889          /*  eventually for the ic706 instead of just throwing the exception
09890             we can check if we are in encode only mode and allow the tx
09891             ctcss code to be changed. but at least the warning message is
09892             issued for now.
09893          */
09894          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09895          {
09896             if(debug)
09897                ast_log(LOG_WARNING,"Setting IC706 Tx CTCSS Code Not Supported. Set Rx Code for both.\n");
09898             return DC_ERROR;
09899          }
09900          for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
09901             if(digitbuf[i] == '*'){
09902                j++;
09903                continue;
09904             }
09905             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09906                return DC_ERROR;
09907             else{
09908                if(j)
09909                   l++;
09910                else
09911                   k++;
09912             }
09913          }
09914          if((j > 1) || (k > 3) || (l > 1))
09915             return DC_ERROR; /* &$@^! */
09916          i = strlen(digitbuf) - 1;
09917          if((j != 1) || (k < 2)|| (l != 1))
09918             break; /* Not yet */
09919          if(debug)
09920             printf("PL digits entered %s\n", digitbuf);
09921             
09922          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
09923          /* see if we have at least 1 */
09924          s = strchr(tmp,'*');
09925          if(s)
09926             *s = '.';
09927          strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1);
09928          strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
09929          
09930          if (setrem(myrpt) == -1){
09931             strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
09932             return DC_ERROR;
09933          }
09934          return DC_COMPLETE;
09935       
09936 
09937       case 6: /* MODE (FM,USB,LSB,AM) */
09938          if(strlen(digitbuf) < 1)
09939             break;
09940 
09941          if(!multimode)
09942             return DC_ERROR; /* Multimode radios only */
09943 
09944          switch(*digitbuf){
09945             case '1':
09946                split_freq(mhz, decimals, myrpt->freq); 
09947                m=atoi(mhz);
09948                if(m < 29) /* No FM allowed below 29MHz! */
09949                   return DC_ERROR;
09950                myrpt->remmode = REM_MODE_FM;
09951                
09952                rpt_telemetry(myrpt,REMMODE,NULL);
09953                break;
09954 
09955             case '2':
09956                myrpt->remmode = REM_MODE_USB;
09957                rpt_telemetry(myrpt,REMMODE,NULL);
09958                break;   
09959 
09960             case '3':
09961                myrpt->remmode = REM_MODE_LSB;
09962                rpt_telemetry(myrpt,REMMODE,NULL);
09963                break;
09964             
09965             case '4':
09966                myrpt->remmode = REM_MODE_AM;
09967                rpt_telemetry(myrpt,REMMODE,NULL);
09968                break;
09969       
09970             default:
09971                return DC_ERROR;
09972          }
09973 
09974          if(setrem(myrpt))
09975             return DC_ERROR;
09976          return DC_COMPLETEQUIET;
09977       case 99:
09978          /* cant log in when logged in */
09979          if (myrpt->loginlevel[0]) 
09980             return DC_ERROR;
09981          *myrpt->loginuser = 0;
09982          myrpt->loginlevel[0] = 0;
09983          cp = ast_strdup(param);
09984          cp1 = strchr(cp,',');
09985          ast_mutex_lock(&myrpt->lock);
09986          if (cp1) 
09987          {
09988             *cp1 = 0;
09989             cp2 = strchr(cp1 + 1,',');
09990             if (cp2) 
09991             {
09992                *cp2 = 0;
09993                strncpy(myrpt->loginlevel,cp2 + 1,
09994                   sizeof(myrpt->loginlevel) - 1);
09995             }
09996             strncpy(myrpt->loginuser,cp1 + 1,sizeof(myrpt->loginuser));
09997             ast_mutex_unlock(&myrpt->lock);
09998             if (myrpt->p.archivedir)
09999             {
10000                char str[100];
10001 
10002                sprintf(str,"LOGIN,%s,%s",
10003                    myrpt->loginuser,myrpt->loginlevel);
10004                donodelog(myrpt,str);
10005             }
10006             if (debug) 
10007                printf("loginuser %s level %s\n",myrpt->loginuser,myrpt->loginlevel);
10008             rpt_telemetry(myrpt,REMLOGIN,NULL);
10009          }
10010          ast_free(cp);
10011          return DC_COMPLETEQUIET;
10012       case 100: /* RX PL Off */
10013          myrpt->rxplon = 0;
10014          setrem(myrpt);
10015          rpt_telemetry(myrpt,REMXXX,(void *)p);
10016          return DC_COMPLETEQUIET;
10017       case 101: /* RX PL On */
10018          myrpt->rxplon = 1;
10019          setrem(myrpt);
10020          rpt_telemetry(myrpt,REMXXX,(void *)p);
10021          return DC_COMPLETEQUIET;
10022       case 102: /* TX PL Off */
10023          myrpt->txplon = 0;
10024          setrem(myrpt);
10025          rpt_telemetry(myrpt,REMXXX,(void *)p);
10026          return DC_COMPLETEQUIET;
10027       case 103: /* TX PL On */
10028          myrpt->txplon = 1;
10029          setrem(myrpt);
10030          rpt_telemetry(myrpt,REMXXX,(void *)p);
10031          return DC_COMPLETEQUIET;
10032       case 104: /* Low Power */
10033          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10034             return DC_ERROR;
10035          myrpt->powerlevel = REM_LOWPWR;
10036          setrem(myrpt);
10037          rpt_telemetry(myrpt,REMXXX,(void *)p);
10038          return DC_COMPLETEQUIET;
10039       case 105: /* Medium Power */
10040          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10041             return DC_ERROR;
10042          if (ISRIG_RTX(myrpt->remoterig)) return DC_ERROR;
10043          myrpt->powerlevel = REM_MEDPWR;
10044          setrem(myrpt);
10045          rpt_telemetry(myrpt,REMXXX,(void *)p);
10046          return DC_COMPLETEQUIET;
10047       case 106: /* Hi Power */
10048          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10049             return DC_ERROR;
10050          myrpt->powerlevel = REM_HIPWR;
10051          setrem(myrpt);
10052          rpt_telemetry(myrpt,REMXXX,(void *)p);
10053          return DC_COMPLETEQUIET;
10054       case 107: /* Bump down 20Hz */
10055          multimode_bump_freq(myrpt, -20);
10056          return DC_COMPLETE;
10057       case 108: /* Bump down 100Hz */
10058          multimode_bump_freq(myrpt, -100);
10059          return DC_COMPLETE;
10060       case 109: /* Bump down 500Hz */
10061          multimode_bump_freq(myrpt, -500);
10062          return DC_COMPLETE;
10063       case 110: /* Bump up 20Hz */
10064          multimode_bump_freq(myrpt, 20);
10065          return DC_COMPLETE;
10066       case 111: /* Bump up 100Hz */
10067          multimode_bump_freq(myrpt, 100);
10068          return DC_COMPLETE;
10069       case 112: /* Bump up 500Hz */
10070          multimode_bump_freq(myrpt, 500);
10071          return DC_COMPLETE;
10072       case 113: /* Scan down slow */
10073          myrpt->scantimer = REM_SCANTIME;
10074          myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
10075          rpt_telemetry(myrpt,REMXXX,(void *)p);
10076          return DC_COMPLETEQUIET;
10077       case 114: /* Scan down quick */
10078          myrpt->scantimer = REM_SCANTIME;
10079          myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
10080          rpt_telemetry(myrpt,REMXXX,(void *)p);
10081          return DC_COMPLETEQUIET;
10082       case 115: /* Scan down fast */
10083          myrpt->scantimer = REM_SCANTIME;
10084          myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
10085          rpt_telemetry(myrpt,REMXXX,(void *)p);
10086          return DC_COMPLETEQUIET;
10087       case 116: /* Scan up slow */
10088          myrpt->scantimer = REM_SCANTIME;
10089          myrpt->hfscanmode = HF_SCAN_UP_SLOW;
10090          rpt_telemetry(myrpt,REMXXX,(void *)p);
10091          return DC_COMPLETEQUIET;
10092       case 117: /* Scan up quick */
10093          myrpt->scantimer = REM_SCANTIME;
10094          myrpt->hfscanmode = HF_SCAN_UP_QUICK;
10095          rpt_telemetry(myrpt,REMXXX,(void *)p);
10096          return DC_COMPLETEQUIET;
10097       case 118: /* Scan up fast */
10098          myrpt->scantimer = REM_SCANTIME;
10099          myrpt->hfscanmode = HF_SCAN_UP_FAST;
10100          rpt_telemetry(myrpt,REMXXX,(void *)p);
10101          return DC_COMPLETEQUIET;
10102       case 119: /* Tune Request */
10103          if(debug > 3)
10104             ast_log(LOG_NOTICE,"TUNE REQUEST\n");
10105          /* if not currently going, and valid to do */
10106          if((!myrpt->tunerequest) && 
10107              ((!strcmp(myrpt->remoterig, remote_rig_ft897) || 
10108             !strcmp(myrpt->remoterig, remote_rig_ic706)) )) { 
10109             myrpt->remotetx = 0;
10110             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
10111             myrpt->tunerequest = 1;
10112             rpt_telemetry(myrpt,TUNE,NULL);
10113             return DC_COMPLETEQUIET;
10114          }
10115          return DC_ERROR;        
10116       case 5: /* Long Status */
10117          rpt_telemetry(myrpt,REMLONGSTATUS,NULL);
10118          return DC_COMPLETEQUIET;
10119       case 140: /* Short Status */
10120          rpt_telemetry(myrpt,REMSHORTSTATUS,NULL);
10121          return DC_COMPLETEQUIET;
10122       case 200:
10123       case 201:
10124       case 202:
10125       case 203:
10126       case 204:
10127       case 205:
10128       case 206:
10129       case 207:
10130       case 208:
10131       case 209:
10132       case 210:
10133       case 211:
10134       case 212:
10135       case 213:
10136       case 214:
10137       case 215:
10138          do_dtmf_local(myrpt,remdtmfstr[p - 200]);
10139          return DC_COMPLETEQUIET;
10140       default:
10141          break;
10142    }
10143    return DC_INDETERMINATE;
10144 }
10145 
10146 
10147 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode)
10148 {
10149 time_t   now;
10150 int   ret,res = 0,src;
10151 
10152    if(debug > 6)
10153       ast_log(LOG_NOTICE,"c=%c  phonemode=%i  dtmfidx=%i\n",c,phonemode,myrpt->dtmfidx);
10154 
10155    time(&myrpt->last_activity_time);
10156    /* Stop scan mode if in scan mode */
10157    if(myrpt->hfscanmode){
10158       stop_scan(myrpt);
10159       return 0;
10160    }
10161 
10162    time(&now);
10163    /* if timed-out */
10164    if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
10165    {
10166       myrpt->dtmfidx = -1;
10167       myrpt->dtmfbuf[0] = 0;
10168       myrpt->dtmf_time_rem = 0;
10169    }
10170    /* if decode not active */
10171    if (myrpt->dtmfidx == -1)
10172    {
10173       /* if not lead-in digit, don't worry */
10174       if (c != myrpt->p.funcchar)
10175       {
10176          if (!myrpt->p.propagate_dtmf)
10177          {
10178             rpt_mutex_lock(&myrpt->lock);
10179             do_dtmf_local(myrpt,c);
10180             rpt_mutex_unlock(&myrpt->lock);
10181          }
10182          return 0;
10183       }
10184       myrpt->dtmfidx = 0;
10185       myrpt->dtmfbuf[0] = 0;
10186       myrpt->dtmf_time_rem = now;
10187       return 0;
10188    }
10189    /* if too many in buffer, start over */
10190    if (myrpt->dtmfidx >= MAXDTMF)
10191    {
10192       myrpt->dtmfidx = 0;
10193       myrpt->dtmfbuf[0] = 0;
10194       myrpt->dtmf_time_rem = now;
10195    }
10196    if (c == myrpt->p.funcchar)
10197    {
10198       /* if star at beginning, or 2 together, erase buffer */
10199       if ((myrpt->dtmfidx < 1) || 
10200          (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
10201       {
10202          myrpt->dtmfidx = 0;
10203          myrpt->dtmfbuf[0] = 0;
10204          myrpt->dtmf_time_rem = now;
10205          return 0;
10206       }
10207    }
10208    myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
10209    myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10210    myrpt->dtmf_time_rem = now;
10211    
10212    
10213    src = SOURCE_RMT;
10214    if (phonemode == 2) src = SOURCE_DPHONE;
10215    else if (phonemode) src = SOURCE_PHONE;
10216    else if (phonemode == 4) src = SOURCE_ALT;
10217    ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
10218    
10219    switch(ret){
10220    
10221       case DC_INDETERMINATE:
10222          res = 0;
10223          break;
10224             
10225       case DC_DOKEY:
10226          if (keyed) *keyed = 1;
10227          res = 0;
10228          break;
10229             
10230       case DC_REQ_FLUSH:
10231          myrpt->dtmfidx = 0;
10232          myrpt->dtmfbuf[0] = 0;
10233          res = 0;
10234          break;
10235             
10236             
10237       case DC_COMPLETE:
10238          res = 1;
10239       case DC_COMPLETEQUIET:
10240          myrpt->totalexecdcommands++;
10241          myrpt->dailyexecdcommands++;
10242          strncpy(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF-1);
10243          myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
10244          myrpt->dtmfbuf[0] = 0;
10245          myrpt->dtmfidx = -1;
10246          myrpt->dtmf_time_rem = 0;
10247          break;
10248             
10249       case DC_ERROR:
10250       default:
10251          myrpt->dtmfbuf[0] = 0;
10252          myrpt->dtmfidx = -1;
10253          myrpt->dtmf_time_rem = 0;
10254          res = 0;
10255          break;
10256    }
10257 
10258    return res;
10259 }
10260 
10261 static int handle_remote_data(struct rpt *myrpt, char *str)
10262 {
10263 /* XXX ATTENTION: if you change the size of these arrays you MUST
10264  * change the limits in corresponding sscanf() calls below. */
10265 char  tmp[300],cmd[300],dest[300],src[300],c;
10266 int   seq,res;
10267 
10268    /* put string in our buffer */
10269    strncpy(tmp,str,sizeof(tmp) - 1);
10270    if (!strcmp(tmp,discstr)) return 0;
10271         if (!strcmp(tmp,newkeystr))
10272         {
10273       myrpt->newkey = 1;
10274                 return 0;
10275         }
10276 
10277 #ifndef  DO_NOT_NOTIFY_MDC1200_ON_REMOTE_BASES
10278    if (tmp[0] == 'I')
10279    {
10280       /* XXX WARNING: be very careful with the limits on the folowing
10281        * sscanf() call, make sure they match the values defined above */
10282       if (sscanf(tmp,"%299s %299s %30x",cmd,src,&seq) != 3)
10283       {
10284          ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
10285          return 0;
10286       }
10287       mdc1200_notify(myrpt,src,seq);
10288       return 0;
10289    }
10290 #endif
10291    /* XXX WARNING: be very careful with the limits on the folowing
10292     * sscanf() call, make sure they match the values defined above */
10293    if (sscanf(tmp,"%299s %299s %299s %30d %1c",cmd,dest,src,&seq,&c) != 5)
10294    {
10295       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
10296       return 0;
10297    }
10298    if (strcmp(cmd,"D"))
10299    {
10300       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
10301       return 0;
10302    }
10303    /* if not for me, ignore */
10304    if (strcmp(dest,myrpt->name)) return 0;
10305    if (myrpt->p.archivedir)
10306    {
10307       char dtmfstr[100];
10308 
10309       sprintf(dtmfstr,"DTMF,%c",c);
10310       donodelog(myrpt,dtmfstr);
10311    }
10312    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
10313    if (!c) return(0);
10314    res = handle_remote_dtmf_digit(myrpt,c, NULL, 0);
10315    if (res != 1)
10316       return res;
10317    rpt_telemetry(myrpt,COMPLETE,NULL);
10318    return 0;
10319 }
10320 
10321 static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode)
10322 {
10323 int   res;
10324 
10325 
10326    if(phonemode == 3) /* simplex phonemode, funcchar key/unkey toggle */
10327    {
10328       if (keyed && *keyed && ((c == myrpt->p.funcchar) || (c == myrpt->p.endchar)))
10329       {
10330          *keyed = 0; /* UNKEY */
10331          return 0;
10332       }
10333       else if (keyed && !*keyed && (c = myrpt->p.funcchar))
10334       {
10335          *keyed = 1; /* KEY */
10336          return 0;
10337       }
10338    }
10339    else /* endchar unkey */
10340    {
10341 
10342       if (keyed && *keyed && (c == myrpt->p.endchar))
10343       {
10344          *keyed = 0;
10345          return DC_INDETERMINATE;
10346       }
10347    }
10348    if (myrpt->p.archivedir)
10349    {
10350       char str[100];
10351 
10352       sprintf(str,"DTMF(P),%c",c);
10353       donodelog(myrpt,str);
10354    }
10355    res = handle_remote_dtmf_digit(myrpt,c,keyed, phonemode);
10356    if (res != 1)
10357       return res;
10358    rpt_telemetry(myrpt,COMPLETE,NULL);
10359    return 0;
10360 }
10361 
10362 static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
10363 {
10364    char *val, *s, *s1, *s2, *tele;
10365    char tmp[300], deststr[300] = "";
10366    char sx[320],*sy;
10367    struct ast_format_cap *cap = NULL;
10368 
10369 
10370    val = node_lookup(myrpt,l->name);
10371    if (!val)
10372    {
10373       fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
10374       return -1;
10375    }
10376 
10377    rpt_mutex_lock(&myrpt->lock);
10378    /* remove from queue */
10379    remque((struct qelem *) l);
10380    rpt_mutex_unlock(&myrpt->lock);
10381    strncpy(tmp,val,sizeof(tmp) - 1);
10382    s = tmp;
10383    s1 = strsep(&s,",");
10384    if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
10385    {
10386       sy = strchr(s1,'/');    
10387       *sy = 0;
10388       sprintf(sx,"%s:4569/%s",s1,sy + 1);
10389       s1 = sx;
10390    }
10391    s2 = strsep(&s,",");
10392    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
10393    tele = strchr(deststr, '/');
10394    if (!tele) {
10395       fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
10396       return -1;
10397    }
10398    *tele++ = 0;
10399    l->elaptime = 0;
10400    l->connecttime = 0;
10401    l->thisconnected = 0;
10402    l->newkey = 0;
10403    l->chan = ast_request(deststr, get_slin_cap(cap), NULL, tele, NULL);
10404    cap = ast_format_cap_destroy(cap);
10405    if (l->chan){
10406       ast_set_read_format_by_id(l->chan, AST_FORMAT_SLINEAR);
10407       ast_set_write_format_by_id(l->chan, AST_FORMAT_SLINEAR);
10408 #ifndef  NEW_ASTERISK
10409       l->chan->whentohangup = 0;
10410 #endif
10411       l->chan->appl = "Apprpt";
10412       l->chan->data = "(Remote Rx)";
10413       ast_verb(3, "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
10414          deststr, tele, ast_channel_name(l->chan));
10415       l->chan->caller.id.number.valid = 1;
10416       ast_free(l->chan->caller.id.number.str);
10417       l->chan->caller.id.number.str = ast_strdup(myrpt->name);
10418                 ast_call(l->chan,tele,999); 
10419 
10420    }
10421    else 
10422    {
10423       ast_verb(3, "Unable to place call to %s/%s on %s\n",
10424          deststr,tele,ast_channel_name(l->chan));
10425       return -1;
10426    }
10427    rpt_mutex_lock(&myrpt->lock);
10428    /* put back in queue */
10429    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
10430    rpt_mutex_unlock(&myrpt->lock);
10431    ast_log(LOG_WARNING,"Reconnect Attempt to %s in process\n",l->name);
10432    if (!l->phonemode) send_newkey(l->chan);
10433    return 0;
10434 }
10435 
10436 /* 0 return=continue, 1 return = break, -1 return = error */
10437 static void local_dtmf_helper(struct rpt *myrpt,char c_in)
10438 {
10439 int   res;
10440 pthread_attr_t attr;
10441 char  cmd[MAXDTMF+1] = "",c;
10442 
10443 
10444    c = c_in & 0x7f;
10445    if (myrpt->p.archivedir)
10446    {
10447       char str[100];
10448 
10449       sprintf(str,"DTMF,MAIN,%c",c);
10450       donodelog(myrpt,str);
10451    }
10452    if (c == myrpt->p.endchar)
10453    {
10454    /* if in simple mode, kill autopatch */
10455       if (myrpt->p.simple && myrpt->callmode)
10456       {   
10457          if(debug)
10458             ast_log(LOG_WARNING, "simple mode autopatch kill\n");
10459          rpt_mutex_lock(&myrpt->lock);
10460          myrpt->callmode = 0;
10461          myrpt->macropatch=0;
10462          channel_revert(myrpt);
10463          rpt_mutex_unlock(&myrpt->lock);
10464          rpt_telemetry(myrpt,TERM,NULL);
10465          return;
10466       }
10467       rpt_mutex_lock(&myrpt->lock);
10468       myrpt->stopgen = 1;
10469       if (myrpt->cmdnode[0])
10470       {
10471          myrpt->cmdnode[0] = 0;
10472          myrpt->dtmfidx = -1;
10473          myrpt->dtmfbuf[0] = 0;
10474          rpt_mutex_unlock(&myrpt->lock);
10475          rpt_telemetry(myrpt,COMPLETE,NULL);
10476          return;
10477       } 
10478       else if(!myrpt->inpadtest)
10479                 {
10480                         rpt_mutex_unlock(&myrpt->lock);
10481                         if (myrpt->p.propagate_phonedtmf)
10482                                do_dtmf_phone(myrpt,NULL,c);
10483          return;
10484                 }
10485       else
10486          rpt_mutex_unlock(&myrpt->lock);
10487    }
10488    rpt_mutex_lock(&myrpt->lock);
10489    if (myrpt->cmdnode[0])
10490    {
10491       rpt_mutex_unlock(&myrpt->lock);
10492       send_link_dtmf(myrpt,c);
10493       return;
10494    }
10495    if (!myrpt->p.simple)
10496    {
10497       if ((!myrpt->inpadtest)&&(c == myrpt->p.funcchar))
10498       {
10499          myrpt->dtmfidx = 0;
10500          myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10501          rpt_mutex_unlock(&myrpt->lock);
10502          time(&myrpt->dtmf_time);
10503          return;
10504       } 
10505       else if (((myrpt->inpadtest)||(c != myrpt->p.endchar)) && (myrpt->dtmfidx >= 0))
10506       {
10507          time(&myrpt->dtmf_time);
10508          
10509          if (myrpt->dtmfidx < MAXDTMF)
10510          {
10511             int src;
10512 
10513             myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
10514             myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10515             
10516             strncpy(cmd, myrpt->dtmfbuf, sizeof(cmd) - 1);
10517             
10518             rpt_mutex_unlock(&myrpt->lock);
10519             src = SOURCE_RPT;
10520             if (c_in & 0x80) src = SOURCE_ALT;
10521             res = collect_function_digits(myrpt, cmd, src, NULL);
10522             rpt_mutex_lock(&myrpt->lock);
10523             switch(res){
10524                 case DC_INDETERMINATE:
10525                break;
10526                 case DC_REQ_FLUSH:
10527                myrpt->dtmfidx = 0;
10528                myrpt->dtmfbuf[0] = 0;
10529                break;
10530                 case DC_COMPLETE:
10531                 case DC_COMPLETEQUIET:
10532                myrpt->totalexecdcommands++;
10533                myrpt->dailyexecdcommands++;
10534                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
10535                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
10536                myrpt->dtmfbuf[0] = 0;
10537                myrpt->dtmfidx = -1;
10538                myrpt->dtmf_time = 0;
10539                break;
10540 
10541                 case DC_ERROR:
10542                 default:
10543                myrpt->dtmfbuf[0] = 0;
10544                myrpt->dtmfidx = -1;
10545                myrpt->dtmf_time = 0;
10546                break;
10547             }
10548             if(res != DC_INDETERMINATE) {
10549                rpt_mutex_unlock(&myrpt->lock);
10550                return;
10551             }
10552          } 
10553       }
10554    }
10555    else /* if simple */
10556    {
10557       if ((!myrpt->callmode) && (c == myrpt->p.funcchar))
10558       {
10559          myrpt->callmode = 1;
10560          myrpt->patchnoct = 0;
10561          myrpt->patchquiet = 0;
10562          myrpt->patchfarenddisconnect = 0;
10563          myrpt->patchdialtime = 0;
10564          strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
10565          myrpt->cidx = 0;
10566          myrpt->exten[myrpt->cidx] = 0;
10567          rpt_mutex_unlock(&myrpt->lock);
10568               pthread_attr_init(&attr);
10569               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10570          ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
10571          return;
10572       }
10573    }
10574    if (myrpt->callmode == 1)
10575    {
10576       myrpt->exten[myrpt->cidx++] = c;
10577       myrpt->exten[myrpt->cidx] = 0;
10578       /* if this exists */
10579       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
10580       {
10581          /* if this really it, end now */
10582          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
10583             myrpt->exten,1,NULL)) 
10584          {
10585             myrpt->callmode = 2;
10586             rpt_mutex_unlock(&myrpt->lock);
10587             if(!myrpt->patchquiet)
10588                rpt_telemetry(myrpt,PROC,NULL); 
10589             return;
10590          }
10591          else /* othewise, reset timer */
10592          {
10593             myrpt->calldigittimer = 1;
10594          }
10595       }
10596       /* if can continue, do so */
10597       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
10598       {
10599          /* call has failed, inform user */
10600          myrpt->callmode = 4;
10601       }
10602       rpt_mutex_unlock(&myrpt->lock);
10603       return;
10604    }
10605    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
10606    {
10607       myrpt->mydtmf = c;
10608    }
10609    rpt_mutex_unlock(&myrpt->lock);
10610    if ((myrpt->dtmfidx < 0) && myrpt->p.propagate_phonedtmf)
10611       do_dtmf_phone(myrpt,NULL,c);
10612    return;
10613 }
10614 
10615 
10616 /* place an ID event in the telemetry queue */
10617 
10618 static void queue_id(struct rpt *myrpt)
10619 {
10620    if(myrpt->p.idtime){ /* ID time must be non-zero */
10621       myrpt->mustid = myrpt->tailid = 0;
10622       myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
10623       rpt_mutex_unlock(&myrpt->lock);
10624       rpt_telemetry(myrpt,ID,NULL);
10625       rpt_mutex_lock(&myrpt->lock);
10626    }
10627 }
10628 
10629 /* Scheduler */
10630 /* must be called locked */
10631 
10632 static void do_scheduler(struct rpt *myrpt)
10633 {
10634    int i,res;
10635 
10636 #ifdef   NEW_ASTERISK
10637    struct ast_tm tmnow;
10638 #else
10639    struct tm tmnow;
10640 #endif
10641    struct ast_variable *skedlist;
10642    char *strs[5],*vp,*val,value[100];
10643 
10644    memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
10645    
10646    if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
10647       ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
10648 
10649    /* Try to get close to a 1 second resolution */
10650    
10651    if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
10652       return;
10653 
10654    rpt_localtime(&myrpt->curtv.tv_sec, &tmnow);
10655 
10656    /* If midnight, then reset all daily statistics */
10657    
10658    if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
10659       myrpt->dailykeyups = 0;
10660       myrpt->dailytxtime = 0;
10661       myrpt->dailykerchunks = 0;
10662       myrpt->dailyexecdcommands = 0;
10663    }
10664 
10665    if(tmnow.tm_sec != 0)
10666       return;
10667 
10668    /* Code below only executes once per minute */
10669 
10670 
10671    /* Don't schedule if remote */
10672 
10673         if (myrpt->remote)
10674                 return;
10675 
10676    /* Don't schedule if disabled */
10677 
10678         if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable){
10679       if(debug > 6)
10680          ast_log(LOG_NOTICE, "Scheduler disabled\n");
10681       return;
10682    }
10683 
10684    if(!myrpt->p.skedstanzaname){ /* No stanza means we do nothing */
10685       if(debug > 6)
10686          ast_log(LOG_NOTICE,"No stanza for scheduler in rpt.conf\n");
10687       return;
10688    }
10689 
10690     /* get pointer to linked list of scheduler entries */
10691     skedlist = ast_variable_browse(myrpt->cfg, myrpt->p.skedstanzaname);
10692 
10693    if(debug > 6){
10694       ast_log(LOG_NOTICE, "Time now: %02d:%02d %02d %02d %02d\n",
10695          tmnow.tm_hour,tmnow.tm_min,tmnow.tm_mday,tmnow.tm_mon + 1, tmnow.tm_wday); 
10696    }
10697    /* walk the list */
10698    for(; skedlist; skedlist = skedlist->next){
10699       if(debug > 6)
10700          ast_log(LOG_NOTICE, "Scheduler entry %s = %s being considered\n",skedlist->name, skedlist->value);
10701       strncpy(value,skedlist->value,99);
10702       value[99] = 0;
10703       /* point to the substrings for minute, hour, dom, month, and dow */
10704       for( i = 0, vp = value ; i < 5; i++){
10705          if(!*vp)
10706             break;
10707          while((*vp == ' ') || (*vp == 0x09)) /* get rid of any leading white space */
10708             vp++;
10709          strs[i] = vp; /* save pointer to beginning of substring */
10710          while((*vp != ' ') && (*vp != 0x09) && (*vp != 0)) /* skip over substring */
10711             vp++;
10712          if(*vp)
10713             *vp++ = 0; /* mark end of substring */
10714       }
10715       if(debug > 6)
10716          ast_log(LOG_NOTICE, "i = %d, min = %s, hour = %s, mday=%s, mon=%s, wday=%s\n",i,
10717             strs[0], strs[1], strs[2], strs[3], strs[4]); 
10718       if(i == 5){
10719          if((*strs[0] != '*')&&(atoi(strs[0]) != tmnow.tm_min))
10720             continue;
10721          if((*strs[1] != '*')&&(atoi(strs[1]) != tmnow.tm_hour))
10722             continue;
10723          if((*strs[2] != '*')&&(atoi(strs[2]) != tmnow.tm_mday))
10724             continue;
10725          if((*strs[3] != '*')&&(atoi(strs[3]) != tmnow.tm_mon + 1))
10726             continue;
10727          if(atoi(strs[4]) == 7)
10728             strs[4] = "0";
10729          if((*strs[4] != '*')&&(atoi(strs[4]) != tmnow.tm_wday))
10730             continue;
10731          if(debug)
10732             ast_log(LOG_NOTICE, "Executing scheduler entry %s = %s\n", skedlist->name, skedlist->value);
10733          if(atoi(skedlist->name) == 0)
10734             return; /* Zero is reserved for the startup macro */
10735          val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, skedlist->name);
10736          if (!val){
10737             ast_log(LOG_WARNING,"Scheduler could not find macro %s\n",skedlist->name);
10738             return; /* Macro not found */
10739          }
10740          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)){
10741             ast_log(LOG_WARNING, "Scheduler could not execute macro %s: Macro buffer full\n",
10742                skedlist->name);
10743             return; /* Macro buffer full */
10744          }
10745          myrpt->macrotimer = MACROTIME;
10746          strncat(myrpt->macrobuf,val,MAXMACRO - 1);
10747       }
10748       else{
10749          ast_log(LOG_WARNING,"Malformed scheduler entry in rpt.conf: %s = %s\n",
10750             skedlist->name, skedlist->value);
10751       }
10752    }
10753 
10754 }
10755 
10756 /* single thread with one file (request) to dial */
10757 static void *rpt(void *this)
10758 {
10759 struct   rpt *myrpt = (struct rpt *)this;
10760 char *tele,*idtalkover,c,myfirst,*p;
10761 int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued;
10762 int tailmessagequeued,ctqueued,dtmfed,lastmyrx,localmsgqueued;
10763 struct ast_channel *who;
10764 struct dahdi_confinfo ci;  /* conference info */
10765 time_t   t;
10766 struct rpt_link *l,*m;
10767 struct rpt_tele *telem;
10768 char tmpstr[300],lstr[MAXLINKLIST];
10769 struct ast_format_cap *cap = NULL;
10770 
10771 
10772    if (myrpt->p.archivedir) mkdir(myrpt->p.archivedir,0600);
10773    sprintf(tmpstr,"%s/%s",myrpt->p.archivedir,myrpt->name);
10774    mkdir(tmpstr,0600);
10775    rpt_mutex_lock(&myrpt->lock);
10776 
10777    telem = myrpt->tele.next;
10778    while(telem != &myrpt->tele)
10779    {
10780       ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
10781       telem = telem->next;
10782    }
10783    rpt_mutex_unlock(&myrpt->lock);
10784    /* find our index, and load the vars initially */
10785    for(i = 0; i < nrpts; i++)
10786    {
10787       if (&rpt_vars[i] == myrpt)
10788       {
10789          load_rpt_vars(i,0);
10790          break;
10791       }
10792    }
10793 
10794    rpt_mutex_lock(&myrpt->lock);
10795    while(myrpt->xlink)
10796    {
10797       myrpt->xlink = 3;
10798       rpt_mutex_unlock(&myrpt->lock);
10799       usleep(100000);
10800       rpt_mutex_lock(&myrpt->lock);
10801    }
10802 #ifdef HAVE_IOPERM
10803    if ((!strcmp(myrpt->remoterig, remote_rig_rbi)) &&
10804      (ioperm(myrpt->p.iobase,1,1) == -1))
10805    {
10806       rpt_mutex_unlock(&myrpt->lock);
10807       ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
10808       myrpt->rpt_thread = AST_PTHREADT_STOP;
10809       pthread_exit(NULL);
10810    }
10811 #endif
10812    strncpy(tmpstr,myrpt->rxchanname,sizeof(tmpstr) - 1);
10813    tele = strchr(tmpstr,'/');
10814    if (!tele)
10815    {
10816       fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
10817       rpt_mutex_unlock(&myrpt->lock);
10818       myrpt->rpt_thread = AST_PTHREADT_STOP;
10819       pthread_exit(NULL);
10820    }
10821    *tele++ = 0;
10822    myrpt->rxchannel = ast_request(tmpstr, get_slin_cap(cap), NULL, tele, NULL);
10823    cap = ast_format_cap_destroy(cap);
10824    myrpt->dahdirxchannel = NULL;
10825    if (!strcasecmp(tmpstr,"DAHDI"))
10826       myrpt->dahdirxchannel = myrpt->rxchannel;
10827    if (myrpt->rxchannel)
10828    {
10829       if (myrpt->rxchannel->_state == AST_STATE_BUSY)
10830       {
10831          fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
10832          rpt_mutex_unlock(&myrpt->lock);
10833          ast_hangup(myrpt->rxchannel);
10834          myrpt->rpt_thread = AST_PTHREADT_STOP;
10835          pthread_exit(NULL);
10836       }
10837       ast_set_read_format_by_id(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10838       ast_set_write_format_by_id(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10839 #ifdef   AST_CDR_FLAG_POST_DISABLED
10840       if (myrpt->rxchannel->cdr)
10841          ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10842 #endif
10843 #ifndef  NEW_ASTERISK
10844       myrpt->rxchannel->whentohangup = 0;
10845 #endif
10846       myrpt->rxchannel->appl = "Apprpt";
10847       myrpt->rxchannel->data = "(Repeater Rx)";
10848       ast_verb(3, "rpt (Rx) initiating call to %s/%s on %s\n",
10849             tmpstr,tele,myrpt->rxchannel->name);
10850       ast_call(myrpt->rxchannel,tele,999);
10851       if (myrpt->rxchannel->_state != AST_STATE_UP)
10852       {
10853          rpt_mutex_unlock(&myrpt->lock);
10854          ast_hangup(myrpt->rxchannel);
10855          myrpt->rpt_thread = AST_PTHREADT_STOP;
10856          pthread_exit(NULL);
10857       }
10858    }
10859    else
10860    {
10861       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
10862       rpt_mutex_unlock(&myrpt->lock);
10863       myrpt->rpt_thread = AST_PTHREADT_STOP;
10864       pthread_exit(NULL);
10865    }
10866    myrpt->dahditxchannel = NULL;
10867    if (myrpt->txchanname)
10868    {
10869       strncpy(tmpstr,myrpt->txchanname,sizeof(tmpstr) - 1);
10870       tele = strchr(tmpstr,'/');
10871       if (!tele)
10872       {
10873          fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
10874          rpt_mutex_unlock(&myrpt->lock);
10875          ast_hangup(myrpt->rxchannel);
10876          myrpt->rpt_thread = AST_PTHREADT_STOP;
10877          pthread_exit(NULL);
10878       }
10879       *tele++ = 0;
10880       myrpt->txchannel = ast_request(tmpstr, get_slin_cap(cap), NULL, tele, NULL);
10881       cap = ast_format_cap_destroy(cap);
10882       if (!strcasecmp(tmpstr,"DAHDI"))
10883          myrpt->dahditxchannel = myrpt->txchannel;
10884       if (myrpt->txchannel)
10885       {
10886          if (myrpt->txchannel->_state == AST_STATE_BUSY)
10887          {
10888             fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
10889             rpt_mutex_unlock(&myrpt->lock);
10890             ast_hangup(myrpt->txchannel);
10891             ast_hangup(myrpt->rxchannel);
10892             myrpt->rpt_thread = AST_PTHREADT_STOP;
10893             pthread_exit(NULL);
10894          }        
10895          ast_set_read_format_by_id(myrpt->txchannel,AST_FORMAT_SLINEAR);
10896          ast_set_write_format_by_id(myrpt->txchannel,AST_FORMAT_SLINEAR);
10897 #ifdef   AST_CDR_FLAG_POST_DISABLED
10898          if (myrpt->txchannel->cdr)
10899             ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10900 #endif
10901 #ifndef  NEW_ASTERISK
10902          myrpt->txchannel->whentohangup = 0;
10903 #endif
10904          myrpt->txchannel->appl = "Apprpt";
10905          myrpt->txchannel->data = "(Repeater Tx)";
10906          ast_verb(3, "rpt (Tx) initiating call to %s/%s on %s\n",
10907                tmpstr,tele,myrpt->txchannel->name);
10908          ast_call(myrpt->txchannel,tele,999);
10909          if (myrpt->rxchannel->_state != AST_STATE_UP)
10910          {
10911             rpt_mutex_unlock(&myrpt->lock);
10912             ast_hangup(myrpt->rxchannel);
10913             ast_hangup(myrpt->txchannel);
10914             myrpt->rpt_thread = AST_PTHREADT_STOP;
10915             pthread_exit(NULL);
10916          }
10917       }
10918       else
10919       {
10920          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
10921          rpt_mutex_unlock(&myrpt->lock);
10922          ast_hangup(myrpt->rxchannel);
10923          myrpt->rpt_thread = AST_PTHREADT_STOP;
10924          pthread_exit(NULL);
10925       }
10926    }
10927    else
10928    {
10929       myrpt->txchannel = myrpt->rxchannel;
10930       if (!strncasecmp(myrpt->rxchanname,"DAHDI",3))
10931          myrpt->dahditxchannel = myrpt->txchannel;
10932    }
10933    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
10934    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
10935    /* allocate a pseudo-channel thru asterisk */
10936    myrpt->pchannel = ast_request("DAHDI", get_slin_cap(cap), NULL, "pseudo", NULL);
10937    cap = ast_format_cap_destroy(cap);
10938    if (!myrpt->pchannel)
10939    {
10940       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10941       rpt_mutex_unlock(&myrpt->lock);
10942       if (myrpt->txchannel != myrpt->rxchannel) 
10943          ast_hangup(myrpt->txchannel);
10944       ast_hangup(myrpt->rxchannel);
10945       myrpt->rpt_thread = AST_PTHREADT_STOP;
10946       pthread_exit(NULL);
10947    }
10948 #ifdef   AST_CDR_FLAG_POST_DISABLED
10949    if (myrpt->pchannel->cdr)
10950       ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10951 #endif
10952    if (!myrpt->dahdirxchannel) myrpt->dahdirxchannel = myrpt->pchannel;
10953    if (!myrpt->dahditxchannel)
10954    {
10955       /* allocate a pseudo-channel thru asterisk */
10956       myrpt->dahditxchannel = ast_request("DAHDI", get_slin_cap(cap), NULL, "pseudo", NULL);
10957       cap = ast_format_cap_destroy(cap);
10958       if (!myrpt->dahditxchannel)
10959       {
10960          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10961          rpt_mutex_unlock(&myrpt->lock);
10962          if (myrpt->txchannel != myrpt->rxchannel) 
10963             ast_hangup(myrpt->txchannel);
10964          ast_hangup(myrpt->rxchannel);
10965          myrpt->rpt_thread = AST_PTHREADT_STOP;
10966          pthread_exit(NULL);
10967       }
10968       ast_set_read_format_by_id(myrpt->dahditxchannel,AST_FORMAT_SLINEAR);
10969       ast_set_write_format_by_id(myrpt->dahditxchannel,AST_FORMAT_SLINEAR);
10970 #ifdef   AST_CDR_FLAG_POST_DISABLED
10971       if (myrpt->dahditxchannel->cdr)
10972          ast_set_flag(myrpt->dahditxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10973 #endif
10974    }
10975    /* allocate a pseudo-channel thru asterisk */
10976    myrpt->monchannel = ast_request("DAHDI", get_slin_cap(cap), NULL, "pseudo", NULL);
10977    cap = ast_format_cap_destroy(cap);
10978    if (!myrpt->monchannel)
10979    {
10980       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10981       rpt_mutex_unlock(&myrpt->lock);
10982       if (myrpt->txchannel != myrpt->rxchannel) 
10983          ast_hangup(myrpt->txchannel);
10984       ast_hangup(myrpt->rxchannel);
10985       myrpt->rpt_thread = AST_PTHREADT_STOP;
10986       pthread_exit(NULL);
10987    }
10988    ast_set_read_format_by_id(myrpt->monchannel,AST_FORMAT_SLINEAR);
10989    ast_set_write_format_by_id(myrpt->monchannel,AST_FORMAT_SLINEAR);
10990 #ifdef   AST_CDR_FLAG_POST_DISABLED
10991    if (myrpt->monchannel->cdr)
10992       ast_set_flag(myrpt->monchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10993 #endif
10994    /* make a conference for the tx */
10995    ci.chan = 0;
10996    ci.confno = -1; /* make a new conf */
10997    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER;
10998    /* first put the channel on the conference in proper mode */
10999    if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11000    {
11001       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
11002       rpt_mutex_unlock(&myrpt->lock);
11003       ast_hangup(myrpt->pchannel);
11004       ast_hangup(myrpt->monchannel);
11005       if (myrpt->txchannel != myrpt->rxchannel) 
11006          ast_hangup(myrpt->txchannel);
11007       ast_hangup(myrpt->rxchannel);
11008       myrpt->rpt_thread = AST_PTHREADT_STOP;
11009       pthread_exit(NULL);
11010    }
11011    /* save tx conference number */
11012    myrpt->txconf = ci.confno;
11013    /* make a conference for the pseudo */
11014    ci.chan = 0;
11015    ci.confno = -1; /* make a new conf */
11016    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
11017       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
11018    /* first put the channel on the conference in announce mode */
11019    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11020    {
11021       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
11022       rpt_mutex_unlock(&myrpt->lock);
11023       ast_hangup(myrpt->pchannel);
11024       ast_hangup(myrpt->monchannel);
11025       if (myrpt->txchannel != myrpt->rxchannel) 
11026          ast_hangup(myrpt->txchannel);
11027       ast_hangup(myrpt->rxchannel);
11028       myrpt->rpt_thread = AST_PTHREADT_STOP;
11029       pthread_exit(NULL);
11030    }
11031    /* save pseudo channel conference number */
11032    myrpt->conf = ci.confno;
11033    /* make a conference for the pseudo */
11034    ci.chan = 0;
11035    if ((strstr(myrpt->txchannel->name,"pseudo") == NULL) &&
11036       (myrpt->dahditxchannel == myrpt->txchannel))
11037    {
11038       /* get tx channel's port number */
11039       if (ioctl(myrpt->txchannel->fds[0],DAHDI_CHANNO,&ci.confno) == -1)
11040       {
11041          ast_log(LOG_WARNING, "Unable to set tx channel's chan number\n");
11042          rpt_mutex_unlock(&myrpt->lock);
11043          ast_hangup(myrpt->pchannel);
11044          ast_hangup(myrpt->monchannel);
11045          if (myrpt->txchannel != myrpt->rxchannel) 
11046             ast_hangup(myrpt->txchannel);
11047          ast_hangup(myrpt->rxchannel);
11048          myrpt->rpt_thread = AST_PTHREADT_STOP;
11049          pthread_exit(NULL);
11050       }
11051       ci.confmode = DAHDI_CONF_MONITORTX;
11052    }
11053    else
11054    {
11055       ci.confno = myrpt->txconf;
11056       ci.confmode = DAHDI_CONF_CONFANNMON;
11057    }
11058    /* first put the channel on the conference in announce mode */
11059    if (ioctl(myrpt->monchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11060    {
11061       ast_log(LOG_WARNING, "Unable to set conference mode for monitor\n");
11062       rpt_mutex_unlock(&myrpt->lock);
11063       ast_hangup(myrpt->pchannel);
11064       ast_hangup(myrpt->monchannel);
11065       if (myrpt->txchannel != myrpt->rxchannel) 
11066          ast_hangup(myrpt->txchannel);
11067       ast_hangup(myrpt->rxchannel);
11068       myrpt->rpt_thread = AST_PTHREADT_STOP;
11069       pthread_exit(NULL);
11070    }
11071    /* allocate a pseudo-channel thru asterisk */
11072    myrpt->parrotchannel = ast_request("DAHDI", get_slin_cap(cap), NULL, "pseudo", NULL);
11073    cap = ast_format_cap_destroy(cap);
11074    if (!myrpt->parrotchannel)
11075    {
11076       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11077       rpt_mutex_unlock(&myrpt->lock);
11078       if (myrpt->txchannel != myrpt->rxchannel) 
11079          ast_hangup(myrpt->txchannel);
11080       ast_hangup(myrpt->rxchannel);
11081       myrpt->rpt_thread = AST_PTHREADT_STOP;
11082       pthread_exit(NULL);
11083    }
11084    ast_set_read_format_by_id(myrpt->parrotchannel,AST_FORMAT_SLINEAR);
11085    ast_set_write_format_by_id(myrpt->parrotchannel,AST_FORMAT_SLINEAR);
11086 #ifdef   AST_CDR_FLAG_POST_DISABLED
11087    if (myrpt->parrotchannel->cdr)
11088       ast_set_flag(myrpt->parrotchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11089 #endif
11090    /* allocate a pseudo-channel thru asterisk */
11091    myrpt->voxchannel = ast_request("DAHDI", get_slin_cap(cap), NULL, "pseudo", NULL);
11092    cap = ast_format_cap_destroy(cap);
11093    if (!myrpt->voxchannel)
11094    {
11095       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11096       rpt_mutex_unlock(&myrpt->lock);
11097       if (myrpt->txchannel != myrpt->rxchannel) 
11098          ast_hangup(myrpt->txchannel);
11099       ast_hangup(myrpt->rxchannel);
11100       myrpt->rpt_thread = AST_PTHREADT_STOP;
11101       pthread_exit(NULL);
11102    }
11103    ast_set_read_format_by_id(myrpt->voxchannel,AST_FORMAT_SLINEAR);
11104    ast_set_write_format_by_id(myrpt->voxchannel,AST_FORMAT_SLINEAR);
11105 #ifdef   AST_CDR_FLAG_POST_DISABLED
11106    if (myrpt->voxchannel->cdr)
11107       ast_set_flag(myrpt->voxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11108 #endif
11109    /* allocate a pseudo-channel thru asterisk */
11110    myrpt->txpchannel = ast_request("DAHDI", get_slin_cap(cap), NULL, "pseudo", NULL);
11111    cap = ast_format_cap_destroy(cap);
11112    if (!myrpt->txpchannel)
11113    {
11114       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11115       rpt_mutex_unlock(&myrpt->lock);
11116       ast_hangup(myrpt->pchannel);
11117       ast_hangup(myrpt->monchannel);
11118       if (myrpt->txchannel != myrpt->rxchannel) 
11119          ast_hangup(myrpt->txchannel);
11120       ast_hangup(myrpt->rxchannel);
11121       myrpt->rpt_thread = AST_PTHREADT_STOP;
11122       pthread_exit(NULL);
11123    }
11124 #ifdef   AST_CDR_FLAG_POST_DISABLED
11125    if (myrpt->txpchannel->cdr)
11126       ast_set_flag(myrpt->txpchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11127 #endif
11128    /* make a conference for the tx */
11129    ci.chan = 0;
11130    ci.confno = myrpt->txconf;
11131    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER ;
11132    /* first put the channel on the conference in proper mode */
11133    if (ioctl(myrpt->txpchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11134    {
11135       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
11136       rpt_mutex_unlock(&myrpt->lock);
11137       ast_hangup(myrpt->txpchannel);
11138       ast_hangup(myrpt->monchannel);
11139       if (myrpt->txchannel != myrpt->rxchannel) 
11140          ast_hangup(myrpt->txchannel);
11141       ast_hangup(myrpt->rxchannel);
11142       myrpt->rpt_thread = AST_PTHREADT_STOP;
11143       pthread_exit(NULL);
11144    }
11145    /* if serial io port, open it */
11146    myrpt->iofd = -1;
11147    if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt,myrpt->p.ioport)) == -1))
11148    {
11149       ast_log(LOG_ERROR, "Unable to open %s\n",myrpt->p.ioport);
11150       rpt_mutex_unlock(&myrpt->lock);
11151       ast_hangup(myrpt->pchannel);
11152       if (myrpt->txchannel != myrpt->rxchannel) 
11153          ast_hangup(myrpt->txchannel);
11154       ast_hangup(myrpt->rxchannel);
11155       pthread_exit(NULL);
11156    }
11157    /* Now, the idea here is to copy from the physical rx channel buffer
11158       into the pseudo tx buffer, and from the pseudo rx buffer into the 
11159       tx channel buffer */
11160    myrpt->links.next = &myrpt->links;
11161    myrpt->links.prev = &myrpt->links;
11162    myrpt->tailtimer = 0;
11163    myrpt->totimer = 0;
11164    myrpt->tmsgtimer = myrpt->p.tailmessagetime;
11165    myrpt->idtimer = myrpt->p.politeid;
11166    myrpt->mustid = myrpt->tailid = 0;
11167    myrpt->callmode = 0;
11168    myrpt->tounkeyed = 0;
11169    myrpt->tonotify = 0;
11170    myrpt->retxtimer = 0;
11171    myrpt->rerxtimer = 0;
11172    myrpt->skedtimer = 0;
11173    myrpt->tailevent = 0;
11174    lasttx = 0;
11175    myrpt->keyed = 0;
11176    myrpt->txkeyed = 0;
11177    time(&myrpt->lastkeyedtime);
11178    myrpt->lastkeyedtime -= RPT_LOCKOUT_SECS;
11179    time(&myrpt->lasttxkeyedtime);
11180    myrpt->lasttxkeyedtime -= RPT_LOCKOUT_SECS;
11181    idtalkover = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
11182    myrpt->dtmfidx = -1;
11183    myrpt->dtmfbuf[0] = 0;
11184    myrpt->rem_dtmfidx = -1;
11185    myrpt->rem_dtmfbuf[0] = 0;
11186    myrpt->dtmf_time = 0;
11187    myrpt->rem_dtmf_time = 0;
11188    myrpt->inpadtest = 0;
11189    myrpt->disgorgetime = 0;
11190    myrpt->lastnodewhichkeyedusup[0] = '\0';
11191    myrpt->dailytxtime = 0;
11192    myrpt->totaltxtime = 0;
11193    myrpt->dailykeyups = 0;
11194    myrpt->totalkeyups = 0;
11195    myrpt->dailykerchunks = 0;
11196    myrpt->totalkerchunks = 0;
11197    myrpt->dailyexecdcommands = 0;
11198    myrpt->totalexecdcommands = 0;
11199    myrpt->timeouts = 0;
11200    myrpt->exten[0] = '\0';
11201    myrpt->lastdtmfcommand[0] = '\0';
11202    voxinit_rpt(myrpt,1);
11203    myrpt->wasvox = 0;
11204    if (myrpt->p.startupmacro)
11205    {
11206       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
11207    }
11208    rpt_mutex_unlock(&myrpt->lock);
11209    val = 1;
11210    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
11211    val = 1;
11212    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
11213    if (myrpt->p.archivedir) donodelog(myrpt,"STARTUP");
11214    dtmfed = 0;
11215    if (myrpt->remoterig && !ISRIG_RTX(myrpt->remoterig)) setrem(myrpt);
11216    lastmyrx = 0;
11217    myfirst = 0;
11218    while (ms >= 0)
11219    {
11220       struct ast_frame *f,*f1,*f2;
11221       struct ast_channel *cs[300],*cs1[300];
11222       int totx=0,elap=0,n,x,toexit=0;
11223 
11224       /* DEBUG Dump */
11225       if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){
11226          struct rpt_link *dl;
11227          struct rpt_tele *dt;
11228 
11229          myrpt->disgorgetime = 0;
11230          ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n");
11231          ast_log(LOG_NOTICE,"totx = %d\n",totx);
11232          ast_log(LOG_NOTICE,"remrx = %d\n",remrx);
11233          ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx);
11234          ast_log(LOG_NOTICE,"elap = %d\n",elap);
11235          ast_log(LOG_NOTICE,"toexit = %d\n",toexit);
11236 
11237          ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed);
11238          ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx);
11239          ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode);
11240          ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
11241          ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed);
11242          ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify);
11243          ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
11244          ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
11245          ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
11246          ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
11247 
11248          dl = myrpt->links.next;
11249                   while(dl != &myrpt->links){
11250             ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",dl->name);
11251             ast_log(LOG_NOTICE,"        link->lasttx %d\n",dl->lasttx);
11252             ast_log(LOG_NOTICE,"        link->lastrx %d\n",dl->lastrx);
11253             ast_log(LOG_NOTICE,"        link->connected %d\n",dl->connected);
11254             ast_log(LOG_NOTICE,"        link->hasconnected %d\n",dl->hasconnected);
11255             ast_log(LOG_NOTICE,"        link->outbound %d\n",dl->outbound);
11256             ast_log(LOG_NOTICE,"        link->disced %d\n",dl->disced);
11257             ast_log(LOG_NOTICE,"        link->killme %d\n",dl->killme);
11258             ast_log(LOG_NOTICE,"        link->disctime %ld\n",dl->disctime);
11259             ast_log(LOG_NOTICE,"        link->retrytimer %ld\n",dl->retrytimer);
11260             ast_log(LOG_NOTICE,"        link->retries = %d\n",dl->retries);
11261             ast_log(LOG_NOTICE,"        link->reconnects = %d\n",dl->reconnects);
11262             ast_log(LOG_NOTICE,"        link->newkey = %d\n",dl->newkey);
11263                            dl = dl->next;
11264                   }
11265                                                                                                                                
11266          dt = myrpt->tele.next;
11267          if(dt != &myrpt->tele)
11268             ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n");
11269                   while(dt != &myrpt->tele){
11270             ast_log(LOG_NOTICE,"        Telemetry mode: %d\n",dt->mode);
11271                            dt = dt->next;
11272                   }
11273          ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n");
11274 
11275       }  
11276 
11277 
11278       if (myrpt->reload)
11279       {
11280          struct rpt_tele *inner_telem;
11281 
11282          rpt_mutex_lock(&myrpt->lock);
11283          inner_telem = myrpt->tele.next;
11284          while(inner_telem != &myrpt->tele)
11285          {
11286             ast_softhangup(inner_telem->chan,AST_SOFTHANGUP_DEV);
11287             inner_telem = inner_telem->next;
11288          }
11289          myrpt->reload = 0;
11290          rpt_mutex_unlock(&myrpt->lock);
11291          usleep(10000);
11292          /* find our index, and load the vars */
11293          for(i = 0; i < nrpts; i++)
11294          {
11295             if (&rpt_vars[i] == myrpt)
11296             {
11297                load_rpt_vars(i,0);
11298                break;
11299             }
11300          }
11301       }
11302 
11303       rpt_mutex_lock(&myrpt->lock);
11304       if (ast_check_hangup(myrpt->rxchannel)) break;
11305       if (ast_check_hangup(myrpt->txchannel)) break;
11306       if (ast_check_hangup(myrpt->pchannel)) break;
11307       if (ast_check_hangup(myrpt->monchannel)) break;
11308       if (myrpt->parrotchannel && 
11309          ast_check_hangup(myrpt->parrotchannel)) break;
11310       if (myrpt->voxchannel && 
11311          ast_check_hangup(myrpt->voxchannel)) break;
11312       if (ast_check_hangup(myrpt->txpchannel)) break;
11313       if (myrpt->dahditxchannel && ast_check_hangup(myrpt->dahditxchannel)) break;
11314 
11315       /* Set local tx with keyed */
11316       myrpt->localtx = myrpt->keyed;
11317       /* If someone's connected, and they're transmitting from their end to us, set remrx true */
11318       l = myrpt->links.next;
11319       remrx = 0;
11320       while(l != &myrpt->links)
11321       {
11322          if (l->lastrx){
11323             remrx = 1;
11324             if(l->name[0] != '0') /* Ignore '0' nodes */
11325                strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
11326          }
11327          l = l->next;
11328       }
11329       /* Create a "must_id" flag for the cleanup ID */      
11330       if(myrpt->p.idtime) /* ID time must be non-zero */
11331          myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
11332       /* Build a fresh totx from myrpt->keyed and autopatch activated */
11333       /* If full duplex, add local tx to totx */
11334       if (myrpt->p.duplex > 1) 
11335       {
11336          totx = myrpt->callmode;
11337          totx = totx || myrpt->localtx;
11338       }
11339       else
11340       {
11341          int myrx = myrpt->localtx || remrx || (!myrpt->callmode);
11342 
11343          if (lastmyrx != myrx)
11344          {
11345             voxinit_rpt(myrpt,!myrx);
11346             lastmyrx = myrx;
11347          }
11348          totx = 0;
11349          if (myrpt->callmode && (myrpt->voxtotimer <= 0))
11350          {
11351             if (myrpt->voxtostate)
11352             {
11353                myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
11354                myrpt->voxtostate = 0;
11355             }           
11356             else
11357             {
11358                myrpt->voxtotimer = myrpt->p.voxrecover_ms;
11359                myrpt->voxtostate = 1;
11360             }
11361          }
11362          if (!myrpt->voxtostate)
11363             totx = myrpt->callmode && myrpt->wasvox;
11364       }
11365       /* Traverse the telemetry list to see what's queued */
11366       identqueued = 0;
11367       localmsgqueued = 0;
11368       othertelemqueued = 0;
11369       tailmessagequeued = 0;
11370       ctqueued = 0;
11371       telem = myrpt->tele.next;
11372       while(telem != &myrpt->tele)
11373       {
11374          if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
11375             identqueued = 1; /* Identification telemetry */
11376          }
11377          else if(telem->mode == TAILMSG)
11378          {
11379             tailmessagequeued = 1; /* Tail message telemetry */
11380          }
11381          else if(telem->mode == STATS_TIME_LOCAL) 
11382          {
11383             localmsgqueued = 1; /* Local message */
11384          }
11385          else
11386          {
11387             if ((telem->mode != UNKEY) && (telem->mode != LINKUNKEY))
11388                othertelemqueued = 1;  /* Other telemetry */
11389             else
11390                ctqueued = 1; /* Courtesy tone telemetry */
11391          }
11392          telem = telem->next;
11393       }
11394    
11395       /* Add in any "other" telemetry, unless specified otherwise */
11396       if (!myrpt->p.notelemtx) totx = totx || othertelemqueued;
11397       /* Update external (to links) transmitter PTT state with everything but */
11398       /* ID, CT, local messages, and tailmessage telemetry */
11399       myrpt->exttx = totx;
11400       totx = totx || myrpt->dtmf_local_timer;
11401       /* If half or 3/4 duplex, add localtx to external link tx */
11402       if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
11403       /* Add in ID telemetry to local transmitter */
11404       totx = totx || remrx;
11405       /* If 3/4 or full duplex, add in ident, CT telemetry, and local messages */
11406       if (myrpt->p.duplex > 0)
11407          totx = totx || identqueued || ctqueued || localmsgqueued;
11408       /* If full duplex, add local dtmf stuff active */
11409       if (myrpt->p.duplex > 1) 
11410       {
11411          totx = totx || (myrpt->dtmfidx > -1) ||
11412             myrpt->cmdnode[0];
11413       }
11414       /* add in parrot stuff */
11415       totx = totx || (myrpt->parrotstate > 1);
11416       /* Reset time out timer variables if there is no activity */
11417       if (!totx) 
11418       {
11419          myrpt->totimer = myrpt->p.totime;
11420          myrpt->tounkeyed = 0;
11421          myrpt->tonotify = 0;
11422       }
11423       else{
11424          myrpt->tailtimer = myrpt->p.s[myrpt->p.sysstate_cur].alternatetail ?
11425             myrpt->p.althangtime : /* Initialize tail timer */
11426             myrpt->p.hangtime;
11427       }
11428       /* Disable the local transmitter if we are timed out */
11429       totx = totx && myrpt->totimer;
11430       /* if timed-out and not said already, say it */
11431       if ((!myrpt->totimer) && (!myrpt->tonotify))
11432       {
11433          myrpt->tonotify = 1;
11434          myrpt->timeouts++;
11435          rpt_mutex_unlock(&myrpt->lock);
11436          rpt_telemetry(myrpt,TIMEOUT,NULL);
11437          rpt_mutex_lock(&myrpt->lock);
11438       }
11439 
11440       /* If unkey and re-key, reset time out timer */
11441       if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
11442       {
11443          myrpt->tounkeyed = 1;
11444       }
11445       if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
11446       {
11447          myrpt->totimer = myrpt->p.totime;
11448          myrpt->tounkeyed = 0;
11449          myrpt->tonotify = 0;
11450          rpt_mutex_unlock(&myrpt->lock);
11451          continue;
11452       }
11453       /* if timed-out and in circuit busy after call */
11454       if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
11455       {
11456           if(debug)
11457             ast_log(LOG_NOTICE, "timed-out and in circuit busy after call\n");
11458          myrpt->callmode = 0;
11459          myrpt->macropatch=0;
11460          channel_revert(myrpt);
11461       }
11462       /* get rid of tail if timed out */
11463       if (!myrpt->totimer) myrpt->tailtimer = 0;
11464       /* if not timed-out, add in tail */
11465       if (myrpt->totimer) totx = totx || myrpt->tailtimer;
11466       /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
11467       /* If tail message, kill the message if someone keys up over it */ 
11468       if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
11469          int hasid = 0,hastalkover = 0;
11470 
11471          telem = myrpt->tele.next;
11472          while(telem != &myrpt->tele){
11473             if(telem->mode == ID){
11474                if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
11475                hasid = 1;
11476             }
11477             if(telem->mode == TAILMSG){
11478                                         if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
11479                                 }
11480             if (telem->mode == IDTALKOVER) hastalkover = 1;
11481             telem = telem->next;
11482          }
11483          rpt_mutex_unlock(&myrpt->lock);
11484          if (hasid && (!hastalkover)) rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
11485          rpt_mutex_lock(&myrpt->lock);
11486       }
11487       /* Try to be polite */
11488       /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
11489       /* If within 30 seconds of the time to ID, try do it in the tail */
11490       /* else if at ID time limit, do it right over the top of them */
11491       /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
11492       if(myrpt->mustid && (!myrpt->idtimer))
11493          queue_id(myrpt);
11494 
11495       if ((myrpt->p.idtime && totx && (!myrpt->exttx) &&
11496           (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) /* ID time must be non-zero */ 
11497          {
11498             myrpt->tailid = 1;
11499          }
11500 
11501       /* If tail timer expires, then check for tail messages */
11502 
11503       if(myrpt->tailevent){
11504          myrpt->tailevent = 0;
11505          if(myrpt->tailid){
11506             totx = 1;
11507             queue_id(myrpt);
11508          }
11509          else if ((myrpt->p.tailmessages[0]) &&
11510             (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
11511                totx = 1;
11512                myrpt->tmsgtimer = myrpt->p.tailmessagetime; 
11513                rpt_mutex_unlock(&myrpt->lock);
11514                rpt_telemetry(myrpt, TAILMSG, NULL);
11515                rpt_mutex_lock(&myrpt->lock);
11516          }  
11517       }
11518 
11519       /* Main TX control */
11520 
11521       /* let telemetry transmit anyway (regardless of timeout) */
11522       if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
11523       totx = totx && !myrpt->p.s[myrpt->p.sysstate_cur].txdisable;
11524       myrpt->txrealkeyed = totx;
11525       totx = totx || (!AST_LIST_EMPTY(&myrpt->txq));
11526       if (totx && (!lasttx))
11527       {
11528          char mydate[100],myfname[100];
11529          time_t myt;
11530 
11531          if (myrpt->monstream) ast_closestream(myrpt->monstream);
11532          if (myrpt->p.archivedir)
11533          {
11534             long blocksleft;
11535 
11536             time(&myt);
11537             strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
11538                localtime(&myt));
11539             sprintf(myfname,"%s/%s/%s",myrpt->p.archivedir,
11540                myrpt->name,mydate);
11541             myrpt->monstream = ast_writefile(myfname,"wav49",
11542                "app_rpt Air Archive",O_CREAT | O_APPEND,0,0600);
11543             if (myrpt->p.monminblocks)
11544             {
11545                blocksleft = diskavail(myrpt);
11546                if (blocksleft >= myrpt->p.monminblocks)
11547                   donodelog(myrpt,"TXKEY,MAIN");
11548             } else donodelog(myrpt,"TXKEY,MAIN");
11549          }
11550          lasttx = 1;
11551          myrpt->txkeyed = 1;
11552          time(&myrpt->lasttxkeyedtime);
11553          myrpt->dailykeyups++;
11554          myrpt->totalkeyups++;
11555          rpt_mutex_unlock(&myrpt->lock);
11556          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
11557          rpt_mutex_lock(&myrpt->lock);
11558       }
11559       if ((!totx) && lasttx)
11560       {
11561          if (myrpt->monstream) ast_closestream(myrpt->monstream);
11562          myrpt->monstream = NULL;
11563 
11564          lasttx = 0;
11565          myrpt->txkeyed = 0;
11566          time(&myrpt->lasttxkeyedtime);
11567          rpt_mutex_unlock(&myrpt->lock);
11568          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
11569          rpt_mutex_lock(&myrpt->lock);
11570          donodelog(myrpt,"TXUNKEY,MAIN");
11571       }
11572       time(&t);
11573       /* if DTMF timeout */
11574       if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t))
11575       {
11576          myrpt->inpadtest = 0;
11577          myrpt->dtmfidx = -1;
11578          myrpt->dtmfbuf[0] = 0;
11579       }        
11580       /* if remote DTMF timeout */
11581       if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
11582       {
11583          myrpt->inpadtest = 0;
11584          myrpt->rem_dtmfidx = -1;
11585          myrpt->rem_dtmfbuf[0] = 0;
11586       }  
11587 
11588       if (myrpt->exttx && myrpt->parrotchannel && 
11589          myrpt->p.parrotmode && (!myrpt->parrotstate))
11590       {
11591          char myfname[300];
11592 
11593          ci.confno = myrpt->conf;
11594          ci.confmode = DAHDI_CONF_CONFANNMON;
11595          ci.chan = 0;
11596 
11597          /* first put the channel on the conference in announce mode */
11598          if (ioctl(myrpt->parrotchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11599          {
11600             ast_log(LOG_WARNING, "Unable to set conference mode for parrot\n");
11601             break;
11602          }
11603 
11604          sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
11605          strcat(myfname,".wav");
11606          unlink(myfname);        
11607          sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
11608          myrpt->parrotstate = 1;
11609          myrpt->parrottimer = myrpt->p.parrottime;
11610          if (myrpt->parrotstream) 
11611             ast_closestream(myrpt->parrotstream);
11612          myrpt->parrotstream = NULL;
11613          myrpt->parrotstream = ast_writefile(myfname,"wav",
11614             "app_rpt Parrot",O_CREAT | O_TRUNC,0,0600);
11615       }
11616 
11617       /* Reconnect */
11618    
11619       l = myrpt->links.next;
11620       while(l != &myrpt->links)
11621       {
11622          if (l->killme)
11623          {
11624             /* remove from queue */
11625             remque((struct qelem *) l);
11626             if (!strcmp(myrpt->cmdnode,l->name))
11627                myrpt->cmdnode[0] = 0;
11628             rpt_mutex_unlock(&myrpt->lock);
11629             /* hang-up on call to device */
11630             if (l->chan) ast_hangup(l->chan);
11631             ast_hangup(l->pchan);
11632             ast_free(l);
11633             rpt_mutex_lock(&myrpt->lock);
11634             /* re-start link traversal */
11635             l = myrpt->links.next;
11636             continue;
11637          }
11638          l = l->next;
11639       }
11640       n = 0;
11641       cs[n++] = myrpt->rxchannel;
11642       cs[n++] = myrpt->pchannel;
11643       cs[n++] = myrpt->monchannel;
11644       if (myrpt->parrotchannel) cs[n++] = myrpt->parrotchannel;
11645       if (myrpt->voxchannel) cs[n++] = myrpt->voxchannel;
11646       cs[n++] = myrpt->txpchannel;
11647       if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
11648       if (myrpt->dahditxchannel != myrpt->txchannel)
11649          cs[n++] = myrpt->dahditxchannel;
11650       l = myrpt->links.next;
11651       while(l != &myrpt->links)
11652       {
11653          if ((!l->killme) && (!l->disctime) && l->chan)
11654          {
11655             cs[n++] = l->chan;
11656             cs[n++] = l->pchan;
11657          }
11658          l = l->next;
11659       }
11660       if ((myrpt->topkeystate == 1) && 
11661           ((t - myrpt->topkeytime) > TOPKEYWAIT))
11662       {
11663          myrpt->topkeystate = 2;
11664          qsort(myrpt->topkey,TOPKEYN,sizeof(struct rpt_topkey),
11665             topcompar);
11666       }
11667       rpt_mutex_unlock(&myrpt->lock);
11668 
11669       if (myrpt->topkeystate == 2)
11670       {
11671          rpt_telemetry(myrpt,TOPKEY,NULL);
11672          myrpt->topkeystate = 3;
11673       }
11674       ms = MSWAIT;
11675       for(x = 0; x < n; x++)
11676       {
11677          int s = -(-x - myrpt->scram - 1) % n;
11678          cs1[x] = cs[s];
11679       }
11680       myrpt->scram++;
11681       who = ast_waitfor_n(cs1,n,&ms);
11682       if (who == NULL) ms = 0;
11683       elap = MSWAIT - ms;
11684       rpt_mutex_lock(&myrpt->lock);
11685       l = myrpt->links.next;
11686       while(l != &myrpt->links)
11687       {
11688          int myrx;
11689 
11690          if (l->voxtotimer) l->voxtotimer -= elap;
11691          if (l->voxtotimer < 0) l->voxtotimer = 0;
11692 
11693          if (l->lasttx != l->lasttx1)
11694          {
11695             voxinit_link(l,!l->lasttx);
11696             l->lasttx1 = l->lasttx;
11697          }
11698          myrx = l->lastrealrx;
11699          if ((l->phonemode) && (l->phonevox))
11700          {
11701             myrx = myrx || (!AST_LIST_EMPTY(&l->rxq));
11702             if (l->voxtotimer <= 0)
11703             {
11704                if (l->voxtostate)
11705                {
11706                   l->voxtotimer = myrpt->p.voxtimeout_ms;
11707                   l->voxtostate = 0;
11708                }           
11709                else
11710                {
11711                   l->voxtotimer = myrpt->p.voxrecover_ms;
11712                   l->voxtostate = 1;
11713                }
11714             }
11715             if (!l->voxtostate)
11716                myrx = myrx || l->wasvox ;
11717          }
11718          l->lastrx = myrx;
11719          if (l->linklisttimer)
11720          {
11721             l->linklisttimer -= elap;
11722             if (l->linklisttimer < 0) l->linklisttimer = 0;
11723          }
11724          if ((!l->linklisttimer) && (l->name[0] != '0') && (!l->isremote))
11725          {
11726             struct   ast_frame lf;
11727 
11728             memset(&lf,0,sizeof(lf));
11729             lf.frametype = AST_FRAME_TEXT;
11730             lf.subclass.integer = 0;
11731             lf.offset = 0;
11732             lf.mallocd = 0;
11733             lf.samples = 0;
11734             l->linklisttimer = LINKLISTTIME;
11735             strcpy(lstr,"L ");
11736             __mklinklist(myrpt,l,lstr + 2);
11737             if (l->chan)
11738             {
11739                lf.datalen = strlen(lstr) + 1;
11740                lf.data.ptr = lstr;
11741                ast_write(l->chan,&lf);
11742                if (debug > 6) ast_log(LOG_NOTICE,
11743                   "@@@@ node %s sent node string %s to node %s\n",
11744                      myrpt->name,lstr,l->name);
11745             }
11746          }
11747          if (l->newkey)
11748          {
11749             if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
11750             {
11751                l->retxtimer = 0;
11752                if (l->chan && l->phonemode == 0) 
11753                {
11754                   if (l->lasttx)
11755                      ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
11756                   else
11757                      ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
11758                }
11759             }
11760             if ((l->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 5))
11761             {
11762                if (debug == 7) printf("@@@@ rx un-key\n");
11763                l->lastrealrx = 0;
11764                l->rerxtimer = 0;
11765                if (l->lastrx1)
11766                {
11767                   if (myrpt->p.archivedir)
11768                   {
11769                      char str[100];
11770    
11771                      sprintf(str,"RXUNKEY(T),%s",l->name);
11772                      donodelog(myrpt,str);
11773                   }
11774                   if(myrpt->p.duplex) 
11775                      rpt_telemetry(myrpt,LINKUNKEY,l);
11776                   l->lastrx1 = 0;
11777                }
11778             }
11779          }
11780          if (l->disctime) /* Disconnect timer active on a channel ? */
11781          {
11782             l->disctime -= elap;
11783             if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
11784                l->disctime = 0; /* Yep */
11785          }
11786 
11787          if (l->retrytimer)
11788          {
11789             l->retrytimer -= elap;
11790             if (l->retrytimer < 0) l->retrytimer = 0;
11791          }
11792 
11793          /* Tally connect time */
11794          l->connecttime += elap;
11795 
11796          /* ignore non-timing channels */
11797          if (l->elaptime < 0)
11798          {
11799             l = l->next;
11800             continue;
11801          }
11802          l->elaptime += elap;
11803          /* if connection has taken too long */
11804          if ((l->elaptime > MAXCONNECTTIME) && 
11805             ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
11806          {
11807             l->elaptime = 0;
11808             rpt_mutex_unlock(&myrpt->lock);
11809             if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
11810             rpt_mutex_lock(&myrpt->lock);
11811             break;
11812          }
11813          if ((!l->chan) && (!l->retrytimer) && l->outbound && 
11814             (l->retries++ < l->max_retries) && (l->hasconnected))
11815          {
11816             if (l->chan) ast_hangup(l->chan);
11817             l->chan = 0;
11818             rpt_mutex_unlock(&myrpt->lock);
11819             if ((l->name[0] != '0') && (!l->isremote))
11820             {
11821                if (attempt_reconnect(myrpt,l) == -1)
11822                {
11823                   l->retrytimer = RETRY_TIMER_MS;
11824                } 
11825             }
11826             else 
11827             {
11828                l->retrytimer = l->max_retries + 1;
11829             }
11830 
11831             rpt_mutex_lock(&myrpt->lock);
11832             break;
11833          }
11834          if ((!l->chan) && (!l->retrytimer) && l->outbound &&
11835             (l->retries >= l->max_retries))
11836          {
11837             /* remove from queue */
11838             remque((struct qelem *) l);
11839             if (!strcmp(myrpt->cmdnode,l->name))
11840                myrpt->cmdnode[0] = 0;
11841             rpt_mutex_unlock(&myrpt->lock);
11842             if (l->name[0] != '0')
11843             {
11844                if (!l->hasconnected)
11845                   rpt_telemetry(myrpt,CONNFAIL,l);
11846                else rpt_telemetry(myrpt,REMDISC,l);
11847             }
11848             if (myrpt->p.archivedir)
11849             {
11850                char str[100];
11851 
11852                if (!l->hasconnected)
11853                   sprintf(str,"LINKFAIL,%s",l->name);
11854                else
11855                   sprintf(str,"LINKDISC,%s",l->name);
11856                donodelog(myrpt,str);
11857             }
11858             /* hang-up on call to device */
11859             ast_hangup(l->pchan);
11860             ast_free(l);
11861                                 rpt_mutex_lock(&myrpt->lock);
11862             break;
11863          }
11864             if ((!l->chan) && (!l->disctime) && (!l->outbound))
11865             {
11866             if(debug)ast_log(LOG_NOTICE, "LINKDISC AA\n");
11867                 /* remove from queue */
11868                 remque((struct qelem *) l);
11869             if(myrpt->links.next==&myrpt->links)channel_revert(myrpt);
11870                 if (!strcmp(myrpt->cmdnode,l->name))myrpt->cmdnode[0] = 0;
11871                 rpt_mutex_unlock(&myrpt->lock);
11872             if (l->name[0] != '0') 
11873             {
11874                   rpt_telemetry(myrpt,REMDISC,l);
11875             }
11876             if (myrpt->p.archivedir)
11877             {
11878                char str[100];
11879                sprintf(str,"LINKDISC,%s",l->name);
11880                donodelog(myrpt,str);
11881             }
11882                 /* hang-up on call to device */
11883                 ast_hangup(l->pchan);
11884                 ast_free(l);
11885                 rpt_mutex_lock(&myrpt->lock);
11886                 break;
11887             }
11888          l = l->next;
11889       }
11890       if (myrpt->linkposttimer)
11891       {
11892          myrpt->linkposttimer -= elap;
11893          if (myrpt->linkposttimer < 0) myrpt->linkposttimer = 0;
11894       }
11895       if (myrpt->linkposttimer <= 0)
11896       {
11897          int nstr;
11898          char lst,*str;
11899          time_t now;
11900 
11901          myrpt->linkposttimer = LINKPOSTTIME;
11902          nstr = 0;
11903          for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
11904          {
11905             /* if is not a real link, ignore it */
11906             if (l->name[0] == '0') continue;
11907             nstr += strlen(l->name) + 1;
11908          }
11909          str = ast_malloc(nstr + 256);
11910          if (!str)
11911          {
11912             ast_log(LOG_NOTICE,"Cannot ast_malloc()\n");
11913             break;
11914          }
11915          nstr = 0;
11916          strcpy(str,"nodes=");
11917          for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
11918          {
11919             /* if is not a real link, ignore it */
11920             if (l->name[0] == '0') continue;
11921             lst = 'T';
11922             if (!l->mode) lst = 'R';
11923             if (!l->thisconnected) lst = 'C';
11924             if (nstr) strcat(str,",");
11925             sprintf(str + strlen(str),"%c%s",lst,l->name);
11926             nstr = 1;
11927          }
11928                   p = strstr(tdesc, "version");
11929                   if(p){
11930             int vmajor,vminor;
11931             if(sscanf(p, "version %30d.%30d", &vmajor, &vminor) == 2)
11932                sprintf(str + strlen(str),"&apprptvers=%d.%d",vmajor,vminor);
11933          }
11934          time(&now);
11935          sprintf(str + strlen(str),"&apprptuptime=%d",(int)(now-starttime));
11936          sprintf(str + strlen(str),
11937          "&totalkerchunks=%d&totalkeyups=%d&totaltxtime=%d&timeouts=%d&totalexecdcommands=%d",
11938          myrpt->totalkerchunks,myrpt->totalkeyups,(int) myrpt->totaltxtime/1000,
11939          myrpt->timeouts,myrpt->totalexecdcommands);
11940          rpt_mutex_unlock(&myrpt->lock);
11941          statpost(myrpt,str);
11942          rpt_mutex_lock(&myrpt->lock);
11943          ast_free(str);
11944       }
11945       if (myrpt->keyposttimer)
11946       {
11947          myrpt->keyposttimer -= elap;
11948          if (myrpt->keyposttimer < 0) myrpt->keyposttimer = 0;
11949       }
11950       if (myrpt->keyposttimer <= 0)
11951       {
11952          char str[100];
11953          int diff = 0;
11954          time_t now;
11955 
11956          myrpt->keyposttimer = KEYPOSTTIME;
11957          time(&now);
11958          if (myrpt->lastkeyedtime)
11959          {
11960             diff = (int)(now - myrpt->lastkeyedtime);
11961          }
11962          sprintf(str,"keyed=%d&keytime=%d",myrpt->keyed,diff);
11963          rpt_mutex_unlock(&myrpt->lock);
11964          statpost(myrpt,str);
11965          rpt_mutex_lock(&myrpt->lock);
11966       }
11967       if(totx){
11968          myrpt->dailytxtime += elap;
11969          myrpt->totaltxtime += elap;
11970       }
11971       i = myrpt->tailtimer;
11972       if (myrpt->tailtimer) myrpt->tailtimer -= elap;
11973       if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
11974       if((i) && (myrpt->tailtimer == 0))
11975          myrpt->tailevent = 1;
11976       if ((!myrpt->p.s[myrpt->p.sysstate_cur].totdisable) && myrpt->totimer) myrpt->totimer -= elap;
11977       if (myrpt->totimer < 0) myrpt->totimer = 0;
11978       if (myrpt->idtimer) myrpt->idtimer -= elap;
11979       if (myrpt->idtimer < 0) myrpt->idtimer = 0;
11980       if (myrpt->tmsgtimer) myrpt->tmsgtimer -= elap;
11981       if (myrpt->tmsgtimer < 0) myrpt->tmsgtimer = 0;
11982       if (myrpt->voxtotimer) myrpt->voxtotimer -= elap;
11983       if (myrpt->voxtotimer < 0) myrpt->voxtotimer = 0;
11984       if (myrpt->exttx)
11985       {
11986          myrpt->parrottimer = myrpt->p.parrottime;
11987       }
11988       else
11989       {
11990          if (myrpt->parrottimer) myrpt->parrottimer -= elap;
11991          if (myrpt->parrottimer < 0) myrpt->parrottimer = 0;
11992       }
11993       /* do macro timers */
11994       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
11995       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
11996       /* do local dtmf timer */
11997       if (myrpt->dtmf_local_timer)
11998       {
11999          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
12000          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
12001       }
12002       do_dtmf_local(myrpt,0);
12003       /* Execute scheduler appx. every 2 tenths of a second */
12004       if (myrpt->skedtimer <= 0){
12005          myrpt->skedtimer = 200;
12006          do_scheduler(myrpt);
12007       }
12008       else
12009          myrpt->skedtimer -=elap;
12010       if (!ms) 
12011       {
12012          rpt_mutex_unlock(&myrpt->lock);
12013          continue;
12014       }
12015       if (myrpt->p.parrotmode && (myrpt->parrotstate == 1) &&
12016          (myrpt->parrottimer <= 0))
12017       {
12018 
12019          ci.confno = 0;
12020          ci.confmode = 0;
12021          ci.chan = 0;
12022 
12023          /* first put the channel on the conference in announce mode */
12024          if (ioctl(myrpt->parrotchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
12025          {
12026             ast_log(LOG_WARNING, "Unable to set conference mode for parrot\n");
12027             break;
12028          }
12029          if (myrpt->parrotstream) 
12030             ast_closestream(myrpt->parrotstream);
12031          myrpt->parrotstream = NULL;
12032          myrpt->parrotstate = 2;
12033          rpt_telemetry(myrpt,PARROT,(void *) ((intptr_t)myrpt->parrotcnt++)); 
12034       }        
12035       if (myrpt->cmdAction.state == CMD_STATE_READY)
12036       { /* there is a command waiting to be processed */
12037          int status;
12038          myrpt->cmdAction.state = CMD_STATE_EXECUTING;
12039          // lose the lock
12040          rpt_mutex_unlock(&myrpt->lock);
12041          // do the function
12042          status = (*function_table[myrpt->cmdAction.functionNumber].function)(myrpt,myrpt->cmdAction.param, myrpt->cmdAction.digits, myrpt->cmdAction.command_source, NULL);
12043          // get the lock again
12044          rpt_mutex_lock(&myrpt->lock);
12045          myrpt->cmdAction.state = CMD_STATE_IDLE;
12046       } /* if myrpt->cmdAction.state == CMD_STATE_READY */
12047       
12048       c = myrpt->macrobuf[0];
12049       time(&t);
12050       if (c && (!myrpt->macrotimer) && 
12051          starttime && (t > (starttime + START_DELAY)))
12052       {
12053          char cin = c & 0x7f;
12054          myrpt->macrotimer = MACROTIME;
12055          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
12056          if ((cin == 'p') || (cin == 'P'))
12057             myrpt->macrotimer = MACROPTIME;
12058          rpt_mutex_unlock(&myrpt->lock);
12059          if (myrpt->p.archivedir)
12060          {
12061             char str[100];
12062 
12063             sprintf(str,"DTMF(M),MAIN,%c",cin);
12064             donodelog(myrpt,str);
12065          }
12066          local_dtmf_helper(myrpt,c);
12067       } else rpt_mutex_unlock(&myrpt->lock);
12068       if (who == myrpt->rxchannel) /* if it was a read from rx */
12069       {
12070          int ismuted;
12071 
12072          f = ast_read(myrpt->rxchannel);
12073          if (!f)
12074          {
12075             if (debug) printf("@@@@ rpt:Hung Up\n");
12076             break;
12077          }
12078          if (f->frametype == AST_FRAME_VOICE)
12079          {
12080 #ifdef   _MDC_DECODE_H_
12081             unsigned char ubuf[2560];
12082             short *sp;
12083             int n;
12084 #endif
12085 
12086             if ((!myrpt->localtx) && (!myrpt->p.linktolink)) {
12087                memset(f->data.ptr,0,f->datalen);
12088             }
12089 
12090 #ifdef   _MDC_DECODE_H_
12091             sp = (short *) f->data;
12092             /* convert block to unsigned char */
12093             for(n = 0; n < f->datalen / 2; n++)
12094             {
12095                ubuf[n] = (*sp++ >> 8) + 128;
12096             }
12097             n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
12098             if (n == 1)
12099             {
12100                   unsigned char op,arg;
12101                   unsigned short unitID;
12102 
12103                   mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
12104                   if (debug > 2)
12105                   {
12106                      ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
12107                      ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
12108                         op & 255,arg & 255,unitID);
12109                   }
12110                   if ((op == 1) && (arg == 0))
12111                   {
12112                      myrpt->lastunit = unitID;
12113                      mdc1200_notify(myrpt,NULL,myrpt->lastunit);
12114                      mdc1200_send(myrpt,myrpt->lastunit);
12115                   }
12116             }
12117             if ((debug > 2) && (i == 2))
12118             {
12119                unsigned char op,arg,ex1,ex2,ex3,ex4;
12120                unsigned short unitID;
12121 
12122                mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
12123                   &ex1,&ex2,&ex3,&ex4);
12124                ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
12125                ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
12126                   op & 255,arg & 255,unitID);
12127                ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
12128                   ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
12129             }
12130 #endif
12131 #ifdef   __RPT_NOTCH
12132             /* apply inbound filters, if any */
12133             rpt_filter(myrpt,f->data,f->datalen / 2);
12134 #endif
12135             if (ioctl(myrpt->dahdirxchannel->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
12136             {
12137                ismuted = 0;
12138             }
12139             if (dtmfed) ismuted = 1;
12140             dtmfed = 0;
12141             if (ismuted)
12142             {
12143                memset(f->data.ptr,0,f->datalen);
12144                if (myrpt->lastf1)
12145                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12146                if (myrpt->lastf2)
12147                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12148             } 
12149             if (f) f2 = ast_frdup(f);
12150             else f2 = NULL;
12151             f1 = myrpt->lastf2;
12152             myrpt->lastf2 = myrpt->lastf1;
12153             myrpt->lastf1 = f2;
12154             if (ismuted)
12155             {
12156                if (myrpt->lastf1)
12157                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12158                if (myrpt->lastf2)
12159                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12160             }
12161             if (f1)
12162             {
12163                ast_write(myrpt->pchannel,f1);
12164                ast_frfree(f1);
12165             }
12166          }
12167 #ifndef  OLD_ASTERISK
12168          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
12169          {
12170             if (myrpt->lastf1)
12171                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12172             if (myrpt->lastf2)
12173                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12174             dtmfed = 1;
12175          }
12176 #endif
12177          else if (f->frametype == AST_FRAME_DTMF)
12178          {
12179             c = (char) f->subclass.integer; /* get DTMF char */
12180             ast_frfree(f);
12181             if (myrpt->lastf1)
12182                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12183             if (myrpt->lastf2)
12184                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12185             dtmfed = 1;
12186             if (!myrpt->keyed) continue;
12187             c = func_xlat(myrpt,c,&myrpt->p.inxlat);
12188             if (c) local_dtmf_helper(myrpt,c);
12189             continue;
12190          }                 
12191          else if (f->frametype == AST_FRAME_CONTROL)
12192          {
12193             if (f->subclass.integer == AST_CONTROL_HANGUP)
12194             {
12195                if (debug) printf("@@@@ rpt:Hung Up\n");
12196                ast_frfree(f);
12197                break;
12198             }
12199             /* if RX key */
12200             if (f->subclass.integer == AST_CONTROL_RADIO_KEY)
12201             {
12202                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink)) 
12203                {
12204                   if (debug == 7) printf("@@@@ rx key\n");
12205                   myrpt->keyed = 1;
12206                   time(&myrpt->lastkeyedtime);
12207                   myrpt->keyposttimer = KEYPOSTSHORTTIME;
12208                }
12209                if (myrpt->p.archivedir)
12210                {
12211                   donodelog(myrpt,"RXKEY,MAIN");
12212                }
12213                if (f->datalen && f->data.ptr)
12214                {
12215                   char busy = 0;
12216 
12217                   if (debug) ast_log(LOG_NOTICE,"Got PL %s on node %s\n",(char *)f->data.ptr,myrpt->name);
12218                   // ctcss code autopatch initiate
12219                   if (strstr((char *)f->data.ptr,"/M/")&& !myrpt->macropatch)
12220                   {
12221                      char value[16] = "";
12222                      strcat(value,"*6");
12223                      myrpt->macropatch=1;
12224                      rpt_mutex_lock(&myrpt->lock);
12225                      if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(value)){
12226                         rpt_mutex_unlock(&myrpt->lock);
12227                         busy=1;
12228                      }
12229                      if(!busy){
12230                         myrpt->macrotimer = MACROTIME;
12231                         strncat(myrpt->macrobuf,value,MAXMACRO - 1);
12232                         if (!busy) strcpy(myrpt->lasttone,(char*)f->data.ptr);
12233                      }
12234                      rpt_mutex_unlock(&myrpt->lock);
12235                   }
12236                   else if (strcmp((char *)f->data.ptr,myrpt->lasttone))
12237                   {
12238                      char *value = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.tonemacro, (char *)f->data.ptr);
12239                      if (value)
12240                      {
12241                         if (debug) ast_log(LOG_NOTICE,"Tone %s doing %s on node %s\n",(char *) f->data.ptr,value,myrpt->name);
12242                         rpt_mutex_lock(&myrpt->lock);
12243                         if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(value)){
12244                            rpt_mutex_unlock(&myrpt->lock);
12245                            busy=1;
12246                         }
12247                         if(!busy){
12248                            myrpt->macrotimer = MACROTIME;
12249                            strncat(myrpt->macrobuf,value,MAXMACRO - 1);
12250                         }
12251                         rpt_mutex_unlock(&myrpt->lock);
12252                      }
12253                      if (!busy) strcpy(myrpt->lasttone,(char*)f->data.ptr);
12254                   }
12255                } else myrpt->lasttone[0] = 0;
12256             }
12257             /* if RX un-key */
12258             if (f->subclass.integer == AST_CONTROL_RADIO_UNKEY)
12259             {
12260                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
12261                {
12262                   if (debug == 7) printf("@@@@ rx un-key\n");
12263                   if(myrpt->p.duplex && myrpt->keyed) {
12264                      rpt_telemetry(myrpt,UNKEY,NULL);
12265                   }
12266                }
12267                myrpt->keyed = 0;
12268                time(&myrpt->lastkeyedtime);
12269                myrpt->keyposttimer = KEYPOSTSHORTTIME;
12270                if (myrpt->p.archivedir)
12271                {
12272                   donodelog(myrpt,"RXUNKEY,MAIN");
12273                }
12274             }
12275          }
12276          ast_frfree(f);
12277          continue;
12278       }
12279       if (who == myrpt->pchannel) /* if it was a read from pseudo */
12280       {
12281          f = ast_read(myrpt->pchannel);
12282          if (!f)
12283          {
12284             if (debug) printf("@@@@ rpt:Hung Up\n");
12285             break;
12286          }
12287          if (f->frametype == AST_FRAME_VOICE)
12288          {
12289             ast_write(myrpt->txpchannel,f);
12290          }
12291          if (f->frametype == AST_FRAME_CONTROL)
12292          {
12293             if (f->subclass.integer == AST_CONTROL_HANGUP)
12294             {
12295                if (debug) printf("@@@@ rpt:Hung Up\n");
12296                ast_frfree(f);
12297                break;
12298             }
12299          }
12300          ast_frfree(f);
12301          continue;
12302       }
12303       if (who == myrpt->txchannel) /* if it was a read from tx */
12304       {
12305          f = ast_read(myrpt->txchannel);
12306          if (!f)
12307          {
12308             if (debug) printf("@@@@ rpt:Hung Up\n");
12309             break;
12310          }
12311          if (f->frametype == AST_FRAME_CONTROL)
12312          {
12313             if (f->subclass.integer == AST_CONTROL_HANGUP)
12314             {
12315                if (debug) printf("@@@@ rpt:Hung Up\n");
12316                ast_frfree(f);
12317                break;
12318             }
12319          }
12320          ast_frfree(f);
12321          continue;
12322       }
12323       if (who == myrpt->dahditxchannel) /* if it was a read from pseudo-tx */
12324       {
12325          f = ast_read(myrpt->dahditxchannel);
12326          if (!f)
12327          {
12328             if (debug) printf("@@@@ rpt:Hung Up\n");
12329             break;
12330          }
12331          if (f->frametype == AST_FRAME_VOICE)
12332          {
12333             struct ast_frame *vframe;
12334 
12335             if (myrpt->p.duplex < 2)
12336             {
12337                if (myrpt->txrealkeyed) 
12338                {
12339                   if ((!myfirst) && myrpt->callmode)
12340                   {
12341                       x = 0;
12342                       AST_LIST_TRAVERSE(&myrpt->txq, vframe,
12343                      frame_list) x++;
12344                       for(;x < myrpt->p.simplexpatchdelay; x++)
12345                       {
12346                         vframe = ast_frdup(f);
12347                         memset(vframe->data.ptr,0,vframe->datalen);
12348                         AST_LIST_INSERT_TAIL(&myrpt->txq,vframe,frame_list);
12349                       }
12350                       myfirst = 1;
12351                   }
12352                   vframe = ast_frdup(f);
12353                   AST_LIST_INSERT_TAIL(&myrpt->txq,
12354                      vframe,frame_list);
12355                } else myfirst = 0;
12356                x = 0;
12357                AST_LIST_TRAVERSE(&myrpt->txq, vframe,
12358                   frame_list) x++;
12359                if (!x)
12360                {
12361                   memset(f->data.ptr,0,f->datalen);
12362                }
12363                else
12364                {
12365                   ast_frfree(f);
12366                   f = AST_LIST_REMOVE_HEAD(&myrpt->txq,
12367                      frame_list);
12368                }
12369             }
12370             else
12371             {
12372                while((vframe = AST_LIST_REMOVE_HEAD(&myrpt->txq,
12373                   frame_list))) ast_frfree(vframe);
12374             }
12375             ast_write(myrpt->txchannel,f);
12376          }
12377          if (f->frametype == AST_FRAME_CONTROL)
12378          {
12379             if (f->subclass.integer == AST_CONTROL_HANGUP)
12380             {
12381                if (debug) printf("@@@@ rpt:Hung Up\n");
12382                ast_frfree(f);
12383                break;
12384             }
12385          }
12386          ast_frfree(f);
12387          continue;
12388       }
12389       toexit = 0;
12390       rpt_mutex_lock(&myrpt->lock);
12391       l = myrpt->links.next;
12392       while(l != &myrpt->links)
12393       {
12394          int remnomute;
12395          struct timeval now;
12396 
12397          if (l->disctime)
12398          {
12399             l = l->next;
12400             continue;
12401          }
12402 
12403          remrx = 0;
12404          /* see if any other links are receiving */
12405          m = myrpt->links.next;
12406          while(m != &myrpt->links)
12407          {
12408             /* if not us, count it */
12409             if ((m != l) && (m->lastrx)) remrx = 1;
12410             m = m->next;
12411          }
12412          rpt_mutex_unlock(&myrpt->lock);
12413          now = ast_tvnow();
12414          if ((who == l->chan) || (!l->lastlinktv.tv_sec) ||
12415             (ast_tvdiff_ms(now,l->lastlinktv) >= 19))
12416          {
12417             l->lastlinktv = now;
12418             remnomute = myrpt->localtx && 
12419                 (!(myrpt->cmdnode[0] || 
12420                (myrpt->dtmfidx > -1)));
12421             totx = (((l->isremote) ? (remnomute) : 
12422                myrpt->exttx) || remrx) && l->mode;
12423             if (l->phonemode == 0 && l->chan && (l->lasttx != totx))
12424             {
12425                if (totx)
12426                {
12427                   ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
12428                }
12429                else
12430                {
12431                   ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
12432                }
12433                if (myrpt->p.archivedir)
12434                {
12435                   char str[100];
12436 
12437                   if (totx)
12438                      sprintf(str,"TXKEY,%s",l->name);
12439                   else
12440                      sprintf(str,"TXUNKEY,%s",l->name);
12441                   donodelog(myrpt,str);
12442                }
12443             }
12444             l->lasttx = totx;
12445          }
12446          rpt_mutex_lock(&myrpt->lock);
12447          if (who == l->chan) /* if it was a read from rx */
12448          {
12449             rpt_mutex_unlock(&myrpt->lock);
12450             f = ast_read(l->chan);
12451             if (!f)
12452             {
12453                rpt_mutex_lock(&myrpt->lock);
12454                __kickshort(myrpt);
12455                rpt_mutex_unlock(&myrpt->lock);
12456                if ((!l->disced) && (!l->outbound))
12457                {
12458                   if ((l->name[0] == '0') || l->isremote)
12459                      l->disctime = 1;
12460                   else
12461                      l->disctime = DISC_TIME;
12462                   rpt_mutex_lock(&myrpt->lock);
12463                   ast_hangup(l->chan);
12464                   l->chan = 0;
12465                   break;
12466                }
12467 
12468                if (l->retrytimer) 
12469                {
12470                   ast_hangup(l->chan);
12471                   l->chan = 0;
12472                   rpt_mutex_lock(&myrpt->lock);
12473                   break; 
12474                }
12475                if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
12476                {
12477                   rpt_mutex_lock(&myrpt->lock);
12478                   if (l->chan) ast_hangup(l->chan);
12479                   l->chan = 0;
12480                   l->hasconnected = 1;
12481                   l->retrytimer = RETRY_TIMER_MS;
12482                   l->elaptime = 0;
12483                   l->connecttime = 0;
12484                   l->thisconnected = 0;
12485                   break;
12486                }
12487                rpt_mutex_lock(&myrpt->lock);
12488                /* remove from queue */
12489                remque((struct qelem *) l);
12490                if (!strcmp(myrpt->cmdnode,l->name))
12491                   myrpt->cmdnode[0] = 0;
12492                __kickshort(myrpt);
12493                rpt_mutex_unlock(&myrpt->lock);
12494                if (!l->hasconnected)
12495                   rpt_telemetry(myrpt,CONNFAIL,l);
12496                else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
12497                if (myrpt->p.archivedir)
12498                {
12499                   char str[100];
12500 
12501                   if (!l->hasconnected)
12502                      sprintf(str,"LINKFAIL,%s",l->name);
12503                   else
12504                      sprintf(str,"LINKDISC,%s",l->name);
12505                   donodelog(myrpt,str);
12506                }
12507                if (l->lastf1) ast_frfree(l->lastf1);
12508                l->lastf1 = NULL;
12509                if (l->lastf2) ast_frfree(l->lastf2);
12510                l->lastf2 = NULL;
12511                /* hang-up on call to device */
12512                ast_hangup(l->chan);
12513                ast_hangup(l->pchan);
12514                ast_free(l);
12515                rpt_mutex_lock(&myrpt->lock);
12516                break;
12517             }
12518             if (f->frametype == AST_FRAME_VOICE)
12519             {
12520                int ismuted,n1;
12521 
12522                if ((l->phonemode) && (l->phonevox))
12523                {
12524                   n1 = dovox(&l->vox,
12525                      f->data.ptr,f->datalen / 2);
12526                   if (n1 != l->wasvox)
12527                   {
12528                      ast_debug(1,"Link Node %s, vox %d\n",l->name,n1);
12529                      l->wasvox = n1;
12530                      l->voxtostate = 0;
12531                      if (n1) l->voxtotimer = myrpt->p.voxtimeout_ms;
12532                      else l->voxtotimer = 0;
12533                   }
12534                   if (l->lastrealrx || n1)
12535                   {
12536                      if (!myfirst)
12537                      {
12538                          x = 0;
12539                          AST_LIST_TRAVERSE(&l->rxq, f1,
12540                         frame_list) x++;
12541                          for(;x < myrpt->p.simplexphonedelay; x++)
12542                         {
12543                            f1 = ast_frdup(f);
12544                            memset(f1->data.ptr,0,f1->datalen);
12545                            AST_LIST_INSERT_TAIL(&l->rxq,
12546                               f1,frame_list);
12547                          }
12548                          myfirst = 1;
12549                      }
12550                      f1 = ast_frdup(f);
12551                      AST_LIST_INSERT_TAIL(&l->rxq,f1,frame_list);
12552                   } else myfirst = 0; 
12553                   x = 0;
12554                   AST_LIST_TRAVERSE(&l->rxq, f1,frame_list) x++;
12555                   if (!x)
12556                   {
12557                      memset(f->data.ptr,0,f->datalen);
12558                   }
12559                   else
12560                   {
12561                      ast_frfree(f);
12562                      f = AST_LIST_REMOVE_HEAD(&l->rxq,frame_list);
12563                   }
12564                   if (ioctl(l->chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
12565                   {
12566                      ismuted = 0;
12567                   }
12568                   /* if not receiving, zero-out audio */
12569                   ismuted |= (!l->lastrx);
12570                   if (l->dtmfed && l->phonemode) ismuted = 1;
12571                   l->dtmfed = 0;
12572                   if (ismuted)
12573                   {
12574                      memset(f->data.ptr,0,f->datalen);
12575                      if (l->lastf1)
12576                         memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12577                      if (l->lastf2)
12578                         memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12579                   } 
12580                   if (f) f2 = ast_frdup(f);
12581                   else f2 = NULL;
12582                   f1 = l->lastf2;
12583                   l->lastf2 = l->lastf1;
12584                   l->lastf1 = f2;
12585                   if (ismuted)
12586                   {
12587                      if (l->lastf1)
12588                         memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12589                      if (l->lastf2)
12590                         memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12591                   }
12592                   if (f1)
12593                   {
12594                      ast_write(l->pchan,f1);
12595                      ast_frfree(f1);
12596                   }
12597                }
12598                else
12599                {
12600                   if (!l->lastrx)
12601                      memset(f->data.ptr,0,f->datalen);
12602                   ast_write(l->pchan,f);
12603                }
12604             }
12605 #ifndef  OLD_ASTERISK
12606             else if (f->frametype == AST_FRAME_DTMF_BEGIN)
12607             {
12608                if (l->lastf1)
12609                   memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12610                if (l->lastf2)
12611                   memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12612                l->dtmfed = 1;
12613             }
12614 #endif
12615             if (f->frametype == AST_FRAME_TEXT)
12616             {
12617                handle_link_data(myrpt,l,f->data.ptr);
12618             }
12619             if (f->frametype == AST_FRAME_DTMF)
12620             {
12621                if (l->lastf1)
12622                   memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12623                if (l->lastf2)
12624                   memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12625                l->dtmfed = 1;
12626                handle_link_phone_dtmf(myrpt,l,f->subclass.integer);
12627             }
12628             if (f->frametype == AST_FRAME_CONTROL)
12629             {
12630                if (f->subclass.integer == AST_CONTROL_ANSWER)
12631                {
12632                   char lconnected = l->connected;
12633 
12634                   __kickshort(myrpt);
12635                   l->connected = 1;
12636                   l->hasconnected = 1;
12637                   l->thisconnected = 1;
12638                   l->elaptime = -1;
12639                   if (!l->phonemode) send_newkey(l->chan);
12640                   if (!l->isremote) l->retries = 0;
12641                   if (!lconnected) 
12642                   {
12643                      rpt_telemetry(myrpt,CONNECTED,l);
12644                      if (myrpt->p.archivedir)
12645                      {
12646                         char str[100];
12647 
12648                         if (l->mode)
12649                            sprintf(str,"LINKTRX,%s",l->name);
12650                         else
12651                            sprintf(str,"LINKMONITOR,%s",l->name);
12652                         donodelog(myrpt,str);
12653                      }
12654                   }     
12655                   else
12656                      l->reconnects++;
12657                }
12658                /* if RX key */
12659                if (f->subclass.integer == AST_CONTROL_RADIO_KEY)
12660                {
12661                   if (debug == 7 ) printf("@@@@ rx key\n");
12662                   l->lastrealrx = 1;
12663                   l->rerxtimer = 0;
12664                   if (!l->lastrx1)
12665                   {
12666                      if (myrpt->p.archivedir)
12667                      {
12668                         char str[100];
12669 
12670                         sprintf(str,"RXKEY,%s",l->name);
12671                         donodelog(myrpt,str);
12672                      }
12673                      l->lastrx1 = 1;
12674                   }
12675                }
12676                /* if RX un-key */
12677                if (f->subclass.integer == AST_CONTROL_RADIO_UNKEY)
12678                {
12679                   if (debug == 7) printf("@@@@ rx un-key\n");
12680                   l->lastrealrx = 0;
12681                   l->rerxtimer = 0;
12682                   if (l->lastrx1)
12683                   {
12684                      if (myrpt->p.archivedir)
12685                      {
12686                         char str[100];
12687 
12688                         sprintf(str,"RXUNKEY,%s",l->name);
12689                         donodelog(myrpt,str);
12690                      }
12691                      l->lastrx1 = 0;
12692                      if(myrpt->p.duplex) 
12693                         rpt_telemetry(myrpt,LINKUNKEY,l);
12694                   }
12695                }
12696                if (f->subclass.integer == AST_CONTROL_HANGUP)
12697                {
12698                   ast_frfree(f);
12699                   rpt_mutex_lock(&myrpt->lock);
12700                   __kickshort(myrpt);
12701                   rpt_mutex_unlock(&myrpt->lock);
12702                   if ((!l->outbound) && (!l->disced))
12703                   {
12704                      if ((l->name[0] == '0') || l->isremote)
12705                         l->disctime = 1;
12706                      else
12707                         l->disctime = DISC_TIME;
12708                      rpt_mutex_lock(&myrpt->lock);
12709                      ast_hangup(l->chan);
12710                      l->chan = 0;
12711                      break;
12712                   }
12713                   if (l->retrytimer) 
12714                   {
12715                      if (l->chan) ast_hangup(l->chan);
12716                      l->chan = 0;
12717                      rpt_mutex_lock(&myrpt->lock);
12718                      break;
12719                   }
12720                   if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
12721                   {
12722                      rpt_mutex_lock(&myrpt->lock);
12723                      if (l->chan) ast_hangup(l->chan);
12724                      l->chan = 0;
12725                      l->hasconnected = 1;
12726                      l->elaptime = 0;
12727                      l->retrytimer = RETRY_TIMER_MS;
12728                      l->connecttime = 0;
12729                      l->thisconnected = 0;
12730                      break;
12731                   }
12732                   rpt_mutex_lock(&myrpt->lock);
12733                   /* remove from queue */
12734                   remque((struct qelem *) l);
12735                   if (!strcmp(myrpt->cmdnode,l->name))
12736                      myrpt->cmdnode[0] = 0;
12737                   __kickshort(myrpt);
12738                   rpt_mutex_unlock(&myrpt->lock);
12739                   if (!l->hasconnected)
12740                      rpt_telemetry(myrpt,CONNFAIL,l);
12741                   else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
12742                   if (myrpt->p.archivedir)
12743                   {
12744                      char str[100];
12745 
12746                      if (!l->hasconnected)
12747                         sprintf(str,"LINKFAIL,%s",l->name);
12748                      else
12749                         sprintf(str,"LINKDISC,%s",l->name);
12750                      donodelog(myrpt,str);
12751                   }
12752                   if (l->lastf1) ast_frfree(l->lastf1);
12753                   l->lastf1 = NULL;
12754                   if (l->lastf2) ast_frfree(l->lastf2);
12755                   l->lastf2 = NULL;
12756                   /* hang-up on call to device */
12757                   ast_hangup(l->chan);
12758                   ast_hangup(l->pchan);
12759                   ast_free(l);
12760                   rpt_mutex_lock(&myrpt->lock);
12761                   break;
12762                }
12763             }
12764             ast_frfree(f);
12765             rpt_mutex_lock(&myrpt->lock);
12766             break;
12767          }
12768          if (who == l->pchan) 
12769          {
12770             rpt_mutex_unlock(&myrpt->lock);
12771             f = ast_read(l->pchan);
12772             if (!f)
12773             {
12774                if (debug) printf("@@@@ rpt:Hung Up\n");
12775                toexit = 1;
12776                rpt_mutex_lock(&myrpt->lock);
12777                break;
12778             }
12779             if (f->frametype == AST_FRAME_VOICE)
12780             {
12781                if (l->chan) ast_write(l->chan,f);
12782             }
12783             if (f->frametype == AST_FRAME_CONTROL)
12784             {
12785                if (f->subclass.integer == AST_CONTROL_HANGUP)
12786                {
12787                   if (debug) printf("@@@@ rpt:Hung Up\n");
12788                   ast_frfree(f);
12789                   toexit = 1;
12790                   rpt_mutex_lock(&myrpt->lock);
12791                   break;
12792                }
12793             }
12794             ast_frfree(f);
12795             rpt_mutex_lock(&myrpt->lock);
12796             break;
12797          }
12798          l = l->next;
12799       }
12800       rpt_mutex_unlock(&myrpt->lock);
12801       if (toexit) break;
12802       if (who == myrpt->monchannel) 
12803       {
12804          f = ast_read(myrpt->monchannel);
12805          if (!f)
12806          {
12807             if (debug) printf("@@@@ rpt:Hung Up\n");
12808             break;
12809          }
12810          if (f->frametype == AST_FRAME_VOICE)
12811          {
12812             if (myrpt->monstream) 
12813                ast_writestream(myrpt->monstream,f);
12814          }
12815          if (f->frametype == AST_FRAME_CONTROL)
12816          {
12817             if (f->subclass.integer == AST_CONTROL_HANGUP)
12818             {
12819                if (debug) printf("@@@@ rpt:Hung Up\n");
12820                ast_frfree(f);
12821                break;
12822             }
12823          }
12824          ast_frfree(f);
12825          continue;
12826       }
12827       if (myrpt->parrotchannel && (who == myrpt->parrotchannel))
12828       {
12829          f = ast_read(myrpt->parrotchannel);
12830          if (!f)
12831          {
12832             if (debug) printf("@@@@ rpt:Hung Up\n");
12833             break;
12834          }
12835          if (!myrpt->p.parrotmode)
12836          {
12837             char myfname[300];
12838 
12839             if (myrpt->parrotstream)
12840             {
12841                ast_closestream(myrpt->parrotstream);
12842                myrpt->parrotstream = 0;
12843             }
12844             sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
12845             strcat(myfname,".wav");
12846             unlink(myfname);        
12847          } else if (f->frametype == AST_FRAME_VOICE)
12848          {
12849             if (myrpt->parrotstream) 
12850                ast_writestream(myrpt->parrotstream,f);
12851          }
12852          if (f->frametype == AST_FRAME_CONTROL)
12853          {
12854             if (f->subclass.integer == AST_CONTROL_HANGUP)
12855             {
12856                if (debug) printf("@@@@ rpt:Hung Up\n");
12857                ast_frfree(f);
12858                break;
12859             }
12860          }
12861          ast_frfree(f);
12862          continue;
12863       }
12864       if (myrpt->voxchannel && (who == myrpt->voxchannel))
12865       {
12866          f = ast_read(myrpt->voxchannel);
12867          if (!f)
12868          {
12869             if (debug) printf("@@@@ rpt:Hung Up\n");
12870             break;
12871          }
12872          if (f->frametype == AST_FRAME_VOICE)
12873          {
12874             n = dovox(&myrpt->vox,f->data.ptr,f->datalen / 2);
12875             if (n != myrpt->wasvox)
12876             {
12877                ast_debug(1,"Node %s, vox %d\n",myrpt->name,n);
12878                myrpt->wasvox = n;
12879                myrpt->voxtostate = 0;
12880                if (n) myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
12881                else myrpt->voxtotimer = 0;
12882             }
12883          }
12884          if (f->frametype == AST_FRAME_CONTROL)
12885          {
12886             if (f->subclass.integer == AST_CONTROL_HANGUP)
12887             {
12888                if (debug) printf("@@@@ rpt:Hung Up\n");
12889                ast_frfree(f);
12890                break;
12891             }
12892          }
12893          ast_frfree(f);
12894          continue;
12895       }
12896       if (who == myrpt->txpchannel) /* if it was a read from remote tx */
12897       {
12898          f = ast_read(myrpt->txpchannel);
12899          if (!f)
12900          {
12901             if (debug) printf("@@@@ rpt:Hung Up\n");
12902             break;
12903          }
12904          if (f->frametype == AST_FRAME_CONTROL)
12905          {
12906             if (f->subclass.integer == AST_CONTROL_HANGUP)
12907             {
12908                if (debug) printf("@@@@ rpt:Hung Up\n");
12909                ast_frfree(f);
12910                break;
12911             }
12912          }
12913          ast_frfree(f);
12914          continue;
12915       }
12916    }
12917    usleep(100000);
12918    ast_hangup(myrpt->pchannel);
12919    ast_hangup(myrpt->monchannel);
12920    if (myrpt->parrotchannel) ast_hangup(myrpt->parrotchannel);
12921    myrpt->parrotstate = 0;
12922    if (myrpt->voxchannel) ast_hangup(myrpt->voxchannel);
12923    ast_hangup(myrpt->txpchannel);
12924    if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
12925    if (myrpt->dahditxchannel != myrpt->txchannel) ast_hangup(myrpt->dahditxchannel);
12926    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
12927    myrpt->lastf1 = NULL;
12928    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
12929    myrpt->lastf2 = NULL;
12930    ast_hangup(myrpt->rxchannel);
12931    rpt_mutex_lock(&myrpt->lock);
12932    l = myrpt->links.next;
12933    while(l != &myrpt->links)
12934    {
12935       struct rpt_link *ll = l;
12936       /* remove from queue */
12937       remque((struct qelem *) l);
12938       /* hang-up on call to device */
12939       if (l->chan) ast_hangup(l->chan);
12940       ast_hangup(l->pchan);
12941       l = l->next;
12942       ast_free(ll);
12943    }
12944    if (myrpt->xlink  == 1) myrpt->xlink = 2;
12945    rpt_mutex_unlock(&myrpt->lock);
12946    if (debug) printf("@@@@ rpt:Hung up channel\n");
12947    myrpt->rpt_thread = AST_PTHREADT_STOP;
12948    pthread_exit(NULL); 
12949    return NULL;
12950 }
12951 
12952    
12953 static void *rpt_master(void *ignore)
12954 {
12955 int   i,n;
12956 pthread_attr_t attr;
12957 struct ast_config *cfg;
12958 char *this,*val;
12959 
12960    /* init nodelog queue */
12961    nodelog.next = nodelog.prev = &nodelog;
12962    /* go thru all the specified repeaters */
12963    this = NULL;
12964    n = 0;
12965 #ifndef OLD_ASTERISK
12966    /* wait until asterisk starts */
12967         while(!ast_test_flag(&ast_options,AST_OPT_FLAG_FULLY_BOOTED))
12968                 usleep(250000);
12969 #endif
12970 #ifdef   NEW_ASTERISK
12971    rpt_vars[n].cfg = ast_config_load("rpt.conf",config_flags);
12972 #else
12973    rpt_vars[n].cfg = ast_config_load("rpt.conf");
12974 #endif
12975    cfg = rpt_vars[n].cfg;
12976    if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
12977       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
12978       pthread_exit(NULL);
12979    }
12980    while((this = ast_category_browse(cfg,this)) != NULL)
12981    {
12982       for(i = 0 ; i < strlen(this) ; i++){
12983          if((this[i] < '0') || (this[i] > '9'))
12984             break;
12985       }
12986       if(i != strlen(this)) continue; /* Not a node defn */
12987       memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
12988       rpt_vars[n].name = ast_strdup(this);
12989       val = (char *) ast_variable_retrieve(cfg,this,"rxchannel");
12990       if (val) rpt_vars[n].rxchanname = ast_strdup(val);
12991       val = (char *) ast_variable_retrieve(cfg,this,"txchannel");
12992       if (val) rpt_vars[n].txchanname = ast_strdup(val);
12993       rpt_vars[n].remote = 0;
12994       rpt_vars[n].remoterig = "";
12995       val = (char *) ast_variable_retrieve(cfg,this,"remote");
12996       if (val) 
12997       {
12998          rpt_vars[n].remoterig = ast_strdup(val);
12999          rpt_vars[n].remote = 1;
13000       }
13001       val = (char *) ast_variable_retrieve(cfg,this,"radiotype");
13002       if (val) rpt_vars[n].remoterig = ast_strdup(val);
13003       ast_mutex_init(&rpt_vars[n].lock);
13004       ast_mutex_init(&rpt_vars[n].remlock);
13005       ast_mutex_init(&rpt_vars[n].statpost_lock);
13006       rpt_vars[n].tele.next = &rpt_vars[n].tele;
13007       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
13008       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
13009       rpt_vars[n].tailmessagen = 0;
13010 #ifdef   _MDC_DECODE_H_
13011       rpt_vars[n].mdc = mdc_decoder_new(8000);
13012 #endif
13013       n++;
13014    }
13015    nrpts = n;
13016    ast_config_destroy(cfg);
13017 
13018    /* start em all */
13019    for(i = 0; i < n; i++)
13020    {
13021       load_rpt_vars(i,1);
13022 
13023       /* if is a remote, don't start one for it */
13024       if (rpt_vars[i].remote)
13025       {
13026          if(retreive_memory(&rpt_vars[i],"init")){ /* Try to retreive initial memory channel */
13027             if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx450))
13028                strncpy(rpt_vars[i].freq, "446.500", sizeof(rpt_vars[i].freq) - 1);
13029             else
13030                strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
13031             strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
13032 
13033             strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
13034             rpt_vars[i].remmode = REM_MODE_FM;
13035             rpt_vars[i].offset = REM_SIMPLEX;
13036             rpt_vars[i].powerlevel = REM_LOWPWR;
13037          }
13038          continue;
13039       }
13040       else /* is a normal repeater */
13041       {
13042           rpt_vars[i].p.memory = rpt_vars[i].name;
13043          if(retreive_memory(&rpt_vars[i],"radiofreq")){ /* Try to retreive initial memory channel */
13044             if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx450))
13045                strncpy(rpt_vars[i].freq, "446.500", sizeof(rpt_vars[i].freq) - 1);
13046             else if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx150))
13047                strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
13048             strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
13049 
13050             strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
13051             rpt_vars[i].remmode = REM_MODE_FM;
13052             rpt_vars[i].offset = REM_SIMPLEX;
13053             rpt_vars[i].powerlevel = REM_LOWPWR;
13054          }
13055          ast_log(LOG_NOTICE,"Normal Repeater Init  %s  %s  %s\n",rpt_vars[i].name, rpt_vars[i].remoterig, rpt_vars[i].freq);
13056       }
13057       if (!rpt_vars[i].p.ident)
13058       {
13059          ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
13060          ast_config_destroy(cfg);
13061          pthread_exit(NULL);
13062       }
13063            pthread_attr_init(&attr);
13064            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13065       ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
13066    }
13067    usleep(500000);
13068    time(&starttime);
13069    for(;;)
13070    {
13071       /* Now monitor each thread, and restart it if necessary */
13072       for(i = 0; i < n; i++)
13073       { 
13074          int rv;
13075          if (rpt_vars[i].remote) continue;
13076          if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP) 
13077             rv = -1;
13078          else
13079             rv = pthread_kill(rpt_vars[i].rpt_thread,0);
13080          if (rv)
13081          {
13082             if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15)
13083             {
13084                if(rpt_vars[i].threadrestarts >= 5)
13085                {
13086                   ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n");
13087                   exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
13088                }
13089                else
13090                {
13091                   ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name);
13092                   rpt_vars[i].threadrestarts++;
13093                }
13094             }
13095             else
13096                rpt_vars[i].threadrestarts = 0;
13097 
13098             rpt_vars[i].lastthreadrestarttime = time(NULL);
13099                  pthread_attr_init(&attr);
13100                  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13101             ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
13102             /* if (!rpt_vars[i].xlink) */
13103                ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
13104          }
13105 
13106       }
13107       for(;;)
13108       {
13109          struct nodelog *nodep;
13110          char *space,datestr[100],fname[300];
13111          int fd;
13112 
13113          ast_mutex_lock(&nodeloglock);
13114          nodep = nodelog.next;
13115          if(nodep == &nodelog) /* if nothing in queue */
13116          {
13117             ast_mutex_unlock(&nodeloglock);
13118             break;
13119          }
13120          remque((struct qelem *)nodep);
13121          ast_mutex_unlock(&nodeloglock);
13122          space = strchr(nodep->str,' ');
13123          if (!space) 
13124          {
13125             ast_free(nodep);
13126             continue;
13127          }
13128          *space = 0;
13129          strftime(datestr,sizeof(datestr) - 1,"%Y%m%d",
13130             localtime(&nodep->timestamp));
13131          sprintf(fname,"%s/%s/%s.txt",nodep->archivedir,
13132             nodep->str,datestr);
13133          fd = open(fname,O_WRONLY | O_CREAT | O_APPEND,0600);
13134          if (fd == -1)
13135          {
13136             ast_log(LOG_ERROR,"Cannot open node log file %s for write",space + 1);
13137             ast_free(nodep);
13138             continue;
13139          }
13140          if (write(fd,space + 1,strlen(space + 1)) !=
13141             strlen(space + 1))
13142          {
13143             ast_log(LOG_ERROR,"Cannot write node log file %s for write",space + 1);
13144             ast_free(nodep);
13145             continue;
13146          }
13147          close(fd);
13148          ast_free(nodep);
13149       }
13150       sleep(2);
13151    }
13152    ast_config_destroy(cfg);
13153    pthread_exit(NULL);
13154 }
13155 
13156 static int rpt_exec(struct ast_channel *chan, const char *data)
13157 {
13158    int res=-1,i,rem_totx,rem_rx,remkeyed,n,phone_mode = 0;
13159    int iskenwood_pci4,authtold,authreq,setting,notremming,reming;
13160    int ismuted,dtmfed,phone_vox = 0;
13161 #ifdef   OLD_ASTERISK
13162    struct localuser *u;
13163 #endif
13164    char tmp[256], keyed = 0,keyed1 = 0;
13165    char *options,*stringp,*tele,c,*altp,*memp;
13166    char sx[320],*sy;
13167    struct   rpt *myrpt;
13168    struct ast_frame *f,*f1,*f2;
13169    struct ast_channel *who;
13170    struct ast_channel *cs[20];
13171    struct   rpt_link *l;
13172    struct dahdi_confinfo ci;  /* conference info */
13173    struct dahdi_params par;
13174    int ms,elap,nullfd;
13175    time_t t,last_timeout_warning;
13176    struct   dahdi_radio_param z;
13177    struct rpt_tele *telem;
13178    int   numlinks;
13179    struct ast_format_cap *cap = NULL;
13180 
13181    nullfd = open("/dev/null",O_RDWR);
13182    if (ast_strlen_zero(data)) {
13183       ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
13184       return -1;
13185    }
13186 
13187    strncpy(tmp, (char *)data, sizeof(tmp)-1);
13188    time(&t);
13189    /* if time has externally shifted negative, screw it */
13190    if (t < starttime) t = starttime + START_DELAY;
13191    if ((!starttime) || (t < (starttime + START_DELAY)))
13192    {
13193       ast_log(LOG_NOTICE,"Node %s rejecting call: too soon!\n",tmp);
13194       ast_safe_sleep(chan,3000);
13195       return -1;
13196    }
13197 
13198    ast_log(LOG_NOTICE,"parsing argument=%s \n",tmp);
13199 
13200    altp=strstr(tmp, "|*");
13201    if(altp){
13202       altp[0]=0;
13203       altp++;
13204     }
13205 
13206    memp=strstr(tmp, "|M");
13207    if(memp){
13208       memp[0]=0;
13209       memp+=2;
13210     }
13211 
13212    stringp=tmp;
13213    strsep(&stringp, "|");
13214    options = stringp;
13215 
13216    ast_log(LOG_NOTICE,"options=%s \n",options);
13217    if(memp>0)ast_log(LOG_NOTICE,"memp=%s \n",memp);
13218    if(altp>0)ast_log(LOG_NOTICE,"altp=%s \n",altp);
13219 
13220    myrpt = NULL;
13221    /* see if we can find our specified one */
13222    for(i = 0; i < nrpts; i++)
13223    {
13224       /* if name matches, assign it and exit loop */
13225       if (!strcmp(tmp,rpt_vars[i].name))
13226       {
13227          myrpt = &rpt_vars[i];
13228          break;
13229       }
13230    }
13231 
13232    pbx_builtin_setvar_helper(chan, "RPT_STAT_ERR", "");
13233 
13234    if (myrpt == NULL)
13235    {
13236       pbx_builtin_setvar_helper(chan, "RPT_STAT_ERR", "NODE_NOT_FOUND");
13237       ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
13238       return (priority_jump(NULL,chan));
13239    }
13240 
13241    numlinks=linkcount(myrpt);
13242 
13243    if(options && *options == 'q')
13244    {
13245       char buf2[128];
13246 
13247       if(myrpt->keyed)
13248          pbx_builtin_setvar_helper(chan, "RPT_STAT_RXKEYED", "1");
13249       else
13250          pbx_builtin_setvar_helper(chan, "RPT_STAT_RXKEYED", "0");   
13251 
13252       if(myrpt->txkeyed)
13253          pbx_builtin_setvar_helper(chan, "RPT_STAT_TXKEYED", "1");
13254       else
13255          pbx_builtin_setvar_helper(chan, "RPT_STAT_TXKEYED", "0");   
13256 
13257       snprintf(buf2,sizeof(buf2),"%s=%i", "RPT_STAT_XLINK", myrpt->xlink);
13258       pbx_builtin_setvar(chan, buf2);
13259       snprintf(buf2,sizeof(buf2),"%s=%i", "RPT_STAT_LINKS", numlinks);
13260       pbx_builtin_setvar(chan, buf2);
13261       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_WASCHAN", myrpt->waschan);
13262       pbx_builtin_setvar(chan, buf2);
13263       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_NOWCHAN", myrpt->nowchan);
13264       pbx_builtin_setvar(chan, buf2);
13265       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_DUPLEX", myrpt->p.duplex);
13266       pbx_builtin_setvar(chan, buf2);
13267       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_PARROT", myrpt->p.parrotmode);
13268       pbx_builtin_setvar(chan, buf2);
13269       //snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_PHONEVOX", myrpt->phonevox);
13270       //pbx_builtin_setvar(chan, buf2);
13271       //snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_CONNECTED", myrpt->connected);
13272       //pbx_builtin_setvar(chan, buf2);
13273       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_CALLMODE", myrpt->callmode);
13274       pbx_builtin_setvar(chan, buf2);
13275       snprintf(buf2,sizeof(buf2),"%s=%s", "RPT_STAT_LASTTONE", myrpt->lasttone);
13276       pbx_builtin_setvar(chan, buf2);
13277 
13278       return priority_jump(myrpt,chan);
13279    }
13280 
13281    if(options && *options == 'o')
13282    {
13283       return(channel_revert(myrpt));
13284    }
13285 
13286    #if 0
13287    if((altp)&&(*options == 'Z'))
13288    {
13289       rpt_push_alt_macro(myrpt,altp);
13290       return 0;
13291    }
13292    #endif
13293 
13294 
13295    /* if not phone access, must be an IAX connection */
13296    if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R') || (*options == 'S')))
13297    {
13298       int val;
13299 
13300       pbx_builtin_setvar_helper(chan, "RPT_STAT_BUSY", "0");
13301        
13302       myrpt->bargechan=0;
13303       if(options && strstr(options, "f")>0)
13304       {
13305          myrpt->bargechan=1;     
13306       }
13307 
13308       if(memp>0)
13309       {
13310          char radiochan;
13311          radiochan=strtod(data,NULL);
13312          // if(myrpt->nowchan!=0 && radiochan!=myrpt->nowchan && !myrpt->bargechan)
13313 
13314          if(numlinks>0 && radiochan!=myrpt->nowchan && !myrpt->bargechan)
13315          {
13316             pbx_builtin_setvar_helper(chan, "RPT_STAT_BUSY", "1");
13317             ast_log(LOG_NOTICE, "Radio Channel Busy.\n");
13318             return (priority_jump(myrpt,chan));
13319          }
13320          else if(radiochan!=myrpt->nowchan || myrpt->bargechan)
13321          {
13322             channel_steer(myrpt,memp); 
13323          }
13324       }
13325       if(altp)rpt_push_alt_macro(myrpt,altp);
13326       phone_mode = 1;
13327       if (*options == 'D') phone_mode = 2;
13328       if (*options == 'S') phone_mode = 3;
13329       ast_set_callerid(chan,"0","app_rpt user","0");
13330       val = 1;
13331       ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
13332       if ((*(options + 1) == 'V') || (*(options + 1) == 'v')) phone_vox = 1;
13333    }
13334    else
13335    {
13336 #ifdef ALLOW_LOCAL_CHANNELS
13337            /* Check to insure the connection is IAX2 or Local*/
13338            if ( (strncmp(ast_channel_name(chan),"IAX2",4)) && (strncmp(ast_channel_name(chan),"Local",5)) ) {
13339                ast_log(LOG_WARNING, "We only accept links via IAX2 or Local!!\n");
13340                return -1;
13341            }
13342 #else
13343       if (strncmp(ast_channel_name(chan),"IAX2",4))
13344       {
13345          ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
13346          return -1;
13347       }
13348 #endif
13349            if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable){ /* Do not allow incoming radio connections if disabled */
13350                  ast_log(LOG_NOTICE, "Connect attempt to node %s  with tx disabled", myrpt->name);
13351                   return -1;
13352          }  
13353    }
13354    if (options && (*options == 'R'))
13355    {
13356       /* Parts of this section taken from app_parkandannounce */
13357       char *return_context;
13358       int length, m, lot, timeout = 0;
13359       char buffer[256],*template;
13360       char *working, *context, *exten, *priority;
13361       char *s,*orig_s;
13362 
13363       rpt_mutex_lock(&myrpt->lock);
13364       m = myrpt->callmode;
13365       rpt_mutex_unlock(&myrpt->lock);
13366 
13367       if ((!myrpt->p.nobusyout) && m)
13368       {
13369          if (chan->_state != AST_STATE_UP)
13370          {
13371             ast_indicate(chan,AST_CONTROL_BUSY);
13372          }
13373          while(ast_safe_sleep(chan,10000) != -1);
13374          return -1;
13375       }
13376 
13377       if (chan->_state != AST_STATE_UP)
13378       {
13379          ast_answer(chan);
13380          if (!phone_mode) send_newkey(chan);
13381       }
13382 
13383       length=strlen(options)+2;
13384       orig_s=ast_malloc(length);
13385       if(!orig_s) {
13386          ast_log(LOG_WARNING, "Out of memory\n");
13387          return -1;
13388       }
13389       s=orig_s;
13390       strncpy(s,options,length);
13391 
13392       template=strsep(&s,"|");
13393       if(!template) {
13394          ast_log(LOG_WARNING, "An announce template must be defined\n");
13395          ast_free(orig_s);
13396          return -1;
13397       } 
13398   
13399       if(s) {
13400          timeout = atoi(strsep(&s, "|"));
13401          timeout *= 1000;
13402       }
13403    
13404       return_context = s;
13405   
13406       if(return_context != NULL) {
13407          /* set the return context. Code borrowed from the Goto builtin */
13408     
13409          working = return_context;
13410          context = strsep(&working, "|");
13411          exten = strsep(&working, "|");
13412          if(!exten) {
13413             /* Only a priority in this one */
13414             priority = context;
13415             exten = NULL;
13416             context = NULL;
13417          } else {
13418             priority = strsep(&working, "|");
13419             if(!priority) {
13420                /* Only an extension and priority in this one */
13421                priority = exten;
13422                exten = context;
13423                context = NULL;
13424          }
13425       }
13426       if(atoi(priority) < 0) {
13427          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
13428          ast_free(orig_s);
13429          return -1;
13430       }
13431       /* At this point we have a priority and maybe an extension and a context */
13432       chan->priority = atoi(priority);
13433 #ifdef OLD_ASTERISK
13434       if(exten && strcasecmp(exten, "BYEXTENSION"))
13435 #else
13436       if(exten)
13437 #endif
13438          strncpy(chan->exten, exten, sizeof(chan->exten)-1);
13439       if(context)
13440          strncpy(chan->context, context, sizeof(chan->context)-1);
13441       } else {  /* increment the priority by default*/
13442          chan->priority++;
13443       }
13444 
13445       ast_verb(3, "Return Context: (%s,%s,%d) ID: %s\n",
13446          chan->context, chan->exten, chan->priority,
13447          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""));
13448       if (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority,
13449          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
13450          ast_verb(3, "Warning: Return Context Invalid, call will return to default|s\n");
13451       }
13452   
13453       /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
13454       before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
13455 
13456       ast_masq_park_call(chan, NULL, timeout, &lot);
13457 
13458       ast_verb(3, "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
13459 
13460       snprintf(buffer, sizeof(buffer) - 1, "%d,%s", lot, template + 1);
13461 
13462       rpt_telemetry(myrpt,REV_PATCH,buffer);
13463 
13464       ast_free(orig_s);
13465 
13466       return 0;
13467 
13468    }
13469 
13470    if (!options)
13471    {
13472         struct ast_hostent ahp;
13473         struct hostent *hp;
13474         struct in_addr ia;
13475         char hisip[100],nodeip[100],*val, *s, *s1, *s2, *s3, *b,*b1;
13476 
13477       /* look at callerid to see what node this comes from */
13478       b = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL);
13479       if (!b) /* if doesn't have caller id */
13480       {
13481          ast_log(LOG_WARNING, "Does not have callerid on %s\n",tmp);
13482          return -1;
13483       }
13484       /* get his IP from IAX2 module */
13485       memset(hisip,0,sizeof(hisip));
13486 #ifdef ALLOW_LOCAL_CHANNELS
13487         /* set IP address if this is a local connection*/
13488         if (strncmp(ast_channel_name(chan),"Local",5)==0) {
13489             strcpy(hisip,"127.0.0.1");
13490         } else {
13491          pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
13492       }
13493 #else
13494       pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
13495 #endif
13496 
13497       if (!hisip[0])
13498       {
13499          ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
13500          return -1;
13501       }
13502       
13503       b1 = ast_strdupa(b);
13504       ast_shrink_phone_number(b1);
13505       if (!strcmp(myrpt->name,b1))
13506       {
13507          ast_log(LOG_WARNING, "Trying to link to self!!\n");
13508          return -1;
13509       }
13510 
13511       if (*b1 < '1')
13512       {
13513          ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n",b1);
13514          return -1;
13515       }
13516 
13517 
13518       /* look for his reported node string */
13519       val = node_lookup(myrpt,b1);
13520       if (!val)
13521       {
13522          ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
13523          return -1;
13524       }
13525       strncpy(tmp,val,sizeof(tmp) - 1);
13526       s = tmp;
13527       s1 = strsep(&s,",");
13528       if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
13529       {
13530          sy = strchr(s1,'/');    
13531          *sy = 0;
13532          sprintf(sx,"%s:4569/%s",s1,sy + 1);
13533          s1 = sx;
13534       }
13535       s2 = strsep(&s,",");
13536       if (!s2)
13537       {
13538          ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n",b1);
13539          return -1;
13540       }
13541                 if (strcmp(s2,"NONE")) {
13542          hp = ast_gethostbyname(s2, &ahp);
13543          if (!hp)
13544          {
13545             ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s2);
13546             return -1;
13547          }
13548          memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
13549 #ifdef   OLD_ASTERISK
13550          ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
13551 #else
13552          strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
13553 #endif
13554          s3 = strchr(hisip,':');
13555          if (s3) *s3 = 0;
13556          if (strcmp(hisip,nodeip))
13557          {
13558             s3 = strchr(s1,'@');
13559             if (s3) s1 = s3 + 1;
13560             s3 = strchr(s1,'/');
13561             if (s3) *s3 = 0;
13562             s3 = strchr(s1,':');
13563             if (s3) *s3 = 0;
13564             hp = ast_gethostbyname(s1, &ahp);
13565             if (!hp)
13566             {
13567                ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s1);
13568                return -1;
13569             }
13570             memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
13571 #ifdef   OLD_ASTERISK
13572             ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
13573 #else
13574             strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
13575 #endif
13576             if (strcmp(hisip,nodeip))
13577             {
13578                ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip);
13579                return -1;
13580             }
13581          }
13582       }
13583    }
13584 
13585    /* if is not a remote */
13586    if (!myrpt->remote)
13587    {
13588       char *b,*b1;
13589       int reconnects = 0;
13590 
13591       rpt_mutex_lock(&myrpt->lock);
13592       i = myrpt->xlink;
13593       rpt_mutex_unlock(&myrpt->lock);
13594       if (i)
13595       {
13596          ast_log(LOG_WARNING, "Cannot connect to node %s, system busy\n",myrpt->name);
13597          return -1;
13598       }
13599       /* look at callerid to see what node this comes from */
13600       b = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL);
13601       if (!b) /* if doesn't have caller id */
13602       {
13603          ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
13604          return -1;
13605       }
13606 
13607       b1 = ast_strdupa(b);
13608       ast_shrink_phone_number(b1);
13609       if (!strcmp(myrpt->name,b1))
13610       {
13611          ast_log(LOG_WARNING, "Trying to link to self!!\n");
13612          return -1;
13613       }
13614       rpt_mutex_lock(&myrpt->lock);
13615       l = myrpt->links.next;
13616       /* try to find this one in queue */
13617       while(l != &myrpt->links)
13618       {
13619          if (l->name[0] == '0') 
13620          {
13621             l = l->next;
13622             continue;
13623          }
13624          /* if found matching string */
13625          if (!strcmp(l->name,b1)) break;
13626          l = l->next;
13627       }
13628       /* if found */
13629       if (l != &myrpt->links) 
13630       {
13631          l->killme = 1;
13632          l->retries = l->max_retries + 1;
13633          l->disced = 2;
13634          reconnects = l->reconnects;
13635          reconnects++;
13636                         rpt_mutex_unlock(&myrpt->lock);
13637          usleep(500000);   
13638       } else 
13639          rpt_mutex_unlock(&myrpt->lock);
13640       /* establish call in tranceive mode */
13641       l = ast_malloc(sizeof(struct rpt_link));
13642       if (!l)
13643       {
13644          ast_log(LOG_WARNING, "Unable to malloc\n");
13645          pthread_exit(NULL);
13646       }
13647       /* zero the silly thing */
13648       memset((char *)l,0,sizeof(struct rpt_link));
13649       l->mode = 1;
13650       strncpy(l->name,b1,MAXNODESTR - 1);
13651       l->isremote = 0;
13652       l->chan = chan;
13653       l->connected = 1;
13654       l->thisconnected = 1;
13655       l->hasconnected = 1;
13656       l->reconnects = reconnects;
13657       l->phonemode = phone_mode;
13658       l->phonevox = phone_vox;
13659       l->lastf1 = NULL;
13660       l->lastf2 = NULL;
13661       l->dtmfed = 0;
13662       voxinit_link(l,1);
13663       ast_set_read_format_by_id(l->chan,AST_FORMAT_SLINEAR);
13664       ast_set_write_format_by_id(l->chan,AST_FORMAT_SLINEAR);
13665       /* allocate a pseudo-channel thru asterisk */
13666       l->pchan = ast_request("DAHDI", get_slin_cap(cap), NULL, "pseudo", NULL);
13667       cap = ast_format_cap_destroy(cap);
13668       if (!l->pchan)
13669       {
13670          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
13671          pthread_exit(NULL);
13672       }
13673       ast_set_read_format_by_id(l->pchan,AST_FORMAT_SLINEAR);
13674       ast_set_write_format_by_id(l->pchan,AST_FORMAT_SLINEAR);
13675 #ifdef   AST_CDR_FLAG_POST_DISABLED
13676       if (l->pchan->cdr)
13677          ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
13678 #endif
13679       /* make a conference for the tx */
13680       ci.chan = 0;
13681       ci.confno = myrpt->conf;
13682       ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
13683       /* first put the channel on the conference in proper mode */
13684       if (ioctl(l->pchan->fds[0],DAHDI_SETCONF,&ci) == -1)
13685       {
13686          ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
13687          pthread_exit(NULL);
13688       }
13689       rpt_mutex_lock(&myrpt->lock);
13690       if ((phone_mode == 2) && (!phone_vox)) l->lastrealrx = 1;
13691       l->max_retries = MAX_RETRIES;
13692       /* insert at end of queue */
13693       insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
13694       __kickshort(myrpt);
13695       rpt_mutex_unlock(&myrpt->lock);
13696       if (chan->_state != AST_STATE_UP) {
13697          ast_answer(chan);
13698          if (!phone_mode) send_newkey(chan);
13699       }
13700       if (myrpt->p.archivedir)
13701       {
13702          char str[100];
13703 
13704          if (l->phonemode)
13705             sprintf(str,"LINK(P),%s",l->name);
13706          else
13707             sprintf(str,"LINK,%s",l->name);
13708          donodelog(myrpt,str);
13709       }
13710       if (!phone_mode) send_newkey(chan);
13711       return 0;
13712    }
13713    /* well, then it is a remote */
13714    rpt_mutex_lock(&myrpt->lock);
13715    /* if remote, error if anyone else already linked */
13716    if (myrpt->remoteon)
13717    {
13718       rpt_mutex_unlock(&myrpt->lock);
13719       usleep(500000);
13720       if (myrpt->remoteon)
13721       {
13722          ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
13723 #ifdef   AST_CDR_FLAG_POST_DISABLED
13724          if (chan->cdr)
13725             ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13726 #endif
13727          return -1;
13728       }     
13729       rpt_mutex_lock(&myrpt->lock);
13730    }
13731    if (myrpt->p.rptnode)
13732    {
13733       char killedit = 0;
13734       time_t now;
13735 
13736       time(&now);
13737       for(i = 0; i < nrpts; i++)
13738       {
13739          if (!strcasecmp(rpt_vars[i].name,myrpt->p.rptnode))
13740          {
13741             if ((rpt_vars[i].links.next != &rpt_vars[i].links) ||
13742                rpt_vars[i].keyed ||
13743                 ((rpt_vars[i].lastkeyedtime + RPT_LOCKOUT_SECS) > now) ||
13744                  rpt_vars[i].txkeyed ||
13745                   ((rpt_vars[i].lasttxkeyedtime + RPT_LOCKOUT_SECS) > now))
13746             {
13747                rpt_mutex_unlock(&myrpt->lock);
13748                ast_log(LOG_WARNING, "Trying to use busy link (repeater node %s) on %s\n",rpt_vars[i].name,tmp);
13749 #ifdef   AST_CDR_FLAG_POST_DISABLED
13750                if (chan->cdr)
13751                   ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13752 #endif
13753                return -1;
13754             }
13755             while(rpt_vars[i].xlink != 3)
13756             {
13757                if (!killedit)
13758                {
13759                   ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
13760                   rpt_vars[i].xlink = 1;
13761                   killedit = 1;
13762                }
13763                rpt_mutex_unlock(&myrpt->lock);
13764                if (ast_safe_sleep(chan,500) == -1)
13765                {
13766 #ifdef   AST_CDR_FLAG_POST_DISABLED
13767                   if (chan->cdr)
13768                      ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13769 #endif
13770                   return -1;
13771                }
13772                rpt_mutex_lock(&myrpt->lock);
13773             }
13774             break;
13775          }
13776       }
13777    }
13778 
13779 #ifdef HAVE_IOPERM
13780    if ( (!strcmp(myrpt->remoterig, remote_rig_rbi)||!strcmp(myrpt->remoterig, remote_rig_ppp16)) &&
13781      (ioperm(myrpt->p.iobase,1,1) == -1))
13782    {
13783       rpt_mutex_unlock(&myrpt->lock);
13784       ast_log(LOG_WARNING, "Can't get io permission on IO port %x hex\n",myrpt->p.iobase);
13785       return -1;
13786    }
13787 #endif
13788    myrpt->remoteon = 1;
13789 #ifdef   OLD_ASTERISK
13790    LOCAL_USER_ADD(u);
13791 #endif
13792    rpt_mutex_unlock(&myrpt->lock);
13793    /* find our index, and load the vars initially */
13794    for(i = 0; i < nrpts; i++)
13795    {
13796       if (&rpt_vars[i] == myrpt)
13797       {
13798          load_rpt_vars(i,0);
13799          break;
13800       }
13801    }
13802    rpt_mutex_lock(&myrpt->lock);
13803    tele = strchr(myrpt->rxchanname,'/');
13804    if (!tele)
13805    {
13806       fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
13807       rpt_mutex_unlock(&myrpt->lock);
13808       pthread_exit(NULL);
13809    }
13810    *tele++ = 0;
13811    myrpt->rxchannel = ast_request(myrpt->rxchanname, get_slin_cap(cap), NULL, tele, NULL);
13812    cap = ast_format_cap_destroy(cap);
13813    myrpt->dahdirxchannel = NULL;
13814    if (!strcasecmp(myrpt->rxchanname,"DAHDI"))
13815       myrpt->dahdirxchannel = myrpt->rxchannel;
13816    if (myrpt->rxchannel)
13817    {
13818       ast_set_read_format_by_id(myrpt->rxchannel,AST_FORMAT_SLINEAR);
13819       ast_set_write_format_by_id(myrpt->rxchannel,AST_FORMAT_SLINEAR);
13820 #ifdef   AST_CDR_FLAG_POST_DISABLED
13821       if (myrpt->rxchannel->cdr)
13822          ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13823 #endif
13824 #ifndef  NEW_ASTERISK
13825       myrpt->rxchannel->whentohangup = 0;
13826 #endif
13827       myrpt->rxchannel->appl = "Apprpt";
13828       myrpt->rxchannel->data = "(Link Rx)";
13829       ast_verb(3, "rpt (Rx) initiating call to %s/%s on %s\n",
13830          myrpt->rxchanname,tele,ast_channel_name(myrpt->rxchannel));
13831       rpt_mutex_unlock(&myrpt->lock);
13832       ast_call(myrpt->rxchannel,tele,999);
13833       rpt_mutex_lock(&myrpt->lock);
13834    }
13835    else
13836    {
13837       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
13838       rpt_mutex_unlock(&myrpt->lock);
13839       pthread_exit(NULL);
13840    }
13841    *--tele = '/';
13842    myrpt->dahditxchannel = NULL;
13843    if (myrpt->txchanname)
13844    {
13845       tele = strchr(myrpt->txchanname,'/');
13846       if (!tele)
13847       {
13848          fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
13849          rpt_mutex_unlock(&myrpt->lock);
13850          ast_hangup(myrpt->rxchannel);
13851          pthread_exit(NULL);
13852       }
13853       *tele++ = 0;
13854       myrpt->txchannel = ast_request(myrpt->txchanname, get_slin_cap(cap), NULL, tele, NULL);
13855       cap = ast_format_cap_destroy(cap);
13856       if (!strncasecmp(myrpt->txchanname,"DAHDI",3))
13857          myrpt->dahditxchannel = myrpt->txchannel;
13858       if (myrpt->txchannel)
13859       {
13860          ast_set_read_format_by_id(myrpt->txchannel,AST_FORMAT_SLINEAR);
13861          ast_set_write_format_by_id(myrpt->txchannel,AST_FORMAT_SLINEAR);
13862 #ifdef   AST_CDR_FLAG_POST_DISABLED
13863          if (myrpt->txchannel->cdr)
13864             ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13865 #endif
13866 #ifndef  NEW_ASTERISK
13867          myrpt->txchannel->whentohangup = 0;
13868 #endif
13869          myrpt->txchannel->appl = "Apprpt";
13870          myrpt->txchannel->data = "(Link Tx)";
13871          ast_verb(3, "rpt (Tx) initiating call to %s/%s on %s\n",
13872             myrpt->txchanname,tele,ast_channel_name(myrpt->txchannel));
13873          rpt_mutex_unlock(&myrpt->lock);
13874          ast_call(myrpt->txchannel,tele,999);
13875          rpt_mutex_lock(&myrpt->lock);
13876       }
13877       else
13878       {
13879          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
13880          rpt_mutex_unlock(&myrpt->lock);
13881          ast_hangup(myrpt->rxchannel);
13882          pthread_exit(NULL);
13883       }
13884       *--tele = '/';
13885    }
13886    else
13887    {
13888       myrpt->txchannel = myrpt->rxchannel;
13889       if (!strncasecmp(myrpt->rxchanname,"DAHDI",3))
13890          myrpt->dahditxchannel = myrpt->rxchannel;
13891    }
13892    /* allocate a pseudo-channel thru asterisk */
13893    myrpt->pchannel = ast_request("DAHDI", get_slin_cap(cap), NULL, "pseudo", NULL);
13894    cap = ast_format_cap_destroy(cap);
13895    if (!myrpt->pchannel)
13896    {
13897       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
13898       rpt_mutex_unlock(&myrpt->lock);
13899       if (myrpt->txchannel != myrpt->rxchannel) 
13900          ast_hangup(myrpt->txchannel);
13901       ast_hangup(myrpt->rxchannel);
13902       pthread_exit(NULL);
13903    }
13904    ast_set_read_format_by_id(myrpt->pchannel,AST_FORMAT_SLINEAR);
13905    ast_set_write_format_by_id(myrpt->pchannel,AST_FORMAT_SLINEAR);
13906 #ifdef   AST_CDR_FLAG_POST_DISABLED
13907    if (myrpt->pchannel->cdr)
13908       ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13909 #endif
13910    if (!myrpt->dahdirxchannel) myrpt->dahdirxchannel = myrpt->pchannel;
13911    if (!myrpt->dahditxchannel) myrpt->dahditxchannel = myrpt->pchannel;
13912    /* make a conference for the pseudo */
13913    ci.chan = 0;
13914    ci.confno = -1; /* make a new conf */
13915    ci.confmode = DAHDI_CONF_CONFANNMON ;
13916    /* first put the channel on the conference in announce/monitor mode */
13917    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
13918    {
13919       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
13920       rpt_mutex_unlock(&myrpt->lock);
13921       ast_hangup(myrpt->pchannel);
13922       if (myrpt->txchannel != myrpt->rxchannel) 
13923          ast_hangup(myrpt->txchannel);
13924       ast_hangup(myrpt->rxchannel);
13925       pthread_exit(NULL);
13926    }
13927    /* save pseudo channel conference number */
13928    myrpt->conf = myrpt->txconf = ci.confno;
13929    /* if serial io port, open it */
13930    myrpt->iofd = -1;
13931    if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt,myrpt->p.ioport)) == -1))
13932    {
13933       rpt_mutex_unlock(&myrpt->lock);
13934       ast_hangup(myrpt->pchannel);
13935       if (myrpt->txchannel != myrpt->rxchannel) 
13936          ast_hangup(myrpt->txchannel);
13937       ast_hangup(myrpt->rxchannel);
13938       pthread_exit(NULL);
13939    }
13940    iskenwood_pci4 = 0;
13941    memset(&z,0,sizeof(z));
13942    if ((myrpt->iofd < 1) && (myrpt->txchannel == myrpt->dahditxchannel))
13943    {
13944       z.radpar = DAHDI_RADPAR_REMMODE;
13945       z.data = DAHDI_RADPAR_REM_NONE;
13946       res = ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z);
13947       /* if PCIRADIO and kenwood selected */
13948       if ((!res) && (!strcmp(myrpt->remoterig,remote_rig_kenwood)))
13949       {
13950          z.radpar = DAHDI_RADPAR_UIOMODE;
13951          z.data = 1;
13952          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13953          {
13954             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
13955             return -1;
13956          }
13957          z.radpar = DAHDI_RADPAR_UIODATA;
13958          z.data = 3;
13959          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13960          {
13961             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
13962             return -1;
13963          }
13964          i = DAHDI_OFFHOOK;
13965          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i) == -1)
13966          {
13967             ast_log(LOG_ERROR,"Cannot set hook\n");
13968             return -1;
13969          }
13970          iskenwood_pci4 = 1;
13971       }
13972    }
13973    if (myrpt->txchannel == myrpt->dahditxchannel)
13974    {
13975       i = DAHDI_ONHOOK;
13976       ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i);
13977       /* if PCIRADIO and Yaesu ft897/ICOM IC-706 selected */
13978       if ((myrpt->iofd < 1) && (!res) &&
13979          ((!strcmp(myrpt->remoterig,remote_rig_ft897)) ||
13980             (!strcmp(myrpt->remoterig,remote_rig_ic706)) ||
13981                (!strcmp(myrpt->remoterig,remote_rig_tm271))))
13982       {
13983          z.radpar = DAHDI_RADPAR_UIOMODE;
13984          z.data = 1;
13985          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13986          {
13987             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
13988             return -1;
13989          }
13990          z.radpar = DAHDI_RADPAR_UIODATA;
13991          z.data = 3;
13992          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13993          {
13994             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
13995             return -1;
13996          }
13997       }
13998    }
13999    myrpt->remoterx = 0;
14000    myrpt->remotetx = 0;
14001    myrpt->retxtimer = 0;
14002    myrpt->rerxtimer = 0;
14003    myrpt->remoteon = 1;
14004    myrpt->dtmfidx = -1;
14005    myrpt->dtmfbuf[0] = 0;
14006    myrpt->dtmf_time_rem = 0;
14007    myrpt->hfscanmode = 0;
14008    myrpt->hfscanstatus = 0;
14009    if (myrpt->p.startupmacro)
14010    {
14011       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
14012    }
14013    time(&myrpt->start_time);
14014    myrpt->last_activity_time = myrpt->start_time;
14015    last_timeout_warning = 0;
14016    myrpt->reload = 0;
14017    myrpt->tele.next = &myrpt->tele;
14018    myrpt->tele.prev = &myrpt->tele;
14019    myrpt->newkey = 0;
14020    rpt_mutex_unlock(&myrpt->lock);
14021    ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR);
14022    ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
14023    rem_rx = 0;
14024    remkeyed = 0;
14025    /* if we are on 2w loop and are a remote, turn EC on */
14026    if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
14027    {
14028       i = 128;
14029       ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_ECHOCANCEL,&i);
14030    }
14031    if (chan->_state != AST_STATE_UP) {
14032       ast_answer(chan);
14033       if (!phone_mode) send_newkey(chan);
14034    }
14035 
14036    if (myrpt->rxchannel == myrpt->dahdirxchannel)
14037    {
14038       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_GET_PARAMS,&par) != -1)
14039       {
14040          if (par.rxisoffhook)
14041          {
14042             ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14043             myrpt->remoterx = 1;
14044             remkeyed = 1;
14045          }
14046       }
14047    }
14048    if (myrpt->p.archivedir)
14049    {
14050       char mycmd[100],mydate[100],*b,*b1;
14051       time_t myt;
14052       long blocksleft;
14053 
14054 
14055       mkdir(myrpt->p.archivedir,0600);
14056       sprintf(mycmd,"%s/%s",myrpt->p.archivedir,myrpt->name);
14057       mkdir(mycmd,0600);
14058       time(&myt);
14059       strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
14060          localtime(&myt));
14061       sprintf(mycmd,"mixmonitor start %s %s/%s/%s.wav49 a",ast_channel_name(chan),
14062          myrpt->p.archivedir,myrpt->name,mydate);
14063       if (myrpt->p.monminblocks)
14064       {
14065          blocksleft = diskavail(myrpt);
14066          if (myrpt->p.remotetimeout)
14067          {
14068             blocksleft -= (myrpt->p.remotetimeout *
14069                MONITOR_DISK_BLOCKS_PER_MINUTE) / 60;
14070          }
14071          if (blocksleft >= myrpt->p.monminblocks)
14072             ast_cli_command(nullfd,mycmd);
14073       } else ast_cli_command(nullfd,mycmd);
14074       /* look at callerid to see what node this comes from */
14075       b = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL);
14076       if (!b) /* if doesn't have caller id */
14077       {
14078          b1 = "0";
14079       } else {
14080          b1 = ast_strdupa(b);
14081          ast_shrink_phone_number(b1);
14082       }
14083       sprintf(mycmd,"CONNECT,%s",b1);
14084       donodelog(myrpt,mycmd);
14085    }
14086    myrpt->loginuser[0] = 0;
14087    myrpt->loginlevel[0] = 0;
14088    myrpt->authtelltimer = 0;
14089    myrpt->authtimer = 0;
14090    authtold = 0;
14091    authreq = 0;
14092    if (myrpt->p.authlevel > 1) authreq = 1;
14093    setrem(myrpt); 
14094    n = 0;
14095    dtmfed = 0;
14096    cs[n++] = chan;
14097    cs[n++] = myrpt->rxchannel;
14098    cs[n++] = myrpt->pchannel;
14099    if (myrpt->rxchannel != myrpt->txchannel)
14100       cs[n++] = myrpt->txchannel;
14101    if (!phone_mode) send_newkey(chan);
14102    /* start un-locked */
14103    for(;;) 
14104    {
14105       if (ast_check_hangup(chan)) break;
14106       if (ast_check_hangup(myrpt->rxchannel)) break;
14107       notremming = 0;
14108       setting = 0;
14109       reming = 0;
14110       telem = myrpt->tele.next;
14111       while(telem != &myrpt->tele)
14112       {
14113          if (telem->mode == SETREMOTE) setting = 1;
14114          if ((telem->mode == SETREMOTE) ||
14115              (telem->mode == SCAN) ||
14116             (telem->mode == TUNE))  reming = 1;
14117          else notremming = 1;
14118          telem = telem->next;
14119       }
14120       if (myrpt->reload)
14121       {
14122          myrpt->reload = 0;
14123          /* find our index, and load the vars */
14124          for(i = 0; i < nrpts; i++)
14125          {
14126             if (&rpt_vars[i] == myrpt)
14127             {
14128                load_rpt_vars(i,0);
14129                break;
14130             }
14131          }
14132       }
14133       time(&t);
14134       if (myrpt->p.remotetimeout)
14135       { 
14136          time_t r;
14137 
14138          r = (t - myrpt->start_time);
14139          if (r >= myrpt->p.remotetimeout)
14140          {
14141             saynode(myrpt,chan,myrpt->name);
14142             sayfile(chan,"rpt/timeout");
14143             ast_safe_sleep(chan,1000);
14144             break;
14145          }
14146          if ((myrpt->p.remotetimeoutwarning) && 
14147              (r >= (myrpt->p.remotetimeout -
14148             myrpt->p.remotetimeoutwarning)) &&
14149                 (r <= (myrpt->p.remotetimeout - 
14150                   myrpt->p.remotetimeoutwarningfreq)))
14151          {
14152             if (myrpt->p.remotetimeoutwarningfreq)
14153             {
14154                 if ((t - last_timeout_warning) >=
14155                myrpt->p.remotetimeoutwarningfreq)
14156                 {
14157                time(&last_timeout_warning);
14158                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
14159                 }
14160             }
14161             else
14162             {
14163                 if (!last_timeout_warning)
14164                 {
14165                time(&last_timeout_warning);
14166                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
14167                 }
14168             }
14169          }
14170       }
14171       if (myrpt->p.remoteinacttimeout && myrpt->last_activity_time)
14172       { 
14173          time_t r;
14174 
14175          r = (t - myrpt->last_activity_time);
14176          if (r >= myrpt->p.remoteinacttimeout)
14177          {
14178             saynode(myrpt,chan,myrpt->name);
14179             ast_safe_sleep(chan,1000);
14180             break;
14181          }
14182          if ((myrpt->p.remotetimeoutwarning) && 
14183              (r >= (myrpt->p.remoteinacttimeout -
14184             myrpt->p.remotetimeoutwarning)) &&
14185                 (r <= (myrpt->p.remoteinacttimeout - 
14186                   myrpt->p.remotetimeoutwarningfreq)))
14187          {
14188             if (myrpt->p.remotetimeoutwarningfreq)
14189             {
14190                 if ((t - last_timeout_warning) >=
14191                myrpt->p.remotetimeoutwarningfreq)
14192                 {
14193                time(&last_timeout_warning);
14194                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
14195                 }
14196             }
14197             else
14198             {
14199                 if (!last_timeout_warning)
14200                 {
14201                time(&last_timeout_warning);
14202                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
14203                 }
14204             }
14205          }
14206       }
14207       ms = MSWAIT;
14208       who = ast_waitfor_n(cs,n,&ms);
14209       if (who == NULL) ms = 0;
14210       elap = MSWAIT - ms;
14211       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
14212       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
14213       if (!ms) continue;
14214       /* do local dtmf timer */
14215       if (myrpt->dtmf_local_timer)
14216       {
14217          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
14218          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
14219       }
14220       rpt_mutex_lock(&myrpt->lock);
14221       do_dtmf_local(myrpt,0);
14222       rpt_mutex_unlock(&myrpt->lock);
14223       //
14224       rem_totx =  myrpt->dtmf_local_timer && (!phone_mode);
14225       rem_totx |= keyed && (!myrpt->tunerequest);
14226       rem_rx = (remkeyed && (!setting)) || (myrpt->tele.next != &myrpt->tele);
14227       if(!strcmp(myrpt->remoterig, remote_rig_ic706))
14228          rem_totx |= myrpt->tunerequest;
14229       //
14230        if((debug > 6) && rem_totx) {
14231          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);
14232       }
14233       if (keyed && (!keyed1))
14234       {
14235          keyed1 = 1;
14236       }
14237 
14238       if (!keyed && (keyed1))
14239       {
14240          time_t myt;
14241 
14242          keyed1 = 0;
14243          time(&myt);
14244          /* if login necessary, and not too soon */
14245          if ((myrpt->p.authlevel) && 
14246              (!myrpt->loginlevel[0]) &&
14247             (myt > (t + 3)))
14248          {
14249             authreq = 1;
14250             authtold = 0;
14251             myrpt->authtelltimer = AUTHTELLTIME - AUTHTXTIME;
14252          }
14253       }
14254 
14255       if (rem_rx && (!myrpt->remoterx))
14256       {
14257          myrpt->remoterx = 1;
14258          ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14259       }
14260       if ((!rem_rx) && (myrpt->remoterx))
14261       {
14262          myrpt->remoterx = 0;
14263          ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
14264       }
14265       /* if auth requested, and not authed yet */
14266       if (authreq && (!myrpt->loginlevel[0]))
14267       {
14268          if ((!authtold) && ((myrpt->authtelltimer += elap)
14269              >= AUTHTELLTIME))
14270          {
14271             authtold = 1;
14272             rpt_telemetry(myrpt,LOGINREQ,NULL);
14273          }
14274          if ((myrpt->authtimer += elap) >= AUTHLOGOUTTIME)
14275          {
14276             break; /* if not logged in, hang up after a time */
14277          }
14278       }
14279       if (myrpt->newkey)
14280       {
14281          if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
14282          {
14283             myrpt->retxtimer = 0;
14284             if ((myrpt->remoterx) && (!myrpt->remotetx))
14285                ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14286             else
14287                ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
14288          }
14289 
14290          if ((myrpt->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 2))
14291          {
14292             keyed = 0;
14293             myrpt->rerxtimer = 0;
14294          }
14295       }
14296       if (rem_totx && (!myrpt->remotetx))
14297       {
14298          /* if not authed, and needed, do not transmit */
14299          if ((!myrpt->p.authlevel) || myrpt->loginlevel[0])
14300          {
14301             if(debug > 6)
14302                ast_log(LOG_NOTICE,"Handle rem_totx=%i.  dtmf_local_timer=%i  tunerequest=%i\n",rem_totx,myrpt->dtmf_local_timer,myrpt->tunerequest);
14303 
14304             myrpt->remotetx = 1;
14305             /* asdf maw ??? is this really what you want? Doesn't it always get executed? */
14306             if((myrpt->remtxfreqok = check_tx_freq(myrpt)))
14307             {
14308                time(&myrpt->last_activity_time);
14309                if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14310                {
14311                   z.radpar = DAHDI_RADPAR_UIODATA;
14312                   z.data = 1;
14313                   if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14314                   {
14315                      ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14316                      return -1;
14317                   }
14318                }
14319                else
14320                {
14321                   ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
14322                }
14323                if (myrpt->p.archivedir) donodelog(myrpt,"TXKEY");
14324             }
14325          }
14326       }
14327       if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
14328       {
14329          myrpt->remotetx = 0;
14330          if(!myrpt->remtxfreqok){
14331             rpt_telemetry(myrpt,UNAUTHTX,NULL);
14332          }
14333          if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14334          {
14335             z.radpar = DAHDI_RADPAR_UIODATA;
14336             z.data = 3;
14337             if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14338             {
14339                ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14340                return -1;
14341             }
14342          }
14343          else
14344          {
14345             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
14346          }
14347          if (myrpt->p.archivedir) donodelog(myrpt,"TXUNKEY");
14348       }
14349       if (myrpt->hfscanmode){
14350          myrpt->scantimer -= elap;
14351          if(myrpt->scantimer <= 0){
14352             if (!reming)
14353             {
14354                myrpt->scantimer = REM_SCANTIME;
14355                rpt_telemetry(myrpt,SCAN,0);
14356             } else myrpt->scantimer = 1;
14357          }
14358       }
14359       rpt_mutex_lock(&myrpt->lock);
14360       c = myrpt->macrobuf[0];
14361       if (c && (!myrpt->macrotimer))
14362       {
14363          myrpt->macrotimer = MACROTIME;
14364          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
14365          if ((c == 'p') || (c == 'P'))
14366             myrpt->macrotimer = MACROPTIME;
14367          rpt_mutex_unlock(&myrpt->lock);
14368          if (myrpt->p.archivedir)
14369          {
14370             char str[100];
14371                sprintf(str,"DTMF(M),%c",c);
14372             donodelog(myrpt,str);
14373          }
14374          if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
14375          continue;
14376       } else rpt_mutex_unlock(&myrpt->lock);
14377       if (who == chan) /* if it was a read from incoming */
14378       {
14379          f = ast_read(chan);
14380          if (!f)
14381          {
14382             if (debug) printf("@@@@ link:Hung Up\n");
14383             break;
14384          }
14385          if (f->frametype == AST_FRAME_VOICE)
14386          {
14387             if (ioctl(chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
14388             {
14389                ismuted = 0;
14390             }
14391             /* if not transmitting, zero-out audio */
14392             ismuted |= (!myrpt->remotetx);
14393             if (dtmfed && phone_mode) ismuted = 1;
14394             dtmfed = 0;
14395             if (ismuted)
14396             {
14397                memset(f->data.ptr,0,f->datalen);
14398                if (myrpt->lastf1)
14399                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14400                if (myrpt->lastf2)
14401                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14402             } 
14403             if (f) f2 = ast_frdup(f);
14404             else f2 = NULL;
14405             f1 = myrpt->lastf2;
14406             myrpt->lastf2 = myrpt->lastf1;
14407             myrpt->lastf1 = f2;
14408             if (ismuted)
14409             {
14410                if (myrpt->lastf1)
14411                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14412                if (myrpt->lastf2)
14413                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14414             }
14415             if (f1)
14416             {
14417                if (phone_mode)
14418                   ast_write(myrpt->txchannel,f1);
14419                else
14420                   ast_write(myrpt->txchannel,f);
14421                ast_frfree(f1);
14422             }
14423          }
14424 #ifndef  OLD_ASTERISK
14425          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
14426          {
14427             if (myrpt->lastf1)
14428                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14429             if (myrpt->lastf2)
14430                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14431             dtmfed = 1;
14432          }
14433 #endif
14434          if (f->frametype == AST_FRAME_DTMF)
14435          {
14436             if (myrpt->lastf1)
14437                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14438             if (myrpt->lastf2)
14439                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14440             dtmfed = 1;
14441             if (handle_remote_phone_dtmf(myrpt,f->subclass.integer,&keyed,phone_mode) == -1)
14442             {
14443                if (debug) printf("@@@@ rpt:Hung Up\n");
14444                ast_frfree(f);
14445                break;
14446             }
14447          }
14448          if (f->frametype == AST_FRAME_TEXT)
14449          {
14450             if (handle_remote_data(myrpt,f->data.ptr) == -1)
14451             {
14452                if (debug) printf("@@@@ rpt:Hung Up\n");
14453                ast_frfree(f);
14454                break;
14455             }
14456          }
14457          if (f->frametype == AST_FRAME_CONTROL)
14458          {
14459             if (f->subclass.integer == AST_CONTROL_HANGUP)
14460             {
14461                if (debug) printf("@@@@ rpt:Hung Up\n");
14462                ast_frfree(f);
14463                break;
14464             }
14465             /* if RX key */
14466             if (f->subclass.integer == AST_CONTROL_RADIO_KEY)
14467             {
14468                if (debug == 7) printf("@@@@ rx key\n");
14469                keyed = 1;
14470                myrpt->rerxtimer = 0;
14471             }
14472             /* if RX un-key */
14473             if (f->subclass.integer == AST_CONTROL_RADIO_UNKEY)
14474             {
14475                myrpt->rerxtimer = 0;
14476                if (debug == 7) printf("@@@@ rx un-key\n");
14477                keyed = 0;
14478             }
14479          }
14480          ast_frfree(f);
14481          continue;
14482       }
14483       if (who == myrpt->rxchannel) /* if it was a read from radio */
14484       {
14485          f = ast_read(myrpt->rxchannel);
14486          if (!f)
14487          {
14488             if (debug) printf("@@@@ link:Hung Up\n");
14489             break;
14490          }
14491          if (f->frametype == AST_FRAME_VOICE)
14492          {
14493             int myreming = 0;
14494 
14495             if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
14496                myreming = reming;
14497 
14498             if (myreming || (!remkeyed) ||
14499             ((myrpt->remote) && (myrpt->remotetx)) ||
14500               ((myrpt->remmode != REM_MODE_FM) &&
14501                 notremming))
14502                memset(f->data.ptr,0,f->datalen); 
14503              ast_write(myrpt->pchannel,f);
14504          }
14505          else if (f->frametype == AST_FRAME_CONTROL)
14506          {
14507             if (f->subclass.integer == AST_CONTROL_HANGUP)
14508             {
14509                if (debug) printf("@@@@ rpt:Hung Up\n");
14510                ast_frfree(f);
14511                break;
14512             }
14513             /* if RX key */
14514             if (f->subclass.integer == AST_CONTROL_RADIO_KEY)
14515             {
14516                if (debug == 7) printf("@@@@ remote rx key\n");
14517                if (!myrpt->remotetx)
14518                {
14519                   remkeyed = 1;
14520                }
14521             }
14522             /* if RX un-key */
14523             if (f->subclass.integer == AST_CONTROL_RADIO_UNKEY)
14524             {
14525                if (debug == 7) printf("@@@@ remote rx un-key\n");
14526                if (!myrpt->remotetx) 
14527                {
14528                   remkeyed = 0;
14529                }
14530             }
14531          }
14532          ast_frfree(f);
14533          continue;
14534       }
14535       if (who == myrpt->pchannel) /* if is remote mix output */
14536       {
14537          f = ast_read(myrpt->pchannel);
14538          if (!f)
14539          {
14540             if (debug) printf("@@@@ link:Hung Up\n");
14541             break;
14542          }
14543          if (f->frametype == AST_FRAME_VOICE)
14544          {
14545             ast_write(chan,f);
14546          }
14547          if (f->frametype == AST_FRAME_CONTROL)
14548          {
14549             if (f->subclass.integer == AST_CONTROL_HANGUP)
14550             {
14551                if (debug) printf("@@@@ rpt:Hung Up\n");
14552                ast_frfree(f);
14553                break;
14554             }
14555          }
14556          ast_frfree(f);
14557          continue;
14558       }
14559       if ((myrpt->rxchannel != myrpt->txchannel) && 
14560          (who == myrpt->txchannel)) /* do this cuz you have to */
14561       {
14562          f = ast_read(myrpt->txchannel);
14563          if (!f)
14564          {
14565             if (debug) printf("@@@@ link:Hung Up\n");
14566             break;
14567          }
14568          if (f->frametype == AST_FRAME_CONTROL)
14569          {
14570             if (f->subclass.integer == AST_CONTROL_HANGUP)
14571             {
14572                if (debug) printf("@@@@ rpt:Hung Up\n");
14573                ast_frfree(f);
14574                break;
14575             }
14576          }
14577          ast_frfree(f);
14578          continue;
14579       }
14580    }
14581    if (myrpt->p.archivedir)
14582    {
14583       char mycmd[100],*b,*b1;
14584 
14585       /* look at callerid to see what node this comes from */
14586       b = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL);
14587       if (!b) /* if doesn't have caller id */
14588       {
14589          b1 = "0";
14590       } else {
14591          b1 = ast_strdupa(b);
14592          ast_shrink_phone_number(b1);
14593       }
14594       sprintf(mycmd,"DISCONNECT,%s",b1);
14595       donodelog(myrpt,mycmd);
14596    }
14597    /* wait for telem to be done */
14598    while(myrpt->tele.next != &myrpt->tele) usleep(100000);
14599    sprintf(tmp,"mixmonitor stop %s",ast_channel_name(chan));
14600    ast_cli_command(nullfd,tmp);
14601    close(nullfd);
14602    rpt_mutex_lock(&myrpt->lock);
14603    myrpt->hfscanmode = 0;
14604    myrpt->hfscanstatus = 0;
14605    myrpt->remoteon = 0;
14606    rpt_mutex_unlock(&myrpt->lock);
14607    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
14608    myrpt->lastf1 = NULL;
14609    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
14610    myrpt->lastf2 = NULL;
14611    if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14612    {
14613       z.radpar = DAHDI_RADPAR_UIOMODE;
14614       z.data = 3;
14615       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14616       {
14617          ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
14618          return -1;
14619       }
14620       z.radpar = DAHDI_RADPAR_UIODATA;
14621       z.data = 3;
14622       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14623       {
14624          ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14625          return -1;
14626       }
14627       i = DAHDI_OFFHOOK;
14628       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i) == -1)
14629       {
14630          ast_log(LOG_ERROR,"Cannot set hook\n");
14631          return -1;
14632       }
14633    }
14634    if (myrpt->iofd) close(myrpt->iofd);
14635    myrpt->iofd = -1;
14636    ast_hangup(myrpt->pchannel);
14637    if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
14638    ast_hangup(myrpt->rxchannel);
14639    closerem(myrpt);
14640    if (myrpt->p.rptnode)
14641    {
14642       rpt_mutex_lock(&myrpt->lock);
14643       for(i = 0; i < nrpts; i++)
14644       {
14645          if (!strcasecmp(rpt_vars[i].name,myrpt->p.rptnode))
14646          {
14647             rpt_vars[i].xlink = 0;
14648             break;
14649          }
14650       }
14651       rpt_mutex_unlock(&myrpt->lock);
14652    }
14653 #ifdef   OLD_ASTERISK
14654    LOCAL_USER_REMOVE(u);
14655 #endif
14656    return res;
14657 }
14658 
14659 #ifndef OLD_ASTERISK
14660 /*!\brief callback to display list of locally configured nodes
14661    \addtogroup Group_AMI
14662  */
14663 static int manager_rpt_local_nodes(struct mansession *s, const struct message *m)
14664 {
14665     int i;
14666     astman_append(s, "<?xml version=\"1.0\"?>\r\n");
14667     astman_append(s, "<nodes>\r\n");
14668     for (i=0; i< nrpts; i++)
14669     {
14670         astman_append(s, "  <node>%s</node>\r\n", rpt_vars[i].name);        
14671     } /* for i */
14672     astman_append(s, "</nodes>\r\n");
14673     astman_append(s, "\r\n"); /* Properly terminate Manager output */
14674     return RESULT_SUCCESS;
14675 } /* manager_rpt_local_nodes() */
14676 
14677 
14678 
14679 /*
14680  * Append Success and ActionID to manager response message
14681  */
14682 
14683 static void rpt_manager_success(struct mansession *s, const struct message *m)
14684 {
14685    const char *id = astman_get_header(m, "ActionID");
14686    if (!ast_strlen_zero(id))
14687       astman_append(s, "ActionID: %s\r\n", id);
14688    astman_append(s, "Response: Success\r\n");
14689 }
14690 
14691 /*
14692 * Dump statistics to manager session
14693 */
14694 
14695 static int rpt_manager_do_stats(struct mansession *s, const struct message *m, char *str)
14696 {
14697    int i,j,numoflinks;
14698    int dailytxtime, dailykerchunks;
14699    time_t now;
14700    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
14701    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
14702    long long totaltxtime;
14703    struct   rpt_link *l;
14704    char *listoflinks[MAX_STAT_LINKS];  
14705    char *lastdtmfcommand,*parrot_ena;
14706    char *tot_state, *ider_state, *patch_state;
14707    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
14708    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
14709    char *transmitterkeyed;
14710    const char *node = astman_get_header(m, "Node");
14711    struct rpt *myrpt;
14712 
14713    static char *not_applicable = "N/A";
14714 
14715    tot_state = ider_state = 
14716    patch_state = reverse_patch_state = 
14717    input_signal = not_applicable;
14718    called_number = lastdtmfcommand = transmitterkeyed = NULL;
14719 
14720    time(&now);
14721    for(i = 0; i < nrpts; i++)
14722    {
14723       if ((node)&&(!strcmp(node,rpt_vars[i].name))){
14724          rpt_manager_success(s,m);
14725 
14726          myrpt = &rpt_vars[i];
14727 
14728          if(myrpt->remote){ /* Remote base ? */
14729             char *loginuser, *loginlevel, *freq, *rxpl, *txpl, *modestr;
14730             char offset = 0, powerlevel = 0, rxplon = 0, txplon = 0, remoteon, remmode = 0, reportfmstuff;
14731             char offsetc,powerlevelc;
14732 
14733             loginuser = loginlevel = freq = rxpl = txpl = NULL;
14734             /* Make a copy of all stat variables while locked */
14735             rpt_mutex_lock(&myrpt->lock); /* LOCK */
14736             if((remoteon = myrpt->remoteon)){
14737                if(!ast_strlen_zero(myrpt->loginuser))
14738                   loginuser = ast_strdup(myrpt->loginuser);
14739                if(!ast_strlen_zero(myrpt->loginlevel))
14740                   loginlevel = ast_strdup(myrpt->loginlevel);
14741                if(!ast_strlen_zero(myrpt->freq))
14742                   freq = ast_strdup(myrpt->freq);
14743                if(!ast_strlen_zero(myrpt->rxpl))
14744                   rxpl = ast_strdup(myrpt->rxpl);
14745                if(!ast_strlen_zero(myrpt->txpl))
14746                   txpl = ast_strdup(myrpt->txpl);
14747                remmode = myrpt->remmode;
14748                offset = myrpt->offset;
14749                powerlevel = myrpt->powerlevel;
14750                rxplon = myrpt->rxplon;
14751                txplon = myrpt->txplon;       
14752             }
14753             rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
14754             astman_append(s, "IsRemoteBase: YES\r\n");
14755             astman_append(s, "RemoteOn: %s\r\n",(remoteon) ? "YES": "NO");
14756             if(remoteon){
14757                if(loginuser){
14758                   astman_append(s, "LogInUser: %s\r\n", loginuser);
14759                   ast_free(loginuser);
14760                }
14761                if(loginlevel){
14762                   astman_append(s, "LogInLevel: %s\r\n", loginlevel);
14763                   ast_free(loginlevel);
14764                }
14765                if(freq){
14766                   astman_append(s, "Freq: %s\r\n", freq);
14767                   ast_free(freq);
14768                }
14769                reportfmstuff = 0;
14770                switch(remmode){
14771                   case REM_MODE_FM:
14772                      modestr = "FM";   
14773                      reportfmstuff = 1;
14774                      break;
14775                   case REM_MODE_AM:
14776                      modestr = "AM";
14777                      break;
14778                   case REM_MODE_USB:
14779                      modestr = "USB";
14780                      break;
14781                   default:
14782                      modestr = "LSB";
14783                      break;
14784                }
14785                astman_append(s, "RemMode: %s\r\n", modestr);
14786                if(reportfmstuff){
14787                   switch(offset){
14788                      case REM_SIMPLEX:
14789                         offsetc = 'S';
14790                         break;
14791                      case REM_MINUS:
14792                         offsetc = '-';
14793                         break;
14794                      default:
14795                         offsetc = '+';
14796                         break;
14797                   }
14798                   astman_append(s, "RemOffset: %c\r\n", offsetc);
14799                   if(rxplon && rxpl){
14800                      astman_append(s, "RxPl: %s\r\n",rxpl);
14801                      ast_free(rxpl);
14802                   }
14803                   if(txplon && txpl){
14804                      astman_append(s, "TxPl: %s\r\n",txpl);
14805                      ast_free(txpl);
14806                   }
14807                }
14808                switch(powerlevel){
14809                   case REM_LOWPWR:
14810                      powerlevelc = 'L';
14811                      break;
14812                   case REM_MEDPWR:
14813                      powerlevelc = 'M';
14814                      break;
14815                   default:
14816                      powerlevelc = 'H';
14817                      break;
14818                }
14819                astman_append(s,"PowerLevel: %c\r\n", powerlevelc);
14820             }
14821             astman_append(s, "\r\n");
14822             return 0; /* End of remote base status reporting */
14823          }  
14824 
14825          /* ELSE Process as a repeater node */
14826          /* Make a copy of all stat variables while locked */
14827          rpt_mutex_lock(&myrpt->lock); /* LOCK */
14828          dailytxtime = myrpt->dailytxtime;
14829          totaltxtime = myrpt->totaltxtime;
14830          dailykeyups = myrpt->dailykeyups;
14831          totalkeyups = myrpt->totalkeyups;
14832          dailykerchunks = myrpt->dailykerchunks;
14833          totalkerchunks = myrpt->totalkerchunks;
14834          dailyexecdcommands = myrpt->dailyexecdcommands;
14835          totalexecdcommands = myrpt->totalexecdcommands;
14836          timeouts = myrpt->timeouts;
14837 
14838 
14839          /* Traverse the list of connected nodes */
14840          reverse_patch_state = "DOWN";
14841          numoflinks = 0;
14842          l = myrpt->links.next;
14843          while(l && (l != &myrpt->links)){
14844             if(numoflinks >= MAX_STAT_LINKS){
14845                ast_log(LOG_NOTICE,
14846                "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
14847                break;
14848             }
14849             if (l->name[0] == '0'){ /* Skip '0' nodes */
14850                reverse_patch_state = "UP";
14851                l = l->next;
14852                continue;
14853             }
14854             listoflinks[numoflinks] = ast_strdup(l->name);
14855             if(listoflinks[numoflinks] == NULL){
14856                break;
14857             }
14858             else{
14859                numoflinks++;
14860             }
14861             l = l->next;
14862          }
14863 
14864          if(myrpt->keyed)
14865             input_signal = "YES";
14866          else
14867             input_signal = "NO";
14868          
14869          if(myrpt->txkeyed)
14870             transmitterkeyed = "YES";
14871          else
14872             transmitterkeyed = "NO";
14873 
14874          if(myrpt->p.parrotmode)
14875             parrot_ena = "ENABLED";
14876          else
14877             parrot_ena = "DISABLED";
14878 
14879          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
14880             sys_ena = "DISABLED";
14881          else
14882             sys_ena = "ENABLED";
14883 
14884          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
14885             tot_ena = "DISABLED";
14886          else
14887             tot_ena = "ENABLED";
14888 
14889          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
14890             link_ena = "DISABLED";
14891          else
14892             link_ena = "ENABLED";
14893 
14894          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
14895             patch_ena = "DISABLED";
14896          else
14897             patch_ena = "ENABLED";
14898 
14899          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
14900             sch_ena = "DISABLED";
14901          else
14902             sch_ena = "ENABLED";
14903 
14904          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
14905             user_funs = "DISABLED";
14906          else
14907             user_funs = "ENABLED";
14908 
14909          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
14910             tail_type = "ALTERNATE";
14911          else
14912             tail_type = "STANDARD";
14913 
14914          if(!myrpt->totimer)
14915             tot_state = "TIMED OUT!";
14916          else if(myrpt->totimer != myrpt->p.totime)
14917             tot_state = "ARMED";
14918          else
14919             tot_state = "RESET";
14920 
14921          if(myrpt->tailid)
14922             ider_state = "QUEUED IN TAIL";
14923          else if(myrpt->mustid)
14924             ider_state = "QUEUED FOR CLEANUP";
14925          else
14926             ider_state = "CLEAN";
14927 
14928          switch(myrpt->callmode){
14929             case 1:
14930                patch_state = "DIALING";
14931                break;
14932             case 2:
14933                patch_state = "CONNECTING";
14934                break;
14935             case 3:
14936                patch_state = "UP";
14937                break;
14938 
14939             case 4:
14940                patch_state = "CALL FAILED";
14941                break;
14942 
14943             default:
14944                patch_state = "DOWN";
14945          }
14946 
14947          if(strlen(myrpt->exten)){
14948             called_number = ast_strdup(myrpt->exten);
14949          }
14950 
14951          if(strlen(myrpt->lastdtmfcommand)){
14952             lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
14953          }
14954          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
14955 
14956          astman_append(s, "IsRemoteBase: NO\r\n");
14957          astman_append(s, "NodeState: %d\r\n", myrpt->p.sysstate_cur);
14958          astman_append(s, "SignalOnInput: %s\r\n", input_signal);
14959          astman_append(s, "TransmitterKeyed: %s\r\n", transmitterkeyed);
14960          astman_append(s, "Transmitter: %s\r\n", sys_ena);
14961          astman_append(s, "Parrot: %s\r\n", parrot_ena);
14962          astman_append(s, "Scheduler: %s\r\n", sch_ena);
14963          astman_append(s, "TailLength: %s\r\n", tail_type);
14964          astman_append(s, "TimeOutTimer: %s\r\n", tot_ena);
14965          astman_append(s, "TimeOutTimerState: %s\r\n", tot_state);
14966          astman_append(s, "TimeOutsSinceSystemInitialization: %d\r\n", timeouts);
14967          astman_append(s, "IdentifierState: %s\r\n", ider_state);
14968          astman_append(s, "KerchunksToday: %d\r\n", dailykerchunks);
14969          astman_append(s, "KerchunksSinceSystemInitialization: %d\r\n", totalkerchunks);
14970          astman_append(s, "KeyupsToday: %d\r\n", dailykeyups);
14971          astman_append(s, "KeyupsSinceSystemInitialization: %d\r\n", totalkeyups);
14972          astman_append(s, "DtmfCommandsToday: %d\r\n", dailyexecdcommands);
14973          astman_append(s, "DtmfCommandsSinceSystemInitialization: %d\r\n", totalexecdcommands);
14974          astman_append(s, "LastDtmfCommandExecuted: %s\r\n", 
14975          (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
14976          hours = dailytxtime/3600000;
14977          dailytxtime %= 3600000;
14978          minutes = dailytxtime/60000;
14979          dailytxtime %= 60000;
14980          seconds = dailytxtime/1000;
14981          dailytxtime %= 1000;
14982 
14983          astman_append(s, "TxTimeToday: %02d:%02d:%02d.%d\r\n",
14984             hours, minutes, seconds, dailytxtime);
14985 
14986          hours = (int) totaltxtime/3600000;
14987          totaltxtime %= 3600000;
14988          minutes = (int) totaltxtime/60000;
14989          totaltxtime %= 60000;
14990          seconds = (int)  totaltxtime/1000;
14991          totaltxtime %= 1000;
14992 
14993          astman_append(s, "TxTimeSinceSystemInitialization: %02d:%02d:%02d.%d\r\n",
14994              hours, minutes, seconds, (int) totaltxtime);
14995 
14996          sprintf(str, "NodesCurrentlyConnectedToUs: ");
14997                         if(!numoflinks){
14998                          strcat(str,"<NONE>");
14999                         }
15000          else{
15001             for(j = 0 ;j < numoflinks; j++){
15002                sprintf(str+strlen(str), "%s", listoflinks[j]);
15003                if(j < numoflinks - 1)
15004                   strcat(str,",");
15005             }
15006          }
15007          astman_append(s,"%s\r\n", str);
15008 
15009          astman_append(s, "Autopatch: %s\r\n", patch_ena);
15010          astman_append(s, "AutopatchState: %s\r\n", patch_state);
15011          astman_append(s, "AutopatchCalledNumber: %s\r\n",
15012          (called_number && strlen(called_number)) ? called_number : not_applicable);
15013          astman_append(s, "ReversePatchIaxrptConnected: %s\r\n", reverse_patch_state);
15014          astman_append(s, "UserLinkingCommands: %s\r\n", link_ena);
15015          astman_append(s, "UserFunctions: %s\r\n", user_funs);
15016 
15017          for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
15018             ast_free(listoflinks[j]);
15019          }
15020          if(called_number){
15021             ast_free(called_number);
15022          }
15023          if(lastdtmfcommand){
15024             ast_free(lastdtmfcommand);
15025          }
15026          astman_append(s, "\r\n"); /* We're Done! */
15027               return 0;
15028       }
15029    }
15030    astman_send_error(s, m, "RptStatus unknown or missing node");
15031    return -1;
15032 }
15033 
15034 
15035 
15036 /*
15037  * Implement the RptStatus Manager Interface
15038  */
15039 
15040 static int manager_rpt_status(struct mansession *s, const struct message *m)
15041 {
15042    int i,res,len,idx;
15043    int uptime,hours,minutes;
15044    time_t now;
15045    const char *cmd = astman_get_header(m, "Command");
15046    char *str;
15047    enum {MGRCMD_RPTSTAT,MGRCMD_NODESTAT};
15048    struct mgrcmdtbl{
15049       const char *cmd;
15050       int index;
15051    };
15052    static struct mgrcmdtbl mct[] = {
15053       {"RptStat",MGRCMD_RPTSTAT},
15054       {"NodeStat",MGRCMD_NODESTAT},
15055       {NULL,0} /* NULL marks end of command table */
15056    };
15057 
15058    time(&now);
15059 
15060    len = 1024; /* Allocate a working buffer */
15061    if(!(str = ast_malloc(len)))
15062       return -1;
15063 
15064    /* Check for Command */
15065    if(ast_strlen_zero(cmd)){
15066       astman_send_error(s, m, "RptStatus missing command");
15067       ast_free(str);
15068       return 0;
15069    }
15070    /* Try to find the command in the table */
15071    for(i = 0 ; mct[i].cmd ; i++){
15072       if(!strcmp(mct[i].cmd, cmd))
15073          break;
15074    }
15075 
15076    if(!mct[i].cmd){ /* Found or not found ? */
15077       astman_send_error(s, m, "RptStatus unknown command");
15078       ast_free(str);
15079       return 0;
15080    }
15081    else
15082       idx = mct[i].index;
15083 
15084    switch(idx){ /* Use the index to go to the correct command */
15085 
15086       case MGRCMD_RPTSTAT:
15087          /* Return Nodes: and a comma separated list of nodes */
15088          if((res = snprintf(str, len, "Nodes: ")) > -1)
15089             len -= res;
15090          else{
15091             ast_free(str);
15092             return 0;
15093          }
15094          for(i = 0; i < nrpts; i++){
15095             if(i < nrpts - 1){
15096                if((res = snprintf(str+strlen(str), len, "%s,",rpt_vars[i].name)) < 0){
15097                   ast_free(str);
15098                   return 0;
15099                }
15100             }
15101             else{
15102                if((res = snprintf(str+strlen(str), len, "%s",rpt_vars[i].name)) < 0){
15103                   ast_free(str);
15104                   return 0;
15105                }
15106             }
15107             len -= res;
15108          }
15109 
15110          rpt_manager_success(s,m);
15111          
15112          if(!nrpts)
15113             astman_append(s, "<NONE>\r\n");
15114          else
15115             astman_append(s, "%s\r\n", str);
15116 
15117          uptime = (int)(now - starttime);
15118                         hours = uptime/3600;
15119                         uptime %= 3600;
15120                         minutes = uptime/60;
15121                         uptime %= 60;
15122 
15123                         astman_append(s, "RptUptime: %02d:%02d:%02d\r\n",
15124                                 hours, minutes, uptime);
15125 
15126          astman_append(s, "\r\n");
15127          break;      
15128 
15129       case  MGRCMD_NODESTAT:
15130          res = rpt_manager_do_stats(s,m,str);
15131          ast_free(str);
15132          return res;
15133 
15134       default:
15135          astman_send_error(s, m, "RptStatus invalid command");
15136          break;
15137    }
15138    ast_free(str);
15139    return 0;
15140 }
15141 
15142 #endif
15143 
15144 #ifdef   OLD_ASTERISK
15145 int unload_module()
15146 #else
15147 static int unload_module(void)
15148 #endif
15149 {
15150    int i, res;
15151 
15152 #ifdef   OLD_ASTERISK
15153    STANDARD_HANGUP_LOCALUSERS;
15154 #endif
15155    for(i = 0; i < nrpts; i++) {
15156       if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
15157                 ast_mutex_destroy(&rpt_vars[i].lock);
15158                 ast_mutex_destroy(&rpt_vars[i].remlock);
15159    }
15160    res = ast_unregister_application(app);
15161 
15162 #ifdef   NEW_ASTERISK
15163    ast_cli_unregister_multiple(rpt_cli, ARRAY_LEN(rpt_cli));
15164 #else
15165    /* Unregister cli extensions */
15166    ast_cli_unregister(&cli_debug);
15167    ast_cli_unregister(&cli_dump);
15168    ast_cli_unregister(&cli_stats);
15169    ast_cli_unregister(&cli_lstats);
15170    ast_cli_unregister(&cli_nodes);
15171    ast_cli_unregister(&cli_local_nodes);
15172    ast_cli_unregister(&cli_reload);
15173    ast_cli_unregister(&cli_restart);
15174    ast_cli_unregister(&cli_fun);
15175    ast_cli_unregister(&cli_fun1);
15176    res |= ast_cli_unregister(&cli_cmd);
15177 #endif
15178 #ifndef OLD_ASTERISK
15179    res |= ast_manager_unregister("RptLocalNodes");
15180    res |= ast_manager_unregister("RptStatus");
15181 #endif
15182    return res;
15183 }
15184 
15185 #ifdef   OLD_ASTERISK
15186 int load_module()
15187 #else
15188 static int load_module(void)
15189 #endif
15190 {
15191    int res;
15192    ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
15193 
15194 #ifdef   NEW_ASTERISK
15195    ast_cli_register_multiple(rpt_cli, ARRAY_LEN(rpt_cli));
15196    res = 0;
15197 #else
15198    /* Register cli extensions */
15199    ast_cli_register(&cli_debug);
15200    ast_cli_register(&cli_dump);
15201    ast_cli_register(&cli_stats);
15202    ast_cli_register(&cli_lstats);
15203    ast_cli_register(&cli_nodes);
15204    ast_cli_register(&cli_local_nodes);
15205    ast_cli_register(&cli_reload);
15206    ast_cli_register(&cli_restart);
15207    ast_cli_register(&cli_fun);
15208    ast_cli_register(&cli_fun1);
15209    res = ast_cli_register(&cli_cmd);
15210 #endif
15211 #ifndef OLD_ASTERISK
15212    res |= ast_manager_register("RptLocalNodes", 0, manager_rpt_local_nodes, "List local node numbers");
15213    res |= ast_manager_register("RptStatus", 0, manager_rpt_status, "Return Rpt Status for CGI");
15214 
15215 #endif
15216    res |= ast_register_application(app, rpt_exec, synopsis, descrip);
15217    return res;
15218 }
15219 
15220 #ifdef   OLD_ASTERISK
15221 char *description()
15222 {
15223    return tdesc;
15224 }
15225 int usecount(void)
15226 {
15227    int res;
15228    STANDARD_USECOUNT(res);
15229    return res;
15230 }
15231 
15232 char *key()
15233 {
15234    return ASTERISK_GPL_KEY;
15235 }
15236 #endif
15237 
15238 #ifdef   OLD_ASTERISK
15239 int reload()
15240 #else
15241 static int reload(void)
15242 #endif
15243 {
15244 int   n;
15245 
15246    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
15247    return(0);
15248 }
15249 
15250 
15251 #ifndef  OLD_ASTERISK
15252 /* STD_MOD(MOD_1, reload, NULL, NULL); */
15253 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application",
15254       .load = load_module,
15255       .unload = unload_module,
15256       .reload = reload,
15257           );
15258 #endif
15259 

Generated on Sat Feb 11 06:33:03 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6